Compare commits

...

19 Commits

Author SHA1 Message Date
Vladislav Khorev
3887208b8d Working on planet 2025-12-12 23:53:34 +03:00
Vladislav Khorev
4c837eff0a merge 2025-12-12 23:07:25 +03:00
Vladislav Khorev
8f9a18d960 Merge branch 'main' into spark 2025-12-12 22:45:57 +03:00
Vlad
bc49540a95 add blend 2025-12-12 17:12:03 +06:00
Vlad
d2605d9108 moved drawEffect() to SparkEmitter 2025-12-12 16:58:23 +06:00
Vlad
115cbbb7fa fix spark 2025-12-11 20:09:41 +06:00
ae1ca71a20 test 2025-12-11 06:42:02 +00:00
c02273d29d added ship velocity using dragging volume 2025-12-10 20:58:10 +06:00
fec7e08c2b added dragging scroll button for music volume 2025-12-10 20:39:09 +06:00
0f937e2e02 added music volume bar, without logic 2025-12-09 21:12:54 +06:00
Vlad
b855cff0e6 added sparks on the back of the spaceship 2025-12-08 19:28:47 +06:00
Vladislav Khorev
b768b27d49 update readme 2025-12-08 00:15:11 +03:00
Vladislav Khorev
c5044d42de merge 2025-12-08 00:08:37 +03:00
Vladislav Khorev
88bc764f08 Working 2025-12-07 19:14:33 +03:00
Vladislav Khorev
72a2b4c47c Fixing minor bugs 2025-12-07 17:48:23 +03:00
Vladislav Khorev
38f4f6b7fc Working on web 2025-12-07 16:46:43 +03:00
Vladislav Khorev
af00e77dc2 Added model 2025-12-05 22:43:57 +03:00
Vladislav Khorev
0322098efa Completed touch interface 2025-12-05 22:27:45 +03:00
Vladislav Khorev
2b19a3eaba Working 2025-12-05 21:27:57 +03:00
46 changed files with 33314 additions and 1545 deletions

3
.gitattributes vendored Normal file
View File

@ -0,0 +1,3 @@
*.bmp filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text

View File

@ -1,10 +1,12 @@
cmake_minimum_required(VERSION 3.16)
project(space_game001 LANGUAGES CXX)
project(space-game001 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(BUILD_CONFIGS Debug Release)
# ==============================
# Папка для всех сторонних либ
# ==============================
@ -16,7 +18,7 @@ macro(log msg)
endmacro()
# ===========================================
# 1) ZLIB (zlib131.zip zlib-1.3.1)
# 1) ZLIB (zlib131.zip zlib-1.3.1) - без изменений
# ===========================================
set(ZLIB_ARCHIVE "${THIRDPARTY_DIR}/zlib131.zip")
set(ZLIB_SRC_DIR "${THIRDPARTY_DIR}/zlib-1.3.1")
@ -50,9 +52,6 @@ file(MAKE_DIRECTORY "${ZLIB_BUILD_DIR}")
set(_have_zlib FALSE)
foreach(candidate
"${ZLIB_INSTALL_DIR}/lib/zlibstatic.lib"
"${ZLIB_INSTALL_DIR}/lib/zlib.lib"
"${ZLIB_INSTALL_DIR}/lib/zlibd.lib"
"${ZLIB_INSTALL_DIR}/lib/zlib1.lib"
)
if(EXISTS "${candidate}")
set(_have_zlib TRUE)
@ -60,6 +59,7 @@ foreach(candidate
endif()
endforeach()
if(NOT _have_zlib)
log("Configuring zlib ...")
execute_process(
@ -74,51 +74,45 @@ if(NOT _have_zlib)
message(FATAL_ERROR "zlib configure failed")
endif()
log("Building zlib (Debug) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--build "${ZLIB_BUILD_DIR}" --config Debug
RESULT_VARIABLE _zlib_build_res
)
if(NOT _zlib_build_res EQUAL 0)
message(FATAL_ERROR "zlib build failed")
endif()
foreach(cfg IN LISTS BUILD_CONFIGS)
log("Building ZLIB (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--build "${ZLIB_BUILD_DIR}" --config ${cfg}
RESULT_VARIABLE _zlib_build_res
)
if(NOT _zlib_build_res EQUAL 0)
message(FATAL_ERROR "ZLIB build failed for configuration ${cfg}")
endif()
log("Installing zlib (Debug) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--install "${ZLIB_BUILD_DIR}" --config Debug
RESULT_VARIABLE _zlib_inst_res
)
if(NOT _zlib_inst_res EQUAL 0)
message(FATAL_ERROR "zlib install failed")
endif()
endif()
set(ZLIB_LIB_FILE "")
foreach(candidate
"${ZLIB_INSTALL_DIR}/lib/zlibstatic.lib"
"${ZLIB_INSTALL_DIR}/lib/zlib.lib"
"${ZLIB_INSTALL_DIR}/lib/zlibd.lib"
"${ZLIB_INSTALL_DIR}/lib/zlib1.lib"
)
if(EXISTS "${candidate}")
set(ZLIB_LIB_FILE "${candidate}")
break()
endif()
endforeach()
if(ZLIB_LIB_FILE STREQUAL "")
message(FATAL_ERROR "Could not find zlib library in ${ZLIB_INSTALL_DIR}/lib")
log("Installing ZLIB (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--install "${ZLIB_BUILD_DIR}" --config ${cfg}
RESULT_VARIABLE _zlib_inst_res
)
if(NOT _zlib_inst_res EQUAL 0)
message(FATAL_ERROR "ZLIB install failed for configuration ${cfg}")
endif()
endforeach()
endif()
# ИСПРАВЛЕНИЕ: Используем свойства для конкретных конфигураций
add_library(zlib_external_lib UNKNOWN IMPORTED GLOBAL)
set_target_properties(zlib_external_lib PROPERTIES
IMPORTED_LOCATION "${ZLIB_LIB_FILE}"
# Динамическая линковка (если zlib.lib - это импорт-библиотека для zlibd.dll)
#IMPORTED_LOCATION_DEBUG "${ZLIB_INSTALL_DIR}/lib/zlibd.lib"
#IMPORTED_LOCATION_RELEASE "${ZLIB_INSTALL_DIR}/lib/zlib.lib"
# Можно также указать статические библиотеки, если вы хотите их использовать
IMPORTED_LOCATION_DEBUG "${ZLIB_INSTALL_DIR}/lib/zlibstaticd.lib"
IMPORTED_LOCATION_RELEASE "${ZLIB_INSTALL_DIR}/lib/zlibstatic.lib"
INTERFACE_INCLUDE_DIRECTORIES "${ZLIB_INSTALL_DIR}/include"
)
# ===========================================
# 2) SDL2 (release-2.32.10.zip SDL-release-2.32.10)
# 2) SDL2 (release-2.32.10.zip SDL-release-2.32.10) - без изменений
# ===========================================
set(SDL2_ARCHIVE "${THIRDPARTY_DIR}/release-2.32.10.zip")
set(SDL2_SRC_DIR "${THIRDPARTY_DIR}/SDL-release-2.32.10")
@ -175,66 +169,56 @@ if(NOT _have_sdl2)
message(FATAL_ERROR "SDL2 configure failed")
endif()
log("Building SDL2 (Debug) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--build "${SDL2_BUILD_DIR}" --config Debug
RESULT_VARIABLE _sdl_build_res
)
if(NOT _sdl_build_res EQUAL 0)
message(FATAL_ERROR "SDL2 build failed")
endif()
# --- ИЗМЕНЕНИЕ: Цикл по конфигурациям Debug и Release ---
foreach(cfg IN LISTS BUILD_CONFIGS)
log("Building SDL2 (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--build "${SDL2_BUILD_DIR}" --config ${cfg}
RESULT_VARIABLE _sdl_build_res
)
if(NOT _sdl_build_res EQUAL 0)
message(FATAL_ERROR "SDL2 build failed for configuration ${cfg}")
endif()
log("Installing SDL2 (Debug) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--install "${SDL2_BUILD_DIR}" --config Debug
RESULT_VARIABLE _sdl_inst_res
)
if(NOT _sdl_inst_res EQUAL 0)
message(FATAL_ERROR "SDL2 install failed")
endif()
log("Installing SDL2 (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--install "${SDL2_BUILD_DIR}" --config ${cfg}
RESULT_VARIABLE _sdl_inst_res
)
if(NOT _sdl_inst_res EQUAL 0)
message(FATAL_ERROR "SDL2 install failed for configuration ${cfg}")
endif()
endforeach()
# ------------------------------------------------------
endif()
set(SDL2_LIB_FILE "")
foreach(candidate
"${SDL2_INSTALL_DIR}/lib/SDL2.lib"
"${SDL2_INSTALL_DIR}/lib/SDL2-static.lib"
"${SDL2_INSTALL_DIR}/lib/SDL2d.lib"
)
if(EXISTS "${candidate}")
set(SDL2_LIB_FILE "${candidate}")
break()
endif()
endforeach()
if(SDL2_LIB_FILE STREQUAL "")
message(FATAL_ERROR "Could not find SDL2 library in ${SDL2_INSTALL_DIR}/lib")
endif()
set(SDL2MAIN_LIB_FILE "")
if(EXISTS "${SDL2_INSTALL_DIR}/lib/SDL2main.lib")
set(SDL2MAIN_LIB_FILE "${SDL2_INSTALL_DIR}/lib/SDL2main.lib")
endif()
# ИСПРАВЛЕНИЕ: SDL2: Используем свойства для конкретных конфигураций
add_library(SDL2_external_lib UNKNOWN IMPORTED GLOBAL)
set_target_properties(SDL2_external_lib PROPERTIES
IMPORTED_LOCATION "${SDL2_LIB_FILE}"
# Динамическая линковка SDL2
IMPORTED_LOCATION_DEBUG "${SDL2_INSTALL_DIR}/lib/SDL2d.lib"
IMPORTED_LOCATION_RELEASE "${SDL2_INSTALL_DIR}/lib/SDL2.lib"
# Оба include-пути: и include, и include/SDL2
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INSTALL_DIR}/include;${SDL2_INSTALL_DIR}/include/SDL2"
)
if(NOT SDL2MAIN_LIB_FILE STREQUAL "")
add_library(SDL2main_external_lib UNKNOWN IMPORTED GLOBAL)
set_target_properties(SDL2main_external_lib PROPERTIES
IMPORTED_LOCATION "${SDL2MAIN_LIB_FILE}"
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INSTALL_DIR}/include"
)
endif()
# SDL2main (обычно статическая)
add_library(SDL2main_external_lib UNKNOWN IMPORTED GLOBAL)
set_target_properties(SDL2main_external_lib PROPERTIES
# ИСПРАВЛЕНО: Указываем пути для Debug и Release, используя
# соглашение, что Debug имеет суффикс 'd', а Release нет.
IMPORTED_LOCATION_DEBUG "${SDL2_INSTALL_DIR}/lib/SDL2maind.lib"
IMPORTED_LOCATION_RELEASE "${SDL2_INSTALL_DIR}/lib/SDL2main.lib"
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INSTALL_DIR}/include"
)
log("-----${SDL2_INSTALL_DIR}/lib/SDL2maind.lib")
# ===========================================
# 3) libpng (v1.6.51.zip libpng-1.6.51)
# ВАЖНО: не вызываем "cmake --install",
# берём .lib из build/Debug
# 3) libpng (v1.6.51.zip libpng-1.6.51) - без изменений
# ===========================================
set(LIBPNG_ARCHIVE "${THIRDPARTY_DIR}/v1.6.51.zip")
set(LIBPNG_SRC_DIR "${THIRDPARTY_DIR}/libpng-1.6.51")
@ -265,18 +249,12 @@ endif()
file(MAKE_DIRECTORY "${LIBPNG_BUILD_DIR}")
# Проверяем, есть ли уже .lib (build/Debug или install/lib)
set(_have_png FALSE)
set(_libpng_candidates
"${LIBPNG_BUILD_DIR}/Debug/libpng16_staticd.lib"
"${LIBPNG_BUILD_DIR}/Debug/libpng16d.lib"
"${LIBPNG_BUILD_DIR}/Debug/png16d.lib"
"${LIBPNG_BUILD_DIR}/libpng16_staticd.lib"
"${LIBPNG_BUILD_DIR}/libpng16d.lib"
"${LIBPNG_INSTALL_DIR}/lib/libpng16_staticd.lib"
"${LIBPNG_INSTALL_DIR}/lib/libpng16d.lib"
"${LIBPNG_INSTALL_DIR}/lib/png16d.lib"
"${LIBPNG_BUILD_DIR}/Release/libpng16_static.lib"
)
set(_have_png FALSE)
foreach(candidate IN LISTS _libpng_candidates)
if(EXISTS "${candidate}")
set(_have_png TRUE)
@ -300,42 +278,141 @@ if(NOT _have_png)
message(FATAL_ERROR "libpng configure failed")
endif()
log("Building libpng (Debug) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--build "${LIBPNG_BUILD_DIR}" --config Debug
RESULT_VARIABLE _png_build_res
)
if(NOT _png_build_res EQUAL 0)
message(FATAL_ERROR "libpng build failed")
endif()
# без --install, чтобы не упереться в INSTALL target
endif()
# Ищем конкретный .lib для линковки
set(LIBPNG_LIB_FILE "")
foreach(candidate IN LISTS _libpng_candidates)
if(EXISTS "${candidate}")
set(LIBPNG_LIB_FILE "${candidate}")
break()
endif()
endforeach()
if(LIBPNG_LIB_FILE STREQUAL "")
message(FATAL_ERROR "Could not find libpng library (checked build/Debug and install/lib)")
# --- ИЗМЕНЕНИЕ: Цикл по конфигурациям Debug и Release ---
foreach(cfg IN LISTS BUILD_CONFIGS)
log("Building libpng (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--build "${LIBPNG_BUILD_DIR}" --config ${cfg}
RESULT_VARIABLE _png_build_res
)
if(NOT _png_build_res EQUAL 0)
message(FATAL_ERROR "libpng build failed for configuration ${cfg}")
endif()
# Поскольку вы не используете "cmake --install" для libpng,
# здесь нет необходимости в дополнительном шаге установки.
# Файлы .lib будут сгенерированы в подкаталоге ${LIBPNG_BUILD_DIR}/${cfg} (например, build/Debug или build/Release).
endforeach()
# ------------------------------------------------------
endif()
add_library(libpng_external_lib UNKNOWN IMPORTED GLOBAL)
set_target_properties(libpng_external_lib PROPERTIES
IMPORTED_LOCATION "${LIBPNG_LIB_FILE}"
# Предполагая, что libpng использует статический вариант
IMPORTED_LOCATION_DEBUG "${LIBPNG_BUILD_DIR}/Debug/libpng16_staticd.lib"
IMPORTED_LOCATION_RELEASE "${LIBPNG_BUILD_DIR}/Release/libpng16_static.lib"
# png.h, pngconf.h в SRC, pnglibconf.h в BUILD
INTERFACE_INCLUDE_DIRECTORIES "${LIBPNG_SRC_DIR};${LIBPNG_BUILD_DIR}"
)
# ===========================================
# Основной проект space_game001
# 4) libzip (v1.11.4.zip libzip-1.11.4) - НОВАЯ ЗАВИСИМОСТЬ
# ===========================================
add_executable(space_game001
set(LIBZIP_ARCHIVE "${THIRDPARTY_DIR}/v1.11.4.zip")
set(LIBZIP_SRC_DIR "${THIRDPARTY_DIR}/libzip-1.11.4")
set(LIBZIP_BUILD_DIR "${LIBZIP_SRC_DIR}/build")
#set(LIBZIP_INSTALL_DIR "${LIBZIP_SRC_DIR}/install")
set(LIBZIP_BASE_DIR "${LIBZIP_SRC_DIR}/install")
if(NOT EXISTS "${LIBZIP_ARCHIVE}")
log("Downloading libzip v1.11.4.zip ...")
file(DOWNLOAD
"https://github.com/nih-at/libzip/archive/refs/tags/v1.11.4.zip"
"${LIBZIP_ARCHIVE}"
SHOW_PROGRESS
)
endif()
if(NOT EXISTS "${LIBZIP_SRC_DIR}/CMakeLists.txt")
log("Extracting libzip v1.11.4.zip to libzip-1.11.4 ...")
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xvf "${LIBZIP_ARCHIVE}"
WORKING_DIRECTORY "${THIRDPARTY_DIR}"
RESULT_VARIABLE _zip_extract_res
)
if(NOT _zip_extract_res EQUAL 0)
message(FATAL_ERROR "Failed to extract libzip archive")
endif()
endif()
file(MAKE_DIRECTORY "${LIBZIP_BUILD_DIR}")
# Проверяем, собран ли уже libzip
set(_have_zip FALSE)
foreach(candidate
"${LIBZIP_BASE_DIR}-Debug/lib/zip.lib"
"${LIBZIP_BASE_DIR}-Release/lib/zip.lib"
)
if(EXISTS "${candidate}")
set(_have_zip TRUE)
break()
endif()
endforeach()
if(NOT _have_zip)
foreach(cfg IN LISTS BUILD_CONFIGS)
log("Configuring libzip (${cfg})...")
execute_process(
COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
-S "${LIBZIP_SRC_DIR}"
-B "${LIBZIP_SRC_DIR}/build-${cfg}"
-DCMAKE_INSTALL_PREFIX=${LIBZIP_BASE_DIR}-${cfg}
-DCMAKE_PREFIX_PATH=${ZLIB_INSTALL_DIR}
-DZLIB_ROOT=${ZLIB_INSTALL_DIR}
-DENABLE_COMMONCRYPTO=OFF
-DENABLE_GNUTLS=OFF
-DENABLE_MBEDTLS=OFF
-DENABLE_OPENSSL=OFF
-DENABLE_WINDOWS_CRYPTO=OFF
-DENABLE_FUZZ=OFF
RESULT_VARIABLE _zip_cfg_res
)
if(NOT _zip_cfg_res EQUAL 0)
message(FATAL_ERROR "libzip configure failed")
endif()
log("Building libzip (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND} --build "${LIBZIP_SRC_DIR}/build-${cfg}" --config ${cfg} -v
RESULT_VARIABLE _zip_build_res
)
if(NOT _zip_build_res EQUAL 0)
message(FATAL_ERROR "libzip build failed for configuration ${cfg}")
endif()
log("Installing libzip (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND} --install "${LIBZIP_SRC_DIR}/build-${cfg}" --config ${cfg} -v
RESULT_VARIABLE _zip_inst_res
)
if(NOT _zip_inst_res EQUAL 0)
message(FATAL_ERROR "libzip install failed for configuration ${cfg}")
endif()
endforeach()
endif()
add_library(libzip_external_lib UNKNOWN IMPORTED GLOBAL)
set_target_properties(libzip_external_lib PROPERTIES
IMPORTED_LOCATION_DEBUG "${LIBZIP_BASE_DIR}-Debug/lib/zip.lib" # ИСПРАВЛЕНО
IMPORTED_LOCATION_RELEASE "${LIBZIP_BASE_DIR}-Release/lib/zip.lib" # ИСПРАВЛЕНО
INTERFACE_INCLUDE_DIRECTORIES "$<IF:$<CONFIG:Debug>,${LIBZIP_BASE_DIR}-Debug/include,${LIBZIP_BASE_DIR}-Release/include>"
# libzip требует zlib для линковки
INTERFACE_LINK_LIBRARIES zlib_external_lib
)
# ===========================================
# Основной проект space-game001
# ===========================================
add_executable(space-game001
main.cpp
Game.cpp
Game.h
@ -353,68 +430,86 @@ add_executable(space_game001
AudioPlayerAsync.h
BoneAnimatedModel.cpp
BoneAnimatedModel.h
Math.cpp
ZLMath.cpp
ZLMath.h
OpenGlExtensions.cpp
OpenGlExtensions.h
Utils.cpp
Utils.h
SparkEmitter.cpp
SparkEmitter.h
PlanetObject.cpp
PlanetObject.h
)
# Установка проекта по умолчанию для Visual Studio
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT space-game001)
# include-пути проекта
target_include_directories(space_game001 PRIVATE
target_include_directories(space-game001 PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/gl"
"${CMAKE_CURRENT_SOURCE_DIR}/cmakeaudioplayer/include"
"${SDL2_INSTALL_DIR}/include"
"${SDL2_INSTALL_DIR}/include/SDL2"
#"${CMAKE_CURRENT_SOURCE_DIR}/gl"
#"${CMAKE_CURRENT_SOURCE_DIR}/cmakeaudioplayer/include"
#"${SDL2_INSTALL_DIR}/include"
#"${SDL2_INSTALL_DIR}/include/SDL2"
#"${LIBZIP_INSTALL_DIR}-Release/include" # Добавил include-путь для libzip
)
set_target_properties(space_game001 PROPERTIES
set_target_properties(space-game001 PROPERTIES
OUTPUT_NAME "space-game001"
)
# Определения препроцессора:
# PNG_ENABLED включает код PNG в TextureManager
# SDL_MAIN_HANDLED отключает переопределение main -> SDL_main
target_compile_definitions(space_game001 PRIVATE
target_compile_definitions(space-game001 PRIVATE
PNG_ENABLED
SDL_MAIN_HANDLED
)
# Линкуем с SDL2main, если он вообще установлен
if(TARGET SDL2main_external_lib)
target_link_libraries(space_game001 PRIVATE SDL2main_external_lib)
endif()
target_link_libraries(space-game001 PRIVATE SDL2main_external_lib)
# Линкуем сторонние библиотеки
target_link_libraries(space_game001 PRIVATE
target_link_libraries(space-game001 PRIVATE
SDL2_external_lib
libpng_external_lib
zlib_external_lib
libzip_external_lib
)
# Линкуем OpenGL (Windows)
if(WIN32)
target_link_libraries(space_game001 PRIVATE opengl32)
target_link_libraries(space-game001 PRIVATE opengl32)
endif()
# ===========================================
# Копирование SDL2d.dll и zlibd.dll рядом с exe
# ===========================================
if (WIN32)
add_custom_command(TARGET space_game001 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Copying SDL2d.dll and zlibd.dll to output folder..."
# SDL2: в Debug - SDL2d.dll, в Release - SDL2.dll
set(SDL2_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2_INSTALL_DIR}/bin/SDL2d.dll,${SDL2_INSTALL_DIR}/bin/SDL2.dll>")
set(SDL2_DLL_DST "$<IF:$<CONFIG:Debug>,$<TARGET_FILE_DIR:space-game001>/SDL2d.dll,$<TARGET_FILE_DIR:space-game001>/SDL2.dll>")
set(LIBZIP_DLL_SRC "$<IF:$<CONFIG:Debug>,${LIBZIP_BASE_DIR}-Debug/bin/zip.dll,${LIBZIP_BASE_DIR}-Release/bin/zip.dll>")
add_custom_command(TARGET space-game001 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Copying DLLs to output folder..."
# Копируем SDL2 (целевое имя всегда SDL2.dll)
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${SDL2_BUILD_DIR}/Debug/SDL2d.dll"
"$<TARGET_FILE_DIR:space_game001>/SDL2d.dll"
"${SDL2_DLL_SRC}"
"${SDL2_DLL_DST}"
# Копируем LIBZIP (целевое имя всегда zip.dll)
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${ZLIB_BUILD_DIR}/Debug/zlibd.dll"
"$<TARGET_FILE_DIR:space_game001>/zlibd.dll"
"${LIBZIP_DLL_SRC}"
"$<TARGET_FILE_DIR:space-game001>/zip.dll"
)
endif()
# ===========================================
# Копирование ресурсов после сборки
# ===========================================
@ -427,15 +522,15 @@ set(RUNTIME_RESOURCE_DIRS
# Копируем ресурсы и шейдеры в папку exe и в корень build/
foreach(resdir IN LISTS RUNTIME_RESOURCE_DIRS)
add_custom_command(TARGET space_game001 POST_BUILD
add_custom_command(TARGET space-game001 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Copying ${resdir} to runtime folders..."
# 1) туда, где лежит exe (build/Debug, build/Release и т.п.)
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_SOURCE_DIR}/${resdir}"
"$<TARGET_FILE_DIR:space_game001>/${resdir}"
"$<TARGET_FILE_DIR:space-game001>/${resdir}"
# 2) в корень build, если захочешь запускать из этой папки
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_SOURCE_DIR}/${resdir}"
"${CMAKE_BINARY_DIR}/${resdir}"
)
endforeach()
endforeach()

View File

@ -8,19 +8,13 @@ namespace ZL {
int Environment::windowHeaderHeight = 0;
int Environment::width = 0;
int Environment::height = 0;
float Environment::zoom = 20.f;
float Environment::zoom = 14.f;
bool Environment::leftPressed = false;
bool Environment::rightPressed = false;
bool Environment::upPressed = false;
bool Environment::downPressed = false;
Vector3f Environment::cameraShift = {0, 0, 0};
Vector3f Environment::characterPos = {0, 0, 0};
float Environment::cameraPhi = 0.f;
float Environment::cameraAlpha = 0.3*M_PI / 2.0;
bool Environment::settings_inverseVertical = false;
SDL_Window* Environment::window = nullptr;
@ -29,6 +23,17 @@ bool Environment::showMouse = false;
bool Environment::exitGameLoop = false;
Matrix3f Environment::shipMatrix = Matrix3f::Identity();
Matrix3f Environment::inverseShipMatrix = Matrix3f::Identity();
bool Environment::tapDownHold = false;
Vector2f Environment::tapDownStartPos = { 0, 0 };
Vector2f Environment::tapDownCurrentPos = { 0, 0 };
Vector3f Environment::shipPosition = {0,0,0};
float Environment::shipVelocity = 0.f;
} // namespace ZL

View File

@ -19,21 +19,25 @@ public:
static bool upPressed;
static bool downPressed;
static Vector3f cameraShift;
static Vector3f characterPos;
static float cameraPhi;
static float cameraAlpha;
static bool settings_inverseVertical;
static Matrix3f shipMatrix;
static Matrix3f inverseShipMatrix;
static SDL_Window* window;
static bool showMouse;
static bool exitGameLoop;
static bool tapDownHold;
static Vector2f tapDownStartPos;
static Vector2f tapDownCurrentPos;
static Vector3f shipPosition;
static float shipVelocity;
};
} // namespace ZL

717
Game.cpp
View File

@ -1,4 +1,4 @@
#include "Game.h"
#include "Game.h"
#include "AnimatedModel.h"
#include "BoneAnimatedModel.h"
#include "Utils.h"
@ -6,160 +6,621 @@
#include <iostream>
#include "TextureManager.h"
#include "TextModel.h"
#include <random>
#include <cmath>
namespace ZL
{
const char* CONST_ZIP_FILE = "";
Game::Game()
: window(nullptr)
, glContext(nullptr)
, newTickCount(0)
, lastTickCount(0)
{
}
Game::~Game() {
if (glContext) {
SDL_GL_DeleteContext(glContext);
}
if (window) {
SDL_DestroyWindow(window);
}
SDL_Quit();
}
void Game::setup() {
glContext = SDL_GL_CreateContext(ZL::Environment::window);
ZL::BindOpenGlFunctions();
ZL::CheckGlError();
// Initialize renderer
#ifdef EMSCRIPTEN
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_web.fragment", CONST_ZIP_FILE);
const char* CONST_ZIP_FILE = "space-game001.zip";
#else
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_desktop.fragment", CONST_ZIP_FILE);
const char* CONST_ZIP_FILE = "";
#endif
//Load texture
spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sship001x.png"));
spaceshipBase = LoadFromTextFile02("./resources/spaceship004.txt");
spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0)));
spaceship.AssignFrom(spaceshipBase);
spaceship.RefreshVBO();
Vector4f generateRandomQuaternion(std::mt19937& gen)
{
// Ðàñïðåäåëåíèå äëÿ ãåíåðàöèè ñëó÷àéíûõ êîîðäèíàò êâàòåðíèîíà
std::normal_distribution<> distrib(0.0, 1.0);
// Ãåíåðèðóåì ÷åòûðå ñëó÷àéíûõ ÷èñëà èç íîðìàëüíîãî ðàñïðåäåëåíèÿ N(0, 1).
// Íîðìàëèçàöèÿ ýòîãî âåêòîðà äàåò ðàâíîìåðíîå ðàñïðåäåëåíèå ïî 4D-ñôåðå (ò.å. êâàòåðíèîí åäèíè÷íîé äëèíû).
Vector4f randomQuat = {
(float)distrib(gen),
(float)distrib(gen),
(float)distrib(gen),
(float)distrib(gen)
};
return randomQuat.normalized();
}
renderer.InitOpenGL();
}
// --- Îñíîâíàÿ ôóíêöèÿ ãåíåðàöèè ---
std::vector<BoxCoords> generateRandomBoxCoords(int N)
{
// Êîíñòàíòû
const float MIN_DISTANCE = 3.0f;
const float MIN_DISTANCE_SQUARED = MIN_DISTANCE * MIN_DISTANCE; // Ðàáîòàåì ñ êâàäðàòîì ðàññòîÿíèÿ
const float MIN_COORD = -100.0f;
const float MAX_COORD = 100.0f;
const int MAX_ATTEMPTS = 1000; // Îãðàíè÷åíèå íà êîëè÷åñòâî ïîïûòîê, ÷òîáû èçáåæàòü áåñêîíå÷íîãî öèêëà
void Game::drawScene() {
static const std::string defaultShaderName = "default";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
std::vector<BoxCoords> boxCoordsArr;
boxCoordsArr.reserve(N); // Ðåçåðâèðóåì ïàìÿòü
glClearColor(0.0f, 0.5f, 1.0f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
// 1. Èíèöèàëèçàöèÿ ãåíåðàòîðà ïñåâäîñëó÷àéíûõ ÷èñåë
// Èñïîëüçóåì Mersenne Twister (mt19937) êàê âûñîêîêà÷åñòâåííûé ãåíåðàòîð
std::random_device rd;
std::mt19937 gen(rd());
glViewport(0, 0, Environment::width, Environment::height);
// 2. Îïðåäåëåíèå ðàâíîìåðíîãî ðàñïðåäåëåíèÿ äëÿ êîîðäèíàò [MIN_COORD, MAX_COORD]
std::uniform_real_distribution<> distrib(MIN_COORD, MAX_COORD);
CheckGlError();
int generatedCount = 0;
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
while (generatedCount < N)
{
bool accepted = false;
int attempts = 0;
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
1, 1000);
renderer.PushMatrix();
// Ïîïûòêà íàéòè ïîäõîäÿùèå êîîðäèíàòû
while (!accepted && attempts < MAX_ATTEMPTS)
{
// Ãåíåðèðóåì íîâûå ñëó÷àéíûå êîîðäèíàòû
Vector3f newPos(
(float)distrib(gen),
(float)distrib(gen),
(float)distrib(gen)
);
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0,0, -1.0f*Environment::zoom });
renderer.RotateMatrix(QuatFromRotateAroundX(M_PI/6.0));
//renderer.RotateMatrix(QuatFromRotateAroundX(Environment::cameraAlpha));
// Ïðîâåðêà ðàññòîÿíèÿ äî âñåõ óæå ñóùåñòâóþùèõ îáúåêòîâ
accepted = true; // Ïðåäïîëàãàåì, ÷òî ïîäõîäèò, ïîêà íå äîêàçàíî îáðàòíîå
for (const auto& existingBox : boxCoordsArr)
{
// Ðàñ÷åò âåêòîðà ðàçíîñòè
Vector3f diff = newPos - existingBox.pos;
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
renderer.DrawVertexRenderStruct(spaceship);
// Ðàñ÷åò êâàäðàòà ðàññòîÿíèÿ
float distanceSquared = diff.squaredNorm();
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
// Åñëè êâàäðàò ðàññòîÿíèÿ ìåíüøå êâàäðàòà ìèíèìàëüíîãî ðàññòîÿíèÿ
if (distanceSquared < MIN_DISTANCE_SQUARED)
{
accepted = false; // Îòêëîíÿåì, ñëèøêîì áëèçêî
break; // Íåò ñìûñëà ïðîâåðÿòü äàëüøå, åñëè îäíî íàðóøåíèå íàéäåíî
}
}
renderer.shaderManager.PopShader();
if (accepted)
{
// 2. Ãåíåðèðóåì ñëó÷àéíûé êâàòåðíèîí
Vector4f randomQuat = generateRandomQuaternion(gen);
CheckGlError();
}
// 3. Ïðåîáðàçóåì åãî â ìàòðèöó âðàùåíèÿ
Matrix3f randomMatrix = QuatToMatrix(randomQuat);
void Game::processTickCount() {
// 4. Äîáàâëÿåì îáúåêò ñ íîâîé ñëó÷àéíîé ìàòðèöåé
boxCoordsArr.emplace_back(BoxCoords{ newPos, randomMatrix });
generatedCount++;
}
attempts++;
}
if (lastTickCount == 0) {
lastTickCount = SDL_GetTicks64();
return;
}
newTickCount = SDL_GetTicks64();
if (newTickCount - lastTickCount > CONST_TIMER_INTERVAL) {
size_t delta = (newTickCount - lastTickCount > CONST_MAX_TIME_INTERVAL) ?
CONST_MAX_TIME_INTERVAL : newTickCount - lastTickCount;
//gameObjects.updateScene(delta);
// Åñëè ïðåâûøåíî ìàêñèìàëüíîå êîëè÷åñòâî ïîïûòîê, âûõîäèì èç öèêëà,
// ÷òîáû èçáåæàòü çàâèñàíèÿ, åñëè N ñëèøêîì âåëèêî èëè äèàïàçîí ñëèøêîì ìàë.
if (!accepted) {
std::cerr << "Ïðåäóïðåæäåíèå: Íå óäàëîñü ñãåíåðèðîâàòü " << N << " îáúåêòîâ. Ñãåíåðèðîâàíî: " << generatedCount << std::endl;
break;
}
}
Environment::cameraAlpha = Environment::cameraAlpha + delta * M_PI / 10000.f;
lastTickCount = newTickCount;
}
}
return boxCoordsArr;
}
void Game::render() {
SDL_GL_MakeCurrent(ZL::Environment::window, glContext);
ZL::CheckGlError();
Game::Game()
: window(nullptr)
, glContext(nullptr)
, newTickCount(0)
, lastTickCount(0)
{
std::vector<Vector3f> emissionPoints = {
Vector3f{-2.1f, 0.9f, 5.0f},
Vector3f{2.1f, 0.9f, 5.0f}
};
sparkEmitter = SparkEmitter(emissionPoints, 100.0f);
}
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawScene();
processTickCount();
Game::~Game() {
if (glContext) {
SDL_GL_DeleteContext(glContext);
}
if (window) {
SDL_DestroyWindow(window);
}
SDL_Quit();
}
SDL_GL_SwapWindow(ZL::Environment::window);
}
void Game::setup() {
glContext = SDL_GL_CreateContext(ZL::Environment::window);
void Game::update() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
Environment::exitGameLoop = true;
}
else if (event.type == SDL_MOUSEWHEEL) {
static const float zoomstep = 2.0f;
if (event.wheel.y > 0) {
Environment::zoom -= zoomstep;
}
else if (event.wheel.y < 0) {
Environment::zoom += zoomstep;
}
if (Environment::zoom < zoomstep) {
Environment::zoom = zoomstep;
}
/*if (Environment::zoom > 4) {
Environment::zoom = 4;
}*/
ZL::BindOpenGlFunctions();
ZL::CheckGlError();
//this->modelMeshRender.data.Scale(0.5);
//this->modelMeshRender.RefreshVBO();
}
// Initialize renderer
}
render();
}
#ifdef EMSCRIPTEN
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_web.fragment", CONST_ZIP_FILE);
} // namespace ZL
#else
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_desktop.fragment", CONST_ZIP_FILE);
#endif
cubemapTexture = std::make_shared<Texture>(
std::array<TextureDataStruct, 6>{
CreateTextureDataFromBmp24("./resources/sky/space_rt.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_lf.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_up.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_dn.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_bk.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_ft.bmp", CONST_ZIP_FILE)
});
cubemap.data = ZL::CreateCubemap(500);
cubemap.RefreshVBO();
//Load texture
spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/DefaultMaterial_BaseColor.png", CONST_ZIP_FILE));
spaceshipBase = LoadFromTextFile02("./resources/spaceship005.txt", CONST_ZIP_FILE);
spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0)));
//spaceshipBase.Move(Vector3f{ -0.52998, -13, 0 });
spaceshipBase.Move(Vector3f{ -0.52998, -10, 10 });
spaceship.AssignFrom(spaceshipBase);
spaceship.RefreshVBO();
//Boxes
boxTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/box/box.png", CONST_ZIP_FILE));
boxBase = LoadFromTextFile02("./resources/box/box.txt", CONST_ZIP_FILE);
boxCoordsArr = generateRandomBoxCoords(50);
boxRenderArr.resize(boxCoordsArr.size());
for (int i = 0; i < boxCoordsArr.size(); i++)
{
boxRenderArr[i].AssignFrom(boxBase);
boxRenderArr[i].RefreshVBO();
}
sparkTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/spark.png", CONST_ZIP_FILE));
sparkEmitter.setTexture(sparkTexture);
buttonTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/button.png", CONST_ZIP_FILE));
button.data.PositionData.push_back({ 100, 100, 0 });
button.data.PositionData.push_back({ 100, 150, 0 });
button.data.PositionData.push_back({ 300, 150, 0 });
button.data.PositionData.push_back({ 100, 100, 0 });
button.data.PositionData.push_back({ 300, 150, 0 });
button.data.PositionData.push_back({ 300, 100, 0 });
button.data.TexCoordData.push_back({ 0,0 });
button.data.TexCoordData.push_back({ 0,1 });
button.data.TexCoordData.push_back({ 1,1 });
button.data.TexCoordData.push_back({ 0,0 });
button.data.TexCoordData.push_back({ 1,1 });
button.data.TexCoordData.push_back({ 1,0 });
button.RefreshVBO();
musicVolumeBarTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/musicVolumeBarTexture.png", CONST_ZIP_FILE));
musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 });
musicVolumeBar.data.PositionData.push_back({ 1190, 600, 0 });
musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 });
musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 });
musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 });
musicVolumeBar.data.PositionData.push_back({ 1200, 100, 0 });
musicVolumeBar.data.TexCoordData.push_back({ 0,0 });
musicVolumeBar.data.TexCoordData.push_back({ 0,1 });
musicVolumeBar.data.TexCoordData.push_back({ 1,1 });
musicVolumeBar.data.TexCoordData.push_back({ 0,0 });
musicVolumeBar.data.TexCoordData.push_back({ 1,1 });
musicVolumeBar.data.TexCoordData.push_back({ 1,0 });
musicVolumeBar.RefreshVBO();
musicVolumeBarButtonTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/musicVolumeBarButton.png", CONST_ZIP_FILE));
float musicVolumeBarButtonButtonCenterY = 350.0f;
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 });
musicVolumeBarButton.data.TexCoordData.push_back({ 0,1 });
musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 });
musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 });
musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 });
musicVolumeBarButton.data.TexCoordData.push_back({ 1,0 });
musicVolumeBarButton.RefreshVBO();
renderer.InitOpenGL();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
planetObject.init();
}
void Game::drawCubemap()
{
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(envShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
1, 1000);
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.RotateMatrix(Environment::inverseShipMatrix);
CheckGlError();
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture->getTexID());
renderer.DrawVertexRenderStruct(cubemap);
CheckGlError();
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.shaderManager.PopShader();
CheckGlError();
}
void Game::drawShip()
{
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
1, 1000);
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
renderer.DrawVertexRenderStruct(spaceship);
sparkEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader();
CheckGlError();
}
void Game::drawBoxes()
{
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
1, 1000);
for (int i = 0; i < boxCoordsArr.size(); i++)
{
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
renderer.RotateMatrix(Environment::inverseShipMatrix);
renderer.TranslateMatrix(-Environment::shipPosition);
renderer.TranslateMatrix(boxCoordsArr[i].pos);
renderer.RotateMatrix(boxCoordsArr[i].m);
glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID());
renderer.DrawVertexRenderStruct(boxRenderArr[i]);
renderer.PopMatrix();
}
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader();
CheckGlError();
}
void Game::UpdateVolumeKnob() {
float musicVolumeBarButtonButtonCenterY = volumeBarMinY + musicVolume * (volumeBarMaxY - volumeBarMinY);
auto& pos = musicVolumeBarButton.data.PositionData;
pos[0] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
pos[1] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
pos[2] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
pos[3] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
pos[4] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
pos[5] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
musicVolumeBarButton.RefreshVBO();
}
void Game::UpdateVolumeFromMouse(int mouseX, int mouseY) {
int uiX = mouseX;
int uiY = Environment::height - mouseY;
Environment::shipVelocity = (musicVolume) * (20.0);
if (uiY < volumeBarMinY || uiY > volumeBarMaxY)
{
return;
}
float t = (uiY - volumeBarMinY) / (volumeBarMaxY - volumeBarMinY);
if (t < 0.0f) t = 0.0f;
if (t > 1.0f) t = 1.0f;
musicVolume = t;
UpdateVolumeKnob();
}
void Game::drawUI()
{
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
glClear(GL_DEPTH_BUFFER_BIT);
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
renderer.PushProjectionMatrix(Environment::width, Environment::height, -1, 1);
renderer.PushMatrix();
renderer.LoadIdentity();
glBindTexture(GL_TEXTURE_2D, buttonTexture->getTexID());
renderer.DrawVertexRenderStruct(button);
glBindTexture(GL_TEXTURE_2D, musicVolumeBarTexture->getTexID());
renderer.DrawVertexRenderStruct(musicVolumeBar);
glBindTexture(GL_TEXTURE_2D, musicVolumeBarButtonTexture->getTexID());
renderer.DrawVertexRenderStruct(musicVolumeBarButton);
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader();
CheckGlError();
}
void Game::drawScene() {
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
glClearColor(0.0f, 0.5f, 1.0f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glViewport(0, 0, Environment::width, Environment::height);
CheckGlError();
drawCubemap();
drawShip();
planetObject.draw(renderer);
drawBoxes();
drawUI();
CheckGlError();
}
void Game::processTickCount() {
if (lastTickCount == 0) {
lastTickCount = SDL_GetTicks64();
return;
}
newTickCount = SDL_GetTicks64();
if (newTickCount - lastTickCount > CONST_TIMER_INTERVAL) {
size_t delta = (newTickCount - lastTickCount > CONST_MAX_TIME_INTERVAL) ?
CONST_MAX_TIME_INTERVAL : newTickCount - lastTickCount;
//gameObjects.updateScene(delta);
sparkEmitter.update(static_cast<float>(delta));
if (Environment::tapDownHold) {
float diffx = Environment::tapDownCurrentPos.v[0] - Environment::tapDownStartPos.v[0];
float diffy = Environment::tapDownCurrentPos.v[1] - Environment::tapDownStartPos.v[1];
if (abs(diffy) > 5.0 || abs(diffx) > 5.0) //threshold
{
float rotationPower = sqrtf(diffx * diffx + diffy * diffy);
//std::cout << rotationPower << std::endl;
float deltaAlpha = rotationPower * delta * M_PI / 500000.f;
Vector3f rotationDirection = { diffy, diffx, 0 };
rotationDirection = rotationDirection.normalized();
Vector4f rotateQuat = {
rotationDirection.v[0] * sin(deltaAlpha * 0.5f),
rotationDirection.v[1] * sin(deltaAlpha * 0.5f),
rotationDirection.v[2] * sin(deltaAlpha * 0.5f),
cos(deltaAlpha * 0.5f) };
Matrix3f rotateMat = QuatToMatrix(rotateQuat);
Environment::shipMatrix = MultMatrixMatrix(Environment::shipMatrix, rotateMat);
Environment::inverseShipMatrix = InverseMatrix(Environment::shipMatrix);
}
}
if (fabs(Environment::shipVelocity) > 0.01f)
{
Vector3f velocityDirection = { 0,0, -Environment::shipVelocity * delta / 1000.f };
Vector3f velocityDirectionAdjusted = MultMatrixVector(Environment::shipMatrix, velocityDirection);
Environment::shipPosition = Environment::shipPosition + velocityDirectionAdjusted;
}
lastTickCount = newTickCount;
}
}
void Game::render() {
SDL_GL_MakeCurrent(ZL::Environment::window, glContext);
ZL::CheckGlError();
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawScene();
processTickCount();
SDL_GL_SwapWindow(ZL::Environment::window);
}
void Game::update() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
Environment::exitGameLoop = true;
}
else if (event.type == SDL_MOUSEBUTTONDOWN) {
// 1. Îáðàáîòêà íàæàòèÿ êíîïêè ìûøè
int mx = event.button.x;
int my = event.button.y;
std::cout << mx << " " << my << '\n';
int uiX = mx;
int uiY = Environment::height - my;
if (uiX >= volumeBarMinX - 40 && uiX <= volumeBarMaxX + 40 &&
uiY >= volumeBarMinY - 40 && uiY <= volumeBarMaxY + 40) {
isDraggingVolume = true;
UpdateVolumeFromMouse(mx, my);
}
else {
Environment::tapDownHold = true;
// Êîîðäèíàòû íà÷àëüíîãî íàæàòèÿ
Environment::tapDownStartPos.v[0] = event.button.x;
Environment::tapDownStartPos.v[1] = event.button.y;
// Íà÷àëüíàÿ ïîçèöèÿ òàêæå ñòàíîâèòñÿ òåêóùåé
Environment::tapDownCurrentPos.v[0] = event.button.x;
Environment::tapDownCurrentPos.v[1] = event.button.y;
}
}
else if (event.type == SDL_MOUSEBUTTONUP) {
// 2. Îáðàáîòêà îòïóñêàíèÿ êíîïêè ìûøè
isDraggingVolume = false;
Environment::tapDownHold = false;
}
else if (event.type == SDL_MOUSEMOTION) {
// 3. Îáðàáîòêà ïåðåìåùåíèÿ ìûøè
int mx = event.motion.x;
int my = event.motion.y;
if (isDraggingVolume) {
// Äâèãàåì ìûøü ïî ñëàéäåðó — ìåíÿåì ãðîìêîñòü è ïîçèöèþ êðóæêà
UpdateVolumeFromMouse(mx, my);
}
if (Environment::tapDownHold) {
// Îáíîâëåíèå òåêóùåé ïîçèöèè, åñëè êíîïêà óäåðæèâàåòñÿ
Environment::tapDownCurrentPos.v[0] = event.motion.x;
Environment::tapDownCurrentPos.v[1] = event.motion.y;
}
}
else if (event.type == SDL_MOUSEWHEEL) {
static const float zoomstep = 2.0f;
if (event.wheel.y > 0) {
Environment::zoom -= zoomstep;
}
else if (event.wheel.y < 0) {
Environment::zoom += zoomstep;
}
if (Environment::zoom < zoomstep) {
Environment::zoom = zoomstep;
}
}
else if (event.type == SDL_KEYUP)
{
if (event.key.keysym.sym == SDLK_i)
{
Environment::shipVelocity += 1.f;
}
if (event.key.keysym.sym == SDLK_k)
{
Environment::shipVelocity -= 1.f;
}
}
}
render();
}
} // namespace ZL

106
Game.h
View File

@ -1,40 +1,92 @@
#pragma once
#pragma once
#include "OpenGlExtensions.h"
#include "Renderer.h"
#include "Environment.h"
#include "TextureManager.h"
#include "SparkEmitter.h"
#include "PlanetObject.h"
namespace ZL {
class Game {
public:
Game();
~Game();
void setup();
void update();
void render();
bool shouldExit() const { return Environment::exitGameLoop; }
private:
void processTickCount();
void drawScene();
struct BoxCoords
{
Vector3f pos;
Matrix3f m;
};
SDL_Window* window;
SDL_GLContext glContext;
Renderer renderer;
size_t newTickCount;
size_t lastTickCount;
static const size_t CONST_TIMER_INTERVAL = 10;
static const size_t CONST_MAX_TIME_INTERVAL = 1000;
std::shared_ptr<Texture> spaceshipTexture;
VertexDataStruct spaceshipBase;
VertexRenderStruct spaceship;
};
class Game {
public:
Game();
~Game();
void setup();
void update();
void render();
bool shouldExit() const { return Environment::exitGameLoop; }
private:
void processTickCount();
void drawScene();
void drawCubemap();
void drawShip();
void drawBoxes();
void drawUI();
SDL_Window* window;
SDL_GLContext glContext;
Renderer renderer;
size_t newTickCount;
size_t lastTickCount;
std::vector<BoxCoords> boxCoordsArr;
std::vector<VertexRenderStruct> boxRenderArr;
std::shared_ptr<Texture> buttonTexture;
VertexRenderStruct button;
std::shared_ptr<Texture> musicVolumeBarTexture;
VertexRenderStruct musicVolumeBar;
std::shared_ptr<Texture> musicVolumeBarButtonTexture;
VertexRenderStruct musicVolumeBarButton;
bool isDraggingVolume = false;
float musicVolume = 0.0f;
float volumeBarMinX = 1190.0f;
float volumeBarMaxX = 1200.0f;
float volumeBarMinY = 100.0f;
float volumeBarMaxY = 600.0f;
float musicVolumeBarButtonButtonCenterX = 1195.0f;
float musicVolumeBarButtonButtonRadius = 25.0f;
void UpdateVolumeFromMouse(int mouseX, int mouseY);
void UpdateVolumeKnob();
static const size_t CONST_TIMER_INTERVAL = 10;
static const size_t CONST_MAX_TIME_INTERVAL = 1000;
std::shared_ptr<Texture> sparkTexture;
std::shared_ptr<Texture> spaceshipTexture;
std::shared_ptr<Texture> cubemapTexture;
VertexDataStruct spaceshipBase;
VertexRenderStruct spaceship;
VertexRenderStruct cubemap;
std::shared_ptr<Texture> boxTexture;
VertexDataStruct boxBase;
SparkEmitter sparkEmitter;
PlanetObject planetObject;
};
} // namespace ZL

292
PlanetObject.cpp Normal file
View File

@ -0,0 +1,292 @@
#include "PlanetObject.h"
#include <random>
#include <cmath>
#include "OpenGlExtensions.h"
#include "Environment.h"
namespace ZL {
struct Triangle
{
std::array<Vector3f, 3> data;
Triangle(Vector3f p1, Vector3f p2, Vector3f p3)
: data{ p1, p2, p3 }
{
}
};
std::vector<Triangle> subdivideTriangles(const std::vector<Triangle>& inputTriangles, PerlinNoise& perlin) {
std::vector<Triangle> output;
output.reserve(inputTriangles.size() * 4);
for (const auto& t : inputTriangles) {
Vector3f a = t.data[0];
Vector3f b = t.data[1];
Vector3f c = t.data[2];
// 1. Вычисляем "сырые" середины
Vector3f m_ab = (a + b) * 0.5f;
Vector3f m_bc = (b + c) * 0.5f;
Vector3f m_ac = (a + c) * 0.5f;
// 2. Нормализуем их (получаем идеальную сферу радиуса 1)
m_ab = m_ab.normalized();
m_bc = m_bc.normalized();
m_ac = m_ac.normalized();
// 3. ПРИМЕНЯЕМ ШУМ: Смещаем точку по радиусу
m_ab = m_ab * perlin.getSurfaceHeight(m_ab);
m_bc = m_bc * perlin.getSurfaceHeight(m_bc);
m_ac = m_ac * perlin.getSurfaceHeight(m_ac);
// 4. Формируем новые треугольники
output.emplace_back(a, m_ab, m_ac);
output.emplace_back(m_ab, b, m_bc);
output.emplace_back(m_ac, m_bc, c);
output.emplace_back(m_ab, m_bc, m_ac);
}
return output;
}
Vector3f calculateSurfaceNormal(Vector3f p_sphere, PerlinNoise& perlin) {
// p_sphere - это нормализованный вектор (точка на идеальной сфере)
float theta = 0.01f; // Шаг для "щупанья" соседей (epsilon)
// Нам нужно найти два вектора, касательных к сфере в точке p_sphere.
// Для этого берем любой вектор (например UP), делаем Cross Product, чтобы получить касательную.
// Если p_sphere совпадает с UP, берем RIGHT.
Vector3f up = Vector3f(0.0f, 1.0f, 0.0f);
if (abs(p_sphere.dot(up)) > 0.99f) {
up = Vector3f(1.0f, 0.0f, 0.0f);
}
Vector3f tangentX = (up.cross(p_sphere)).normalized();
Vector3f tangentY = (p_sphere.cross(tangentX)).normalized();
// Точки на идеальной сфере со смещением
Vector3f p0_dir = p_sphere;
Vector3f p1_dir = (p_sphere + tangentX * theta).normalized();
Vector3f p2_dir = (p_sphere + tangentY * theta).normalized();
// Реальные точки на искаженной поверхности
// p = dir * height(dir)
Vector3f p0 = p0_dir * perlin.getSurfaceHeight(p0_dir);
Vector3f p1 = p1_dir * perlin.getSurfaceHeight(p1_dir);
Vector3f p2 = p2_dir * perlin.getSurfaceHeight(p2_dir);
// Вектора от центральной точки к соседям
Vector3f v1 = p1 - p0;
Vector3f v2 = p2 - p0;
// Нормаль - это перпендикуляр к этим двум векторам
// Порядок (v2, v1) или (v1, v2) зависит от системы координат,
// здесь подбираем так, чтобы нормаль смотрела наружу.
return (-v2.cross(v1)).normalized();
}
VertexDataStruct trianglesToVertices(const std::vector<Triangle>& triangles, PerlinNoise& perlin) {
VertexDataStruct buffer;
buffer.PositionData.reserve(triangles.size() * 3);
buffer.NormalData.reserve(triangles.size() * 3);
for (const auto& t : triangles) {
// Проходим по всем 3 вершинам треугольника
for (int i = 0; i < 3; i++) {
// p_geometry - это уже точка на поверхности (с шумом)
Vector3f p_geometry = t.data[i];
// Нам нужно восстановить направление от центра к этой точке,
// чтобы передать его в функцию расчета нормали.
// Так как (0,0,0) - центр, то normalize(p) даст нам направление.
Vector3f p_dir = p_geometry.normalized();
// Считаем аналитическую нормаль для этой конкретной точки
Vector3f normal = calculateSurfaceNormal(p_dir, perlin);
buffer.PositionData.push_back({ p_geometry });
//buffer.NormalData.push_back({ normal });
//buffer.TexCoordData.push_back({ 0.0f, 0.0f });
}
}
return buffer;
}
// Генерация геометрии октаэдра с дублированием вершин для Flat Shading
VertexDataStruct generateOctahedron(PerlinNoise& perlin) {
VertexDataStruct buffer;
std::vector<Triangle> v = {
Triangle{
{ 0.0f, 1.0f, 0.0f}, // Top
{ 0.0f, 0.0f, 1.0f}, // Front
{ 1.0f, 0.0f, 0.0f}, // Right
},
Triangle{
{ 0.0f, 1.0f, 0.0f}, // Top
{ 1.0f, 0.0f, 0.0f}, // Right
{ 0.0f, 0.0f, -1.0f}, // Back
},
Triangle{
{ 0.0f, 1.0f, 0.0f}, // Top
{ 0.0f, 0.0f, -1.0f}, // Back
{-1.0f, 0.0f, 0.0f}, // Left
},
Triangle{
{ 0.0f, 1.0f, 0.0f}, // Top
{-1.0f, 0.0f, 0.0f}, // Left
{ 0.0f, 0.0f, 1.0f}, // Front
},
Triangle{
{ 0.0f, -1.0f, 0.0f}, // Bottom
{ 1.0f, 0.0f, 0.0f}, // Right
{ 0.0f, 0.0f, 1.0f}, // Front
},
Triangle{
{ 0.0f, -1.0f, 0.0f}, // Bottom
{ 0.0f, 0.0f, 1.0f}, // Front
{-1.0f, 0.0f, 0.0f}, // Left
},
Triangle{
{ 0.0f, -1.0f, 0.0f}, // Bottom
{-1.0f, 0.0f, 0.0f}, // Left
{ 0.0f, 0.0f, -1.0f}, // Back
},
Triangle{
{ 0.0f, -1.0f, 0.0f}, // Bottom
{ 0.0f, 0.0f, -1.0f}, // Back
{ 1.0f, 0.0f, 0.0f}, // Right
}
};
v = subdivideTriangles(v, perlin);
v = subdivideTriangles(v, perlin);
v = subdivideTriangles(v, perlin);
v = subdivideTriangles(v, perlin);
v = subdivideTriangles(v, perlin);
for (int i = 0; i < v.size(); i++) {
Vector3f p1 = v[i].data[0];
Vector3f p2 = v[i].data[1];
Vector3f p3 = v[i].data[2];
// Считаем нормаль грани через векторное произведение
Vector3f edge1 = p2 - p1;
Vector3f edge2 = p3 - p1;
Vector3f normal = (edge1.cross(edge2)).normalized();
// Дублируем нормаль для всех трех вершин треугольника (Flat shading)
buffer.PositionData.push_back({ p1 });
buffer.PositionData.push_back({ p2 });
buffer.PositionData.push_back({ p3 });
/*buffer.NormalData.push_back({normal});
buffer.NormalData.push_back({ normal });
buffer.NormalData.push_back({ normal });
buffer.TexCoordData.push_back({ 0.0f, 0.0f });
buffer.TexCoordData.push_back({ 0.0f, 0.0f });
buffer.TexCoordData.push_back({ 0.0f, 0.0f });*/
}
return buffer;
}
VertexDataStruct generateSphere(int subdivisions, PerlinNoise& perlin) {
// 1. Исходный октаэдр
std::vector<Triangle> geometry = {
Triangle{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f, 0.0f}}, // Top-Front-Right
Triangle{{ 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // Top-Right-Back
Triangle{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}}, // Top-Back-Left
Triangle{{ 0.0f, 1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // Top-Left-Front
Triangle{{ 0.0f, -1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // Bottom-Right-Front
Triangle{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}}, // Bottom-Front-Left
Triangle{{ 0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // Bottom-Left-Back
Triangle{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, { 1.0f, 0.0f, 0.0f}} // Bottom-Back-Right
};
// 2. ПРИМЕНЯЕМ ШУМ К ИСХОДНЫМ ВЕРШИНАМ
// Проходимся по всем треугольникам и всем вершинам в них
for (auto& t : geometry) {
for (int i = 0; i < 3; i++) {
// Нормализуем (на всякий случай, хотя у октаэдра они и так норм)
Vector3f dir = t.data[i].normalized();
// Применяем высоту
t.data[i] = dir * perlin.getSurfaceHeight(dir);
}
}
// 3. Разбиваем N раз (новые вершины будут получать шум внутри функции)
for (int i = 0; i < subdivisions; i++) {
geometry = subdivideTriangles(geometry, perlin);
}
// 4. Генерируем нормали
// Благодаря тому, что мы реально сдвигали вершины, Flat Shading нормали
// рассчитаются правильно относительно нового рельефа.
return trianglesToVertices(geometry, perlin);
}
PlanetObject::PlanetObject()
{
}
void PlanetObject::init() {
planetMesh = generateSphere(7, perlin);
planetMesh.Scale(100.f);
planetMesh.Move({ 0,0,-200 });
planetRenderStruct.data = planetMesh;
planetRenderStruct.RefreshVBO();
}
void PlanetObject::prepareDrawData() {
if (!drawDataDirty) return;
drawDataDirty = false;
}
void PlanetObject::draw(Renderer& renderer) {
prepareDrawData();
static const std::string defaultShaderName = "defaultColor";
static const std::string vPositionName = "vPosition";
renderer.shaderManager.PushShader(defaultShaderName);
renderer.EnableVertexAttribArray(vPositionName);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
1, 1000);
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
renderer.RotateMatrix(Environment::inverseShipMatrix);
renderer.TranslateMatrix(-Environment::shipPosition);
renderer.DrawVertexRenderStruct(planetRenderStruct);
CheckGlError();
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.shaderManager.PopShader();
CheckGlError();
}
void PlanetObject::update(float deltaTimeMs) {
}
} // namespace ZL

100
PlanetObject.h Normal file
View File

@ -0,0 +1,100 @@
#pragma once
#include "ZLMath.h"
#include "Renderer.h"
#include "TextureManager.h"
#include <vector>
#include <chrono>
#include <iostream>
#include <string>
#include <array>
#include <numeric>
#include <random>
#include <algorithm>
namespace ZL {
class PerlinNoise {
std::vector<int> p;
public:
PerlinNoise() {
p.resize(256);
std::iota(p.begin(), p.end(), 0);
// Перемешиваем для случайности (можно задать seed)
std::default_random_engine engine(12345);
std::shuffle(p.begin(), p.end(), engine);
p.insert(p.end(), p.begin(), p.end()); // Дублируем для переполнения
}
float fade(float t) { return t * t * t * (t * (t * 6 - 15) + 10); }
float lerp(float t, float a, float b) { return a + t * (b - a); }
float grad(int hash, float x, float y, float z) {
int h = hash & 15;
float u = h < 8 ? x : y;
float v = h < 4 ? y : (h == 12 || h == 14 ? x : z);
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
float noise(float x, float y, float z) {
int X = (int)floor(x) & 255;
int Y = (int)floor(y) & 255;
int Z = (int)floor(z) & 255;
x -= floor(x);
y -= floor(y);
z -= floor(z);
float u = fade(x);
float v = fade(y);
float w = fade(z);
int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z;
int B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z;
return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), grad(p[BA], x - 1, y, z)),
lerp(u, grad(p[AB], x, y - 1, z), grad(p[BB], x - 1, y - 1, z))),
lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), grad(p[BA + 1], x - 1, y, z - 1)),
lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1))));
}
float getSurfaceHeight(Vector3f pos) {
// Частота шума (чем больше, тем больше "холмов")
float frequency = 7.0f;
// Получаем значение шума (обычно от -1 до 1)
float noiseValue = noise(pos.v[0] * frequency, pos.v[1] * frequency, pos.v[2] * frequency);
// Переводим из диапазона [-1, 1] в [0, 1]
noiseValue = (noiseValue + 1.0f) * 0.5f;
// Масштабируем: хотим отклонение от 1.0 до 1.1
// Значит амплитуда = 0.1
float height = 1.0f + (noiseValue * 0.1f); // * 0.2 даст вариацию высоты
return height;
}
};
class PlanetObject {
private:
PerlinNoise perlin;
void prepareDrawData();
VertexDataStruct planetMesh;
VertexRenderStruct planetRenderStruct;
public:
PlanetObject();
void init();
void update(float deltaTimeMs);
void draw(Renderer& renderer);
private:
bool drawDataDirty = true;
};
} // namespace ZL

View File

@ -2,6 +2,7 @@
download from https://cmake.org/download/
Windows x64 Installer: cmake-4.2.0-windows-x86_64.msi
@ -83,7 +84,7 @@ zlibstaticd.lib;libpng16_staticd.lib;SDL2d.lib;SDL2maind.lib;opengl32.lib;glu32.
```
C:\Work\Projects\emsdk\emsdk.bat activate latest
C:\Work\Projects\emsdk\emsdk_env.bat
emcc main.cpp Game.cpp Math.cpp Physics.cpp Renderer.cpp ShaderManager.cpp TextureManager.cpp Utils.cpp OpenGlExtensions.cpp -O2 -std=c++14 -sTOTAL_MEMORY=33554432 -sUSE_SDL_IMAGE=2 -sSDL2_IMAGE_FORMATS="[""png""]" -sUSE_SDL=2 --preload-file background.bmp --preload-file bird.bmp32 --preload-file default.fragment --preload-file default.vertex --preload-file game_over.bmp32 --preload-file pipe.bmp32 -o jumpingbird.html
emcc main.cpp Game.cpp Math.cpp Physics.cpp Renderer.cpp ShaderManager.cpp TextureManager.cpp Utils.cpp OpenGlExtensions.cpp -O2 -std=c++14 -sTOTAL_MEMORY=33554432 -sUSE_SDL_IMAGE=2 -sSDL2_IMAGE_FORMATS="[""png""]" -sUSE_SDL=2 --preload-file background.bmp --preload-file bird.bmp32 --preload-file default.fragment --preload-file default.vertex --preload-file game_over.bmp32 --preload-file pipe.bmp32 -o space-game001.html
```
```
@ -143,7 +144,12 @@ emcc main.cpp Game.cpp Environment.cpp GameObjectManager.cpp BoneAnimatedModel.c
# Windows:
emcc main.cpp Game.cpp Environment.cpp GameObjectManager.cpp BoneAnimatedModel.cpp GameWorld.cpp InputManager.cpp Inventory.cpp ObjLoader.cpp QuestScripts.cpp RenderSystem.cpp Math.cpp Physics.cpp Renderer.cpp TextModel.cpp ShaderManager.cpp TextureManager.cpp Utils.cpp OpenGlExtensions.cpp -O2 -std=c++14 -pthread -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE=4 -sTOTAL_MEMORY=4294967296 -sINITIAL_MEMORY=3221225472 -sMAXIMUM_MEMORY=4294967296 -sALLOW_MEMORY_GROWTH=1 -I./thirdparty/libzip-1.11.3/build-emcmake/install/include -L./thirdparty/libzip-1.11.3/build-emcmake/install/lib -lzip -lz -sUSE_SDL_IMAGE=2 -sUSE_SDL=2 -sUSE_LIBPNG=1 --preload-file data.zip -o viola.html
emcc --clear-cache
embuilder build sdl2 sdl2_ttf sdl2_image sdl2_image_jpg sdl2_image_png
emcc main.cpp Game.cpp Environment.cpp BoneAnimatedModel.cpp ZLMath.cpp Renderer.cpp TextModel.cpp ShaderManager.cpp TextureManager.cpp Utils.cpp OpenGlExtensions.cpp -O2 -std=c++14 -pthread -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE=4 -sTOTAL_MEMORY=4294967296 -sINITIAL_MEMORY=3221225472 -sMAXIMUM_MEMORY=4294967296 -sALLOW_MEMORY_GROWTH=1 -I./thirdparty/libzip-1.11.3/build-emcmake/install/include -L./thirdparty/libzip-1.11.3/build-emcmake/install/lib -lzip -lz -sUSE_SDL_IMAGE=2 -sUSE_SDL=2 -sUSE_LIBPNG=1 --preload-file space-game001.zip -o space-game001.html
emrun --no_browser --port 8080 .
```

View File

@ -196,6 +196,71 @@ namespace ZL {
return result;
}
VertexDataStruct CreateCubemap(float scale)
{
VertexDataStruct cubemapVertexDataStruct;
// +x
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, scale });
// -x
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, scale });
// +y
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, scale });
// -y
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, scale });
// +z
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, scale });
// -z
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, -scale });
return cubemapVertexDataStruct;
}
void VertexRenderStruct::RefreshVBO()
{
//Check if main thread, check if data is not empty...
@ -538,6 +603,35 @@ namespace ZL {
SetMatrix();
}
void Renderer::RotateMatrix(const Matrix3f& m3)
{
Matrix4f m = Matrix4f::Identity();
m.m[0] = m3.m[0];
m.m[1] = m3.m[1];
m.m[2] = m3.m[2];
m.m[4] = m3.m[3];
m.m[5] = m3.m[4];
m.m[6] = m3.m[5];
m.m[8] = m3.m[6];
m.m[9] = m3.m[7];
m.m[10] = m3.m[8];
m = ModelviewMatrixStack.top() * m;
if (ModelviewMatrixStack.size() == 0)
{
throw std::runtime_error("Modelview matrix stack underflow!!!!");
}
ModelviewMatrixStack.pop();
ModelviewMatrixStack.push(m);
SetMatrix();
}
void Renderer::PushSpecialMatrix(const Matrix4f& m)
{
if (ModelviewMatrixStack.size() > 64)

View File

@ -75,6 +75,7 @@ namespace ZL {
VertexDataStruct CreateRect2D(Vector2f center, Vector2f halfWidthHeight, float zLevel);
VertexDataStruct CreateRectHorizontalSections2D(Vector2f center, Vector2f halfWidthHeight, float zLevel, size_t sectionCount);
VertexDataStruct CreateCube3D(float scale);
VertexDataStruct CreateCubemap(float scale = 1000.f);
class Renderer
@ -101,6 +102,7 @@ namespace ZL {
void ScaleMatrix(float scale);
void ScaleMatrix(const Vector3f& scale);
void RotateMatrix(const Vector4f& q);
void RotateMatrix(const Matrix3f& m3);
void PushSpecialMatrix(const Matrix4f& m);
void PopMatrix();

297
SparkEmitter.cpp Normal file
View File

@ -0,0 +1,297 @@
#include "SparkEmitter.h"
#include <random>
#include <cmath>
#include "OpenGlExtensions.h"
namespace ZL {
SparkEmitter::SparkEmitter()
: emissionRate(100.0f), isActive(true), drawDataDirty(true), maxParticles(200) {
particles.resize(maxParticles);
drawPositions.reserve(maxParticles * 6);
drawTexCoords.reserve(maxParticles * 6);
lastEmissionTime = std::chrono::steady_clock::now();
sparkQuad.data = VertexDataStruct();
}
SparkEmitter::SparkEmitter(const std::vector<Vector3f>& positions, float rate)
: emissionPoints(positions), emissionRate(rate), isActive(true),
drawDataDirty(true), maxParticles(positions.size() * 100) {
particles.resize(maxParticles);
drawPositions.reserve(maxParticles * 6);
drawTexCoords.reserve(maxParticles * 6);
lastEmissionTime = std::chrono::steady_clock::now();
sparkQuad.data = VertexDataStruct();
}
SparkEmitter::SparkEmitter(const std::vector<Vector3f>& positions,
std::shared_ptr<Texture> tex,
float rate)
: emissionPoints(positions), texture(tex), emissionRate(rate),
isActive(true), drawDataDirty(true), maxParticles(positions.size() * 100) {
particles.resize(maxParticles);
drawPositions.reserve(maxParticles * 6);
drawTexCoords.reserve(maxParticles * 6);
lastEmissionTime = std::chrono::steady_clock::now();
sparkQuad.data = VertexDataStruct();
}
void SparkEmitter::setTexture(std::shared_ptr<Texture> tex) {
texture = tex;
}
void SparkEmitter::prepareDrawData() {
if (!drawDataDirty) return;
drawPositions.clear();
drawTexCoords.clear();
if (getActiveParticleCount() == 0) {
drawDataDirty = false;
return;
}
std::vector<std::pair<const SparkParticle*, float>> sortedParticles;
sortedParticles.reserve(getActiveParticleCount());
for (const auto& particle : particles) {
if (particle.active) {
sortedParticles.push_back({ &particle, particle.position.v[2] });
}
}
std::sort(sortedParticles.begin(), sortedParticles.end(),
[](const auto& a, const auto& b) {
return a.second > b.second;
});
for (const auto& [particlePtr, depth] : sortedParticles) {
const auto& particle = *particlePtr;
Vector3f pos = particle.position;
float size = 0.04f * particle.scale;
drawPositions.push_back({ pos.v[0] - size, pos.v[1] - size, pos.v[2] });
drawTexCoords.push_back({ 0.0f, 0.0f });
drawPositions.push_back({ pos.v[0] - size, pos.v[1] + size, pos.v[2] });
drawTexCoords.push_back({ 0.0f, 1.0f });
drawPositions.push_back({ pos.v[0] + size, pos.v[1] + size, pos.v[2] });
drawTexCoords.push_back({ 1.0f, 1.0f });
drawPositions.push_back({ pos.v[0] - size, pos.v[1] - size, pos.v[2] });
drawTexCoords.push_back({ 0.0f, 0.0f });
drawPositions.push_back({ pos.v[0] + size, pos.v[1] + size, pos.v[2] });
drawTexCoords.push_back({ 1.0f, 1.0f });
drawPositions.push_back({ pos.v[0] + size, pos.v[1] - size, pos.v[2] });
drawTexCoords.push_back({ 1.0f, 0.0f });
}
drawDataDirty = false;
}
void SparkEmitter::draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight) {
if (getActiveParticleCount() == 0) {
return;
}
if (!texture) {
return;
}
prepareDrawData();
if (drawPositions.empty()) {
return;
}
sparkQuad.data.PositionData = drawPositions;
sparkQuad.data.TexCoordData = drawTexCoords;
sparkQuad.RefreshVBO();
static const std::string defaultShaderName = "default";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
float aspectRatio = static_cast<float>(screenWidth) / static_cast<float>(screenHeight);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, aspectRatio, 1, 1000);
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Аддитивное смешивание для эффекта свечения
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0, 0, -1.0f * zoom });
renderer.DrawVertexRenderStruct(sparkQuad);
renderer.PopMatrix();
renderer.PopProjectionMatrix();
glDisable(GL_BLEND);
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader();
}
void SparkEmitter::update(float deltaTimeMs) {
auto currentTime = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
currentTime - lastEmissionTime).count();
if (isActive && elapsed >= emissionRate) {
emit();
lastEmissionTime = currentTime;
drawDataDirty = true;
}
bool anyChanged = false;
for (auto& particle : particles) {
if (particle.active) {
Vector3f oldPosition = particle.position;
float oldScale = particle.scale;
particle.position.v[0] += particle.velocity.v[0] * deltaTimeMs / 1000.0f;
particle.position.v[1] += particle.velocity.v[1] * deltaTimeMs / 1000.0f;
particle.position.v[2] += particle.velocity.v[2] * deltaTimeMs / 1000.0f;
particle.lifeTime += deltaTimeMs;
if (particle.lifeTime >= particle.maxLifeTime) {
particle.active = false;
anyChanged = true;
}
else {
float lifeRatio = particle.lifeTime / particle.maxLifeTime;
particle.scale = 1.0f - lifeRatio * 0.8f;
if (oldPosition.v[0] != particle.position.v[0] ||
oldPosition.v[1] != particle.position.v[1] ||
oldPosition.v[2] != particle.position.v[2] ||
oldScale != particle.scale) {
anyChanged = true;
}
}
}
}
if (anyChanged) {
drawDataDirty = true;
}
}
void SparkEmitter::emit() {
if (emissionPoints.empty()) return;
bool emitted = false;
for (int i = 0; i < emissionPoints.size(); ++i) {
bool particleFound = false;
for (auto& particle : particles) {
if (!particle.active) {
initParticle(particle, i);
particle.active = true;
particle.lifeTime = 0;
particle.position = emissionPoints[i];
particle.emitterIndex = i;
particleFound = true;
emitted = true;
break;
}
}
if (!particleFound && !particles.empty()) {
size_t oldestIndex = 0;
float maxLifeTime = 0;
for (size_t j = 0; j < particles.size(); ++j) {
if (particles[j].lifeTime > maxLifeTime) {
maxLifeTime = particles[j].lifeTime;
oldestIndex = j;
}
}
initParticle(particles[oldestIndex], i);
particles[oldestIndex].active = true;
particles[oldestIndex].lifeTime = 0;
particles[oldestIndex].position = emissionPoints[i];
particles[oldestIndex].emitterIndex = i;
emitted = true;
}
}
if (emitted) {
drawDataDirty = true;
}
}
void SparkEmitter::setEmissionPoints(const std::vector<Vector3f>& positions) {
emissionPoints = positions;
maxParticles = positions.size() * 100;
particles.resize(maxParticles);
drawDataDirty = true;
}
void SparkEmitter::initParticle(SparkParticle& particle, int emitterIndex) {
particle.velocity = getRandomVelocity(emitterIndex);
particle.scale = 1.0f;
particle.maxLifeTime = 800.0f + (rand() % 400);
particle.emitterIndex = emitterIndex;
}
Vector3f SparkEmitter::getRandomVelocity(int emitterIndex) {
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_real_distribution<> angleDist(0, 2 * M_PI);
static std::uniform_real_distribution<> speedDist(0.5f, 2.0f);
static std::uniform_real_distribution<> zSpeedDist(1.0f, 3.0f);
float angle = angleDist(gen);
float speed = speedDist(gen);
float zSpeed = zSpeedDist(gen);
if (emitterIndex == 0) {
return Vector3f{
cosf(angle) * speed - 0.3f,
sinf(angle) * speed,
zSpeed
};
}
else {
return Vector3f{
cosf(angle) * speed + 0.3f,
sinf(angle) * speed,
zSpeed
};
}
}
const std::vector<SparkParticle>& SparkEmitter::getParticles() const {
return particles;
}
size_t SparkEmitter::getActiveParticleCount() const {
size_t count = 0;
for (const auto& particle : particles) {
if (particle.active) {
count++;
}
}
return count;
}
} // namespace ZL

66
SparkEmitter.h Normal file
View File

@ -0,0 +1,66 @@
#pragma once
#include "ZLMath.h"
#include "Renderer.h"
#include "TextureManager.h"
#include <vector>
#include <chrono>
namespace ZL {
struct SparkParticle {
Vector3f position;
Vector3f velocity;
float scale;
float lifeTime;
float maxLifeTime;
bool active;
int emitterIndex;
SparkParticle() : position({ 0,0,0 }), velocity({ 0,0,0 }), scale(1.0f),
lifeTime(0), maxLifeTime(1000.0f), active(false), emitterIndex(0) {
}
};
class SparkEmitter {
private:
std::vector<SparkParticle> particles;
std::vector<Vector3f> emissionPoints;
std::chrono::steady_clock::time_point lastEmissionTime;
float emissionRate;
bool isActive;
std::vector<Vector3f> drawPositions;
std::vector<Vector2f> drawTexCoords;
bool drawDataDirty;
VertexRenderStruct sparkQuad;
std::shared_ptr<Texture> texture;
int maxParticles;
void prepareDrawData();
public:
SparkEmitter();
SparkEmitter(const std::vector<Vector3f>& positions, float rate = 100.0f);
SparkEmitter(const std::vector<Vector3f>& positions,
std::shared_ptr<Texture> tex,
float rate = 100.0f);
void setEmissionPoints(const std::vector<Vector3f>& positions);
void setTexture(std::shared_ptr<Texture> tex);
void update(float deltaTimeMs);
void emit();
void draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight);
const std::vector<SparkParticle>& getParticles() const;
size_t getActiveParticleCount() const;
private:
void initParticle(SparkParticle& particle, int emitterIndex);
Vector3f getRandomVelocity(int emitterIndex);
};
} // namespace ZL

View File

@ -2,6 +2,7 @@
#ifdef PNG_ENABLED
#include "png.h"
#endif
#include <iostream>
namespace ZL
{
@ -46,6 +47,85 @@ namespace ZL
}
Texture::Texture(const std::array<TextureDataStruct, 6>& texDataArray)
{
// Ïðîâåðêà, ÷òî âñå ãðàíè èìåþò îäèíàêîâûå ðàçìåðû
width = texDataArray[0].width;
height = texDataArray[0].height;
for (size_t i = 1; i < 6; ++i) {
if (texDataArray[i].width != width || texDataArray[i].height != height) {
throw std::runtime_error("Cubemap faces must have the same dimensions");
}
}
glGenTextures(1, &texID);
if (texID == 0)
{
throw std::runtime_error("glGenTextures did not work for cubemap");
}
glBindTexture(GL_TEXTURE_CUBE_MAP, texID);
CheckGlError();
// Íàñòðîéêà ïàðàìåòðîâ äëÿ Cubemap
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Èñïîëüçóåì GL_LINEAR äëÿ MIN_FILTER, òàê êàê ìèïìàïû çäåñü íå ãåíåðèðóþòñÿ
// Åñëè áû èñïîëüçîâàëèñü ìèïìàïû (e.g., GL_LINEAR_MIPMAP_LINEAR), íóæíî áûëî áû âûçâàòü glGenerateMipmap.
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// Îáÿçàòåëüíûå ïàðàìåòðû îáåðòêè äëÿ Cubemap
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// GL_TEXTURE_WRAP_R íå ïîääåðæèâàåòñÿ â WebGL 1.0/OpenGL ES 2.0 è âûçûâàåò îøèáêó.
// Îãðàíè÷èâàåì åãî âûçîâ òîëüêî äëÿ íàñòîëüíûõ ïëàòôîðì.
#ifndef EMSCRIPTEN
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
#endif
CheckGlError(); // Ïðîâåðêà ïîñëå óñòàíîâêè ïàðàìåòðîâ
// Çàãðóçêà äàííûõ äëÿ êàæäîé èç 6 ãðàíåé
// GL_TEXTURE_CUBE_MAP_POSITIVE_X + i äàåò ãðàíè: +X (0), -X (1), +Y (2), -Y (3), +Z (4), -Z (5)
for (int i = 0; i < 6; ++i)
{
GLint internalFormat;
GLenum format;
// Â WebGL 1.0/OpenGL ES 2.0 âíóòðåííèé ôîðìàò (internalFormat)
// äîëæåí ñòðîãî ñîîòâåòñòâîâàòü ôîðìàòó äàííûõ (format).
if (texDataArray[i].bitSize == TextureDataStruct::BS_24BIT)
{
internalFormat = GL_RGB; // internalFormat
format = GL_RGB; // format
}
else // BS_32BIT
{
internalFormat = GL_RGBA; // internalFormat
format = GL_RGBA; // format
}
glTexImage2D(
GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, // Öåëåâàÿ ãðàíü
0, // Óðîâåíü MIP-òåêñòóðû
internalFormat, // Âíóòðåííèé ôîðìàò (äîëæåí ñîâïàäàòü ñ ôîðìàòîì)
static_cast<GLsizei>(width),
static_cast<GLsizei>(height),
0, // Ãðàíèöà (âñåãäà 0)
format, // Ôîðìàò èñõîäíûõ äàííûõ
GL_UNSIGNED_BYTE, // Òèï äàííûõ
texDataArray[i].data.data() // Óêàçàòåëü íà äàííûå
);
CheckGlError();
}
// Ñíèìàåì ïðèâÿçêó äëÿ ÷èñòîòû
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}
Texture::~Texture()
{
glDeleteTextures(1, &texID);
@ -170,36 +250,84 @@ namespace ZL
#ifdef PNG_ENABLED
TextureDataStruct CreateTextureDataFromPng(const std::string& fullFileName)
// Ñòðóêòóðà äëÿ õðàíåíèÿ äàííûõ î ôàéëå/ìàññèâå è òåêóùåé ïîçèöèè ÷òåíèÿ
struct png_data_t {
const char* data;
size_t size;
size_t offset;
};
// Ïîëüçîâàòåëüñêàÿ ôóíêöèÿ ÷òåíèÿ äëÿ libpng
// 'png_ptr' - óêàçàòåëü íà ñòðóêòóðó png
// 'out_ptr' - êóäà çàïèñûâàòü ïðî÷èòàííûå äàííûå
// 'bytes_to_read' - ñêîëüêî áàéò íóæíî ïðî÷èòàòü
void user_read_data(png_structp png_ptr, png_bytep out_ptr, png_size_t bytes_to_read) {
// Ïîëó÷àåì óêàçàòåëü íà íàøó ñòðóêòóðó png_data_t, êîòîðóþ ìû óñòàíîâèëè ñ ïîìîùüþ png_set_read_fn
png_data_t* data = (png_data_t*)png_get_io_ptr(png_ptr);
if (data->offset + bytes_to_read > data->size) {
// Ïîïûòêà ïðî÷èòàòü áîëüøå, ÷åì åñòü â ìàññèâå.
// Âìåñòî âûçîâà ñòàíäàðòíîé îøèáêè, ìû ìîæåì ïðîñòî ïðî÷èòàòü îñòàòîê èëè âûçâàòü îøèáêó.
//  ýòîì ñëó÷àå ìû âûçîâåì îøèáêó libpng.
png_error(png_ptr, "PNG Read Error: Attempted to read past end of data buffer.");
bytes_to_read = data->size - data->offset; // Óñòàíàâëèâàåì, ÷òîáû ïðî÷èòàòü îñòàâøååñÿ
}
// Êîïèðóåì äàííûå èç íàøåãî ìàññèâà â áóôåð libpng
std::memcpy(out_ptr, data->data + data->offset, bytes_to_read);
// Îáíîâëÿåì ñìåùåíèå
data->offset += bytes_to_read;
}
// Ïîëüçîâàòåëüñêàÿ ôóíêöèÿ ïðåäóïðåæäåíèé (ïî æåëàíèþ, ìîæíî èñïîëüçîâàòü nullptr)
void user_warning_fn(png_structp png_ptr, png_const_charp warning_msg) {
// Çäåñü ìîæíî ðåàëèçîâàòü ëîãèðîâàíèå ïðåäóïðåæäåíèé
//throw std::runtime_error();
std::cout << "PNG Warning: " << warning_msg << std::endl;
}
// Ïîëüçîâàòåëüñêàÿ ôóíêöèÿ îøèáîê (îáÿçàòåëüíà äëÿ setjmp)
void user_error_fn(png_structp png_ptr, png_const_charp error_msg) {
// Çäåñü ìîæíî ðåàëèçîâàòü ëîãèðîâàíèå îøèáîê
std::cout << "PNG Error: " << error_msg << std::endl;
// Îáÿçàòåëüíî âûçûâàåì longjmp äëÿ âûõîäà èç ïðîöåññà ÷òåíèÿ/çàïèñè PNG
longjmp(png_jmpbuf(png_ptr), 1);
}
TextureDataStruct CreateTextureDataFromPng(const std::vector<char>& fileArr)
{
TextureDataStruct texData;
FILE* file = fopen(fullFileName.c_str(), "rb");
if (!file) {
fclose(file);
throw std::runtime_error("Could not open file " + fullFileName);
}
// Ñòðóêòóðà äëÿ óïðàâëåíèÿ ÷òåíèåì èç ìàññèâà
png_data_t png_data = { fileArr.data(), fileArr.size(), 0 };
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!png) {
fclose(file);
throw std::runtime_error("Could not create PNG read structure");
}
png_infop info = png_create_info_struct(png);
if (!info) {
fclose(file);
png_destroy_read_struct(&png, nullptr, nullptr);
throw std::runtime_error("Could not create PNG info structure");
}
// === Óñòàíîâêà ïîëüçîâàòåëüñêèõ ôóíêöèé ÷òåíèÿ è îáðàáîòêè îøèáîê ===
// 1. Óñòàíîâêà îáðàáîò÷èêà îøèáîê è longjmp
if (setjmp(png_jmpbuf(png))) {
png_destroy_read_struct(&png, &info, nullptr);
fclose(file);
throw std::runtime_error("Error during PNG read");
throw std::runtime_error("Error during PNG read (longjmp was executed)");
}
png_init_io(png, file);
// 2. Óñòàíîâêà ïîëüçîâàòåëüñêèõ ôóíêöèé äëÿ îáðàáîòêè îøèáîê è ïðåäóïðåæäåíèé
// Âìåñòî nullptr â error_ptr è warning_ptr ìîæíî ïåðåäàòü óêàçàòåëü íà ñâîþ ñòðóêòóðó äàííûõ, åñëè íåîáõîäèìî
png_set_error_fn(png, nullptr, user_error_fn, user_warning_fn);
// 3. Óñòàíîâêà ïîëüçîâàòåëüñêîé ôóíêöèè ÷òåíèÿ è ïåðåäà÷à åé íàøåé ñòðóêòóðû png_data
png_set_read_fn(png, &png_data, user_read_data);
// ===================================================================
png_read_info(png, info);
texData.width = png_get_image_width(png, info);
@ -207,6 +335,7 @@ namespace ZL
png_byte color_type = png_get_color_type(png, info);
png_byte bit_depth = png_get_bit_depth(png, info);
// === Áëîê ïðåîáðàçîâàíèé (îñòàâëåí áåç èçìåíåíèé) ===
if (bit_depth == 16)
png_set_strip_16(png);
@ -229,8 +358,9 @@ namespace ZL
png_set_gray_to_rgb(png);
png_read_update_info(png, info);
// ====================================================
// === ×òåíèå ïèêñåëåé (îñòàâëåí áåç èçìåíåíèé) ===
png_bytep* row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * texData.height);
for (int y = 0; y < texData.height; y++) {
row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info));
@ -238,8 +368,6 @@ namespace ZL
png_read_image(png, row_pointers);
fclose(file);
bool has_alpha = (color_type & PNG_COLOR_MASK_ALPHA) || (png_get_valid(png, info, PNG_INFO_tRNS));
size_t dataSize;
@ -258,11 +386,9 @@ namespace ZL
dataSize = texData.width * texData.height * channels;
texData.data.resize(dataSize);
//for (int y = 0; y < texData.height; y++) { //Go in reverse because of UV coord start point
for (int y = texData.height-1; y >= 0; y--) {
//png_bytep row = row_pointers[y];//Go in reverse because of UV coord start point
png_bytep row = row_pointers[texData.height - 1 - y];
for (int y = texData.height - 1; y >= 0; y--) {
png_bytep row = row_pointers[texData.height - 1 - y];
for (int x = 0; x < texData.width; x++) {
png_bytep px = &(row[x * 4]);
texData.data[(y * texData.width + x) * channels + 0] = px[0]; // R
@ -272,14 +398,33 @@ namespace ZL
texData.data[(y * texData.width + x) * channels + 3] = px[3]; // A
}
}
//free(row_pointers[y]);//Go in reverse because of UV coord start point
free(row_pointers[texData.height - 1 - y]);//Go in reverse because of UV coord start point
free(row_pointers[texData.height - 1 - y]);
}
free(row_pointers);
// ==================================================
png_destroy_read_struct(&png, &info, nullptr);
return texData;
}
TextureDataStruct CreateTextureDataFromPng(const std::string& fullFileName, const std::string& ZIPFileName)
{
std::vector<char> fileArr;
fileArr = !ZIPFileName.empty() ? readFileFromZIP(fullFileName, ZIPFileName) : readFile(fullFileName);
if (fileArr.empty()) {
throw std::runtime_error("Could not read file data into memory");
}
// Âûçûâàåì íîâóþ ôóíêöèþ, êîòîðàÿ ðàáîòàåò ñ ìàññèâîì áàéò
return CreateTextureDataFromPng(fileArr);
}
#endif
}

View File

@ -3,6 +3,10 @@
#include "OpenGlExtensions.h"
#include "Utils.h"
#ifdef EMSCRIPTEN
#define PNG_ENABLED
#endif
namespace ZL
{
@ -29,6 +33,9 @@ namespace ZL
Texture(const TextureDataStruct& texData);
//Cubemap texture:
Texture(const std::array<TextureDataStruct, 6>& texDataArray);
~Texture();
GLuint getTexID();
@ -42,6 +49,8 @@ namespace ZL
TextureDataStruct CreateTextureDataFromBmp24(const std::string& fullFileName, const std::string& ZIPFileName="");
TextureDataStruct CreateTextureDataFromBmp32(const std::string& fullFileName, const std::string& ZIPFileName="");
#ifdef PNG_ENABLED
TextureDataStruct CreateTextureDataFromPng(const std::string& fullFileName);
TextureDataStruct CreateTextureDataFromPng(const std::string& fullFileName, const std::string& ZIPFileName = "");
#endif
}

View File

@ -5,7 +5,9 @@
#include <iostream>
#include <algorithm>
#include <fstream>
//#include <zip.h>
#ifdef EMSCRIPTEN
#include <zip.h>
#endif
namespace ZL
{
@ -42,7 +44,8 @@ namespace ZL
}
std::vector<char> readFileFromZIP(const std::string& filename, const std::string& zipfilename) {
/*const std::string zipPath = zipfilename;
#ifdef EMSCRIPTEN
const std::string zipPath = zipfilename;
int zipErr;
zip_t* archive = zip_open(zipPath.c_str(), ZIP_RDONLY, &zipErr);
if (!archive) {
@ -77,8 +80,10 @@ namespace ZL
zip_fclose(zipFile);
zip_close(archive);
return fileData;*/
return fileData;
#else
return {};
#endif
}
bool findString(const char* in, char* list)

1491
Math.cpp → ZLMath.cpp Executable file → Normal file

File diff suppressed because it is too large Load Diff

267
ZLMath.h Normal file → Executable file
View File

@ -1,111 +1,156 @@
#pragma once
#include <array>
#include <exception>
#include <stdexcept>
#include <cmath>
namespace ZL {
struct Vector4f
{
std::array<float, 4> v = { 0.f, 0.f, 0.f, 0.f };
Vector4f normalized() const {
double norm = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);
Vector4f r;
r.v[0] = v[0] / norm;
r.v[1] = v[1] / norm;
r.v[2] = v[2] / norm;
r.v[3] = v[3] / norm;
return r;
}
double dot(const Vector4f& other) const {
return v[0] * other.v[0] + v[1] * other.v[1] + v[2] * other.v[2] + v[3] * other.v[3];
}
};
struct Vector3f
{
std::array<float, 3> v = { 0.f, 0.f, 0.f };
};
struct Vector2f
{
std::array<float, 2> v = {0.f, 0.f};
};
Vector2f operator+(const Vector2f& x, const Vector2f& y);
Vector2f operator-(const Vector2f& x, const Vector2f& y);
Vector3f operator+(const Vector3f& x, const Vector3f& y);
Vector3f operator-(const Vector3f& x, const Vector3f& y);
Vector4f operator+(const Vector4f& x, const Vector4f& y);
Vector4f operator-(const Vector4f& x, const Vector4f& y);
struct Matrix3f
{
std::array<float, 9> m = { 0.f, 0.f, 0.f,
0.f, 0.f, 0.f,
0.f, 0.f, 0.f, };
static Matrix3f Identity();
};
struct Matrix4f
{
std::array<float, 16> m = { 0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f };
static Matrix4f Identity();
float& operator()(int row, int col) {
//return m[row * 4 + col]; //OpenGL specific
return m[col * 4 + row];
}
const float& operator()(int row, int col) const {
//return m[row * 4 + col];
return m[col * 4 + row];
}
};
Matrix4f operator*(const Matrix4f& m1, const Matrix4f& m2);
Matrix4f MakeOrthoMatrix(float width, float height, float zNear, float zFar);
Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar);
Matrix3f QuatToMatrix(const Vector4f& q);
Vector4f MatrixToQuat(const Matrix3f& m);
Vector4f QuatFromRotateAroundX(float angle);
Vector4f QuatFromRotateAroundY(float angle);
Vector4f QuatFromRotateAroundZ(float angle);
Vector3f operator*(Vector3f v, float scale);
Vector4f operator*(Vector4f v, float scale);
Vector3f MultVectorMatrix(Vector3f v, Matrix3f mt);
Vector4f MultVectorMatrix(Vector4f v, Matrix4f mt);
Vector4f MultMatrixVector(Matrix4f mt, Vector4f v);
Vector4f slerp(const Vector4f& q1, const Vector4f& q2, float t);
Matrix3f InverseMatrix(const Matrix3f& m);
Matrix4f InverseMatrix(const Matrix4f& m);
Matrix3f MultMatrixMatrix(const Matrix3f& m1, const Matrix3f& m2);
Matrix4f MultMatrixMatrix(const Matrix4f& m1, const Matrix4f& m2);
Matrix4f MakeMatrix4x4(const Matrix3f& m, const Vector3f pos);
};
#pragma once
#include <array>
#include <exception>
#include <stdexcept>
#include <cmath>
namespace ZL {
struct Vector4f
{
std::array<float, 4> v = { 0.f, 0.f, 0.f, 0.f };
Vector4f normalized() const {
double norm = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);
Vector4f r;
r.v[0] = v[0] / norm;
r.v[1] = v[1] / norm;
r.v[2] = v[2] / norm;
r.v[3] = v[3] / norm;
return r;
}
double dot(const Vector4f& other) const {
return v[0] * other.v[0] + v[1] * other.v[1] + v[2] * other.v[2] + v[3] * other.v[3];
}
};
struct Vector3f
{
std::array<float, 3> v = { 0.f, 0.f, 0.f };
Vector3f()
{
}
Vector3f(float x, float y, float z)
: v{x,y,z}
{
}
Vector3f normalized() const {
double norm = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
Vector3f r;
r.v[0] = v[0] / norm;
r.v[1] = v[1] / norm;
r.v[2] = v[2] / norm;
return r;
}
float squaredNorm() const {
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
}
float dot(const Vector3f& other) const {
return v[0] * other.v[0] + v[1] * other.v[1] + v[2] * other.v[2];
}
Vector3f cross(const Vector3f& other) const {
return Vector3f(
v[1] * other.v[2] - v[2] * other.v[1],
v[2] * other.v[0] - v[0] * other.v[2],
v[0] * other.v[1] - v[1] * other.v[0]
);
}
// Îïåðàòîð âû÷èòàíèÿ
/*Vector3f operator-(const Vector3f& other) const {
return Vector3f(v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2]);
}*/
};
struct Vector2f
{
std::array<float, 2> v = {0.f, 0.f};
};
Vector2f operator+(const Vector2f& x, const Vector2f& y);
Vector2f operator-(const Vector2f& x, const Vector2f& y);
Vector3f operator+(const Vector3f& x, const Vector3f& y);
Vector3f operator-(const Vector3f& x, const Vector3f& y);
Vector4f operator+(const Vector4f& x, const Vector4f& y);
Vector4f operator-(const Vector4f& x, const Vector4f& y);
Vector3f operator-(const Vector3f& x);
struct Matrix3f
{
std::array<float, 9> m = { 0.f, 0.f, 0.f,
0.f, 0.f, 0.f,
0.f, 0.f, 0.f, };
static Matrix3f Identity();
};
struct Matrix4f
{
std::array<float, 16> m = { 0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f };
static Matrix4f Identity();
float& operator()(int row, int col) {
//return m[row * 4 + col]; //OpenGL specific
return m[col * 4 + row];
}
const float& operator()(int row, int col) const {
//return m[row * 4 + col];
return m[col * 4 + row];
}
};
Matrix4f operator*(const Matrix4f& m1, const Matrix4f& m2);
Matrix4f MakeOrthoMatrix(float width, float height, float zNear, float zFar);
Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar);
Matrix3f QuatToMatrix(const Vector4f& q);
Vector4f MatrixToQuat(const Matrix3f& m);
Vector4f QuatFromRotateAroundX(float angle);
Vector4f QuatFromRotateAroundY(float angle);
Vector4f QuatFromRotateAroundZ(float angle);
Vector3f operator*(Vector3f v, float scale);
Vector4f operator*(Vector4f v, float scale);
Vector3f MultVectorMatrix(Vector3f v, Matrix3f mt);
Vector4f MultVectorMatrix(Vector4f v, Matrix4f mt);
Vector4f MultMatrixVector(Matrix4f mt, Vector4f v);
Vector3f MultMatrixVector(Matrix3f mt, Vector3f v);
Vector4f slerp(const Vector4f& q1, const Vector4f& q2, float t);
Matrix3f InverseMatrix(const Matrix3f& m);
Matrix4f InverseMatrix(const Matrix4f& m);
Matrix3f MultMatrixMatrix(const Matrix3f& m1, const Matrix3f& m2);
Matrix4f MultMatrixMatrix(const Matrix4f& m1, const Matrix4f& m2);
Matrix4f MakeMatrix4x4(const Matrix3f& m, const Vector3f pos);
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
import bpy
import bmesh
mesh_name = "chassis_low"
output_path = "C:\\Work\\Projects\\space-game001\\blender scripts\\output\\spaceship005.txt"
mesh_obj = bpy.data.objects.get(mesh_name)
if mesh_obj and mesh_obj.type == 'MESH':
# Обязательно применяем трансформации, чтобы координаты были актуальными
# Но для чистоты эксперимента берем mesh data как есть
# Работаем с копией меша, чтобы применить триангуляцию (если нужно)
# и не испортить сцену, но пока используем bmesh напрямую
bm = bmesh.new()
bm.from_mesh(mesh_obj.data)
# Получаем слой UV
uv_layer = bm.loops.layers.uv.active
# Словарь для хранения уникальных вершин:
# Ключ: (x, y, z, nx, ny, nz, u, v) -> Значение: новый_индекс
unique_verts_map = {}
final_vertices = [] # Список для записи в файл
final_indices = [] # Список индексов треугольников
# Проходим по всем фейсам
for face in bm.faces:
face_indices = []
# Проходим по углам (loops) фейса
for loop in face.loops:
vert = loop.vert
# 1. Координаты (округляем для надежности сравнения float)
co = (round(vert.co.x, 6), round(vert.co.y, 6), round(vert.co.z, 6))
# 2. Нормаль (если используете Smooth shading, берите vert.normal, если Flat - face.normal)
# Для простоты берем нормаль вершины
no = (round(vert.normal.x, 6), round(vert.normal.y, 6), round(vert.normal.z, 6))
# 3. UV координаты
if uv_layer:
raw_uv = loop[uv_layer].uv
uv = (round(raw_uv.x, 6), round(raw_uv.y, 6))
else:
uv = (0.0, 0.0)
# Собираем уникальный ключ данных вершины
vert_data_key = (co, no, uv)
# Проверяем, есть ли такая комбинация уже
if vert_data_key in unique_verts_map:
index = unique_verts_map[vert_data_key]
else:
index = len(final_vertices)
unique_verts_map[vert_data_key] = index
final_vertices.append(vert_data_key)
face_indices.append(index)
# Триангуляция "на лету" (если фейс - квадрат, делим на два треугольника)
# Простейший метод fan (0, 1, 2), (0, 2, 3)...
for i in range(1, len(face_indices) - 1):
final_indices.append(face_indices[0])
final_indices.append(face_indices[i])
final_indices.append(face_indices[i+1])
# --- ЗАПИСЬ В ФАЙЛ ---
with open(output_path, "w") as file:
file.write(f"===Vertices (Split by UV/Normal): {len(final_vertices)}\n")
# Формат строки: ID: X Y Z | NX NY NZ | U V
for idx, v_data in enumerate(final_vertices):
co, no, uv = v_data
file.write(f"V {idx}: Pos({co[0]}, {co[1]}, {co[2]}) Norm({no[0]}, {no[1]}, {no[2]}) UV({uv[0]}, {uv[1]})\n")
file.write(f"\n===Triangles (Indices): {len(final_indices) // 3}\n")
# Записываем тройками
for i in range(0, len(final_indices), 3):
file.write(f"Tri: {final_indices[i]} {final_indices[i+1]} {final_indices[i+2]}\n")
bm.free()
print(f"Export done. Original verts: {len(mesh_obj.data.vertices)}, Split verts: {len(final_vertices)}")
else:
print("Mesh not found")

106
main.cpp
View File

@ -1,78 +1,88 @@
#include "Game.h"
#include "Environment.h"
#include <iostream>
ZL::Game game;
void MainLoop() {
game.update();
}
int main(int argc, char* argv[]) {
constexpr int CONST_WIDTH = 1280;
constexpr int CONST_HEIGHT = 720;
try
{
constexpr int CONST_WIDTH = 1280;
constexpr int CONST_HEIGHT = 720;
ZL::Environment::width = CONST_WIDTH;
ZL::Environment::height = CONST_HEIGHT;
ZL::Environment::width = CONST_WIDTH;
ZL::Environment::height = CONST_HEIGHT;
#ifdef EMSCRIPTEN
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::cerr << "SDL_Init failed: " << SDL_GetError() << std::endl;
return 1;
}
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::cerr << "SDL_Init failed: " << SDL_GetError() << std::endl;
return 1;
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_Window* win = SDL_CreateWindow("Space Ship Game",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
CONST_WIDTH, CONST_HEIGHT,
SDL_WINDOW_OPENGL);
SDL_Window* win = SDL_CreateWindow("Space Ship Game",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
CONST_WIDTH, CONST_HEIGHT,
SDL_WINDOW_OPENGL);
if (!win) {
std::cerr << "SDL_CreateWindow failed: " << SDL_GetError() << std::endl;
return 1;
}
if (!win) {
std::cerr << "SDL_CreateWindow failed: " << SDL_GetError() << std::endl;
return 1;
}
SDL_GLContext glContext = SDL_GL_CreateContext(win);
if (!glContext) {
std::cerr << "SDL_GL_CreateContext failed: " << SDL_GetError() << std::endl;
return 1;
}
SDL_GLContext glContext = SDL_GL_CreateContext(win);
if (!glContext) {
std::cerr << "SDL_GL_CreateContext failed: " << SDL_GetError() << std::endl;
return 1;
}
// Привязка контекста к окну — важно!
SDL_GL_MakeCurrent(win, glContext);
// Привязка контекста к окну — важно!
SDL_GL_MakeCurrent(win, glContext);
ZL::Environment::window = win;
ZL::Environment::window = win;
#else
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
SDL_Log("SDL init failed: %s", SDL_GetError());
return 1;
}
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
SDL_Log("SDL init failed: %s", SDL_GetError());
return 1;
}
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_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);
ZL::Environment::window = SDL_CreateWindow(
"Space Ship Game",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
CONST_WIDTH, CONST_HEIGHT,
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
);
ZL::Environment::window = SDL_CreateWindow(
"Space Ship Game",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
CONST_WIDTH, CONST_HEIGHT,
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
);
SDL_GLContext ctx = SDL_GL_CreateContext(ZL::Environment::window);
SDL_GL_MakeCurrent(ZL::Environment::window, ctx);
SDL_GLContext ctx = SDL_GL_CreateContext(ZL::Environment::window);
SDL_GL_MakeCurrent(ZL::Environment::window, ctx);
#endif
game.setup();
game.setup();
#ifdef EMSCRIPTEN
emscripten_set_main_loop(MainLoop, 0, 1);
emscripten_set_main_loop(MainLoop, 0, 1);
#else
while (!game.shouldExit()) {
game.update();
SDL_Delay(2);
}
while (!game.shouldExit()) {
game.update();
SDL_Delay(2);
}
#endif
}
catch (const std::exception& e)
{
std::cout << e.what() << std::endl;
}
return 0;
}

BIN
resources/DefaultMaterial_BaseColor.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/box/box.png (Stored with Git LFS) Normal file

Binary file not shown.

29
resources/box/box.txt Normal file
View File

@ -0,0 +1,29 @@
===Vertices (Split by UV/Normal): 14
V 0: Pos(1.0, 1.0, 1.0) Norm(0.57735, 0.57735, 0.57735) UV(0.5, 0.5)
V 1: Pos(-1.0, 1.0, 1.0) Norm(-0.57735, 0.57735, 0.57735) UV(0.75, 0.5)
V 2: Pos(-1.0, -1.0, 1.0) Norm(-0.57735, -0.57735, 0.57735) UV(0.75, 0.75)
V 3: Pos(1.0, -1.0, 1.0) Norm(0.57735, -0.57735, 0.57735) UV(0.5, 0.75)
V 4: Pos(1.0, -1.0, -1.0) Norm(0.57735, -0.57735, -0.57735) UV(0.25, 0.75)
V 5: Pos(-1.0, -1.0, 1.0) Norm(-0.57735, -0.57735, 0.57735) UV(0.5, 1.0)
V 6: Pos(-1.0, -1.0, -1.0) Norm(-0.57735, -0.57735, -0.57735) UV(0.25, 1.0)
V 7: Pos(-1.0, -1.0, -1.0) Norm(-0.57735, -0.57735, -0.57735) UV(0.25, 0.0)
V 8: Pos(-1.0, -1.0, 1.0) Norm(-0.57735, -0.57735, 0.57735) UV(0.5, 0.0)
V 9: Pos(-1.0, 1.0, 1.0) Norm(-0.57735, 0.57735, 0.57735) UV(0.5, 0.25)
V 10: Pos(-1.0, 1.0, -1.0) Norm(-0.57735, 0.57735, -0.57735) UV(0.25, 0.25)
V 11: Pos(-1.0, 1.0, -1.0) Norm(-0.57735, 0.57735, -0.57735) UV(0.0, 0.5)
V 12: Pos(1.0, 1.0, -1.0) Norm(0.57735, 0.57735, -0.57735) UV(0.25, 0.5)
V 13: Pos(-1.0, -1.0, -1.0) Norm(-0.57735, -0.57735, -0.57735) UV(0.0, 0.75)
===Triangles (Indices): 12
Tri: 0 1 2
Tri: 0 2 3
Tri: 4 3 5
Tri: 4 5 6
Tri: 7 8 9
Tri: 7 9 10
Tri: 11 12 4
Tri: 11 4 13
Tri: 12 0 3
Tri: 12 3 4
Tri: 10 9 0
Tri: 10 0 12

BIN
resources/button.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/musicVolumeBarButton.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/musicVolumeBarTexture.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/sky/space_bk.bmp (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/sky/space_dn.bmp (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/sky/space_ft.bmp (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/sky/space_lf.bmp (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/sky/space_rt.bmp (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/sky/space_up.bmp (Stored with Git LFS) Normal file

Binary file not shown.

15036
resources/spaceship005.txt Normal file

File diff suppressed because it is too large Load Diff

BIN
resources/spark.png (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 653 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 599 KiB

After

Width:  |  Height:  |  Size: 131 B

View File

@ -5,8 +5,8 @@ varying vec2 texCoord;
void main()
{
vec4 color = texture2D(Texture,texCoord).rgba;
gl_FragColor = vec4(color.rgb*0.9 + vec3(0.1, 0.1, 0.1), 1.0);
//gl_FragColor = vec4(color.rgb*0.9 + vec3(0.1, 0.1, 0.1), 1.0);
//gl_FragColor = color;
gl_FragColor = color;
}

13
shaders/env.fragment Normal file
View File

@ -0,0 +1,13 @@
uniform samplerCube Texture;
varying vec3 dir;
void main(){
gl_FragColor = textureCube(Texture, normalize(dir));
//if (dir.z < 0)
//{
// gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
//}
//gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

12
shaders/env.vertex Normal file
View File

@ -0,0 +1,12 @@
attribute vec3 vPosition;
uniform mat4 ProjectionModelViewMatrix;
varying vec3 dir;
void main(){
vec4 realVertexPos = vec4(vPosition.xyz, 1.0);
gl_Position = ProjectionModelViewMatrix * realVertexPos;
dir = vPosition;
}

View File

@ -0,0 +1,8 @@
uniform samplerCube Texture;
varying vec3 dir;
void main(){
gl_FragColor = textureCube(Texture, normalize(dir));
}

7
shaders/env_web.fragment Normal file
View File

@ -0,0 +1,7 @@
precision mediump float;
uniform samplerCube Texture;
varying vec3 dir;
void main(){
gl_FragColor = textureCube(Texture, normalize(dir));
}

View File

@ -1,31 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31402.337
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "space-game001", "space-game001.vcxproj", "{400A41AE-F904-4D49-9DBC-95934D0EF82E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{400A41AE-F904-4D49-9DBC-95934D0EF82E}.Debug|x64.ActiveCfg = Debug|x64
{400A41AE-F904-4D49-9DBC-95934D0EF82E}.Debug|x64.Build.0 = Debug|x64
{400A41AE-F904-4D49-9DBC-95934D0EF82E}.Debug|x86.ActiveCfg = Debug|Win32
{400A41AE-F904-4D49-9DBC-95934D0EF82E}.Debug|x86.Build.0 = Debug|Win32
{400A41AE-F904-4D49-9DBC-95934D0EF82E}.Release|x64.ActiveCfg = Release|x64
{400A41AE-F904-4D49-9DBC-95934D0EF82E}.Release|x64.Build.0 = Release|x64
{400A41AE-F904-4D49-9DBC-95934D0EF82E}.Release|x86.ActiveCfg = Release|Win32
{400A41AE-F904-4D49-9DBC-95934D0EF82E}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3D1B89D-D5F1-4E33-8439-56D6C43B07A2}
EndGlobalSection
EndGlobal

View File

@ -1,184 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{400a41ae-f904-4d49-9dbc-95934d0ef82e}</ProjectGuid>
<RootNamespace>ZeptoLabTest1</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>space-game001</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<TargetName>Viola</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>PNG_ENABLED;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>..\SDL-release-2.32.10\include;..\libpng-1.6.51\build\install\include;C:\Work\OpenAL 1.1 SDK\include;..\Projects\libogg\include;..\vorbis\include</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>zlibstaticd.lib;libpng16_staticd.lib;SDL2d.lib;SDL2maind.lib;opengl32.lib;glu32.lib;shell32.lib;opengl32.lib;glu32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>..\SDL-release-2.32.10\build\install\lib;..\libpng-1.6.51\build\install\lib;..\zlib-1.3.1\build\install\lib</AdditionalLibraryDirectories>
<EntryPointSymbol>
</EntryPointSymbol>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>C:\Work\SDL2-2.28.3\include;C:\Work\Projects\lpng1645\build\install\include;C:\Work\OpenAL 1.1 SDK\include;C:\Work\Projects\libogg\include;C:\Work\Projects\vorbis\include</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libogg_static.lib;audioplayer.lib;vorbisfile.lib;vorbis.lib;OpenAL32.lib;SDL2.lib;SDL2main.lib;opengl32.lib;glu32.lib;shell32.lib;opengl32.lib;glu32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Work\Projects\ZeptoLabTest1\cmakeaudioplayer\build\Release;C:\Work\SDL2-2.28.3\lib\x64;C:\Work\Projects\vorbis\build\lib\Release;C:\Work\OpenAL 1.1 SDK\libs\Win64;C:\Work\Projects\libogg\win32\VS2010\x64\Release</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="AudioPlayerAsync.cpp" />
<ClCompile Include="BoneAnimatedModel.cpp" />
<ClCompile Include="Environment.cpp" />
<ClCompile Include="Game.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="Math.cpp" />
<ClCompile Include="OpenGlExtensions.cpp" />
<ClCompile Include="Renderer.cpp" />
<ClCompile Include="ShaderManager.cpp" />
<ClCompile Include="TextModel.cpp" />
<ClCompile Include="TextureManager.cpp" />
<ClCompile Include="Utils.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AnimatedModel.h" />
<ClInclude Include="AudioPlayerAsync.h" />
<ClInclude Include="BoneAnimatedModel.h" />
<ClInclude Include="Environment.h" />
<ClInclude Include="Game.h" />
<ClInclude Include="Math.h" />
<ClInclude Include="OpenGlExtensions.h" />
<ClInclude Include="Renderer.h" />
<ClInclude Include="ShaderManager.h" />
<ClInclude Include="TextModel.h" />
<ClInclude Include="TextureManager.h" />
<ClInclude Include="Utils.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -1,93 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TextureManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Renderer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ShaderManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="OpenGlExtensions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Math.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Game.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="BoneAnimatedModel.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TextModel.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Environment.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AudioPlayerAsync.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="TextureManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Renderer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ShaderManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="OpenGlExtensions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Math.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Game.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AnimatedModel.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BoneAnimatedModel.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TextModel.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Environment.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AudioPlayerAsync.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

100
space-game001plain.html Normal file
View File

@ -0,0 +1,100 @@
<!doctypehtml>
<html lang=en-us>
<head>
<meta charset=utf-8>
<meta content="text/html; charset=utf-8" http-equiv=Content-Type>
<title>Space Game</title>
<style>
body {
font-family: arial;
margin: 0;
overflow: hidden;
padding: 0;
min-height: 100vh;
background-color: #000;
}
.emscripten {
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block
}
div.emscripten {
text-align: center
}
div.emscripten_border {
border: 1px solid #000
}
canvas.emscripten {
border: 0 none;
background-color: #000;
width: 90%;
height: 100vh;
}
@-webkit-keyframes rotation {
from {
-webkit-transform: rotate(0)
}
to {
-webkit-transform: rotate(360deg)
}
}
@-moz-keyframes rotation {
from {
-moz-transform: rotate(0)
}
to {
-moz-transform: rotate(360deg)
}
}
@-o-keyframes rotation {
from {
-o-transform: rotate(0)
}
to {
-o-transform: rotate(360deg)
}
}
@keyframes rotation {
from {
transform: rotate(0)
}
to {
transform: rotate(360deg)
}
}
#status {
display: none;
}
#progress {
height: 20px;
width: 300px
}
</style>
</head>
<body>
<div class=emscripten id=status></div>
<div class=emscripten><progress hidden id=progress max=100 value=0></progress></div>
<div class=emscripten_border><canvas class=emscripten id=canvas oncontextmenu=event.preventDefault()
tabindex=-1></canvas></div>
<script>var statusElement = document.getElementById("status"), progressElement = document.getElementById("progress"), spinnerElement = document.getElementById("spinner"), Module = { print: function () { var e = document.getElementById("output"); return e && (e.value = ""), function (t) { arguments.length > 1 && (t = Array.prototype.slice.call(arguments).join(" ")), console.log(t), e && (e.value += t + "\n", e.scrollTop = e.scrollHeight) } }(), canvas: (() => { var e = document.getElementById("canvas"); return e.addEventListener("webglcontextlost", (e => { alert("WebGL context lost. You will need to reload the page."), e.preventDefault() }), !1), e })(), setStatus: e => { if (Module.setStatus.last || (Module.setStatus.last = { time: Date.now(), text: "" }), e !== Module.setStatus.last.text) { var t = e.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/), n = Date.now(); t && n - Module.setStatus.last.time < 30 || (Module.setStatus.last.time = n, Module.setStatus.last.text = e, t ? (e = t[1], progressElement.value = 100 * parseInt(t[2]), progressElement.max = 100 * parseInt(t[4]), progressElement.hidden = !1, spinnerElement.hidden = !1) : (progressElement.value = null, progressElement.max = null, progressElement.hidden = !0, e || (spinnerElement.style.display = "none")), statusElement.innerHTML = e) } }, totalDependencies: 0, monitorRunDependencies: e => { this.totalDependencies = Math.max(this.totalDependencies, e), Module.setStatus(e ? "Preparing... (" + (this.totalDependencies - e) + "/" + this.totalDependencies + ")" : "All downloads complete.") } }; Module.setStatus("Downloading..."), window.onerror = e => { Module.setStatus("Exception thrown, see JavaScript console"), spinnerElement.style.display = "none", Module.setStatus = e => { e && console.error("[post-exception status] " + e) } }</script>
<script async src=space-game001.js></script>
</body>
</html>