Compare commits
41
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f197dfcf02 | ||
|
|
1af829bf49 | ||
|
|
7287f4b619 | ||
|
|
14b43239b5 | ||
|
|
7fc46d36a1 | ||
|
|
29834d528a | ||
|
|
e690d0f8e2 | ||
|
|
854a425d85 | ||
|
|
0464bed4cf | ||
|
|
7c272a2ee6 | ||
|
|
db25abc305 | ||
|
|
57ff27b0f6 | ||
|
|
a91d7c04e8 | ||
|
|
16ba536481 | ||
|
|
7a1961b5d1 | ||
|
|
af550f56a7 | ||
|
|
27fb7a448c | ||
|
|
2b6af91992 | ||
|
|
4afb9d6f4f | ||
|
|
fe361885c0 | ||
|
|
3887208b8d | ||
|
|
4c837eff0a | ||
|
|
8f9a18d960 | ||
|
|
bc49540a95 | ||
|
|
d2605d9108 | ||
|
|
115cbbb7fa | ||
|
|
ae1ca71a20 | ||
|
|
c02273d29d | ||
|
|
fec7e08c2b | ||
|
|
0f937e2e02 | ||
|
|
b855cff0e6 | ||
|
|
b768b27d49 | ||
|
|
c5044d42de | ||
|
|
88bc764f08 | ||
|
|
72a2b4c47c | ||
|
|
38f4f6b7fc | ||
|
|
af00e77dc2 | ||
|
|
0322098efa | ||
|
|
2b19a3eaba | ||
|
|
69941dd86d | ||
|
|
0843ee4fa4 |
No files matched your search
@@ -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
|
||||||
@@ -400,3 +400,4 @@ jumpingbird.*
|
|||||||
jumpingbird.data
|
jumpingbird.data
|
||||||
build
|
build
|
||||||
build-emcmake
|
build-emcmake
|
||||||
|
thirdparty1
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Math.h"
|
#include "ZLMath.h"
|
||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
|||||||
+544
@@ -0,0 +1,544 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
project(space-game001 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
set(BUILD_CONFIGS Debug Release)
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
# Папка для всех сторонних либ
|
||||||
|
# ==============================
|
||||||
|
set(THIRDPARTY_DIR "${CMAKE_SOURCE_DIR}/thirdparty1")
|
||||||
|
file(MAKE_DIRECTORY "${THIRDPARTY_DIR}")
|
||||||
|
|
||||||
|
macro(log msg)
|
||||||
|
message(STATUS "${msg}")
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# ===========================================
|
||||||
|
# 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")
|
||||||
|
set(ZLIB_BUILD_DIR "${ZLIB_SRC_DIR}/build")
|
||||||
|
set(ZLIB_INSTALL_DIR "${ZLIB_SRC_DIR}/install")
|
||||||
|
|
||||||
|
if(NOT EXISTS "${ZLIB_ARCHIVE}")
|
||||||
|
log("Downloading zlib131.zip ...")
|
||||||
|
file(DOWNLOAD
|
||||||
|
"https://www.zlib.net/zlib131.zip"
|
||||||
|
"${ZLIB_ARCHIVE}"
|
||||||
|
SHOW_PROGRESS
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${ZLIB_SRC_DIR}/CMakeLists.txt")
|
||||||
|
log("Extracting zlib131.zip to zlib-1.3.1 ...")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E tar xvf "${ZLIB_ARCHIVE}"
|
||||||
|
WORKING_DIRECTORY "${THIRDPARTY_DIR}"
|
||||||
|
RESULT_VARIABLE _zlib_extract_res
|
||||||
|
)
|
||||||
|
if(NOT _zlib_extract_res EQUAL 0)
|
||||||
|
message(FATAL_ERROR "Failed to extract zlib archive")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(MAKE_DIRECTORY "${ZLIB_BUILD_DIR}")
|
||||||
|
|
||||||
|
# проверяем, собран ли уже zlib
|
||||||
|
set(_have_zlib FALSE)
|
||||||
|
foreach(candidate
|
||||||
|
"${ZLIB_INSTALL_DIR}/lib/zlibstatic.lib"
|
||||||
|
)
|
||||||
|
if(EXISTS "${candidate}")
|
||||||
|
set(_have_zlib TRUE)
|
||||||
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
|
||||||
|
if(NOT _have_zlib)
|
||||||
|
log("Configuring zlib ...")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND}
|
||||||
|
-G "${CMAKE_GENERATOR}"
|
||||||
|
-S "${ZLIB_SRC_DIR}"
|
||||||
|
-B "${ZLIB_BUILD_DIR}"
|
||||||
|
-DCMAKE_INSTALL_PREFIX=${ZLIB_INSTALL_DIR}
|
||||||
|
RESULT_VARIABLE _zlib_cfg_res
|
||||||
|
)
|
||||||
|
if(NOT _zlib_cfg_res EQUAL 0)
|
||||||
|
message(FATAL_ERROR "zlib configure 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 (${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
|
||||||
|
# Динамическая линковка (если 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) - без изменений
|
||||||
|
# ===========================================
|
||||||
|
set(SDL2_ARCHIVE "${THIRDPARTY_DIR}/release-2.32.10.zip")
|
||||||
|
set(SDL2_SRC_DIR "${THIRDPARTY_DIR}/SDL-release-2.32.10")
|
||||||
|
set(SDL2_BUILD_DIR "${SDL2_SRC_DIR}/build")
|
||||||
|
set(SDL2_INSTALL_DIR "${SDL2_SRC_DIR}/install")
|
||||||
|
|
||||||
|
if(NOT EXISTS "${SDL2_ARCHIVE}")
|
||||||
|
log("Downloading SDL2 release-2.32.10.zip ...")
|
||||||
|
file(DOWNLOAD
|
||||||
|
"https://github.com/libsdl-org/SDL/archive/refs/tags/release-2.32.10.zip"
|
||||||
|
"${SDL2_ARCHIVE}"
|
||||||
|
SHOW_PROGRESS
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${SDL2_SRC_DIR}/CMakeLists.txt")
|
||||||
|
log("Extracting SDL2 archive to SDL-release-2.32.10 ...")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E tar xvf "${SDL2_ARCHIVE}"
|
||||||
|
WORKING_DIRECTORY "${THIRDPARTY_DIR}"
|
||||||
|
RESULT_VARIABLE _sdl_extract_res
|
||||||
|
)
|
||||||
|
if(NOT _sdl_extract_res EQUAL 0)
|
||||||
|
message(FATAL_ERROR "Failed to extract SDL2 archive")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(MAKE_DIRECTORY "${SDL2_BUILD_DIR}")
|
||||||
|
|
||||||
|
set(_have_sdl2 FALSE)
|
||||||
|
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(_have_sdl2 TRUE)
|
||||||
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(NOT _have_sdl2)
|
||||||
|
log("Configuring SDL2 ...")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND}
|
||||||
|
-G "${CMAKE_GENERATOR}"
|
||||||
|
-S "${SDL2_SRC_DIR}"
|
||||||
|
-B "${SDL2_BUILD_DIR}"
|
||||||
|
-DCMAKE_INSTALL_PREFIX=${SDL2_INSTALL_DIR}
|
||||||
|
-DCMAKE_PREFIX_PATH=${ZLIB_INSTALL_DIR} # путь к zlib для SDL2
|
||||||
|
RESULT_VARIABLE _sdl_cfg_res
|
||||||
|
)
|
||||||
|
if(NOT _sdl_cfg_res EQUAL 0)
|
||||||
|
message(FATAL_ERROR "SDL2 configure 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 (${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()
|
||||||
|
|
||||||
|
|
||||||
|
# ИСПРАВЛЕНИЕ: SDL2: Используем свойства для конкретных конфигураций
|
||||||
|
add_library(SDL2_external_lib UNKNOWN IMPORTED GLOBAL)
|
||||||
|
set_target_properties(SDL2_external_lib PROPERTIES
|
||||||
|
# Динамическая линковка 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 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) - без изменений
|
||||||
|
# ===========================================
|
||||||
|
set(LIBPNG_ARCHIVE "${THIRDPARTY_DIR}/v1.6.51.zip")
|
||||||
|
set(LIBPNG_SRC_DIR "${THIRDPARTY_DIR}/libpng-1.6.51")
|
||||||
|
set(LIBPNG_BUILD_DIR "${LIBPNG_SRC_DIR}/build")
|
||||||
|
set(LIBPNG_INSTALL_DIR "${LIBPNG_SRC_DIR}/install") # на будущее
|
||||||
|
|
||||||
|
if(NOT EXISTS "${LIBPNG_ARCHIVE}")
|
||||||
|
log("Downloading libpng v1.6.51.zip ...")
|
||||||
|
file(DOWNLOAD
|
||||||
|
"https://github.com/pnggroup/libpng/archive/refs/tags/v1.6.51.zip"
|
||||||
|
"${LIBPNG_ARCHIVE}"
|
||||||
|
SHOW_PROGRESS
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${LIBPNG_SRC_DIR}/CMakeLists.txt")
|
||||||
|
log("Extracting libpng v1.6.51.zip to libpng-1.6.51 ...")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E tar xvf "${LIBPNG_ARCHIVE}"
|
||||||
|
WORKING_DIRECTORY "${THIRDPARTY_DIR}"
|
||||||
|
RESULT_VARIABLE _png_extract_res
|
||||||
|
)
|
||||||
|
if(NOT _png_extract_res EQUAL 0)
|
||||||
|
message(FATAL_ERROR "Failed to extract libpng archive")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(MAKE_DIRECTORY "${LIBPNG_BUILD_DIR}")
|
||||||
|
|
||||||
|
# Проверяем, есть ли уже .lib (build/Debug или install/lib)
|
||||||
|
set(_libpng_candidates
|
||||||
|
"${LIBPNG_BUILD_DIR}/Debug/libpng16_staticd.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)
|
||||||
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(NOT _have_png)
|
||||||
|
log("Configuring libpng ...")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND}
|
||||||
|
-G "${CMAKE_GENERATOR}"
|
||||||
|
-S "${LIBPNG_SRC_DIR}"
|
||||||
|
-B "${LIBPNG_BUILD_DIR}"
|
||||||
|
-DCMAKE_INSTALL_PREFIX=${LIBPNG_INSTALL_DIR}
|
||||||
|
-DCMAKE_PREFIX_PATH=${ZLIB_INSTALL_DIR}
|
||||||
|
-DZLIB_ROOT=${ZLIB_INSTALL_DIR}
|
||||||
|
RESULT_VARIABLE _png_cfg_res
|
||||||
|
)
|
||||||
|
if(NOT _png_cfg_res EQUAL 0)
|
||||||
|
message(FATAL_ERROR "libpng configure failed")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# --- ИЗМЕНЕНИЕ: Цикл по конфигурациям 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
|
||||||
|
# Предполагая, что 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}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# ===========================================
|
||||||
|
# 4) libzip (v1.11.4.zip → libzip-1.11.4) - НОВАЯ ЗАВИСИМОСТЬ
|
||||||
|
# ===========================================
|
||||||
|
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
|
||||||
|
Environment.cpp
|
||||||
|
Environment.h
|
||||||
|
Renderer.cpp
|
||||||
|
Renderer.h
|
||||||
|
ShaderManager.cpp
|
||||||
|
ShaderManager.h
|
||||||
|
TextureManager.cpp
|
||||||
|
TextureManager.h
|
||||||
|
TextModel.cpp
|
||||||
|
TextModel.h
|
||||||
|
AudioPlayerAsync.cpp
|
||||||
|
AudioPlayerAsync.h
|
||||||
|
BoneAnimatedModel.cpp
|
||||||
|
BoneAnimatedModel.h
|
||||||
|
ZLMath.cpp
|
||||||
|
ZLMath.h
|
||||||
|
OpenGlExtensions.cpp
|
||||||
|
OpenGlExtensions.h
|
||||||
|
Utils.cpp
|
||||||
|
Utils.h
|
||||||
|
SparkEmitter.cpp
|
||||||
|
SparkEmitter.h
|
||||||
|
PlanetObject.cpp
|
||||||
|
PlanetObject.h
|
||||||
|
PlanetData.cpp
|
||||||
|
PlanetData.h
|
||||||
|
Perlin.cpp
|
||||||
|
Perlin.h
|
||||||
|
StoneObject.cpp
|
||||||
|
StoneObject.h
|
||||||
|
FrameBuffer.cpp
|
||||||
|
FrameBuffer.h
|
||||||
|
)
|
||||||
|
|
||||||
|
# Установка проекта по умолчанию для Visual Studio
|
||||||
|
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT space-game001)
|
||||||
|
|
||||||
|
# include-пути проекта
|
||||||
|
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"
|
||||||
|
#"${LIBZIP_INSTALL_DIR}-Release/include" # Добавил include-путь для libzip
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
PNG_ENABLED
|
||||||
|
SDL_MAIN_HANDLED
|
||||||
|
)
|
||||||
|
|
||||||
|
# Линкуем с SDL2main, если он вообще установлен
|
||||||
|
target_link_libraries(space-game001 PRIVATE SDL2main_external_lib)
|
||||||
|
|
||||||
|
# Линкуем сторонние библиотеки
|
||||||
|
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)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ===========================================
|
||||||
|
# Копирование SDL2d.dll и zlibd.dll рядом с exe
|
||||||
|
# ===========================================
|
||||||
|
if (WIN32)
|
||||||
|
|
||||||
|
# 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_DLL_SRC}"
|
||||||
|
"${SDL2_DLL_DST}"
|
||||||
|
|
||||||
|
# Копируем LIBZIP (целевое имя всегда zip.dll)
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
"${LIBZIP_DLL_SRC}"
|
||||||
|
"$<TARGET_FILE_DIR:space-game001>/zip.dll"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ===========================================
|
||||||
|
# Копирование ресурсов после сборки
|
||||||
|
# ===========================================
|
||||||
|
|
||||||
|
# Какие папки с ресурсами нужно копировать
|
||||||
|
set(RUNTIME_RESOURCE_DIRS
|
||||||
|
"resources"
|
||||||
|
"shaders"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Копируем ресурсы и шейдеры в папку exe и в корень build/
|
||||||
|
foreach(resdir IN LISTS RUNTIME_RESOURCE_DIRS)
|
||||||
|
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}"
|
||||||
|
# 2) в корень build, если захочешь запускать из этой папки
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
"${CMAKE_SOURCE_DIR}/${resdir}"
|
||||||
|
"${CMAKE_BINARY_DIR}/${resdir}"
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
+16
-7
@@ -8,19 +8,13 @@ namespace ZL {
|
|||||||
int Environment::windowHeaderHeight = 0;
|
int Environment::windowHeaderHeight = 0;
|
||||||
int Environment::width = 0;
|
int Environment::width = 0;
|
||||||
int Environment::height = 0;
|
int Environment::height = 0;
|
||||||
float Environment::zoom = 20.f;
|
float Environment::zoom = 18.f;
|
||||||
|
|
||||||
bool Environment::leftPressed = false;
|
bool Environment::leftPressed = false;
|
||||||
bool Environment::rightPressed = false;
|
bool Environment::rightPressed = false;
|
||||||
bool Environment::upPressed = false;
|
bool Environment::upPressed = false;
|
||||||
bool Environment::downPressed = 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;
|
bool Environment::settings_inverseVertical = false;
|
||||||
|
|
||||||
SDL_Window* Environment::window = nullptr;
|
SDL_Window* Environment::window = nullptr;
|
||||||
@@ -29,6 +23,21 @@ bool Environment::showMouse = false;
|
|||||||
|
|
||||||
bool Environment::exitGameLoop = 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,45000.f};
|
||||||
|
|
||||||
|
float Environment::shipVelocity = 0.f;
|
||||||
|
|
||||||
|
|
||||||
|
const float Environment::CONST_Z_NEAR = 5.f;
|
||||||
|
const float Environment::CONST_Z_FAR = 5000.f;
|
||||||
|
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
+16
-8
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Math.h"
|
#include "ZLMath.h"
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -19,21 +19,29 @@ public:
|
|||||||
static bool upPressed;
|
static bool upPressed;
|
||||||
static bool downPressed;
|
static bool downPressed;
|
||||||
|
|
||||||
static Vector3f cameraShift;
|
|
||||||
static Vector3f characterPos;
|
|
||||||
static float cameraPhi;
|
|
||||||
static float cameraAlpha;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static bool settings_inverseVertical;
|
static bool settings_inverseVertical;
|
||||||
|
|
||||||
|
static Matrix3f shipMatrix;
|
||||||
|
static Matrix3f inverseShipMatrix;
|
||||||
|
|
||||||
static SDL_Window* window;
|
static SDL_Window* window;
|
||||||
|
|
||||||
static bool showMouse;
|
static bool showMouse;
|
||||||
static bool exitGameLoop;
|
static bool exitGameLoop;
|
||||||
|
|
||||||
|
|
||||||
|
static bool tapDownHold;
|
||||||
|
static Vector2f tapDownStartPos;
|
||||||
|
static Vector2f tapDownCurrentPos;
|
||||||
|
|
||||||
|
static Vector3f shipPosition;
|
||||||
|
static float shipVelocity;
|
||||||
|
|
||||||
|
static const float CONST_Z_NEAR;
|
||||||
|
static const float CONST_Z_FAR;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#include "FrameBuffer.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include "Environment.h"
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
FrameBuffer::FrameBuffer(int w, int h) : width(w), height(h) {
|
||||||
|
// 1. Ñîçäàåì FBO
|
||||||
|
glGenFramebuffers(1, &fbo);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
|
||||||
|
// 2. Ñîçäàåì òåêñòóðó, êóäà áóäåì "ôîòîãðàôèðîâàòü"
|
||||||
|
glGenTextures(1, &textureID);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
||||||
|
|
||||||
|
// Óñòàíàâëèâàåì ïàðàìåòðû òåêñòóðû
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
// 3. Ïðèâÿçûâàåì òåêñòóðó ê FBO
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0);
|
||||||
|
|
||||||
|
// Ïðîâåðêà ãîòîâíîñòè
|
||||||
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
|
std::cerr << "Error: Framebuffer is not complete!" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameBuffer::~FrameBuffer() {
|
||||||
|
glDeleteFramebuffers(1, &fbo);
|
||||||
|
glDeleteTextures(1, &textureID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameBuffer::Bind() {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
glViewport(0, 0, width, height); // Âàæíî: óñòàíàâëèâàåì âüþïîðò ïîä ðàçìåð òåêñòóðû
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameBuffer::Unbind() {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
// Çäåñü æåëàòåëüíî âîçâðàùàòü âüþïîðò ê ðàçìåðàì ýêðàíà,
|
||||||
|
// íàïðèìåð, ÷åðåç Environment::width/height
|
||||||
|
glViewport(0, 0, Environment::width, Environment::height);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "OpenGlExtensions.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
class FrameBuffer {
|
||||||
|
private:
|
||||||
|
GLuint fbo = 0;
|
||||||
|
GLuint textureID = 0;
|
||||||
|
int width, height;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FrameBuffer(int w, int h);
|
||||||
|
~FrameBuffer();
|
||||||
|
|
||||||
|
// Çàïðåùàåì êîïèðîâàíèå, êàê â VBOHolder
|
||||||
|
FrameBuffer(const FrameBuffer&) = delete;
|
||||||
|
FrameBuffer& operator=(const FrameBuffer&) = delete;
|
||||||
|
|
||||||
|
void Bind(); // Íà÷àòü ðåíäåð â ýòîò áóôåð
|
||||||
|
void Unbind(); // Âåðíóòüñÿ ê îáû÷íîìó ðåíäåðó â ýêðàí
|
||||||
|
|
||||||
|
GLuint getTextureID() const { return textureID; }
|
||||||
|
int getWidth() const { return width; }
|
||||||
|
int getHeight() const { return height; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "AnimatedModel.h"
|
#include "AnimatedModel.h"
|
||||||
#include "BoneAnimatedModel.h"
|
#include "BoneAnimatedModel.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
@@ -6,160 +6,650 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "TextureManager.h"
|
#include "TextureManager.h"
|
||||||
#include "TextModel.h"
|
#include "TextModel.h"
|
||||||
|
#include "StoneObject.h"
|
||||||
|
#include <random>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
namespace ZL
|
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
|
#ifdef EMSCRIPTEN
|
||||||
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_web.fragment", CONST_ZIP_FILE);
|
const char* CONST_ZIP_FILE = "space-game001.zip";
|
||||||
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_web.fragment", CONST_ZIP_FILE);
|
|
||||||
#else
|
#else
|
||||||
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE);
|
const char* CONST_ZIP_FILE = "";
|
||||||
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_desktop.fragment", CONST_ZIP_FILE);
|
|
||||||
#endif
|
#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();
|
|
||||||
|
|
||||||
|
|
||||||
renderer.InitOpenGL();
|
Vector4f generateRandomQuaternion(std::mt19937& gen)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
std::normal_distribution<> distrib(0.0, 1.0);
|
||||||
|
|
||||||
void Game::drawScene() {
|
Vector4f randomQuat = {
|
||||||
static const std::string defaultShaderName = "default";
|
(float)distrib(gen),
|
||||||
static const std::string vPositionName = "vPosition";
|
(float)distrib(gen),
|
||||||
static const std::string vTexCoordName = "vTexCoord";
|
(float)distrib(gen),
|
||||||
static const std::string textureUniformName = "Texture";
|
(float)distrib(gen)
|
||||||
|
};
|
||||||
|
|
||||||
glClearColor(0.0f, 0.5f, 1.0f, 1.0f);
|
return randomQuat.normalized();
|
||||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
}
|
||||||
|
|
||||||
glViewport(0, 0, Environment::width, Environment::height);
|
|
||||||
|
|
||||||
CheckGlError();
|
|
||||||
|
|
||||||
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 });
|
|
||||||
renderer.RotateMatrix(QuatFromRotateAroundX(M_PI/6.0));
|
|
||||||
//renderer.RotateMatrix(QuatFromRotateAroundX(Environment::cameraAlpha));
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
|
|
||||||
renderer.DrawVertexRenderStruct(spaceship);
|
|
||||||
|
|
||||||
renderer.PopMatrix();
|
|
||||||
renderer.PopProjectionMatrix();
|
|
||||||
renderer.DisableVertexAttribArray(vPositionName);
|
|
||||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
|
||||||
|
|
||||||
renderer.shaderManager.PopShader();
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
Environment::cameraAlpha = Environment::cameraAlpha + delta * M_PI / 10000.f;
|
|
||||||
|
|
||||||
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_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;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//this->modelMeshRender.data.Scale(0.5);
|
|
||||||
//this->modelMeshRender.RefreshVBO();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
std::vector<BoxCoords> generateRandomBoxCoords(int N)
|
||||||
render();
|
{
|
||||||
}
|
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;
|
||||||
|
std::vector<BoxCoords> boxCoordsArr;
|
||||||
|
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
|
||||||
|
std::uniform_real_distribution<> distrib(MIN_COORD, MAX_COORD);
|
||||||
|
|
||||||
|
int generatedCount = 0;
|
||||||
|
|
||||||
|
while (generatedCount < N)
|
||||||
|
{
|
||||||
|
bool accepted = false;
|
||||||
|
int attempts = 0;
|
||||||
|
|
||||||
|
while (!accepted && attempts < MAX_ATTEMPTS)
|
||||||
|
{
|
||||||
|
Vector3f newPos(
|
||||||
|
(float)distrib(gen),
|
||||||
|
(float)distrib(gen),
|
||||||
|
(float)distrib(gen)
|
||||||
|
);
|
||||||
|
|
||||||
|
accepted = true;
|
||||||
|
for (const auto& existingBox : boxCoordsArr)
|
||||||
|
{
|
||||||
|
|
||||||
|
Vector3f diff = newPos - existingBox.pos;
|
||||||
|
|
||||||
|
float distanceSquared = diff.squaredNorm();
|
||||||
|
|
||||||
|
if (distanceSquared < MIN_DISTANCE_SQUARED)
|
||||||
|
{
|
||||||
|
accepted = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accepted)
|
||||||
|
{
|
||||||
|
Vector4f randomQuat = generateRandomQuaternion(gen);
|
||||||
|
|
||||||
|
Matrix3f randomMatrix = QuatToMatrix(randomQuat);
|
||||||
|
|
||||||
|
boxCoordsArr.emplace_back(BoxCoords{ newPos, randomMatrix });
|
||||||
|
generatedCount++;
|
||||||
|
}
|
||||||
|
attempts++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!accepted) {
|
||||||
|
std::cerr << "Ïðåäóïðåæäåíèå: Íå óäàëîñü ñãåíåðèðîâàòü " << N << " îáúåêòîâ. Ñãåíåðèðîâàíî: " << generatedCount << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return boxCoordsArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_web.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "./shaders/defaultAtmosphere.vertex", "./shaders/defaultAtmosphere.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("defaultColorPlanet", "./shaders/defaultColorPlanet.vertex", "./shaders/defaultColorPlanet_web.fragment", CONST_ZIP_FILE);
|
||||||
|
|
||||||
|
#else
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor_fog.vertex", "./shaders/defaultColor_fog_desktop.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env_sky.vertex", "./shaders/env_sky_desktop.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "./shaders/defaultAtmosphere.vertex", "./shaders/defaultAtmosphere.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("defaultColor2", "./shaders/defaultColor_fog2.vertex", "./shaders/defaultColor_fog2_desktop.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("defaultColorStones", "./shaders/defaultColor_fog_stones.vertex", "./shaders/defaultColor_fog_stones_desktop.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("planetBake", "./shaders/planet_bake.vertex", "./shaders/planet_bake_desktop.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("planetStone", "./shaders/planet_stone.vertex", "./shaders/planet_stone_desktop.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("planetLand", "./shaders/planet_land.vertex", "./shaders/planet_land_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_shine.png", CONST_ZIP_FILE));
|
||||||
|
spaceshipBase = LoadFromTextFile02("./resources/spaceship006.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].data = CreateBaseConvexPolyhedron(1999);
|
||||||
|
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();
|
||||||
|
|
||||||
|
rockTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", ""));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::drawCubemap(float skyPercent)
|
||||||
|
{
|
||||||
|
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";
|
||||||
|
static const std::string skyPercentUniformName = "skyPercent";
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(envShaderName);
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
renderer.RenderUniform1f(skyPercentUniformName, skyPercent);
|
||||||
|
renderer.EnableVertexAttribArray(vPositionName);
|
||||||
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||||
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||||
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||||
|
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),
|
||||||
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||||
|
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),
|
||||||
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||||
|
|
||||||
|
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({ 0.f, 0.f, 45000.f });
|
||||||
|
renderer.TranslateMatrix(boxCoordsArr[i].pos);
|
||||||
|
renderer.RotateMatrix(boxCoordsArr[i].m);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID());
|
||||||
|
//glBindTexture(GL_TEXTURE_2D, rockTexture->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, 1.0f, 0.0f, 1.0f);
|
||||||
|
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
glViewport(0, 0, Environment::width, Environment::height);
|
||||||
|
|
||||||
|
CheckGlError();
|
||||||
|
|
||||||
|
float skyPercent = 0.0;
|
||||||
|
float distance = planetObject.distanceToPlanetSurface(Environment::shipPosition);
|
||||||
|
if (distance > 1900.f)
|
||||||
|
{
|
||||||
|
skyPercent = 0.0f;
|
||||||
|
}
|
||||||
|
else if (distance < 1000.f)
|
||||||
|
{
|
||||||
|
skyPercent = 1.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
skyPercent = (1900.f - distance) / 900.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
drawCubemap(skyPercent);
|
||||||
|
planetObject.draw(renderer);
|
||||||
|
if (planetObject.distanceToPlanetSurface(Environment::shipPosition) > 100.f)
|
||||||
|
{
|
||||||
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
drawShip();
|
||||||
|
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));
|
||||||
|
planetObject.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 += 500.f;
|
||||||
|
}
|
||||||
|
if (event.key.keysym.sym == SDLK_k)
|
||||||
|
{
|
||||||
|
Environment::shipVelocity -= 500.f;
|
||||||
|
}
|
||||||
|
if (event.key.keysym.sym == SDLK_o)
|
||||||
|
{
|
||||||
|
Environment::shipVelocity += 50.f;
|
||||||
|
}
|
||||||
|
if (event.key.keysym.sym == SDLK_l)
|
||||||
|
{
|
||||||
|
Environment::shipVelocity -= 50.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
@@ -1,40 +1,95 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "OpenGlExtensions.h"
|
#include "OpenGlExtensions.h"
|
||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
#include "TextureManager.h"
|
#include "TextureManager.h"
|
||||||
|
#include "SparkEmitter.h"
|
||||||
|
#include "PlanetObject.h"
|
||||||
|
|
||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
class Game {
|
|
||||||
public:
|
|
||||||
Game();
|
|
||||||
~Game();
|
|
||||||
|
|
||||||
void setup();
|
struct BoxCoords
|
||||||
void update();
|
{
|
||||||
void render();
|
Vector3f pos;
|
||||||
|
Matrix3f m;
|
||||||
|
};
|
||||||
|
|
||||||
bool shouldExit() const { return Environment::exitGameLoop; }
|
|
||||||
|
|
||||||
private:
|
class Game {
|
||||||
void processTickCount();
|
public:
|
||||||
void drawScene();
|
Game();
|
||||||
|
~Game();
|
||||||
|
|
||||||
SDL_Window* window;
|
void setup();
|
||||||
SDL_GLContext glContext;
|
void update();
|
||||||
Renderer renderer;
|
void render();
|
||||||
|
|
||||||
size_t newTickCount;
|
|
||||||
size_t lastTickCount;
|
|
||||||
|
|
||||||
static const size_t CONST_TIMER_INTERVAL = 10;
|
bool shouldExit() const { return Environment::exitGameLoop; }
|
||||||
static const size_t CONST_MAX_TIME_INTERVAL = 1000;
|
|
||||||
|
private:
|
||||||
|
void processTickCount();
|
||||||
|
void drawScene();
|
||||||
|
void drawCubemap(float skyPercent);
|
||||||
|
void drawShip();
|
||||||
|
void drawBoxes();
|
||||||
|
void drawUI();
|
||||||
|
|
||||||
|
SDL_Window* window;
|
||||||
|
SDL_GLContext glContext;
|
||||||
|
Renderer renderer;
|
||||||
|
|
||||||
|
size_t newTickCount;
|
||||||
|
size_t lastTickCount;
|
||||||
|
|
||||||
|
std::shared_ptr<Texture> rockTexture;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
std::shared_ptr<Texture> spaceshipTexture;
|
|
||||||
VertexDataStruct spaceshipBase;
|
|
||||||
VertexRenderStruct spaceship;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
#include "Perlin.h"
|
||||||
|
#include <cmath>
|
||||||
|
#include <numeric>
|
||||||
|
#include <random>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
PerlinNoise::PerlinNoise() {
|
||||||
|
p.resize(256);
|
||||||
|
std::iota(p.begin(), p.end(), 0);
|
||||||
|
// Ïåðåìåøèâàåì äëÿ ñëó÷àéíîñòè (ìîæíî çàäàòü seed)
|
||||||
|
std::default_random_engine engine(77777);
|
||||||
|
std::shuffle(p.begin(), p.end(), engine);
|
||||||
|
p.insert(p.end(), p.begin(), p.end()); // Äóáëèðóåì äëÿ ïåðåïîëíåíèÿ
|
||||||
|
}
|
||||||
|
|
||||||
|
PerlinNoise::PerlinNoise(uint64_t seed) {
|
||||||
|
p.resize(256);
|
||||||
|
std::iota(p.begin(), p.end(), 0);
|
||||||
|
// Ïåðåìåøèâàåì äëÿ ñëó÷àéíîñòè (èñïîëüçóåì ïåðåäàííûé seed)
|
||||||
|
std::default_random_engine engine(static_cast<unsigned int>(seed));
|
||||||
|
std::shuffle(p.begin(), p.end(), engine);
|
||||||
|
p.insert(p.end(), p.begin(), p.end()); // Äóáëèðóåì äëÿ ïåðåïîëíåíèÿ
|
||||||
|
}
|
||||||
|
|
||||||
|
float PerlinNoise::fade(float t) { return t * t * t * (t * (t * 6 - 15) + 10); }
|
||||||
|
|
||||||
|
float PerlinNoise::lerp(float t, float a, float b) { return a + t * (b - a); }
|
||||||
|
|
||||||
|
float PerlinNoise::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 PerlinNoise::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 PerlinNoise::getSurfaceHeight(Vector3f pos, float noiseCoeff) {
|
||||||
|
// ×àñòîòà øóìà (÷åì áîëüøå, òåì áîëüøå "õîëìîâ")
|
||||||
|
float frequency = 7.0f;
|
||||||
|
|
||||||
|
// Ïîëó÷àåì çíà÷åíèå øóìà (îáû÷íî îò -1 äî 1)
|
||||||
|
float noiseValue = noise(pos.v[0] * frequency, pos.v[1] * frequency, pos.v[2] * frequency);
|
||||||
|
|
||||||
|
// Ìàñøòàáèðóåì: õîòèì îòêëîíåíèå îò 1.0 äî 1.1 (ïðèìåðíî)
|
||||||
|
float height = 1.0f + (noiseValue * noiseCoeff);
|
||||||
|
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
#include "ZLMath.h"
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
class PerlinNoise {
|
||||||
|
std::vector<int> p;
|
||||||
|
public:
|
||||||
|
PerlinNoise();
|
||||||
|
PerlinNoise(uint64_t seed);
|
||||||
|
|
||||||
|
float fade(float t);
|
||||||
|
float lerp(float t, float a, float b);
|
||||||
|
float grad(int hash, float x, float y, float z);
|
||||||
|
|
||||||
|
float noise(float x, float y, float z);
|
||||||
|
|
||||||
|
float getSurfaceHeight(Vector3f pos, float noiseCoeff);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
+493
@@ -0,0 +1,493 @@
|
|||||||
|
#include "PlanetData.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <numeric>
|
||||||
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
const float PlanetData::PLANET_RADIUS = 20000.f;
|
||||||
|
const Vector3f PlanetData::PLANET_CENTER_OFFSET = Vector3f{ 0.f, 0.f, 0.0f };
|
||||||
|
|
||||||
|
// --- Êîíñòàíòû äèàïàçîíîâ (ïåðåíåñåíû èç PlanetObject.cpp) ---
|
||||||
|
|
||||||
|
VertexID generateEdgeID(const VertexID& id1, const VertexID& id2) {
|
||||||
|
return id1 < id2 ? id1 + "_" + id2 : id2 + "_" + id1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Âñïîìîãàòåëüíàÿ ôóíêöèÿ äëÿ ïðîåêöèè (ëîêàëüíàÿ)
|
||||||
|
static Vector3f projectPointOnPlane(const Vector3f& P, const Vector3f& A, const Vector3f& B, const Vector3f& C) {
|
||||||
|
Vector3f AB = B + A * (-1.0f);
|
||||||
|
Vector3f AC = C + A * (-1.0f);
|
||||||
|
Vector3f N = AB.cross(AC).normalized();
|
||||||
|
Vector3f AP = P + A * (-1.0f);
|
||||||
|
float distance = N.dot(AP);
|
||||||
|
return P + N * (-distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
PlanetData::PlanetData()
|
||||||
|
: perlin(77777)
|
||||||
|
, colorPerlin(123123)
|
||||||
|
, currentLod(0)
|
||||||
|
{
|
||||||
|
currentLod = planetMeshLods.size() - 1; // Start with max LOD
|
||||||
|
|
||||||
|
initialVertexMap = {
|
||||||
|
{{ 0.0f, 1.0f, 0.0f}, "A"},
|
||||||
|
{{ 0.0f, -1.0f, 0.0f}, "B"},
|
||||||
|
{{ 1.0f, 0.0f, 0.0f}, "C"},
|
||||||
|
{{-1.0f, 0.0f, 0.0f}, "D"},
|
||||||
|
{{ 0.0f, 0.0f, 1.0f}, "E"},
|
||||||
|
{{ 0.0f, 0.0f, -1.0f}, "F"}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanetData::init() {
|
||||||
|
for (int i = 0; i < planetMeshLods.size(); i++) {
|
||||||
|
planetMeshLods[i] = generateSphere(i, 0.025f);
|
||||||
|
planetMeshLods[i].Scale(PLANET_RADIUS);
|
||||||
|
planetMeshLods[i].Move(PLANET_CENTER_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < planetMeshLodsNoDist.size(); i++) {
|
||||||
|
planetMeshLodsNoDist[i] = generateSphere(i, 0);
|
||||||
|
planetMeshLodsNoDist[i].Scale(PLANET_RADIUS);
|
||||||
|
planetMeshLodsNoDist[i].Move(PLANET_CENTER_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
planetAtmosphereLod = generateSphere(5, 0);
|
||||||
|
planetAtmosphereLod.Scale(PLANET_RADIUS * 1.03);
|
||||||
|
planetAtmosphereLod.Move(PLANET_CENTER_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
const LodLevel& PlanetData::getLodLevel(int level) const {
|
||||||
|
return planetMeshLods.at(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
const LodLevel& PlanetData::getLodLevelNoDist(int level) const {
|
||||||
|
return planetMeshLodsNoDist.at(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
const LodLevel& PlanetData::getAtmosphereLod() const {
|
||||||
|
return planetAtmosphereLod;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlanetData::getCurrentLodIndex() const {
|
||||||
|
return currentLod;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlanetData::getMaxLodIndex() const {
|
||||||
|
return static_cast<int>(planetMeshLods.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<float, float> PlanetData::calculateZRange(float dToPlanetSurface) {
|
||||||
|
|
||||||
|
|
||||||
|
float currentZNear;
|
||||||
|
float currentZFar;
|
||||||
|
float alpha;
|
||||||
|
|
||||||
|
if (dToPlanetSurface > 2000)
|
||||||
|
{
|
||||||
|
currentZNear = 1000;
|
||||||
|
currentZFar = currentZNear * 100;
|
||||||
|
}
|
||||||
|
else if (dToPlanetSurface > 1200)
|
||||||
|
{
|
||||||
|
currentZNear = 500;
|
||||||
|
currentZFar = currentZNear * 100;
|
||||||
|
}
|
||||||
|
else if (dToPlanetSurface > 650)
|
||||||
|
{
|
||||||
|
currentZNear = 250;
|
||||||
|
currentZFar = currentZNear * 100;
|
||||||
|
}
|
||||||
|
else if (dToPlanetSurface > 160)
|
||||||
|
{
|
||||||
|
currentZNear = 125;
|
||||||
|
currentZFar = currentZNear * 150;
|
||||||
|
}
|
||||||
|
else if (dToPlanetSurface > 100)
|
||||||
|
{
|
||||||
|
currentZNear = 65;
|
||||||
|
currentZFar = currentZNear * 170;
|
||||||
|
}
|
||||||
|
else if (dToPlanetSurface > 40)
|
||||||
|
{
|
||||||
|
currentZNear = 32;
|
||||||
|
currentZFar = 10000.f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentZNear = 16;
|
||||||
|
currentZFar = 5000.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { currentZNear, currentZFar };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float PlanetData::distanceToPlanetSurface(const Vector3f& viewerPosition) {
|
||||||
|
Vector3f shipLocalPosition = viewerPosition - PLANET_CENTER_OFFSET;
|
||||||
|
|
||||||
|
// Èñïîëüçóåì getTrianglesUnderCamera äëÿ ïîèñêà
|
||||||
|
// ÂÍÈÌÀÍÈÅ: Çäåñü ðåêóðñèÿ ëîãèêè. Ìåòîä getTrianglesUnderCamera èñïîëüçóåò âíóòðè viewerPosition.
|
||||||
|
// ×òîáû íå äóáëèðîâàòü êîä, ïåðåïèøåì ëîãèêó ïîèñêà çäåñü èëè áóäåì èñïîëüçîâàòü óæå íàéäåííûé ðàíåå.
|
||||||
|
// Äëÿ ïðîñòîòû îñòàâèì ëîãèêó êàê â îðèãèíàëå, íî àäàïòèðîâàííóþ.
|
||||||
|
|
||||||
|
// ÂÀÆÍÎ: getTrianglesUnderCamera - ýòî "òÿæåëàÿ" ôóíêöèÿ. Â îðèãèíàëå îíà âûçûâàëàñü âíóòðè distanceToPlanetSurface.
|
||||||
|
// Íî îíà òðåáóåò LOD. Èñïîëüçóåì MAX LOD äëÿ òî÷íîñòè.
|
||||||
|
|
||||||
|
// Ðåêóðñèâíûé ïîèñê òðåóãîëüíèêîâ ïîä êàìåðîé.
|
||||||
|
// Çäåñü íàì íóæíî ðåàëèçîâàòü àíàëîã triangleUnderCamera, íî íå çàâèñÿùèé îò ãëîáàëüíîãî ñîñòîÿíèÿ.
|
||||||
|
// Â îðèãèíàëå ôóíêöèÿ triangleUnderCamera áûëà ðåêóðñèâíîé.
|
||||||
|
// Íèæå ÿ ðåàëèçóþ èòåðàòèâíûé èëè ðåêóðñèâíûé ïîäõîä âíóòðè getTrianglesUnderCamera.
|
||||||
|
|
||||||
|
// Âðåìåííîå ðåøåíèå: ïîëíàÿ êîïèÿ ëîãèêè ïîèñêà òðåóãîëüíèêà
|
||||||
|
// Íî íàì íóæåí äîñòóï ê ìåòîäó.
|
||||||
|
std::vector<int> targetTriangles = getTrianglesUnderCamera(viewerPosition);
|
||||||
|
|
||||||
|
if (targetTriangles.empty()) {
|
||||||
|
return (shipLocalPosition.length() - PLANET_RADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
float lowestDistance;
|
||||||
|
|
||||||
|
int tri_index = targetTriangles[0];
|
||||||
|
const auto& posData = planetMeshLods[currentLod].vertexData.PositionData;
|
||||||
|
|
||||||
|
size_t data_index = tri_index * 3;
|
||||||
|
if (data_index + 2 >= posData.size()) {
|
||||||
|
return (shipLocalPosition.length() - PLANET_RADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vector3f& A = posData[data_index];
|
||||||
|
const Vector3f& B = posData[data_index + 1];
|
||||||
|
const Vector3f& C = posData[data_index + 2];
|
||||||
|
|
||||||
|
Vector3f P_proj = projectPointOnPlane(shipLocalPosition, A, B, C);
|
||||||
|
Vector3f P_closest = P_proj;
|
||||||
|
|
||||||
|
lowestDistance = (shipLocalPosition - P_closest).length();
|
||||||
|
|
||||||
|
if (targetTriangles.size() <= 1)
|
||||||
|
{
|
||||||
|
return lowestDistance;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < targetTriangles.size(); i++)
|
||||||
|
{
|
||||||
|
int tri_index = targetTriangles[i];
|
||||||
|
const auto& posData = planetMeshLods[currentLod].vertexData.PositionData;
|
||||||
|
|
||||||
|
size_t data_index = tri_index * 3;
|
||||||
|
if (data_index + 2 >= posData.size()) {
|
||||||
|
return (shipLocalPosition.length() - PLANET_RADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vector3f& A = posData[data_index];
|
||||||
|
const Vector3f& B = posData[data_index + 1];
|
||||||
|
const Vector3f& C = posData[data_index + 2];
|
||||||
|
|
||||||
|
Vector3f P_proj = projectPointOnPlane(shipLocalPosition, A, B, C);
|
||||||
|
Vector3f P_closest = P_proj;
|
||||||
|
|
||||||
|
if (lowestDistance < (shipLocalPosition - P_closest).length())
|
||||||
|
{
|
||||||
|
lowestDistance = (shipLocalPosition - P_closest).length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lowestDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Ðåàëèçàöèÿ getTrianglesUnderCamera (áûâøàÿ triangleUnderCamera) ---
|
||||||
|
// Âñïîìîãàòåëüíàÿ ðåêóðñèâíàÿ ôóíêöèÿ, ñêðûòàÿ îò ïóáëè÷íîãî API
|
||||||
|
static std::vector<int> recursiveTriangleSearch(int lod, const Vector3f& pos, const std::array<LodLevel, MAX_LOD_LEVELS>& meshes) {
|
||||||
|
std::vector<int> r;
|
||||||
|
// Ëîãèêà óðîâíÿ 0 (áàçîâûé îêòàýäð)
|
||||||
|
if (lod == 0) {
|
||||||
|
if (pos.v[1] >= 0) {
|
||||||
|
if (pos.v[0] >= 0 && pos.v[2] >= 0) r.push_back(0);
|
||||||
|
if (pos.v[0] >= 0 && pos.v[2] <= 0) r.push_back(1);
|
||||||
|
if (pos.v[0] <= 0 && pos.v[2] <= 0) r.push_back(2);
|
||||||
|
if (pos.v[0] <= 0 && pos.v[2] >= 0) r.push_back(3);
|
||||||
|
}
|
||||||
|
if (pos.v[1] <= 0) {
|
||||||
|
if (pos.v[0] >= 0 && pos.v[2] >= 0) r.push_back(4);
|
||||||
|
if (pos.v[0] <= 0 && pos.v[2] >= 0) r.push_back(5);
|
||||||
|
if (pos.v[0] <= 0 && pos.v[2] <= 0) r.push_back(6);
|
||||||
|
if (pos.v[0] >= 0 && pos.v[2] <= 0) r.push_back(7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Ðåêóðñèâíûé øàã
|
||||||
|
std::vector<int> r0 = recursiveTriangleSearch(lod - 1, pos, meshes);
|
||||||
|
for (int tri0 : r0) {
|
||||||
|
Vector3f a = meshes[lod - 1].vertexData.PositionData[tri0 * 3];
|
||||||
|
Vector3f b = meshes[lod - 1].vertexData.PositionData[tri0 * 3 + 1];
|
||||||
|
Vector3f c = meshes[lod - 1].vertexData.PositionData[tri0 * 3 + 2];
|
||||||
|
|
||||||
|
std::vector<int> result = PlanetData::find_sub_triangle_spherical(a, b, c, pos);
|
||||||
|
for (int trix : result) {
|
||||||
|
r.push_back(tri0 * 4 + trix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<int> PlanetData::getTrianglesUnderCamera(const Vector3f& viewerPosition) {
|
||||||
|
// Âûçûâàåì ðåêóðñèþ ñ òåêóùèì LOD
|
||||||
|
return recursiveTriangleSearch(currentLod, viewerPosition, planetMeshLods);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Îñòàëüíûå ìåòîäû (check_spherical_side, generateSphere è ò.ä.) ---
|
||||||
|
// (Êîïèðóéòå ðåàëèçàöèþ èç ñòàðîãî PlanetObject.cpp,
|
||||||
|
// çàìåíÿÿ îáðàùåíèÿ ê Environment::shipPosition íà àðãóìåíòû, åñëè íóæíî,
|
||||||
|
// è èñïîëüçóÿ this->planetMeshLods)
|
||||||
|
|
||||||
|
float PlanetData::check_spherical_side(const Vector3f& V1, const Vector3f& V2, const Vector3f& P, const Vector3f& V3, float epsilon) {
|
||||||
|
Vector3f N_plane = V1.cross(V2);
|
||||||
|
float sign_P = P.dot(N_plane);
|
||||||
|
float sign_V3 = V3.dot(N_plane);
|
||||||
|
return sign_P * sign_V3;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlanetData::is_inside_spherical_triangle(const Vector3f& P, const Vector3f& V1, const Vector3f& V2, const Vector3f& V3, float epsilon) {
|
||||||
|
if (check_spherical_side(V1, V2, P, V3, epsilon) < -epsilon) return false;
|
||||||
|
if (check_spherical_side(V2, V3, P, V1, epsilon) < -epsilon) return false;
|
||||||
|
if (check_spherical_side(V3, V1, P, V2, epsilon) < -epsilon) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> PlanetData::find_sub_triangle_spherical(const Vector3f& a_orig, const Vector3f& b_orig, const Vector3f& c_orig, const Vector3f& px_orig) {
|
||||||
|
const float EPSILON = 1e-6f;
|
||||||
|
std::vector<int> result;
|
||||||
|
const Vector3f a = a_orig.normalized();
|
||||||
|
const Vector3f b = b_orig.normalized();
|
||||||
|
const Vector3f c = c_orig.normalized();
|
||||||
|
const Vector3f pxx_normalized = px_orig.normalized();
|
||||||
|
const Vector3f m_ab = ((a + b) * 0.5f).normalized();
|
||||||
|
const Vector3f m_bc = ((b + c) * 0.5f).normalized();
|
||||||
|
const Vector3f m_ac = ((a + c) * 0.5f).normalized();
|
||||||
|
|
||||||
|
if (is_inside_spherical_triangle(pxx_normalized, a, m_ab, m_ac, EPSILON)) result.push_back(0);
|
||||||
|
if (is_inside_spherical_triangle(pxx_normalized, m_ab, b, m_bc, EPSILON)) result.push_back(1);
|
||||||
|
if (is_inside_spherical_triangle(pxx_normalized, m_ac, m_bc, c, EPSILON)) result.push_back(2);
|
||||||
|
if (is_inside_spherical_triangle(pxx_normalized, m_ab, m_bc, m_ac, EPSILON)) result.push_back(3);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Triangle> PlanetData::subdivideTriangles(const std::vector<Triangle>& input, float noiseCoeff) {
|
||||||
|
std::vector<Triangle> output;
|
||||||
|
|
||||||
|
for (const auto& t : input) {
|
||||||
|
// Âåðøèíû è èõ ID
|
||||||
|
const Vector3f& a = t.data[0];
|
||||||
|
const Vector3f& b = t.data[1];
|
||||||
|
const Vector3f& c = t.data[2];
|
||||||
|
const VertexID& id_a = t.ids[0];
|
||||||
|
const VertexID& id_b = t.ids[1];
|
||||||
|
const VertexID& id_c = t.ids[2];
|
||||||
|
|
||||||
|
// 1. Âû÷èñëÿåì ñåðåäèíû (êîîðäèíàòû)
|
||||||
|
Vector3f m_ab = ((a + b) * 0.5f).normalized();
|
||||||
|
Vector3f m_bc = ((b + c) * 0.5f).normalized();
|
||||||
|
Vector3f m_ac = ((a + c) * 0.5f).normalized();
|
||||||
|
|
||||||
|
Vector3f pm_ab = m_ab * perlin.getSurfaceHeight(m_ab, noiseCoeff);
|
||||||
|
Vector3f pm_bc = m_bc * perlin.getSurfaceHeight(m_bc, noiseCoeff);
|
||||||
|
Vector3f pm_ac = m_ac * perlin.getSurfaceHeight(m_ac, noiseCoeff);
|
||||||
|
|
||||||
|
// 2. Âû÷èñëÿåì ID íîâûõ âåðøèí
|
||||||
|
VertexID id_mab = generateEdgeID(id_a, id_b);
|
||||||
|
VertexID id_mbc = generateEdgeID(id_b, id_c);
|
||||||
|
VertexID id_mac = generateEdgeID(id_a, id_c);
|
||||||
|
|
||||||
|
// 3. Ôîðìèðóåì 4 íîâûõ òðåóãîëüíèêà
|
||||||
|
output.emplace_back(Triangle{ {a, pm_ab, pm_ac}, {id_a, id_mab, id_mac} }); // 0
|
||||||
|
output.emplace_back(Triangle{ {pm_ab, b, pm_bc}, {id_mab, id_b, id_mbc} }); // 1
|
||||||
|
output.emplace_back(Triangle{ {pm_ac, pm_bc, c}, {id_mac, id_mbc, id_c} }); // 2
|
||||||
|
output.emplace_back(Triangle{ {pm_ab, pm_bc, pm_ac}, {id_mab, id_mbc, id_mac} }); // 3
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
LodLevel PlanetData::trianglesToVertices(const std::vector<Triangle>& geometry) {
|
||||||
|
LodLevel result;
|
||||||
|
result.triangles = geometry;
|
||||||
|
|
||||||
|
size_t vertexCount = geometry.size() * 3;
|
||||||
|
result.vertexData.PositionData.reserve(vertexCount);
|
||||||
|
result.vertexData.NormalData.reserve(vertexCount);
|
||||||
|
result.vertexData.TexCoordData.reserve(vertexCount);
|
||||||
|
result.vertexData.TangentData.reserve(vertexCount); // Äîáàâëÿåì ðåçåðâ
|
||||||
|
result.vertexData.BinormalData.reserve(vertexCount);
|
||||||
|
result.VertexIDs.reserve(vertexCount);
|
||||||
|
|
||||||
|
const std::array<Vector2f, 3> triangleUVs = {
|
||||||
|
Vector2f(0.5f, 1.0f),
|
||||||
|
Vector2f(0.0f, 0.0f),
|
||||||
|
Vector2f(1.0f, 0.0f)
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& t : geometry) {
|
||||||
|
// --- Âû÷èñëÿåì ëîêàëüíûé áàçèñ òðåóãîëüíèêà (êàê â GetRotationForTriangle) ---
|
||||||
|
Vector3f vA = t.data[0];
|
||||||
|
Vector3f vB = t.data[1];
|
||||||
|
Vector3f vC = t.data[2];
|
||||||
|
|
||||||
|
Vector3f x_axis = (vC - vB).normalized(); // Íàïðàâëåíèå U
|
||||||
|
|
||||||
|
Vector3f edge1 = vB - vA;
|
||||||
|
Vector3f edge2 = vC - vA;
|
||||||
|
Vector3f z_axis = edge1.cross(edge2).normalized(); // Íîðìàëü ïëîñêîñòè
|
||||||
|
|
||||||
|
// Ïðîâåðêà íàïðàâëåíèÿ íîðìàëè íàðóæó (îò öåíòðà ïëàíåòû)
|
||||||
|
Vector3f centerToTri = (vA + vB + vC).normalized();
|
||||||
|
if (z_axis.dot(centerToTri) < 0) {
|
||||||
|
z_axis = z_axis * -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3f y_axis = z_axis.cross(x_axis).normalized(); // Íàïðàâëåíèå V
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
result.vertexData.PositionData.push_back(t.data[i]);
|
||||||
|
result.vertexData.NormalData.push_back(z_axis); // Ïëîñêàÿ íîðìàëü ãðàíè äëÿ Parallax
|
||||||
|
result.vertexData.TexCoordData.push_back(triangleUVs[i]);
|
||||||
|
|
||||||
|
// Çàïèñûâàåì âû÷èñëåííûé áàçèñ â êàæäóþ âåðøèíó òðåóãîëüíèêà
|
||||||
|
result.vertexData.TangentData.push_back(x_axis);
|
||||||
|
result.vertexData.BinormalData.push_back(y_axis);
|
||||||
|
|
||||||
|
result.VertexIDs.push_back(t.ids[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LodLevel PlanetData::generateSphere(int subdivisions, float noiseCoeff) {
|
||||||
|
// 1. Èñõîäíûé îêòàýäð è ïðèñâîåíèå ID
|
||||||
|
std::vector<Triangle> geometry = {
|
||||||
|
// Âåðõíÿÿ ïîëóñôåðà (Y > 0)
|
||||||
|
{{ 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // 0
|
||||||
|
{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, { 1.0f, 0.0f, 0.0f}}, // 1
|
||||||
|
{{ 0.0f, 1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // 2
|
||||||
|
{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}}, // 3
|
||||||
|
// Íèæíÿÿ ïîëóñôåðà (Y < 0)
|
||||||
|
{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f, 0.0f}}, // 4
|
||||||
|
{{ 0.0f, -1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // 5
|
||||||
|
{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}}, // 6
|
||||||
|
{{ 0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}} // 7
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ïðèñâîåíèå ID èñõîäíûì âåðøèíàì
|
||||||
|
for (auto& t : geometry) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
// Èñïîëüçóåì map äëÿ ïîëó÷åíèÿ ID ïî ÷èñòûì êîîðäèíàòàì (íîðì. == ÷èñòûå)
|
||||||
|
t.ids[i] = initialVertexMap[t.data[i].normalized()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 3. Ðàçáèâàåì N ðàç (â subdivideTriangles ãåíåðèðóþòñÿ ID íîâûõ âåðøèí)
|
||||||
|
for (int i = 0; i < subdivisions; i++) {
|
||||||
|
geometry = subdivideTriangles(geometry, noiseCoeff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Ãåíåðèðóåì PositionData, NormalData è VertexIDs
|
||||||
|
LodLevel lodLevel = trianglesToVertices(geometry);
|
||||||
|
|
||||||
|
// 5. Ñîçäàíèå V2T-Map íà îñíîâå VertexIDs (ÒÎÏÎËÎÃÈ×ÅÑÊÈÉ ÊËÞ×)
|
||||||
|
V2TMap v2tMap;
|
||||||
|
const auto& finalVertexIDs = lodLevel.VertexIDs;
|
||||||
|
size_t num_triangles = geometry.size();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_triangles; ++i) {
|
||||||
|
for (int j = 0; j < 3; ++j) {
|
||||||
|
VertexID v_id = finalVertexIDs[i * 3 + j];
|
||||||
|
|
||||||
|
// Åñëè êëþ÷ óæå åñòü, ïðîñòî äîáàâëÿåì èíäåêñ
|
||||||
|
v2tMap[v_id].push_back((int)i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lodLevel.v2tMap = v2tMap;
|
||||||
|
|
||||||
|
// 6. Ïðèìåíåíèå ôèíàëüíîãî øóìà (åñëè âû õîòåëè, ÷òîáû øóì áûë òîëüêî çäåñü)
|
||||||
|
// Çäåñü ìû äîëæíû áûëè áû ïðèìåíèòü øóì ê buffer.PositionData,
|
||||||
|
// íî â âàøåì èñõîäíîì êîäå øóì ïðèìåíÿëñÿ ðàíåå.
|
||||||
|
// Ïðåäïîëàãàåì, ÷òî øóì áóäåò ïðèìåíåí çäåñü (èíà÷å v2tMap íå áóäåò ñîîòâåòñòâîâàòü).
|
||||||
|
// ÂÎÑÑÒÀÍÎÂÈÌ ØÀÃ 2, íî äëÿ ôèíàëüíîé ãåîìåòðèè:
|
||||||
|
for (size_t i = 0; i < lodLevel.vertexData.PositionData.size(); i++) {
|
||||||
|
Vector3f dir = lodLevel.vertexData.PositionData[i].normalized();
|
||||||
|
lodLevel.vertexData.PositionData[i] = dir * perlin.getSurfaceHeight(dir, noiseCoeff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 7. Ãåíåðàöèÿ ColorData
|
||||||
|
lodLevel.vertexData.ColorData.reserve(geometry.size() * 3);
|
||||||
|
const Vector3f baseColor = { 0.498f, 0.416f, 0.0f };
|
||||||
|
const float colorFrequency = 5.0f;
|
||||||
|
const float colorAmplitude = 0.2f;
|
||||||
|
const Vector3f offsetR = { 0.1f, 0.2f, 0.3f };
|
||||||
|
const Vector3f offsetG = { 0.5f, 0.4f, 0.6f };
|
||||||
|
const Vector3f offsetB = { 0.9f, 0.8f, 0.7f };
|
||||||
|
|
||||||
|
|
||||||
|
for (size_t i = 0; i < geometry.size(); i++) {
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
// Èñïîëüçóåì íîðìàëèçîâàííûé âåêòîð èç PositionData (êîòîðûé ðàâåí NormalData)
|
||||||
|
Vector3f dir = lodLevel.vertexData.NormalData[i * 3 + j];
|
||||||
|
|
||||||
|
// Âû÷èñëåíèå öâåòîâîãî øóìà
|
||||||
|
float noiseR = colorPerlin.noise(
|
||||||
|
(dir.v[0] + offsetR.v[0]) * colorFrequency,
|
||||||
|
(dir.v[1] + offsetR.v[1]) * colorFrequency,
|
||||||
|
(dir.v[2] + offsetR.v[2]) * colorFrequency
|
||||||
|
);
|
||||||
|
// ... (àíàëîãè÷íî äëÿ noiseG è noiseB)
|
||||||
|
|
||||||
|
// Çäåñü ìû èñïîëüçóåì çàãëóøêè, òàê êàê íåò ïîëíîãî îïðåäåëåíèÿ PerlinNoise
|
||||||
|
float noiseG = 0.0f;
|
||||||
|
float noiseB = 0.0f;
|
||||||
|
|
||||||
|
Vector3f colorOffset = {
|
||||||
|
noiseR * colorAmplitude,
|
||||||
|
noiseG * colorAmplitude,
|
||||||
|
noiseB * colorAmplitude
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector3f finalColor = baseColor + colorOffset;
|
||||||
|
|
||||||
|
lodLevel.vertexData.ColorData.push_back(finalColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lodLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Ïðèìåð findNeighbors:
|
||||||
|
std::vector<int> PlanetData::findNeighbors(int index, int lod) {
|
||||||
|
const V2TMap& v2tMap = planetMeshLods[lod].v2tMap;
|
||||||
|
const auto& vertexIDs = planetMeshLods[lod].VertexIDs;
|
||||||
|
if ((index * 3 + 2) >= vertexIDs.size()) return {};
|
||||||
|
std::set<int> neighbors;
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
VertexID v_id = vertexIDs[index * 3 + i];
|
||||||
|
auto it = v2tMap.find(v_id);
|
||||||
|
if (it != v2tMap.end()) {
|
||||||
|
for (int tri_index : it->second) {
|
||||||
|
if (tri_index != index) {
|
||||||
|
neighbors.insert(tri_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::vector<int>(neighbors.begin(), neighbors.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
+117
@@ -0,0 +1,117 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ZLMath.h"
|
||||||
|
#include "Perlin.h"
|
||||||
|
#include "Renderer.h" // Äëÿ VertexDataStruct
|
||||||
|
#include <vector>
|
||||||
|
#include <array>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
using VertexID = std::string;
|
||||||
|
using V2TMap = std::map<VertexID, std::vector<int>>;
|
||||||
|
|
||||||
|
VertexID generateEdgeID(const VertexID& id1, const VertexID& id2);
|
||||||
|
|
||||||
|
constexpr static int MAX_LOD_LEVELS = 6;
|
||||||
|
//constexpr static int MAX_LOD_LEVELS = 3;
|
||||||
|
|
||||||
|
struct Triangle
|
||||||
|
{
|
||||||
|
std::array<Vector3f, 3> data;
|
||||||
|
std::array<VertexID, 3> ids;
|
||||||
|
|
||||||
|
Triangle(Vector3f p1, Vector3f p2, Vector3f p3)
|
||||||
|
: data{ p1, p2, p3 }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Triangle(std::array<Vector3f, 3> idata, std::array<VertexID, 3> iids)
|
||||||
|
: data{ idata }
|
||||||
|
, ids{ iids }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LodLevel
|
||||||
|
{
|
||||||
|
std::vector<Triangle> triangles;
|
||||||
|
VertexDataStruct vertexData;
|
||||||
|
std::vector<VertexID> VertexIDs;
|
||||||
|
V2TMap v2tMap;
|
||||||
|
|
||||||
|
void Scale(float s)
|
||||||
|
{
|
||||||
|
vertexData.Scale(s);
|
||||||
|
for (auto& t : triangles) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
t.data[i] = t.data[i] * s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Move(Vector3f pos)
|
||||||
|
{
|
||||||
|
vertexData.Move(pos);
|
||||||
|
for (auto& t : triangles) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
t.data[i] = t.data[i] + pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PlanetData {
|
||||||
|
public:
|
||||||
|
static const float PLANET_RADIUS;
|
||||||
|
static const Vector3f PLANET_CENTER_OFFSET;
|
||||||
|
|
||||||
|
private:
|
||||||
|
PerlinNoise perlin;
|
||||||
|
PerlinNoise colorPerlin;
|
||||||
|
|
||||||
|
std::array<LodLevel, MAX_LOD_LEVELS> planetMeshLods;
|
||||||
|
std::array<LodLevel, MAX_LOD_LEVELS> planetMeshLodsNoDist;
|
||||||
|
LodLevel planetAtmosphereLod;
|
||||||
|
|
||||||
|
int currentLod; // Ëîãè÷åñêèé òåêóùèé óðîâåíü äåòàëèçàöèè
|
||||||
|
|
||||||
|
std::map<Vector3f, VertexID> initialVertexMap;
|
||||||
|
|
||||||
|
// Âíóòðåííèå ìåòîäû ãåíåðàöèè
|
||||||
|
std::vector<Triangle> subdivideTriangles(const std::vector<Triangle>& inputTriangles, float noiseCoeff);
|
||||||
|
LodLevel trianglesToVertices(const std::vector<Triangle>& triangles);
|
||||||
|
LodLevel generateSphere(int subdivisions, float noiseCoeff);
|
||||||
|
|
||||||
|
// Âñïîìîãàòåëüíûå ìåòîäû ìàòåìàòèêè
|
||||||
|
static float check_spherical_side(const Vector3f& V1, const Vector3f& V2, const Vector3f& P, const Vector3f& V3, float epsilon = 1e-6f);
|
||||||
|
static bool is_inside_spherical_triangle(const Vector3f& P, const Vector3f& V1, const Vector3f& V2, const Vector3f& V3, float epsilon);
|
||||||
|
|
||||||
|
public:
|
||||||
|
PlanetData();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
// Ìåòîäû äîñòóïà ê äàííûì (äëÿ ðåíäåðåðà)
|
||||||
|
const LodLevel& getLodLevel(int level) const;
|
||||||
|
const LodLevel& getLodLevelNoDist(int level) const;
|
||||||
|
const LodLevel& getAtmosphereLod() const;
|
||||||
|
int getCurrentLodIndex() const;
|
||||||
|
int getMaxLodIndex() const;
|
||||||
|
|
||||||
|
// Ëîãèêà
|
||||||
|
std::pair<float, float> calculateZRange(float distanceToSurface);
|
||||||
|
float distanceToPlanetSurface(const Vector3f& viewerPosition);
|
||||||
|
|
||||||
|
// Âîçâðàùàåò èíäåêñû òðåóãîëüíèêîâ, âèäèìûõ êàìåðîé
|
||||||
|
std::vector<int> getTrianglesUnderCamera(const Vector3f& viewerPosition);
|
||||||
|
|
||||||
|
std::vector<int> findNeighbors(int index, int lod);
|
||||||
|
|
||||||
|
static std::vector<int> find_sub_triangle_spherical(const Vector3f& a_orig, const Vector3f& b_orig, const Vector3f& c_orig, const Vector3f& px_orig);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
@@ -0,0 +1,570 @@
|
|||||||
|
#include "PlanetObject.h"
|
||||||
|
#include <random>
|
||||||
|
#include <cmath>
|
||||||
|
#include "OpenGlExtensions.h"
|
||||||
|
#include "Environment.h"
|
||||||
|
#include "StoneObject.h"
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
|
||||||
|
Matrix3f GetRotationForTriangle(const Triangle& tri) {
|
||||||
|
// Для треугольника №0:
|
||||||
|
// tri.data[0] = {0, 20000, 0} (A)
|
||||||
|
// tri.data[1] = {0, 0, 20000} (B)
|
||||||
|
// tri.data[2] = {20000, 0, 0} (C)
|
||||||
|
|
||||||
|
Vector3f vA = tri.data[0];
|
||||||
|
Vector3f vB = tri.data[1];
|
||||||
|
Vector3f vC = tri.data[2];
|
||||||
|
|
||||||
|
// 1. Вычисляем ось X (горизонталь).
|
||||||
|
// Нам нужна грань BC: от (0, 0, 20000) до (20000, 0, 0)
|
||||||
|
Vector3f x_axis = (vC - vB).normalized();
|
||||||
|
|
||||||
|
|
||||||
|
// 2. Вычисляем нормаль (ось Z).
|
||||||
|
// Порядок cross product (AB x AC) определит "лицевую" сторону.
|
||||||
|
Vector3f edge1 = vB - vA;
|
||||||
|
Vector3f edge2 = vC - vA;
|
||||||
|
Vector3f z_axis = edge1.cross(edge2).normalized();
|
||||||
|
|
||||||
|
// 3. Вычисляем ось Y (вертикаль).
|
||||||
|
// В ортонормированном базисе Y всегда перпендикулярна Z и X.
|
||||||
|
Vector3f y_axis = z_axis.cross(x_axis).normalized();
|
||||||
|
|
||||||
|
// 4. Формируем прямую матрицу поворота (Rotation/World Matrix).
|
||||||
|
Matrix3f rot;
|
||||||
|
|
||||||
|
// Столбец 0: Ось X
|
||||||
|
rot.m[0] = x_axis.v[0];
|
||||||
|
rot.m[3] = x_axis.v[1];
|
||||||
|
rot.m[6] = x_axis.v[2];
|
||||||
|
|
||||||
|
// Столбец 1: Ось Y
|
||||||
|
rot.m[1] = y_axis.v[0];
|
||||||
|
rot.m[4] = y_axis.v[1];
|
||||||
|
rot.m[7] = y_axis.v[2];
|
||||||
|
|
||||||
|
// Столбец 2: Ось Z
|
||||||
|
rot.m[2] = z_axis.v[0];
|
||||||
|
rot.m[5] = z_axis.v[1];
|
||||||
|
rot.m[8] = z_axis.v[2];
|
||||||
|
|
||||||
|
return rot;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlanetObject::PlanetObject()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanetObject::init() {
|
||||||
|
// 1. Инициализируем данные (генерация мешей)
|
||||||
|
planetData.init();
|
||||||
|
|
||||||
|
// 2. Забираем данные для VBO
|
||||||
|
// Берем максимальный LOD для начальной отрисовки
|
||||||
|
int lodIndex = planetData.getMaxLodIndex();
|
||||||
|
planetRenderStruct.data = planetData.getLodLevel(lodIndex).vertexData;
|
||||||
|
planetRenderStruct.RefreshVBO();
|
||||||
|
|
||||||
|
planetRenderStructCut.data = planetData.getLodLevelNoDist(lodIndex).vertexData;
|
||||||
|
|
||||||
|
planetRenderStructCut.data.PositionData.resize(3);
|
||||||
|
|
||||||
|
planetRenderStructCut.RefreshVBO();
|
||||||
|
//sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand2.png", ""));
|
||||||
|
sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand2.png", ""));
|
||||||
|
stoneTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", ""));
|
||||||
|
|
||||||
|
// Атмосфера
|
||||||
|
planetAtmosphereRenderStruct.data = planetData.getAtmosphereLod().vertexData;
|
||||||
|
planetAtmosphereRenderStruct.RefreshVBO();
|
||||||
|
|
||||||
|
|
||||||
|
planetStones = CreateStoneGroupData(778, planetData.getLodLevel(lodIndex));
|
||||||
|
planetStones.inflate({ 0/*,1,2,3,4,5,6,7*/ });
|
||||||
|
planetStonesToBakeRenderStruct.AssignFrom(planetStones.mesh);
|
||||||
|
planetStonesToBakeRenderStruct.RefreshVBO();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanetObject::prepareDrawData() {
|
||||||
|
if (!drawDataDirty) return;
|
||||||
|
drawDataDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PlanetObject::update(float deltaTimeMs) {
|
||||||
|
// 1. Получаем базовые треугольники под камерой
|
||||||
|
auto lr = planetData.getTrianglesUnderCamera(Environment::shipPosition);
|
||||||
|
int currentLod = planetData.getCurrentLodIndex();
|
||||||
|
|
||||||
|
// Временный вектор для сбора новых индексов
|
||||||
|
std::vector<int> newIndices;
|
||||||
|
std::set<int> used;
|
||||||
|
|
||||||
|
// Рекурсивно (или итеративно, как у тебя) собираем индексы видимых зон
|
||||||
|
for (int i : lr) {
|
||||||
|
if (used.insert(i).second) newIndices.push_back(i);
|
||||||
|
|
||||||
|
auto neighbors = planetData.findNeighbors(i, currentLod);
|
||||||
|
for (int n : neighbors) {
|
||||||
|
if (used.insert(n).second) newIndices.push_back(n);
|
||||||
|
|
||||||
|
auto neighbors2 = planetData.findNeighbors(n, currentLod);
|
||||||
|
for (int n2 : neighbors2) {
|
||||||
|
if (used.insert(n2).second) newIndices.push_back(n2);
|
||||||
|
|
||||||
|
auto neighbors3 = planetData.findNeighbors(n, currentLod);
|
||||||
|
|
||||||
|
for (int n3 : neighbors3) {
|
||||||
|
if (used.insert(n3).second) newIndices.push_back(n3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Сортируем новый список, чтобы порядок не влиял на сравнение
|
||||||
|
std::sort(newIndices.begin(), newIndices.end());
|
||||||
|
|
||||||
|
// 3. Сравниваем с тем, что было нарисовано в прошлый раз
|
||||||
|
if (newIndices != triangleIndicesToDraw) {
|
||||||
|
// Обновляем список индексов (используем move для эффективности)
|
||||||
|
triangleIndicesToDraw = std::move(newIndices);
|
||||||
|
|
||||||
|
// --- ОБНОВЛЯЕМ ЖЕЛТУЮ ЗОНУ (только когда изменился состав треугольников) ---
|
||||||
|
const auto& fullMesh = planetData.getLodLevel(currentLod).vertexData;
|
||||||
|
planetRenderYellowStruct.data.PositionData.clear();
|
||||||
|
planetRenderYellowStruct.data.TexCoordData.clear();
|
||||||
|
|
||||||
|
for (int i : triangleIndicesToDraw) {
|
||||||
|
// Копируем геометрию для подсветки
|
||||||
|
for (int j = 0; j < 3; ++j) {
|
||||||
|
planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3 + j]);
|
||||||
|
planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3 + j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (planetRenderYellowStruct.data.PositionData.size() > 0)
|
||||||
|
{
|
||||||
|
planetRenderYellowStruct.RefreshVBO();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- ОБНОВЛЯЕМ КАМНИ (через новую структуру StoneGroup) ---
|
||||||
|
if (triangleIndicesToDraw.size() > 0)
|
||||||
|
{
|
||||||
|
planetStones.inflate(triangleIndicesToDraw);
|
||||||
|
// Используем AssignFrom, он внутри сам вызывает RefreshVBO
|
||||||
|
planetStonesRenderStruct.AssignFrom(planetStones.mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PlanetObject::bakeStoneTexture(Renderer& renderer) {
|
||||||
|
glViewport(0, 0, 512, 512);
|
||||||
|
glClearColor(224 / 255.f, 201 / 255.f, 167 / 255.f, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
|
||||||
|
static const std::string defaultShaderName2 = "planetBake";
|
||||||
|
static const std::string vPositionName = "vPosition";
|
||||||
|
static const std::string vTexCoordName = "vTexCoord";
|
||||||
|
static const std::string textureUniformName = "Texture";
|
||||||
|
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(defaultShaderName2);
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
renderer.EnableVertexAttribArray(vPositionName);
|
||||||
|
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||||
|
|
||||||
|
float dist = planetData.distanceToPlanetSurface(Environment::shipPosition);
|
||||||
|
auto zRange = planetData.calculateZRange(dist);
|
||||||
|
const float currentZNear = zRange.first;
|
||||||
|
const float currentZFar = zRange.second;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Triangle tr = planetData.getLodLevelNoDist(planetData.getCurrentLodIndex()).triangles[0];
|
||||||
|
|
||||||
|
// 1. Получаем матрицу вращения (оси в столбцах)
|
||||||
|
Matrix3f mr = GetRotationForTriangle(tr);
|
||||||
|
|
||||||
|
// 2. Трансформируем вершины в локальное пространство экрана, чтобы найти габариты
|
||||||
|
// Используем MultMatrixVector(Matrix, Vector).
|
||||||
|
// Если ваша функция считает V * M, то передайте Inverse(mr).
|
||||||
|
Vector3f rA = MultMatrixVector(mr, tr.data[0]);
|
||||||
|
Vector3f rB = MultMatrixVector(mr, tr.data[1]);
|
||||||
|
Vector3f rC = MultMatrixVector(mr, tr.data[2]);
|
||||||
|
|
||||||
|
// 3. Вычисляем реальные границы треугольника после поворота
|
||||||
|
float minX = min(rA.v[0], min(rB.v[0], rC.v[0]));
|
||||||
|
float maxX = max(rA.v[0], max(rB.v[0], rC.v[0]));
|
||||||
|
float minY = min(rA.v[1], min(rB.v[1], rC.v[1]));
|
||||||
|
float maxY = max(rA.v[1], max(rB.v[1], rC.v[1]));
|
||||||
|
|
||||||
|
|
||||||
|
// Находим центр и размеры
|
||||||
|
float width = maxX - minX;
|
||||||
|
float height = maxY - minY;
|
||||||
|
float centerX = (minX + maxX) * 0.5f;
|
||||||
|
float centerY = (minY + maxY) * 0.5f;
|
||||||
|
|
||||||
|
width = width * 0.995;
|
||||||
|
height = height * 0.995;
|
||||||
|
|
||||||
|
renderer.PushProjectionMatrix(
|
||||||
|
centerX - width*0.5, centerX + width * 0.5,
|
||||||
|
centerY - height * 0.5, centerY + height * 0.5,
|
||||||
|
150, 200000);
|
||||||
|
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.LoadIdentity();
|
||||||
|
// Сдвигаем камеру по Z
|
||||||
|
renderer.TranslateMatrix(Vector3f{ 0, 0, -45000 });
|
||||||
|
|
||||||
|
// Применяем вращение
|
||||||
|
renderer.RotateMatrix(mr);
|
||||||
|
|
||||||
|
|
||||||
|
// Извлекаем нормаль треугольника (это 3-й столбец нашей матрицы вращения)
|
||||||
|
Vector3f planeNormal = { mr.m[2], mr.m[5], mr.m[8] };
|
||||||
|
|
||||||
|
renderer.RenderUniform3fv("uPlanePoint", &tr.data[0].v[0]);
|
||||||
|
renderer.RenderUniform3fv("uPlaneNormal", &planeNormal.v[0]);
|
||||||
|
renderer.RenderUniform1f("uMaxHeight", StoneParams::BASE_SCALE * 1.1f); // Соответствует BASE_SCALE + perturbation
|
||||||
|
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID());
|
||||||
|
renderer.PushMatrix();
|
||||||
|
|
||||||
|
renderer.DrawVertexRenderStruct(planetRenderStructCut);
|
||||||
|
renderer.PopMatrix();
|
||||||
|
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
glCullFace(GL_BACK); // Отсекаем задние грани
|
||||||
|
if (planetStonesToBakeRenderStruct.data.PositionData.size() > 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID());
|
||||||
|
renderer.DrawVertexRenderStruct(planetStonesToBakeRenderStruct);
|
||||||
|
CheckGlError();
|
||||||
|
}
|
||||||
|
glDisable(GL_CULL_FACE); // Не забываем выключить, чтобы не сломать остальной рендер
|
||||||
|
renderer.PopMatrix();
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||||
|
renderer.DisableVertexAttribArray(vPositionName);
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
CheckGlError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PlanetObject::draw(Renderer& renderer) {
|
||||||
|
|
||||||
|
prepareDrawData();
|
||||||
|
|
||||||
|
{
|
||||||
|
if (stoneMapFB == nullptr)
|
||||||
|
{
|
||||||
|
stoneMapFB = std::make_unique<FrameBuffer>(512, 512);
|
||||||
|
}
|
||||||
|
stoneMapFB->Bind();
|
||||||
|
|
||||||
|
bakeStoneTexture(renderer);
|
||||||
|
|
||||||
|
stoneMapFB->Unbind();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//bakeStoneTexture(renderer);
|
||||||
|
|
||||||
|
glViewport(0, 0, Environment::width, Environment::height);
|
||||||
|
//--------------------------
|
||||||
|
|
||||||
|
|
||||||
|
drawPlanet(renderer);
|
||||||
|
//drawYellowZone(renderer);
|
||||||
|
drawStones(renderer);
|
||||||
|
|
||||||
|
drawAtmosphere(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanetObject::drawPlanet(Renderer& renderer)
|
||||||
|
{
|
||||||
|
static const std::string defaultShaderName = "planetLand";
|
||||||
|
|
||||||
|
static const std::string vPositionName = "vPosition";
|
||||||
|
static const std::string vColorName = "vColor";
|
||||||
|
static const std::string vNormalName = "vNormal";
|
||||||
|
static const std::string vTexCoordName = "vTexCoord";
|
||||||
|
static const std::string textureUniformName = "Texture";
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(defaultShaderName);
|
||||||
|
|
||||||
|
renderer.EnableVertexAttribArray(vPositionName);
|
||||||
|
renderer.EnableVertexAttribArray(vColorName);
|
||||||
|
renderer.EnableVertexAttribArray(vNormalName);
|
||||||
|
renderer.EnableVertexAttribArray("vTangent");
|
||||||
|
renderer.EnableVertexAttribArray("vBinormal");
|
||||||
|
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||||
|
|
||||||
|
float dist = planetData.distanceToPlanetSurface(Environment::shipPosition);
|
||||||
|
auto zRange = planetData.calculateZRange(dist);
|
||||||
|
const float currentZNear = zRange.first;
|
||||||
|
const float currentZFar = zRange.second;
|
||||||
|
|
||||||
|
// 2. Применяем динамическую матрицу проекции
|
||||||
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||||
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||||
|
currentZNear, currentZFar);
|
||||||
|
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.LoadIdentity();
|
||||||
|
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
||||||
|
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
||||||
|
|
||||||
|
renderer.TranslateMatrix(-Environment::shipPosition);
|
||||||
|
|
||||||
|
const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix();
|
||||||
|
|
||||||
|
renderer.RenderUniform1i("Texture", 0);
|
||||||
|
renderer.RenderUniform1i("BakedTexture", 1);
|
||||||
|
|
||||||
|
|
||||||
|
Triangle tr = planetData.getLodLevel(planetData.getCurrentLodIndex()).triangles[0]; // Берем базовый треугольник
|
||||||
|
Matrix3f mr = GetRotationForTriangle(tr); // Та же матрица, что и при запекании
|
||||||
|
|
||||||
|
// Позиция камеры (корабля) в мире
|
||||||
|
renderer.RenderUniform3fv("uViewPos", &Environment::shipPosition.v[0]);
|
||||||
|
|
||||||
|
//renderer.RenderUniform1f("uHeightScale", 0.03f);
|
||||||
|
renderer.RenderUniform1f("uHeightScale", 0.0f);
|
||||||
|
|
||||||
|
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
||||||
|
renderer.RenderUniform1f("uCurrentZFar", currentZFar);
|
||||||
|
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, stoneMapFB->getTextureID());
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID());
|
||||||
|
|
||||||
|
renderer.DrawVertexRenderStruct(planetRenderStruct);
|
||||||
|
CheckGlError();
|
||||||
|
|
||||||
|
renderer.PopMatrix();
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||||
|
renderer.DisableVertexAttribArray(vNormalName);
|
||||||
|
renderer.DisableVertexAttribArray("vTangent");
|
||||||
|
renderer.DisableVertexAttribArray("vBinormal");
|
||||||
|
renderer.DisableVertexAttribArray(vColorName);
|
||||||
|
renderer.DisableVertexAttribArray(vPositionName);
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
CheckGlError();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanetObject::drawStones(Renderer& renderer)
|
||||||
|
{
|
||||||
|
static const std::string defaultShaderName2 = "planetStone";
|
||||||
|
static const std::string vPositionName = "vPosition";
|
||||||
|
static const std::string vColorName = "vColor";
|
||||||
|
static const std::string vNormalName = "vNormal";
|
||||||
|
static const std::string vTexCoordName = "vTexCoord";
|
||||||
|
static const std::string textureUniformName = "Texture";
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(defaultShaderName2);
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
renderer.EnableVertexAttribArray(vPositionName);
|
||||||
|
renderer.EnableVertexAttribArray(vColorName);
|
||||||
|
renderer.EnableVertexAttribArray(vNormalName);
|
||||||
|
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||||
|
|
||||||
|
float dist = planetData.distanceToPlanetSurface(Environment::shipPosition);
|
||||||
|
auto zRange = planetData.calculateZRange(dist);
|
||||||
|
const float currentZNear = zRange.first;
|
||||||
|
const float currentZFar = zRange.second;
|
||||||
|
|
||||||
|
// 2. Применяем динамическую матрицу проекции
|
||||||
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||||
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||||
|
currentZNear, currentZFar);
|
||||||
|
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.LoadIdentity();
|
||||||
|
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
||||||
|
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
||||||
|
renderer.TranslateMatrix(-Environment::shipPosition);
|
||||||
|
|
||||||
|
|
||||||
|
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
||||||
|
renderer.RenderUniform1f("uCurrentZFar", currentZFar);
|
||||||
|
renderer.RenderUniform3fv("uViewPos", &Environment::shipPosition.v[0]);
|
||||||
|
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
glCullFace(GL_BACK);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
if (planetStonesRenderStruct.data.PositionData.size() > 0)
|
||||||
|
{
|
||||||
|
glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID());
|
||||||
|
renderer.DrawVertexRenderStruct(planetStonesRenderStruct);
|
||||||
|
CheckGlError();
|
||||||
|
}
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
|
||||||
|
renderer.PopMatrix();
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||||
|
renderer.DisableVertexAttribArray(vNormalName);
|
||||||
|
renderer.DisableVertexAttribArray(vColorName);
|
||||||
|
renderer.DisableVertexAttribArray(vPositionName);
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
CheckGlError();
|
||||||
|
|
||||||
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanetObject::drawYellowZone(Renderer& renderer)
|
||||||
|
{
|
||||||
|
|
||||||
|
static const std::string defaultShaderName = "planetLand";
|
||||||
|
static const std::string vPositionName = "vPosition";
|
||||||
|
static const std::string vColorName = "vColor";
|
||||||
|
static const std::string vNormalName = "vNormal";
|
||||||
|
static const std::string vTexCoordName = "vTexCoord";
|
||||||
|
static const std::string textureUniformName = "Texture";
|
||||||
|
|
||||||
|
float dist = planetData.distanceToPlanetSurface(Environment::shipPosition);
|
||||||
|
auto zRange = planetData.calculateZRange(dist);
|
||||||
|
const float currentZNear = zRange.first;
|
||||||
|
const float currentZFar = zRange.second;
|
||||||
|
|
||||||
|
|
||||||
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
|
if (planetRenderYellowStruct.data.PositionData.size() > 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(defaultShaderName);
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
renderer.EnableVertexAttribArray(vPositionName);
|
||||||
|
renderer.EnableVertexAttribArray(vColorName);
|
||||||
|
renderer.EnableVertexAttribArray(vNormalName);
|
||||||
|
renderer.EnableVertexAttribArray("vTangent");
|
||||||
|
renderer.EnableVertexAttribArray("vBinormal");
|
||||||
|
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||||
|
|
||||||
|
// 2. Применяем динамическую матрицу проекции
|
||||||
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||||
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||||
|
currentZNear, currentZFar);
|
||||||
|
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.LoadIdentity();
|
||||||
|
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
||||||
|
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
||||||
|
|
||||||
|
renderer.TranslateMatrix(-Environment::shipPosition);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
||||||
|
renderer.RenderUniform1f("uCurrentZFar", currentZFar);
|
||||||
|
|
||||||
|
renderer.RenderUniform3fv("uViewPos", &Environment::shipPosition.v[0]);
|
||||||
|
|
||||||
|
Vector3f color2 = { 1.0, 1.0, 0.0 };
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID());
|
||||||
|
|
||||||
|
renderer.RenderUniform3fv("uColor", &color2.v[0]);
|
||||||
|
renderer.DrawVertexRenderStruct(planetRenderYellowStruct);
|
||||||
|
//glDisable(GL_BLEND);
|
||||||
|
CheckGlError();
|
||||||
|
|
||||||
|
|
||||||
|
renderer.PopMatrix();
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||||
|
renderer.DisableVertexAttribArray(vNormalName);
|
||||||
|
renderer.DisableVertexAttribArray("vTangent");
|
||||||
|
renderer.DisableVertexAttribArray("vBinormal");
|
||||||
|
renderer.DisableVertexAttribArray(vColorName);
|
||||||
|
renderer.DisableVertexAttribArray(vPositionName);
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
CheckGlError();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanetObject::drawAtmosphere(Renderer& renderer) {
|
||||||
|
static const std::string defaultShaderName = "defaultAtmosphere";
|
||||||
|
static const std::string vPositionName = "vPosition";
|
||||||
|
static const std::string vNormalName = "vNormal";
|
||||||
|
//glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(defaultShaderName);
|
||||||
|
renderer.EnableVertexAttribArray(vPositionName);
|
||||||
|
renderer.EnableVertexAttribArray(vNormalName);
|
||||||
|
|
||||||
|
|
||||||
|
float dist = planetData.distanceToPlanetSurface(Environment::shipPosition);
|
||||||
|
auto zRange = planetData.calculateZRange(dist);
|
||||||
|
const float currentZNear = zRange.first;
|
||||||
|
const float currentZFar = zRange.second;
|
||||||
|
|
||||||
|
// 2. Применяем динамическую матрицу проекции
|
||||||
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||||
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||||
|
currentZNear, currentZFar);
|
||||||
|
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.LoadIdentity();
|
||||||
|
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
||||||
|
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
||||||
|
renderer.TranslateMatrix(-Environment::shipPosition);
|
||||||
|
|
||||||
|
const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix();
|
||||||
|
|
||||||
|
Vector3f color = { 0.0, 0.5, 1.0 };
|
||||||
|
|
||||||
|
renderer.RenderUniform3fv("uColor", &color.v[0]);
|
||||||
|
|
||||||
|
renderer.RenderUniformMatrix4fv("ModelViewMatrix", false, &viewMatrix.m[0]);
|
||||||
|
|
||||||
|
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Аддитивное смешивание для эффекта свечения
|
||||||
|
|
||||||
|
renderer.DrawVertexRenderStruct(planetAtmosphereRenderStruct);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
renderer.PopMatrix();
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
|
||||||
|
renderer.DisableVertexAttribArray(vNormalName);
|
||||||
|
renderer.DisableVertexAttribArray(vPositionName);
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
CheckGlError();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
float PlanetObject::distanceToPlanetSurface(const Vector3f& viewerPosition)
|
||||||
|
{
|
||||||
|
return planetData.distanceToPlanetSurface(viewerPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#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>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include "Perlin.h"
|
||||||
|
#include "PlanetData.h"
|
||||||
|
#include "StoneObject.h"
|
||||||
|
#include "FrameBuffer.h"
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
class PlanetObject {
|
||||||
|
public:
|
||||||
|
// Агрегация: логика и данные теперь здесь
|
||||||
|
PlanetData planetData;
|
||||||
|
|
||||||
|
// Данные только для рендеринга (OpenGL specific)
|
||||||
|
VertexRenderStruct planetRenderStruct;
|
||||||
|
VertexRenderStruct planetRenderStructCut;
|
||||||
|
VertexRenderStruct planetRenderYellowStruct;
|
||||||
|
VertexRenderStruct planetAtmosphereRenderStruct;
|
||||||
|
VertexRenderStruct planetStonesRenderStruct;
|
||||||
|
VertexRenderStruct planetStonesToBakeRenderStruct;
|
||||||
|
StoneGroup planetStones;
|
||||||
|
|
||||||
|
std::vector<int> triangleIndicesToDraw;
|
||||||
|
|
||||||
|
std::shared_ptr<Texture> sandTexture;
|
||||||
|
std::shared_ptr<Texture> stoneTexture;
|
||||||
|
|
||||||
|
bool drawDataDirty = true;
|
||||||
|
void prepareDrawData();
|
||||||
|
|
||||||
|
std::unique_ptr<FrameBuffer> stoneMapFB;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PlanetObject();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void update(float deltaTimeMs);
|
||||||
|
void bakeStoneTexture(Renderer& renderer);
|
||||||
|
void draw(Renderer& renderer);
|
||||||
|
void drawStones(Renderer& renderer);
|
||||||
|
void drawPlanet(Renderer& renderer);
|
||||||
|
void drawYellowZone(Renderer& renderer);
|
||||||
|
void drawAtmosphere(Renderer& renderer);
|
||||||
|
|
||||||
|
|
||||||
|
float distanceToPlanetSurface(const Vector3f& viewerPosition);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
@@ -1,9 +1,90 @@
|
|||||||
|
# Windows
|
||||||
|
|
||||||
|
download from https://cmake.org/download/
|
||||||
|
|
||||||
|
|
||||||
|
Windows x64 Installer: cmake-4.2.0-windows-x86_64.msi
|
||||||
|
|
||||||
|
|
||||||
|
download from https://github.com/libsdl-org/SDL/releases/tag/release-2.32.10
|
||||||
|
|
||||||
|
SDL2-2.32.10-win32-x64.zip
|
||||||
|
|
||||||
|
SDL2-2.32.10:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd C:\..\SDL-realese-2.32.10
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -G "Visual Studio 18 2026" -DCMAKE_INSTALL_PREFIX=install ..
|
||||||
|
cmake --build . --config Debug
|
||||||
|
cmake --install . --config Debug
|
||||||
|
```
|
||||||
|
|
||||||
|
download from https://www.zlib.net/
|
||||||
|
|
||||||
|
zlib source code, version 1.3.1, zipfile format (1616K, SHA-256 hash 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17):
|
||||||
|
US (zlib.net)
|
||||||
|
|
||||||
|
zlib-1.3.1:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd C:\..\zlib-1.3.1
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -G "Visual Studio 18 2026" -DCMAKE_INSTALL_PREFIX=install ..
|
||||||
|
cmake --build . --config Debug
|
||||||
|
cmake --install . --config Debug
|
||||||
|
```
|
||||||
|
|
||||||
|
download from https://github.com/pnggroup/libpng/releases/tag/v1.6.51
|
||||||
|
|
||||||
|
Source code (zip)
|
||||||
|
|
||||||
|
libpng-1.6.51:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd C:\..\libpng-1.6.51
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
```
|
||||||
|
|
||||||
|
To build libpng, you need to specify the path to the zlib installation directory as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake -DCMAKE_PREFIX_PATH="../zlib-1.3.1/build/install" -DCMAKE_INSTALL_PREFIX=install -G "Visual Studio 18 2026" ..
|
||||||
|
cmake --build . --config Debug
|
||||||
|
cmake --install . --config Debug
|
||||||
|
```
|
||||||
|
|
||||||
|
Настройка проекта в Visual Studio:
|
||||||
|
|
||||||
|
Перейдите в Project Properties (правый клик на проект, "Properties").
|
||||||
|
|
||||||
|
C/C++ - ОБЩИЕ; Дополнительные каталоги включаемых файлов, проверить чтобы был добавлен путь к папке include:(пример)
|
||||||
|
|
||||||
|
..\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
|
||||||
|
|
||||||
|
|
||||||
|
Компоновщик - ОБЩИЕ; Доподнительные каталоги библиотек (пример)
|
||||||
|
|
||||||
|
..\SDL-release-2.32.10\build\install\lib;..\libpng-1.6.51\build\install\lib;..\zlib-1.3.1\build\install\lib
|
||||||
|
|
||||||
|
Компоновщик - ВВОД; Дополнительные зависимости, добавить zlibstaticd.lib (пример)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
в папку ..\projectGAME01\x64\Debug добавить файл SDL2d.dll
|
||||||
|
который можно скопировать из папки ..\SDL-release-2.32.10\build\Debug
|
||||||
|
|
||||||
|
|
||||||
# Script to run:
|
# Script to run:
|
||||||
|
|
||||||
```
|
```
|
||||||
C:\Work\Projects\emsdk\emsdk.bat activate latest
|
C:\Work\Projects\emsdk\emsdk.bat activate latest
|
||||||
C:\Work\Projects\emsdk\emsdk_env.bat
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -63,7 +144,12 @@ emcc main.cpp Game.cpp Environment.cpp GameObjectManager.cpp BoneAnimatedModel.c
|
|||||||
|
|
||||||
|
|
||||||
# Windows:
|
# 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 .
|
emrun --no_browser --port 8080 .
|
||||||
```
|
```
|
||||||
|
|||||||
+141
-5
@@ -196,6 +196,71 @@ namespace ZL {
|
|||||||
return result;
|
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()
|
void VertexRenderStruct::RefreshVBO()
|
||||||
{
|
{
|
||||||
//Check if main thread, check if data is not empty...
|
//Check if main thread, check if data is not empty...
|
||||||
@@ -229,7 +294,6 @@ namespace ZL {
|
|||||||
glBufferData(GL_ARRAY_BUFFER, data.TexCoordData.size() * 8, &data.TexCoordData[0], GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, data.TexCoordData.size() * 8, &data.TexCoordData[0], GL_STATIC_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (data.NormalData.size() > 0)
|
if (data.NormalData.size() > 0)
|
||||||
{
|
{
|
||||||
if (!normalVBO)
|
if (!normalVBO)
|
||||||
@@ -366,6 +430,18 @@ namespace ZL {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::PushProjectionMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar)
|
||||||
|
{
|
||||||
|
Matrix4f m = MakeOrthoMatrix(xmin, xmax, ymin, ymax, zNear, zFar);
|
||||||
|
ProjectionMatrixStack.push(m);
|
||||||
|
SetMatrix();
|
||||||
|
|
||||||
|
if (ProjectionMatrixStack.size() > CONST_MATRIX_STACK_SIZE)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Projection matrix stack overflow!!!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar)
|
void Renderer::PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar)
|
||||||
{
|
{
|
||||||
Matrix4f m = MakePerspectiveMatrix(fovY, aspectRatio, zNear, zFar);
|
Matrix4f m = MakePerspectiveMatrix(fovY, aspectRatio, zNear, zFar);
|
||||||
@@ -394,6 +470,12 @@ namespace ZL {
|
|||||||
return ProjectionModelViewMatrix;
|
return ProjectionModelViewMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Matrix4f Renderer::GetCurrentModelViewMatrix()
|
||||||
|
{
|
||||||
|
return ModelviewMatrixStack.top();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Renderer::SetMatrix()
|
void Renderer::SetMatrix()
|
||||||
{
|
{
|
||||||
if (ProjectionMatrixStack.size() <= 0)
|
if (ProjectionMatrixStack.size() <= 0)
|
||||||
@@ -406,15 +488,16 @@ namespace ZL {
|
|||||||
throw std::runtime_error("Modelview matrix stack out!");
|
throw std::runtime_error("Modelview matrix stack out!");
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectionModelViewMatrix = ProjectionMatrixStack.top() * ModelviewMatrixStack.top();
|
Matrix4f& modelViewMatrix = ModelviewMatrixStack.top();
|
||||||
|
ProjectionModelViewMatrix = ProjectionMatrixStack.top() * modelViewMatrix;
|
||||||
|
|
||||||
static const std::string ProjectionModelViewMatrixName = "ProjectionModelViewMatrix";
|
static const std::string ProjectionModelViewMatrixName = "ProjectionModelViewMatrix";
|
||||||
|
|
||||||
//static const std::string ProjectionMatrixName = "ProjectionMatrix";
|
|
||||||
|
|
||||||
RenderUniformMatrix4fv(ProjectionModelViewMatrixName, false, &ProjectionModelViewMatrix.m[0]);
|
RenderUniformMatrix4fv(ProjectionModelViewMatrixName, false, &ProjectionModelViewMatrix.m[0]);
|
||||||
|
|
||||||
//RenderUniformMatrix4fv(ProjectionMatrixName, false, &ProjectionMatrixStack.top().m[0]);
|
static const std::string ModelViewMatrixName = "ModelViewMatrix";
|
||||||
|
|
||||||
|
RenderUniformMatrix4fv(ModelViewMatrixName, false, &modelViewMatrix.m[0]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,6 +621,35 @@ namespace ZL {
|
|||||||
SetMatrix();
|
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)
|
void Renderer::PushSpecialMatrix(const Matrix4f& m)
|
||||||
{
|
{
|
||||||
if (ModelviewMatrixStack.size() > 64)
|
if (ModelviewMatrixStack.size() > 64)
|
||||||
@@ -576,6 +688,18 @@ namespace ZL {
|
|||||||
glDisableVertexAttribArray(shader->attribList[attribName]);
|
glDisableVertexAttribArray(shader->attribList[attribName]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::RenderUniformMatrix3fv(const std::string& uniformName, bool transpose, const float* value)
|
||||||
|
{
|
||||||
|
auto shader = shaderManager.GetCurrentShader();
|
||||||
|
|
||||||
|
auto uniform = shader->uniformList.find(uniformName);
|
||||||
|
|
||||||
|
if (uniform != shader->uniformList.end())
|
||||||
|
{
|
||||||
|
glUniformMatrix3fv(uniform->second, 1, transpose, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Renderer::RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value)
|
void Renderer::RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value)
|
||||||
{
|
{
|
||||||
@@ -614,6 +738,18 @@ namespace ZL {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::RenderUniform1f(const std::string& uniformName, float value)
|
||||||
|
{
|
||||||
|
auto shader = shaderManager.GetCurrentShader();
|
||||||
|
|
||||||
|
auto uniform = shader->uniformList.find(uniformName);
|
||||||
|
|
||||||
|
if (uniform != shader->uniformList.end())
|
||||||
|
{
|
||||||
|
glUniform1fv(uniform->second, 1, &value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Renderer::VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer)
|
void Renderer::VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer)
|
||||||
|
|||||||
+7
-2
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "OpenGlExtensions.h"
|
#include "OpenGlExtensions.h"
|
||||||
#include "Math.h"
|
#include "ZLMath.h"
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include "ShaderManager.h"
|
#include "ShaderManager.h"
|
||||||
@@ -75,6 +75,7 @@ namespace ZL {
|
|||||||
VertexDataStruct CreateRect2D(Vector2f center, Vector2f halfWidthHeight, float zLevel);
|
VertexDataStruct CreateRect2D(Vector2f center, Vector2f halfWidthHeight, float zLevel);
|
||||||
VertexDataStruct CreateRectHorizontalSections2D(Vector2f center, Vector2f halfWidthHeight, float zLevel, size_t sectionCount);
|
VertexDataStruct CreateRectHorizontalSections2D(Vector2f center, Vector2f halfWidthHeight, float zLevel, size_t sectionCount);
|
||||||
VertexDataStruct CreateCube3D(float scale);
|
VertexDataStruct CreateCube3D(float scale);
|
||||||
|
VertexDataStruct CreateCubemap(float scale = 1000.f);
|
||||||
|
|
||||||
|
|
||||||
class Renderer
|
class Renderer
|
||||||
@@ -92,6 +93,7 @@ namespace ZL {
|
|||||||
void InitOpenGL();
|
void InitOpenGL();
|
||||||
|
|
||||||
void PushProjectionMatrix(float width, float height, float zNear = 0.f, float zFar = 1.f);
|
void PushProjectionMatrix(float width, float height, float zNear = 0.f, float zFar = 1.f);
|
||||||
|
void PushProjectionMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar);
|
||||||
void PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar);
|
void PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar);
|
||||||
void PopProjectionMatrix();
|
void PopProjectionMatrix();
|
||||||
|
|
||||||
@@ -101,11 +103,13 @@ namespace ZL {
|
|||||||
void ScaleMatrix(float scale);
|
void ScaleMatrix(float scale);
|
||||||
void ScaleMatrix(const Vector3f& scale);
|
void ScaleMatrix(const Vector3f& scale);
|
||||||
void RotateMatrix(const Vector4f& q);
|
void RotateMatrix(const Vector4f& q);
|
||||||
|
void RotateMatrix(const Matrix3f& m3);
|
||||||
void PushSpecialMatrix(const Matrix4f& m);
|
void PushSpecialMatrix(const Matrix4f& m);
|
||||||
void PopMatrix();
|
void PopMatrix();
|
||||||
|
|
||||||
|
|
||||||
Matrix4f GetProjectionModelViewMatrix();
|
Matrix4f GetProjectionModelViewMatrix();
|
||||||
|
Matrix4f GetCurrentModelViewMatrix();
|
||||||
|
|
||||||
void SetMatrix();
|
void SetMatrix();
|
||||||
|
|
||||||
@@ -116,10 +120,11 @@ namespace ZL {
|
|||||||
void DisableVertexAttribArray(const std::string& attribName);
|
void DisableVertexAttribArray(const std::string& attribName);
|
||||||
|
|
||||||
|
|
||||||
|
void RenderUniformMatrix3fv(const std::string& uniformName, bool transpose, const float* value);
|
||||||
void RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value);
|
void RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value);
|
||||||
void RenderUniform1i(const std::string& uniformName, const int value);
|
void RenderUniform1i(const std::string& uniformName, const int value);
|
||||||
void RenderUniform3fv(const std::string& uniformName, const float* value);
|
void RenderUniform3fv(const std::string& uniformName, const float* value);
|
||||||
|
void RenderUniform1f(const std::string& uniformName, float value);
|
||||||
|
|
||||||
void VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer);
|
void VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer);
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -11,6 +11,8 @@ namespace ZL {
|
|||||||
|
|
||||||
char infoLog[CONST_INFOLOG_LENGTH];
|
char infoLog[CONST_INFOLOG_LENGTH];
|
||||||
int infoLogLength;
|
int infoLogLength;
|
||||||
|
char infoLog2[CONST_INFOLOG_LENGTH];
|
||||||
|
int infoLogLength2;
|
||||||
|
|
||||||
int vertexShaderCompiled;
|
int vertexShaderCompiled;
|
||||||
int fragmentShaderCompiled;
|
int fragmentShaderCompiled;
|
||||||
@@ -37,7 +39,8 @@ namespace ZL {
|
|||||||
|
|
||||||
glCompileShader(fragmentShader);
|
glCompileShader(fragmentShader);
|
||||||
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentShaderCompiled);
|
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentShaderCompiled);
|
||||||
glGetShaderInfoLog(fragmentShader, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog);
|
glGetShaderInfoLog(fragmentShader, CONST_INFOLOG_LENGTH, &infoLogLength2, infoLog2);
|
||||||
|
|
||||||
|
|
||||||
if (!vertexShaderCompiled)
|
if (!vertexShaderCompiled)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,299 @@
|
|||||||
|
#include "SparkEmitter.h"
|
||||||
|
#include <random>
|
||||||
|
#include <cmath>
|
||||||
|
#include "OpenGlExtensions.h"
|
||||||
|
#include "Environment.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, Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||||
|
|
||||||
|
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
|
||||||
@@ -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
|
||||||
+276
@@ -0,0 +1,276 @@
|
|||||||
|
#include "StoneObject.h"
|
||||||
|
|
||||||
|
#include "Utils.h"
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <random>
|
||||||
|
#include <cmath>
|
||||||
|
#include "Renderer.h"
|
||||||
|
#include "PlanetData.h"
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
|
||||||
|
// --- ÊÎÍÑÒÀÍÒÛ ÏÀÐÀÌÅÒÐÎÂ (êàê âû ïðîñèëè) ---
|
||||||
|
const float StoneParams::BASE_SCALE = 17.0f; // Îáùèé ðàçìåð êàìíÿ
|
||||||
|
//const float StoneParams::BASE_SCALE = 5000.0f; // Îáùèé ðàçìåð êàìíÿ
|
||||||
|
//const float StoneParams::MIN_AXIS_SCALE = 1.0f; // Ìèíèìàëüíîå ðàñòÿæåíèå/ñæàòèå ïî îñè
|
||||||
|
//const float StoneParams::MAX_AXIS_SCALE = 1.0f; // Ìàêñèìàëüíîå ðàñòÿæåíèå/ñæàòèå ïî îñè
|
||||||
|
//const float StoneParams::MIN_PERTURBATION = 0.0f; // Ìèíèìàëüíîå ðàäèàëüíîå âîçìóùåíèå âåðøèíû
|
||||||
|
//const float StoneParams::MAX_PERTURBATION = 0.0f; // Ìàêñèìàëüíîå ðàäèàëüíîå âîçìóùåíèå âåðøèíû
|
||||||
|
const float StoneParams::MIN_AXIS_SCALE = 0.5f; // Ìèíèìàëüíîå ðàñòÿæåíèå/ñæàòèå ïî îñè
|
||||||
|
const float StoneParams::MAX_AXIS_SCALE = 1.5f; // Ìàêñèìàëüíîå ðàñòÿæåíèå/ñæàòèå ïî îñè
|
||||||
|
const float StoneParams::MIN_PERTURBATION = 0.05f; // Ìèíèìàëüíîå ðàäèàëüíîå âîçìóùåíèå âåðøèíû
|
||||||
|
const float StoneParams::MAX_PERTURBATION = 0.25f; // Ìàêñèìàëüíîå ðàäèàëüíîå âîçìóùåíèå âåðøèíû
|
||||||
|
const int StoneParams::STONES_PER_TRIANGLE = 100;
|
||||||
|
|
||||||
|
// Âñïîìîãàòåëüíàÿ ôóíêöèÿ äëÿ ïîëó÷åíèÿ ñëó÷àéíîãî ÷èñëà â äèàïàçîíå [min, max]
|
||||||
|
float getRandomFloat(std::mt19937& gen, float min, float max) {
|
||||||
|
std::uniform_real_distribution<> distrib(min, max);
|
||||||
|
return static_cast<float>(distrib(gen));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Âñïîìîãàòåëüíàÿ ôóíêöèÿ äëÿ ãåíåðàöèè ñëó÷àéíîé òî÷êè íà òðåóãîëüíèêå
|
||||||
|
// Èñïîëüçóåò áàðèöåíòðè÷åñêèå êîîðäèíàòû
|
||||||
|
Vector3f GetRandomPointOnTriangle(const Triangle& t, std::mt19937& engine) {
|
||||||
|
std::uniform_real_distribution<> distrib(0.0f, 1.0f);
|
||||||
|
|
||||||
|
float r1 = getRandomFloat(engine, 0.0f, 1.0f);
|
||||||
|
float r2 = getRandomFloat(engine, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
// Ïðåîáðàçîâàíèå r1, r2 äëÿ ïîëó÷åíèÿ ðàâíîìåðíîãî ðàñïðåäåëåíèÿ
|
||||||
|
float a = 1.0f - std::sqrt(r1);
|
||||||
|
float b = std::sqrt(r1) * r2;
|
||||||
|
float c = 1.0f - a - b; // c = sqrt(r1) * (1 - r2)
|
||||||
|
|
||||||
|
// Áàðèöåíòðè÷åñêèå êîîðäèíàòû
|
||||||
|
// P = a*p1 + b*p2 + c*p3
|
||||||
|
Vector3f p1_term = t.data[0] * a;
|
||||||
|
Vector3f p2_term = t.data[1] * b;
|
||||||
|
Vector3f p3_term = t.data[2] * c;
|
||||||
|
|
||||||
|
return p1_term + p2_term + p3_term;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Èêîñàýäð (íà îñíîâå çîëîòîãî ñå÷åíèÿ phi)
|
||||||
|
// Êîîðäèíàòû ìîãóò áûòü âû÷èñëåíû çàðàíåå äëÿ êîíñòàíòíîãî èêîñàýäðà.
|
||||||
|
// Çäåñü òîëüêî îáúÿâëåíèå, ÷òîáû ïîêàçàòü èäåþ.
|
||||||
|
|
||||||
|
VertexDataStruct CreateBaseConvexPolyhedron(uint64_t seed) {
|
||||||
|
|
||||||
|
// const size_t SUBDIVISION_LEVEL = 1; // Óðîâåíü ïîäðàçäåëåíèÿ (äëÿ áîëåå êðóãëîãî êàìíÿ, ïîêà îïóñòèì)
|
||||||
|
|
||||||
|
std::mt19937 engine(static_cast<unsigned int>(seed));
|
||||||
|
|
||||||
|
// Çîëîòîå ñå÷åíèå
|
||||||
|
const float t = (1.0f + std::sqrt(5.0f)) / 2.0f;
|
||||||
|
|
||||||
|
// 12 âåðøèí èêîñàýäðà
|
||||||
|
std::vector<Vector3f> initialVertices = {
|
||||||
|
{ -1, t, 0 }, { 1, t, 0 }, { -1, -t, 0 }, { 1, -t, 0 },
|
||||||
|
{ 0, -1, t }, { 0, 1, t }, { 0, -1, -t }, { 0, 1, -t },
|
||||||
|
{ t, 0, -1 }, { t, 0, 1 }, { -t, 0, -1 }, { -t, 0, 1 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// 20 òðåóãîëüíûõ ãðàíåé (èíäåêñû âåðøèí)
|
||||||
|
std::vector<std::array<int, 3>> faces = {
|
||||||
|
// 5 òðåóãîëüíèêîâ âîêðóã âåðøèíû 0
|
||||||
|
{0, 11, 5}, {0, 5, 1}, {0, 1, 7}, {0, 7, 10}, {0, 10, 11},
|
||||||
|
// 5 ñìåæíûõ ïîëîñ
|
||||||
|
{1, 5, 9}, {5, 11, 4}, {11, 10, 2}, {10, 7, 6}, {7, 1, 8},
|
||||||
|
// 5 òðåóãîëüíèêîâ âîêðóã âåðøèíû 3
|
||||||
|
{3, 9, 4}, {3, 4, 2}, {3, 2, 6}, {3, 6, 8}, {3, 8, 9},
|
||||||
|
// 5 ñìåæíûõ ïîëîñ
|
||||||
|
{4, 9, 5}, {2, 4, 11}, {6, 2, 10}, {8, 6, 7}, {9, 8, 1}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1. Íîðìàëèçàöèÿ è Âîçìóùåíèå (Perturbation)
|
||||||
|
for (Vector3f& v : initialVertices) {
|
||||||
|
v = v.normalized() * StoneParams::BASE_SCALE; // Íîðìàëèçàöèÿ ê ñôåðå ðàäèóñà BASE_SCALE
|
||||||
|
|
||||||
|
// Ðàäèàëüíîå âîçìóùåíèå:
|
||||||
|
float perturbation = getRandomFloat(engine, StoneParams::MIN_PERTURBATION, StoneParams::MAX_PERTURBATION);
|
||||||
|
v = v * (1.0f + perturbation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Òðàíñôîðìàöèÿ (Ìàñøòàáèðîâàíèå è Ïîâîðîò)
|
||||||
|
|
||||||
|
// Ñëó÷àéíûå ìàñøòàáû ïî îñÿì
|
||||||
|
Vector3f scaleFactors = {
|
||||||
|
getRandomFloat(engine, StoneParams::MIN_AXIS_SCALE, StoneParams::MAX_AXIS_SCALE),
|
||||||
|
getRandomFloat(engine, StoneParams::MIN_AXIS_SCALE, StoneParams::MAX_AXIS_SCALE),
|
||||||
|
getRandomFloat(engine, StoneParams::MIN_AXIS_SCALE, StoneParams::MAX_AXIS_SCALE)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ïðèìåíÿåì ìàñøòàáèðîâàíèå
|
||||||
|
for (Vector3f& v : initialVertices) {
|
||||||
|
v.v[0] *= scaleFactors.v[0];
|
||||||
|
v.v[1] *= scaleFactors.v[1];
|
||||||
|
v.v[2] *= scaleFactors.v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ñëó÷àéíûé ïîâîðîò (íàïðèìåð, âîêðóã òðåõ îñåé)
|
||||||
|
Vector4f qx = QuatFromRotateAroundX(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
|
Vector4f qy = QuatFromRotateAroundY(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
|
Vector4f qz = QuatFromRotateAroundZ(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
|
Vector4f qFinal = slerp(qx, qy, 0.5f); // Ïðîñòîé ïðèìåð êîìáèíèðîâàíèÿ
|
||||||
|
qFinal = slerp(qFinal, qz, 0.5f).normalized();
|
||||||
|
Matrix3f rotationMatrix = QuatToMatrix(qFinal);
|
||||||
|
|
||||||
|
for (Vector3f& v : initialVertices) {
|
||||||
|
v = MultMatrixVector(rotationMatrix, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Ñãëàæåííûå Íîðìàëè è Ôîðìèðîâàíèå Mesh
|
||||||
|
VertexDataStruct result;
|
||||||
|
// Êàðòà äëÿ íàêîïëåíèÿ íîðìàëåé ïî óíèêàëüíûì ïîçèöèÿì âåðøèí
|
||||||
|
// (Òðåáóåò îïðåäåëåííîãî îïåðàòîðà < äëÿ Vector3f â ZLMath.h, êîòîðûé ó âàñ åñòü)
|
||||||
|
std::map<Vector3f, Vector3f> smoothNormalsMap;
|
||||||
|
|
||||||
|
// Ïðåäâàðèòåëüíîå çàïîëíåíèå êàðòû íîðìàëÿìè
|
||||||
|
for (const auto& face : faces) {
|
||||||
|
Vector3f p1 = initialVertices[face[0]];
|
||||||
|
Vector3f p2 = initialVertices[face[1]];
|
||||||
|
Vector3f p3 = initialVertices[face[2]];
|
||||||
|
|
||||||
|
// Íîðìàëü ãðàíè: (p2 - p1) x (p3 - p1)
|
||||||
|
Vector3f faceNormal = (p2 - p1).cross(p3 - p1).normalized();
|
||||||
|
|
||||||
|
smoothNormalsMap[p1] = smoothNormalsMap[p1] + faceNormal;
|
||||||
|
smoothNormalsMap[p2] = smoothNormalsMap[p2] + faceNormal;
|
||||||
|
smoothNormalsMap[p3] = smoothNormalsMap[p3] + faceNormal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Íîðìàëèçàöèÿ íàêîïëåííûõ íîðìàëåé
|
||||||
|
for (auto& pair : smoothNormalsMap) {
|
||||||
|
pair.second = pair.second.normalized();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 4. Ôèíàëüíîå çàïîëíåíèå VertexDataStruct è Òåêñòóðíûå Êîîðäèíàòû
|
||||||
|
for (const auto& face : faces) {
|
||||||
|
Vector3f p1 = initialVertices[face[0]];
|
||||||
|
Vector3f p2 = initialVertices[face[1]];
|
||||||
|
Vector3f p3 = initialVertices[face[2]];
|
||||||
|
|
||||||
|
// Ïîçèöèè
|
||||||
|
result.PositionData.push_back(p1);
|
||||||
|
result.PositionData.push_back(p2);
|
||||||
|
result.PositionData.push_back(p3);
|
||||||
|
|
||||||
|
// Ñãëàæåííûå Íîðìàëè (èç êàðòû)
|
||||||
|
result.NormalData.push_back(smoothNormalsMap[p1]);
|
||||||
|
result.NormalData.push_back(smoothNormalsMap[p2]);
|
||||||
|
result.NormalData.push_back(smoothNormalsMap[p3]);
|
||||||
|
|
||||||
|
// Òåêñòóðíûå Êîîðäèíàòû (Ïëàíàðíàÿ ïðîåêöèÿ íà ïëîñêîñòü ãðàíè)
|
||||||
|
// p1 -> (0, 0), p2 -> (L_12, 0), p3 -> (L_13 * cos(angle), L_13 * sin(angle))
|
||||||
|
// Ãäå L_xy - äëèíà âåêòîðà, angle - óãîë ìåæäó p2-p1 è p3-p1
|
||||||
|
|
||||||
|
Vector3f uAxis = (p2 - p1).normalized();
|
||||||
|
Vector3f vRaw = p3 - p1;
|
||||||
|
|
||||||
|
// Ïðîåêöèÿ vRaw íà uAxis
|
||||||
|
float uProjLen = vRaw.dot(uAxis);
|
||||||
|
|
||||||
|
// Âåêòîð V ïåðïåíäèêóëÿðíûé U: vRaw - uProj
|
||||||
|
Vector3f vAxisRaw = vRaw - (uAxis * uProjLen);
|
||||||
|
|
||||||
|
// Äëèíà îñè V
|
||||||
|
float vLen = vAxisRaw.length();
|
||||||
|
|
||||||
|
// Íîðìàëèçîâàííàÿ îñü V
|
||||||
|
Vector3f vAxis = vAxisRaw.normalized();
|
||||||
|
|
||||||
|
// Êîîðäèíàòû (u, v) äëÿ p1, p2, p3 îòíîñèòåëüíî p1
|
||||||
|
Vector2f uv1 = { 0.0f, 0.0f };
|
||||||
|
Vector2f uv2 = { (p2 - p1).length(), 0.0f }; // p2-p1 âäîëü îñè U
|
||||||
|
Vector2f uv3 = { uProjLen, vLen }; // p3-p1: u-êîìïîíåíòà = uProjLen, v-êîìïîíåíòà = vLen
|
||||||
|
|
||||||
|
// Íàõîäèì ìàêñèìàëüíûé ðàçìåð, ÷òîáû ìàñøòàáèðîâàòü â [0, 1]
|
||||||
|
float maxUV = max(uv2.v[0], max(uv3.v[0], uv3.v[1]));
|
||||||
|
|
||||||
|
if (maxUV > 0.000001f) {
|
||||||
|
// Ìàñøòàáèðóåì:
|
||||||
|
result.TexCoordData.push_back(uv1);
|
||||||
|
result.TexCoordData.push_back(uv2 * (1.f / maxUV));
|
||||||
|
result.TexCoordData.push_back(uv3 * (1.f / maxUV));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Ïðåäîòâðàùåíèå äåëåíèÿ íà íîëü äëÿ âûðîæäåííûõ ãðàíåé
|
||||||
|
result.TexCoordData.push_back({ 0.0f, 0.0f });
|
||||||
|
result.TexCoordData.push_back({ 0.0f, 0.0f });
|
||||||
|
result.TexCoordData.push_back({ 0.0f, 0.0f });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
StoneGroup CreateStoneGroupData(uint64_t globalSeed, const LodLevel& planetLodLevel) {
|
||||||
|
StoneGroup group;
|
||||||
|
|
||||||
|
// Ðåçåðâèðóåì ìåñòî ïîä âñå òðåóãîëüíèêè òåêóùåãî LOD
|
||||||
|
group.allInstances.resize(planetLodLevel.triangles.size());
|
||||||
|
|
||||||
|
for (size_t tIdx = 0; tIdx < planetLodLevel.triangles.size(); ++tIdx) {
|
||||||
|
const Triangle& tri = planetLodLevel.triangles[tIdx];
|
||||||
|
std::mt19937 engine(static_cast<unsigned int>(globalSeed));
|
||||||
|
|
||||||
|
for (int i = 0; i < StoneParams::STONES_PER_TRIANGLE; ++i) {
|
||||||
|
StoneInstance instance;
|
||||||
|
instance.seed = globalSeed;// + tIdx * 1000 + i; // Óíèêàëüíûé ñèä äëÿ êàæäîãî êàìíÿ
|
||||||
|
|
||||||
|
instance.position = GetRandomPointOnTriangle(tri, engine);
|
||||||
|
|
||||||
|
//instance.position = Vector3f(5000.0f, 5000.0f, 5000.0f);
|
||||||
|
// Ãåíåðèðóåì ñëó÷àéíûå ïàðàìåòðû îäèí ðàç
|
||||||
|
instance.scale = {
|
||||||
|
getRandomFloat(engine, 0.5f, 1.5f),
|
||||||
|
getRandomFloat(engine, 0.5f, 1.5f),
|
||||||
|
getRandomFloat(engine, 0.5f, 1.5f)
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector4f qx = QuatFromRotateAroundX(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
|
Vector4f qy = QuatFromRotateAroundY(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
|
Vector4f qz = QuatFromRotateAroundZ(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
|
instance.rotation = slerp(slerp(qx, qy, 0.5f), qz, 0.5f).normalized();
|
||||||
|
|
||||||
|
group.allInstances[tIdx].push_back(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StoneGroup::inflate(const std::vector<int>& triangleIndices) {
|
||||||
|
// 1. Î÷èùàåì òåêóùèé ìåø ïåðåä çàïîëíåíèåì
|
||||||
|
mesh.PositionData.clear();
|
||||||
|
mesh.NormalData.clear();
|
||||||
|
mesh.TexCoordData.clear();
|
||||||
|
|
||||||
|
static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337);
|
||||||
|
|
||||||
|
// 2. Íàïîëíÿåì ìåø òîëüêî äëÿ âèäèìûõ òðåóãîëüíèêîâ
|
||||||
|
for (int tIdx : triangleIndices) {
|
||||||
|
if (tIdx >= allInstances.size()) continue;
|
||||||
|
|
||||||
|
for (const auto& inst : allInstances[tIdx]) {
|
||||||
|
Matrix3f rotMat = QuatToMatrix(inst.rotation);
|
||||||
|
|
||||||
|
for (size_t j = 0; j < baseStone.PositionData.size(); ++j) {
|
||||||
|
Vector3f p = baseStone.PositionData[j];
|
||||||
|
Vector3f n = baseStone.NormalData[j];
|
||||||
|
|
||||||
|
// Ìàñøòàá -> Ïîâîðîò -> Ñìåùåíèå
|
||||||
|
p.v[0] *= inst.scale.v[0];
|
||||||
|
p.v[1] *= inst.scale.v[1];
|
||||||
|
p.v[2] *= inst.scale.v[2];
|
||||||
|
|
||||||
|
mesh.PositionData.push_back(MultMatrixVector(rotMat, p) + inst.position);
|
||||||
|
mesh.NormalData.push_back(MultMatrixVector(rotMat, n));
|
||||||
|
mesh.TexCoordData.push_back(baseStone.TexCoordData[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace ZL
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ZLMath.h"
|
||||||
|
#include "Renderer.h"
|
||||||
|
#include "PlanetData.h"
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
struct StoneParams
|
||||||
|
{
|
||||||
|
static const float BASE_SCALE; // Îáùèé ðàçìåð êàìíÿ
|
||||||
|
static const float MIN_AXIS_SCALE; // Ìèíèìàëüíîå ðàñòÿæåíèå/ñæàòèå ïî îñè
|
||||||
|
static const float MAX_AXIS_SCALE; // Ìàêñèìàëüíîå ðàñòÿæåíèå/ñæàòèå ïî îñè
|
||||||
|
static const float MIN_PERTURBATION; // Ìèíèìàëüíîå ðàäèàëüíîå âîçìóùåíèå âåðøèíû
|
||||||
|
static const float MAX_PERTURBATION; // Ìàêñèìàëüíîå ðàäèàëüíîå âîçìóùåíèå âåðøèíû
|
||||||
|
static const int STONES_PER_TRIANGLE;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StoneInstance {
|
||||||
|
uint64_t seed;
|
||||||
|
Vector3f position;
|
||||||
|
Vector3f scale;
|
||||||
|
Vector4f rotation;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StoneGroup {
|
||||||
|
// mesh.PositionData è ïðî÷èå áóäóò çàïîëíÿòüñÿ â inflate()
|
||||||
|
VertexDataStruct mesh;
|
||||||
|
|
||||||
|
// Âíåøíèé âåêòîð — èíäåêñ òðåóãîëüíèêà ïëàíåòû,
|
||||||
|
// âíóòðåííèé — ñïèñîê êàìíåé íà ýòîì òðåóãîëüíèêå
|
||||||
|
std::vector<std::vector<StoneInstance>> allInstances;
|
||||||
|
|
||||||
|
// Î÷èùàåò ñòàðóþ ãåîìåòðèþ è ãåíåðèðóåò íîâóþ äëÿ óêàçàííûõ èíäåêñîâ
|
||||||
|
void inflate(const std::vector<int>& triangleIndices);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Òåïåðü âîçâðàùàåò çàãîòîâêó ñî âñåìè ïàðàìåòðàìè, íî áåç òÿæåëîãî ìåøà
|
||||||
|
StoneGroup CreateStoneGroupData(uint64_t globalSeed, const LodLevel& planetLodLevel);
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Math.h"
|
#include "ZLMath.h"
|
||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
|||||||
+164
-19
@@ -2,6 +2,7 @@
|
|||||||
#ifdef PNG_ENABLED
|
#ifdef PNG_ENABLED
|
||||||
#include "png.h"
|
#include "png.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace ZL
|
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()
|
Texture::~Texture()
|
||||||
{
|
{
|
||||||
glDeleteTextures(1, &texID);
|
glDeleteTextures(1, &texID);
|
||||||
@@ -170,36 +250,84 @@ namespace ZL
|
|||||||
|
|
||||||
#ifdef PNG_ENABLED
|
#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;
|
TextureDataStruct texData;
|
||||||
|
|
||||||
FILE* file = fopen(fullFileName.c_str(), "rb");
|
// Ñòðóêòóðà äëÿ óïðàâëåíèÿ ÷òåíèåì èç ìàññèâà
|
||||||
if (!file) {
|
png_data_t png_data = { fileArr.data(), fileArr.size(), 0 };
|
||||||
fclose(file);
|
|
||||||
throw std::runtime_error("Could not open file " + fullFileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||||
if (!png) {
|
if (!png) {
|
||||||
fclose(file);
|
|
||||||
throw std::runtime_error("Could not create PNG read structure");
|
throw std::runtime_error("Could not create PNG read structure");
|
||||||
}
|
}
|
||||||
|
|
||||||
png_infop info = png_create_info_struct(png);
|
png_infop info = png_create_info_struct(png);
|
||||||
if (!info) {
|
if (!info) {
|
||||||
fclose(file);
|
|
||||||
png_destroy_read_struct(&png, nullptr, nullptr);
|
png_destroy_read_struct(&png, nullptr, nullptr);
|
||||||
throw std::runtime_error("Could not create PNG info structure");
|
throw std::runtime_error("Could not create PNG info structure");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === Óñòàíîâêà ïîëüçîâàòåëüñêèõ ôóíêöèé ÷òåíèÿ è îáðàáîòêè îøèáîê ===
|
||||||
|
// 1. Óñòàíîâêà îáðàáîò÷èêà îøèáîê è longjmp
|
||||||
if (setjmp(png_jmpbuf(png))) {
|
if (setjmp(png_jmpbuf(png))) {
|
||||||
png_destroy_read_struct(&png, &info, nullptr);
|
png_destroy_read_struct(&png, &info, nullptr);
|
||||||
fclose(file);
|
throw std::runtime_error("Error during PNG read (longjmp was executed)");
|
||||||
throw std::runtime_error("Error during PNG read");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
png_read_info(png, info);
|
||||||
|
|
||||||
texData.width = png_get_image_width(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 color_type = png_get_color_type(png, info);
|
||||||
png_byte bit_depth = png_get_bit_depth(png, info);
|
png_byte bit_depth = png_get_bit_depth(png, info);
|
||||||
|
|
||||||
|
// === Áëîê ïðåîáðàçîâàíèé (îñòàâëåí áåç èçìåíåíèé) ===
|
||||||
if (bit_depth == 16)
|
if (bit_depth == 16)
|
||||||
png_set_strip_16(png);
|
png_set_strip_16(png);
|
||||||
|
|
||||||
@@ -229,8 +358,9 @@ namespace ZL
|
|||||||
png_set_gray_to_rgb(png);
|
png_set_gray_to_rgb(png);
|
||||||
|
|
||||||
png_read_update_info(png, info);
|
png_read_update_info(png, info);
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
// === ×òåíèå ïèêñåëåé (îñòàâëåí áåç èçìåíåíèé) ===
|
||||||
png_bytep* row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * texData.height);
|
png_bytep* row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * texData.height);
|
||||||
for (int y = 0; y < texData.height; y++) {
|
for (int y = 0; y < texData.height; y++) {
|
||||||
row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info));
|
row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info));
|
||||||
@@ -238,8 +368,6 @@ namespace ZL
|
|||||||
|
|
||||||
png_read_image(png, row_pointers);
|
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));
|
bool has_alpha = (color_type & PNG_COLOR_MASK_ALPHA) || (png_get_valid(png, info, PNG_INFO_tRNS));
|
||||||
|
|
||||||
size_t dataSize;
|
size_t dataSize;
|
||||||
@@ -259,9 +387,7 @@ namespace ZL
|
|||||||
texData.data.resize(dataSize);
|
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--) {
|
||||||
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];
|
png_bytep row = row_pointers[texData.height - 1 - y];
|
||||||
for (int x = 0; x < texData.width; x++) {
|
for (int x = 0; x < texData.width; x++) {
|
||||||
png_bytep px = &(row[x * 4]);
|
png_bytep px = &(row[x * 4]);
|
||||||
@@ -272,14 +398,33 @@ namespace ZL
|
|||||||
texData.data[(y * texData.width + x) * channels + 3] = px[3]; // A
|
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]);
|
||||||
free(row_pointers[texData.height - 1 - y]);//Go in reverse because of UV coord start point
|
|
||||||
}
|
}
|
||||||
free(row_pointers);
|
free(row_pointers);
|
||||||
|
// ==================================================
|
||||||
|
|
||||||
png_destroy_read_struct(&png, &info, nullptr);
|
png_destroy_read_struct(&png, &info, nullptr);
|
||||||
|
|
||||||
return texData;
|
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
|
#endif
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+10
-1
@@ -3,6 +3,10 @@
|
|||||||
#include "OpenGlExtensions.h"
|
#include "OpenGlExtensions.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
#define PNG_ENABLED
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ZL
|
namespace ZL
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -29,6 +33,9 @@ namespace ZL
|
|||||||
|
|
||||||
Texture(const TextureDataStruct& texData);
|
Texture(const TextureDataStruct& texData);
|
||||||
|
|
||||||
|
//Cubemap texture:
|
||||||
|
Texture(const std::array<TextureDataStruct, 6>& texDataArray);
|
||||||
|
|
||||||
~Texture();
|
~Texture();
|
||||||
|
|
||||||
GLuint getTexID();
|
GLuint getTexID();
|
||||||
@@ -42,6 +49,8 @@ namespace ZL
|
|||||||
TextureDataStruct CreateTextureDataFromBmp24(const std::string& fullFileName, const std::string& ZIPFileName="");
|
TextureDataStruct CreateTextureDataFromBmp24(const std::string& fullFileName, const std::string& ZIPFileName="");
|
||||||
TextureDataStruct CreateTextureDataFromBmp32(const std::string& fullFileName, const std::string& ZIPFileName="");
|
TextureDataStruct CreateTextureDataFromBmp32(const std::string& fullFileName, const std::string& ZIPFileName="");
|
||||||
#ifdef PNG_ENABLED
|
#ifdef PNG_ENABLED
|
||||||
TextureDataStruct CreateTextureDataFromPng(const std::string& fullFileName);
|
TextureDataStruct CreateTextureDataFromPng(const std::string& fullFileName, const std::string& ZIPFileName = "");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,9 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
//#include <zip.h>
|
#ifdef EMSCRIPTEN
|
||||||
|
#include <zip.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ZL
|
namespace ZL
|
||||||
{
|
{
|
||||||
@@ -42,7 +44,8 @@ namespace ZL
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> readFileFromZIP(const std::string& filename, const std::string& zipfilename) {
|
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;
|
int zipErr;
|
||||||
zip_t* archive = zip_open(zipPath.c_str(), ZIP_RDONLY, &zipErr);
|
zip_t* archive = zip_open(zipPath.c_str(), ZIP_RDONLY, &zipErr);
|
||||||
if (!archive) {
|
if (!archive) {
|
||||||
@@ -77,8 +80,10 @@ namespace ZL
|
|||||||
zip_fclose(zipFile);
|
zip_fclose(zipFile);
|
||||||
zip_close(archive);
|
zip_close(archive);
|
||||||
|
|
||||||
return fileData;*/
|
return fileData;
|
||||||
|
#else
|
||||||
return {};
|
return {};
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool findString(const char* in, char* list)
|
bool findString(const char* in, char* list)
|
||||||
|
|||||||
Executable → Regular
+66
-1
@@ -1,4 +1,4 @@
|
|||||||
#include "Math.h"
|
#include "ZLMath.h"
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@@ -45,6 +45,16 @@ namespace ZL {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3f operator-(const Vector3f& x)
|
||||||
|
{
|
||||||
|
Vector3f result;
|
||||||
|
|
||||||
|
result.v[0] = -x.v[0];
|
||||||
|
result.v[1] = -x.v[1];
|
||||||
|
result.v[2] = -x.v[2];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Vector4f operator+(const Vector4f& x, const Vector4f& y)
|
Vector4f operator+(const Vector4f& x, const Vector4f& y)
|
||||||
{
|
{
|
||||||
Vector4f result;
|
Vector4f result;
|
||||||
@@ -67,6 +77,8 @@ namespace ZL {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Matrix3f Matrix3f::Identity()
|
Matrix3f Matrix3f::Identity()
|
||||||
{
|
{
|
||||||
Matrix3f r;
|
Matrix3f r;
|
||||||
@@ -177,6 +189,38 @@ namespace ZL {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Matrix4f MakeOrthoMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar)
|
||||||
|
{
|
||||||
|
float width = xmax - xmin;
|
||||||
|
float height = ymax - ymin;
|
||||||
|
float depthRange = zFar - zNear;
|
||||||
|
|
||||||
|
if (width <= 0 || height <= 0 || depthRange <= 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid dimensions for orthogonal matrix");
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix4f r;
|
||||||
|
|
||||||
|
// Масштабирование
|
||||||
|
r.m[0] = 2.f / width;
|
||||||
|
r.m[5] = 2.f / height;
|
||||||
|
r.m[10] = -1.f / depthRange;
|
||||||
|
|
||||||
|
// Обнуление неиспользуемых компонентов
|
||||||
|
r.m[1] = r.m[2] = r.m[3] = 0;
|
||||||
|
r.m[4] = r.m[6] = r.m[7] = 0;
|
||||||
|
r.m[8] = r.m[9] = r.m[11] = 0;
|
||||||
|
|
||||||
|
// Трансляция (смещение)
|
||||||
|
r.m[12] = -(xmax + xmin) / width;
|
||||||
|
r.m[13] = -(ymax + ymin) / height;
|
||||||
|
r.m[14] = zNear / depthRange;
|
||||||
|
r.m[15] = 1.f;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar)
|
Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar)
|
||||||
{
|
{
|
||||||
float tanHalfFovy = tan(fovY / 2.f);
|
float tanHalfFovy = tan(fovY / 2.f);
|
||||||
@@ -597,6 +641,16 @@ namespace ZL {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2f operator*(Vector2f v, float scale)
|
||||||
|
{
|
||||||
|
Vector2f r = v;
|
||||||
|
|
||||||
|
r.v[0] = v.v[0] * scale;
|
||||||
|
r.v[1] = v.v[1] * scale;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
Vector3f operator*(Vector3f v, float scale)
|
Vector3f operator*(Vector3f v, float scale)
|
||||||
{
|
{
|
||||||
Vector3f r = v;
|
Vector3f r = v;
|
||||||
@@ -655,6 +709,17 @@ namespace ZL {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3f MultMatrixVector(Matrix3f mt, Vector3f v)
|
||||||
|
{
|
||||||
|
Vector3f r;
|
||||||
|
|
||||||
|
r.v[0] = v.v[0] * mt.m[0] + v.v[1] * mt.m[3] + v.v[2] * mt.m[6];
|
||||||
|
r.v[1] = v.v[0] * mt.m[1] + v.v[1] * mt.m[4] + v.v[2] * mt.m[7];
|
||||||
|
r.v[2] = v.v[0] * mt.m[2] + v.v[1] * mt.m[5] + v.v[2] * mt.m[8];
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
Vector4f slerp(const Vector4f& q1, const Vector4f& q2, float t)
|
Vector4f slerp(const Vector4f& q1, const Vector4f& q2, float t)
|
||||||
{
|
{
|
||||||
const float epsilon = 1e-6f;
|
const float epsilon = 1e-6f;
|
||||||
@@ -13,6 +13,9 @@ namespace ZL {
|
|||||||
|
|
||||||
Vector4f normalized() const {
|
Vector4f normalized() const {
|
||||||
double norm = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);
|
double norm = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);
|
||||||
|
if (norm <= 0.000001f) {
|
||||||
|
return { 0,0, 0, 0};
|
||||||
|
}
|
||||||
Vector4f r;
|
Vector4f r;
|
||||||
|
|
||||||
r.v[0] = v[0] / norm;
|
r.v[0] = v[0] / norm;
|
||||||
@@ -31,11 +34,72 @@ namespace ZL {
|
|||||||
struct Vector3f
|
struct Vector3f
|
||||||
{
|
{
|
||||||
std::array<float, 3> v = { 0.f, 0.f, 0.f };
|
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]);
|
||||||
|
if (norm <= 0.000001f) {
|
||||||
|
return { 0,0,0 };
|
||||||
|
}
|
||||||
|
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 length() const
|
||||||
|
{
|
||||||
|
return sqrt(squaredNorm());
|
||||||
|
}
|
||||||
|
|
||||||
|
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]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const Vector3f& other) const {
|
||||||
|
if (v[0] != other.v[0]) return v[0] < other.v[0];
|
||||||
|
if (v[1] != other.v[1]) return v[1] < other.v[1];
|
||||||
|
return v[2] < other.v[2];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct Vector2f
|
struct Vector2f
|
||||||
{
|
{
|
||||||
std::array<float, 2> v = {0.f, 0.f};
|
std::array<float, 2> v = {0.f, 0.f};
|
||||||
|
|
||||||
|
Vector2f()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2f(float x, float y)
|
||||||
|
: v{ x,y }
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector2f operator+(const Vector2f& x, const Vector2f& y);
|
Vector2f operator+(const Vector2f& x, const Vector2f& y);
|
||||||
@@ -49,6 +113,8 @@ namespace ZL {
|
|||||||
|
|
||||||
Vector4f operator-(const Vector4f& x, const Vector4f& y);
|
Vector4f operator-(const Vector4f& x, const Vector4f& y);
|
||||||
|
|
||||||
|
Vector3f operator-(const Vector3f& x);
|
||||||
|
|
||||||
|
|
||||||
struct Matrix3f
|
struct Matrix3f
|
||||||
{
|
{
|
||||||
@@ -82,6 +148,7 @@ namespace ZL {
|
|||||||
Matrix4f operator*(const Matrix4f& m1, const Matrix4f& m2);
|
Matrix4f operator*(const Matrix4f& m1, const Matrix4f& m2);
|
||||||
|
|
||||||
Matrix4f MakeOrthoMatrix(float width, float height, float zNear, float zFar);
|
Matrix4f MakeOrthoMatrix(float width, float height, float zNear, float zFar);
|
||||||
|
Matrix4f MakeOrthoMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar);
|
||||||
|
|
||||||
Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar);
|
Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar);
|
||||||
|
|
||||||
@@ -93,12 +160,14 @@ namespace ZL {
|
|||||||
Vector4f QuatFromRotateAroundY(float angle);
|
Vector4f QuatFromRotateAroundY(float angle);
|
||||||
Vector4f QuatFromRotateAroundZ(float angle);
|
Vector4f QuatFromRotateAroundZ(float angle);
|
||||||
|
|
||||||
|
Vector2f operator*(Vector2f v, float scale);
|
||||||
Vector3f operator*(Vector3f v, float scale);
|
Vector3f operator*(Vector3f v, float scale);
|
||||||
Vector4f operator*(Vector4f v, float scale);
|
Vector4f operator*(Vector4f v, float scale);
|
||||||
|
|
||||||
Vector3f MultVectorMatrix(Vector3f v, Matrix3f mt);
|
Vector3f MultVectorMatrix(Vector3f v, Matrix3f mt);
|
||||||
Vector4f MultVectorMatrix(Vector4f v, Matrix4f mt);
|
Vector4f MultVectorMatrix(Vector4f v, Matrix4f mt);
|
||||||
Vector4f MultMatrixVector(Matrix4f mt, Vector4f v);
|
Vector4f MultMatrixVector(Matrix4f mt, Vector4f v);
|
||||||
|
Vector3f MultMatrixVector(Matrix3f mt, Vector3f v);
|
||||||
|
|
||||||
Vector4f slerp(const Vector4f& q1, const Vector4f& q2, float t);
|
Vector4f slerp(const Vector4f& q1, const Vector4f& q2, float t);
|
||||||
Matrix3f InverseMatrix(const Matrix3f& m);
|
Matrix3f InverseMatrix(const Matrix3f& m);
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -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")
|
||||||
@@ -1,78 +1,88 @@
|
|||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
ZL::Game game;
|
ZL::Game game;
|
||||||
void MainLoop() {
|
void MainLoop() {
|
||||||
game.update();
|
game.update();
|
||||||
}
|
}
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
constexpr int CONST_WIDTH = 1280;
|
try
|
||||||
constexpr int CONST_HEIGHT = 720;
|
{
|
||||||
|
constexpr int CONST_WIDTH = 1280;
|
||||||
|
constexpr int CONST_HEIGHT = 720;
|
||||||
|
|
||||||
ZL::Environment::width = CONST_WIDTH;
|
ZL::Environment::width = CONST_WIDTH;
|
||||||
ZL::Environment::height = CONST_HEIGHT;
|
ZL::Environment::height = CONST_HEIGHT;
|
||||||
|
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef EMSCRIPTEN
|
||||||
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
|
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||||
std::cerr << "SDL_Init failed: " << SDL_GetError() << std::endl;
|
std::cerr << "SDL_Init failed: " << SDL_GetError() << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
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_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||||
|
|
||||||
SDL_Window* win = SDL_CreateWindow("Space Ship Game",
|
SDL_Window* win = SDL_CreateWindow("Space Ship Game",
|
||||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||||
CONST_WIDTH, CONST_HEIGHT,
|
CONST_WIDTH, CONST_HEIGHT,
|
||||||
SDL_WINDOW_OPENGL);
|
SDL_WINDOW_OPENGL);
|
||||||
|
|
||||||
if (!win) {
|
if (!win) {
|
||||||
std::cerr << "SDL_CreateWindow failed: " << SDL_GetError() << std::endl;
|
std::cerr << "SDL_CreateWindow failed: " << SDL_GetError() << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_GLContext glContext = SDL_GL_CreateContext(win);
|
SDL_GLContext glContext = SDL_GL_CreateContext(win);
|
||||||
if (!glContext) {
|
if (!glContext) {
|
||||||
std::cerr << "SDL_GL_CreateContext failed: " << SDL_GetError() << std::endl;
|
std::cerr << "SDL_GL_CreateContext failed: " << SDL_GetError() << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Привязка контекста к окну — важно!
|
// Привязка контекста к окну — важно!
|
||||||
SDL_GL_MakeCurrent(win, glContext);
|
SDL_GL_MakeCurrent(win, glContext);
|
||||||
|
|
||||||
ZL::Environment::window = win;
|
ZL::Environment::window = win;
|
||||||
#else
|
#else
|
||||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
|
||||||
SDL_Log("SDL init failed: %s", SDL_GetError());
|
SDL_Log("SDL init failed: %s", SDL_GetError());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_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_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||||
|
|
||||||
ZL::Environment::window = SDL_CreateWindow(
|
ZL::Environment::window = SDL_CreateWindow(
|
||||||
"Space Ship Game",
|
"Space Ship Game",
|
||||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||||
CONST_WIDTH, CONST_HEIGHT,
|
CONST_WIDTH, CONST_HEIGHT,
|
||||||
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
|
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
|
||||||
);
|
);
|
||||||
|
|
||||||
SDL_GLContext ctx = SDL_GL_CreateContext(ZL::Environment::window);
|
SDL_GLContext ctx = SDL_GL_CreateContext(ZL::Environment::window);
|
||||||
SDL_GL_MakeCurrent(ZL::Environment::window, ctx);
|
SDL_GL_MakeCurrent(ZL::Environment::window, ctx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
game.setup();
|
game.setup();
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef EMSCRIPTEN
|
||||||
emscripten_set_main_loop(MainLoop, 0, 1);
|
emscripten_set_main_loop(MainLoop, 0, 1);
|
||||||
#else
|
#else
|
||||||
while (!game.shouldExit()) {
|
while (!game.shouldExit()) {
|
||||||
game.update();
|
game.update();
|
||||||
SDL_Delay(2);
|
SDL_Delay(2);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
std::cout << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -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
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
BIN
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 |
@@ -0,0 +1,48 @@
|
|||||||
|
// Фрагментный шейдер:
|
||||||
|
uniform vec3 uColor;
|
||||||
|
uniform float uDistanceToPlanetSurface; // Расстояние корабля до поверхности
|
||||||
|
|
||||||
|
// Константы затухания, определенные прямо в шейдере
|
||||||
|
const float DIST_FOG_MAX = 2000.0;
|
||||||
|
const float DIST_FOG_MIN = 1000.0;
|
||||||
|
|
||||||
|
varying vec3 vViewNormal;
|
||||||
|
varying vec3 vViewPosition;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// --- 1. Расчет плотности по Френелю (краевой эффект) ---
|
||||||
|
vec3 viewVector = normalize(-vViewPosition);
|
||||||
|
float NdotV = dot(vViewNormal, viewVector);
|
||||||
|
float factor = 1.0 - abs(NdotV);
|
||||||
|
float atmosphereDensity = pow(factor, 5.0);
|
||||||
|
|
||||||
|
// --- 2. Расчет коэффициента затухания по дистанции ---
|
||||||
|
|
||||||
|
float distanceFactor = 1.0;
|
||||||
|
|
||||||
|
if (uDistanceToPlanetSurface > DIST_FOG_MAX)
|
||||||
|
{
|
||||||
|
// Дистанция > 2000.0: Полностью видно (Factor = 1.0)
|
||||||
|
distanceFactor = 1.0;
|
||||||
|
}
|
||||||
|
else if (uDistanceToPlanetSurface < DIST_FOG_MIN)
|
||||||
|
{
|
||||||
|
// Дистанция < 1000.0: Полностью не видно (Factor = 0.0)
|
||||||
|
distanceFactor = 0.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Плавный переход (линейная интерполяция)
|
||||||
|
// normalizedDistance: от 0.0 (на DIST_FOG_MIN) до 1.0 (на DIST_FOG_MAX)
|
||||||
|
float normalizedDistance = (uDistanceToPlanetSurface - DIST_FOG_MIN) / (DIST_FOG_MAX - DIST_FOG_MIN);
|
||||||
|
|
||||||
|
distanceFactor = clamp(normalizedDistance, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 3. Финальный цвет и прозрачность ---
|
||||||
|
|
||||||
|
float finalAlpha = atmosphereDensity * distanceFactor;
|
||||||
|
|
||||||
|
gl_FragColor = vec4(uColor, finalAlpha);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// Вершинный шейдер:
|
||||||
|
attribute vec3 vPosition;
|
||||||
|
attribute vec3 vNormal; // <-- Новый атрибут
|
||||||
|
|
||||||
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
uniform mat4 ModelViewMatrix;
|
||||||
|
|
||||||
|
// Выходные переменные (передаются во фрагментный шейдер)
|
||||||
|
varying vec3 vViewNormal;
|
||||||
|
varying vec3 vViewPosition;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// 1. Позиция в пространстве вида (View Space)
|
||||||
|
vec4 positionView = ModelViewMatrix * vec4(vPosition, 1.0);
|
||||||
|
vViewPosition = positionView.xyz;
|
||||||
|
|
||||||
|
// 2. Нормаль в пространстве вида (View Space)
|
||||||
|
// Преобразуем нормаль, используя ModelViewMatrix. Поскольку нормаль - это вектор,
|
||||||
|
// трансляционная часть (четвертый столбец) матрицы нам не нужна.
|
||||||
|
// Если бы было неединообразное масштабирование, потребовалась бы Inverse Transpose Matrix.
|
||||||
|
// В вашем случае, где есть только униформное масштабирование и вращение,
|
||||||
|
// достаточно просто умножить на ModelViewMatrix:
|
||||||
|
vViewNormal = normalize((ModelViewMatrix * vec4(vNormal, 0.0)).xyz);
|
||||||
|
// W=0.0 для векторов, чтобы игнорировать трансляцию
|
||||||
|
|
||||||
|
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||||
|
}
|
||||||
@@ -1,11 +1,23 @@
|
|||||||
attribute vec3 vPosition;
|
attribute vec3 vPosition;
|
||||||
attribute vec3 vColor;
|
attribute vec3 vColor;
|
||||||
|
attribute vec3 vNormal;
|
||||||
|
attribute vec2 vTexCoord; // <-- Обычные UV (если используются)
|
||||||
|
|
||||||
varying vec3 color;
|
varying vec3 color;
|
||||||
|
varying vec3 normal;
|
||||||
|
|
||||||
|
varying vec2 TexCoord; // <-- Передаем UV
|
||||||
|
|
||||||
uniform mat4 ProjectionModelViewMatrix;
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
uniform mat4 ModelViewMatrix;
|
||||||
|
uniform vec3 uLightDirection;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||||
color = vColor;
|
|
||||||
|
normal = normalize((ModelViewMatrix * vec4(vNormal, 0.0)).xyz);
|
||||||
|
|
||||||
|
color = vColor;
|
||||||
|
TexCoord = vTexCoord;
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,22 @@
|
|||||||
//precision mediump float;
|
varying vec3 color; // Цвет вершины (с шумом)
|
||||||
varying vec3 color;
|
varying vec3 normal;
|
||||||
|
varying vec3 lightDirection_VS;
|
||||||
|
varying vec2 TexCoord; // UV-координаты
|
||||||
|
|
||||||
|
uniform sampler2D Texture;
|
||||||
|
uniform vec3 uLightDirection;
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
//gl_FragColor = vec4(color, 1.0);
|
// 1. Получаем цвет из текстуры и смешиваем с цветовым шумом
|
||||||
gl_FragColor = vec4(1.0, 1.0, 0.5, 1.0);
|
vec4 textureColor = texture2D(Texture, TexCoord);
|
||||||
|
vec3 finalColor = textureColor.rgb * color;
|
||||||
|
|
||||||
|
// 3. Расчет освещения
|
||||||
|
float diffuse = max(0.0, dot(normal, uLightDirection));
|
||||||
|
float ambient = 0.2;
|
||||||
|
float lightingFactor = min(1.0, ambient + diffuse);
|
||||||
|
|
||||||
|
|
||||||
|
gl_FragColor = vec4(finalColor * lightingFactor, 1.0);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// Вершинный шейдер (Vertex Shader)
|
||||||
|
|
||||||
|
attribute vec3 vPosition;
|
||||||
|
attribute vec3 vColor;
|
||||||
|
attribute vec3 vNormal;
|
||||||
|
attribute vec2 vTexCoord;
|
||||||
|
|
||||||
|
varying vec3 color;
|
||||||
|
varying vec3 normal;
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying float viewZ; // <--- НОВОЕ: Z-координата в пространстве вида (View Space)
|
||||||
|
varying vec3 pos;
|
||||||
|
|
||||||
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
uniform mat4 ModelViewMatrix; // Нужна для преобразования vPosition в View Space
|
||||||
|
uniform vec3 uLightDirection;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Преобразование позиции в пространство вида (View Space)
|
||||||
|
vec4 viewPosition = ModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||||
|
|
||||||
|
// Сохраняем отрицательную Z-координату. В OpenGL Z-координата (глубина)
|
||||||
|
// в пространстве вида обычно отрицательна, но для расчета тумана
|
||||||
|
// удобнее использовать положительное значение.
|
||||||
|
viewZ = -viewPosition.z;
|
||||||
|
|
||||||
|
pos = vPosition.xyz;
|
||||||
|
|
||||||
|
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||||
|
|
||||||
|
normal = normalize((ModelViewMatrix * vec4(vNormal, 0.0)).xyz);
|
||||||
|
color = vColor;
|
||||||
|
TexCoord = vTexCoord;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// Вершинный шейдер (Vertex Shader)
|
||||||
|
|
||||||
|
attribute vec3 vPosition;
|
||||||
|
attribute vec3 vColor;
|
||||||
|
attribute vec3 vNormal;
|
||||||
|
attribute vec2 vTexCoord;
|
||||||
|
|
||||||
|
varying vec3 color;
|
||||||
|
varying vec3 normal;
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying float viewZ; // <--- НОВОЕ: Z-координата в пространстве вида (View Space)
|
||||||
|
varying vec3 pos;
|
||||||
|
|
||||||
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
uniform mat4 ModelViewMatrix; // Нужна для преобразования vPosition в View Space
|
||||||
|
uniform vec3 uLightDirection;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Преобразование позиции в пространство вида (View Space)
|
||||||
|
vec4 viewPosition = ModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||||
|
|
||||||
|
// Сохраняем отрицательную Z-координату. В OpenGL Z-координата (глубина)
|
||||||
|
// в пространстве вида обычно отрицательна, но для расчета тумана
|
||||||
|
// удобнее использовать положительное значение.
|
||||||
|
viewZ = -viewPosition.z;
|
||||||
|
|
||||||
|
pos = vPosition.xyz;
|
||||||
|
|
||||||
|
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||||
|
|
||||||
|
normal = normalize((ModelViewMatrix * vec4(vNormal, 0.0)).xyz);
|
||||||
|
color = vColor;
|
||||||
|
TexCoord = vTexCoord;
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
// ---Фрагментный шейдер (Fragment Shader)
|
||||||
|
|
||||||
|
varying vec3 color;
|
||||||
|
varying vec3 normal;
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying float viewZ;
|
||||||
|
varying vec3 pos;
|
||||||
|
|
||||||
|
uniform sampler2D Texture;
|
||||||
|
uniform vec3 uLightDirection;
|
||||||
|
uniform float uDistanceToPlanetSurface;
|
||||||
|
uniform float uCurrentZFar;
|
||||||
|
|
||||||
|
// Константы для тумана:
|
||||||
|
//const vec4 FOG_COLOR = vec4(0.0, 0.3, 0.3, 1.0); // Синий туман
|
||||||
|
const vec4 FOG_COLOR = vec4(0.0, 0.5, 1.0, 1.0); // Синий туман
|
||||||
|
|
||||||
|
// Параметры "Distance Fog"
|
||||||
|
const float DIST_FOG_MAX = 2000.0;
|
||||||
|
const float DIST_FOG_MIN = 1000.0;
|
||||||
|
|
||||||
|
// Параметры "Z-Far Fog"
|
||||||
|
// Насколько близко к Zfar должен начинаться туман (например, 10% от Zfar)
|
||||||
|
const float Z_FOG_START_RATIO = 0.9;
|
||||||
|
// Какую долю от Zfar должен покрывать туман (например, 10% от Zfar)
|
||||||
|
const float Z_FOG_RANGE_RATIO = 0.1;
|
||||||
|
uniform vec3 uColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// ... (1. Получаем цвет и 2. Расчет освещения)
|
||||||
|
vec4 textureColor = texture2D(Texture, TexCoord);
|
||||||
|
vec3 finalColor = textureColor.rgb;
|
||||||
|
|
||||||
|
float diffuse = max(0.0, dot(normal, uLightDirection));
|
||||||
|
float ambient = 0.2;
|
||||||
|
float lightingFactor = min(1.0, ambient + diffuse);
|
||||||
|
vec3 litColor = finalColor * lightingFactor;
|
||||||
|
|
||||||
|
|
||||||
|
// 3. Расчет коэффициента тумана (fogFactor)
|
||||||
|
float fogFactor = 0.0;
|
||||||
|
|
||||||
|
// --- 3.1. Расчет коэффициента тумана на основе расстояния до поверхности (Distance Fog) ---
|
||||||
|
// Этот туман работает на больших расстояниях и постепенно исчезает,
|
||||||
|
// уступая место Z-Far Fog при приближении к планете.
|
||||||
|
|
||||||
|
if (uDistanceToPlanetSurface >= DIST_FOG_MIN && uDistanceToPlanetSurface <DIST_FOG_MAX) {
|
||||||
|
// Нормализация: 0.0f при DIST_FOG_MAX, 1.0f при DIST_FOG_MIN
|
||||||
|
float distRange = DIST_FOG_MAX - DIST_FOG_MIN;
|
||||||
|
float distNormalized = clamp((uDistanceToPlanetSurface - DIST_FOG_MIN) / distRange, 0.0, 1.0);
|
||||||
|
|
||||||
|
// alpha = 0.0 (Далеко) ... 1.0 (Близко к 1000.f)
|
||||||
|
fogFactor = 1.0 - distNormalized;
|
||||||
|
}
|
||||||
|
if (uDistanceToPlanetSurface < DIST_FOG_MIN)
|
||||||
|
{
|
||||||
|
fogFactor = 1.0;
|
||||||
|
}
|
||||||
|
// Если uDistanceToPlanetSurface < 1000.0f, то fogFactor = 0.0f (пока не пересчитан ниже),
|
||||||
|
// что позволяет Z-Far Fog взять контроль.
|
||||||
|
|
||||||
|
|
||||||
|
// --- 3.2. Расчет коэффициента тумана на основе Z-глубины (Z-Far Fog) ---
|
||||||
|
// Этот туман работает всегда, но его эффект усиливается при уменьшении uCurrentZFar,
|
||||||
|
// гарантируя, что все, что подходит к границе uCurrentZFar, будет скрыто.
|
||||||
|
|
||||||
|
// Точка начала тумана: 90% от uCurrentZFar
|
||||||
|
float farFogStart = uCurrentZFar * 0.075;
|
||||||
|
// Длина перехода тумана: 10% от uCurrentZFar
|
||||||
|
float depthRange = uCurrentZFar * 0.1;
|
||||||
|
|
||||||
|
|
||||||
|
float farFogFactor = 0.0;
|
||||||
|
|
||||||
|
if (depthRange > 0.0) {
|
||||||
|
// Нормализация Z-глубины: 0.0f при farFogStart, 1.0f при farFogStart + depthRange
|
||||||
|
farFogFactor = clamp((abs(viewZ) - farFogStart) / depthRange, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 3.3. Объединение ---
|
||||||
|
|
||||||
|
// Когда мы далеко (fogFactor > 0.0), Distance Fog доминирует.
|
||||||
|
// Когда мы близко (fogFactor = 0.0), Z-Far Fog берет управление.
|
||||||
|
// Если оба активны, берем максимум (например, когда фрагмент далек от игрока, но игрок все еще в зоне Distance Fog).
|
||||||
|
//fogFactor = max(fogFactor, farFogFactor);
|
||||||
|
fogFactor = fogFactor * farFogFactor;
|
||||||
|
|
||||||
|
|
||||||
|
// 4. Смешивание цвета с туманом
|
||||||
|
|
||||||
|
//vec3 mountainColor = vec3((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.5,0.0);
|
||||||
|
//gl_FragColor = mix(vec4(uColor* finalColor.rgb, 1.0), FOG_COLOR, fogFactor);
|
||||||
|
//gl_FragColor = vec4((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.0,0.0, 1.0);
|
||||||
|
//gl_FragColor = vec4(fogFactor, 0.5,0.5, 1.0);
|
||||||
|
gl_FragColor = vec4(textureColor.rgb, 1.0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
// ---Фрагментный шейдер (Fragment Shader)
|
||||||
|
|
||||||
|
varying vec3 color;
|
||||||
|
varying vec3 normal;
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying float viewZ;
|
||||||
|
varying vec3 pos;
|
||||||
|
|
||||||
|
uniform sampler2D Texture;
|
||||||
|
uniform vec3 uLightDirection;
|
||||||
|
uniform float uDistanceToPlanetSurface;
|
||||||
|
uniform float uCurrentZFar;
|
||||||
|
|
||||||
|
// Константы для тумана:
|
||||||
|
//const vec4 FOG_COLOR = vec4(0.0, 0.5, 0.5, 1.0); // Синий туман
|
||||||
|
const vec4 FOG_COLOR = vec4(0.0, 0.5, 1.0, 1.0); // Синий туман
|
||||||
|
|
||||||
|
// Параметры "Distance Fog"
|
||||||
|
const float DIST_FOG_MAX = 2000.0;
|
||||||
|
const float DIST_FOG_MIN = 1000.0;
|
||||||
|
|
||||||
|
// Параметры "Z-Far Fog"
|
||||||
|
// Насколько близко к Zfar должен начинаться туман (например, 10% от Zfar)
|
||||||
|
const float Z_FOG_START_RATIO = 0.8;
|
||||||
|
// Какую долю от Zfar должен покрывать туман (например, 10% от Zfar)
|
||||||
|
const float Z_FOG_RANGE_RATIO = 0.15;
|
||||||
|
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// ... (1. Получаем цвет и 2. Расчет освещения)
|
||||||
|
vec4 textureColor = texture2D(Texture, TexCoord);
|
||||||
|
//vec3 finalColor = textureColor.rgb * color;
|
||||||
|
vec3 finalColor = textureColor.rgb;
|
||||||
|
|
||||||
|
float diffuse = max(0.0, dot(normal, uLightDirection));
|
||||||
|
float ambient = 0.2;
|
||||||
|
float lightingFactor = min(1.0, ambient + diffuse);
|
||||||
|
vec3 litColor = finalColor * lightingFactor;
|
||||||
|
|
||||||
|
|
||||||
|
// 3. Расчет коэффициента тумана (fogFactor)
|
||||||
|
float fogFactor = 0.0;
|
||||||
|
|
||||||
|
// --- 3.1. Расчет коэффициента тумана на основе расстояния до поверхности (Distance Fog) ---
|
||||||
|
// Этот туман работает на больших расстояниях и постепенно исчезает,
|
||||||
|
// уступая место Z-Far Fog при приближении к планете.
|
||||||
|
|
||||||
|
if (uDistanceToPlanetSurface >= DIST_FOG_MIN && uDistanceToPlanetSurface <DIST_FOG_MAX) {
|
||||||
|
// Нормализация: 0.0f при DIST_FOG_MAX, 1.0f при DIST_FOG_MIN
|
||||||
|
float distRange = DIST_FOG_MAX - DIST_FOG_MIN;
|
||||||
|
float distNormalized = clamp((uDistanceToPlanetSurface - DIST_FOG_MIN) / distRange, 0.0, 1.0);
|
||||||
|
|
||||||
|
// alpha = 0.0 (Далеко) ... 1.0 (Близко к 1000.f)
|
||||||
|
fogFactor = 1.0 - distNormalized;
|
||||||
|
}
|
||||||
|
if (uDistanceToPlanetSurface < DIST_FOG_MIN)
|
||||||
|
{
|
||||||
|
fogFactor = 1.0;
|
||||||
|
}
|
||||||
|
// Если uDistanceToPlanetSurface < 1000.0f, то fogFactor = 0.0f (пока не пересчитан ниже),
|
||||||
|
// что позволяет Z-Far Fog взять контроль.
|
||||||
|
|
||||||
|
|
||||||
|
// --- 3.2. Расчет коэффициента тумана на основе Z-глубины (Z-Far Fog) ---
|
||||||
|
// Этот туман работает всегда, но его эффект усиливается при уменьшении uCurrentZFar,
|
||||||
|
// гарантируя, что все, что подходит к границе uCurrentZFar, будет скрыто.
|
||||||
|
|
||||||
|
// Точка начала тумана: 90% от uCurrentZFar
|
||||||
|
float farFogStart = uCurrentZFar * 0.075;
|
||||||
|
// Длина перехода тумана: 10% от uCurrentZFar
|
||||||
|
float depthRange = uCurrentZFar * 0.1;
|
||||||
|
|
||||||
|
|
||||||
|
float farFogFactor = 0.0;
|
||||||
|
|
||||||
|
if (depthRange > 0.0) {
|
||||||
|
// Нормализация Z-глубины: 0.0f при farFogStart, 1.0f при farFogStart + depthRange
|
||||||
|
farFogFactor = clamp((abs(viewZ) - farFogStart) / depthRange, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 3.3. Объединение ---
|
||||||
|
|
||||||
|
// Когда мы далеко (fogFactor > 0.0), Distance Fog доминирует.
|
||||||
|
// Когда мы близко (fogFactor = 0.0), Z-Far Fog берет управление.
|
||||||
|
// Если оба активны, берем максимум (например, когда фрагмент далек от игрока, но игрок все еще в зоне Distance Fog).
|
||||||
|
//fogFactor = max(fogFactor, farFogFactor);
|
||||||
|
fogFactor = fogFactor * farFogFactor;
|
||||||
|
|
||||||
|
|
||||||
|
// 4. Смешивание цвета с туманом
|
||||||
|
|
||||||
|
//vec3 mountainColor = vec3((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.5,0.0);
|
||||||
|
gl_FragColor = mix(vec4(finalColor.rgb, 0.5), FOG_COLOR, fogFactor);
|
||||||
|
//gl_FragColor = vec4((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.0,0.0, 1.0);
|
||||||
|
//gl_FragColor = vec4(finalColor.rgb, 1.0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
attribute vec3 vPosition;
|
||||||
|
attribute vec2 vTexCoord;
|
||||||
|
attribute vec3 vNormal;
|
||||||
|
attribute vec3 vTangent; // Новые атрибуты
|
||||||
|
attribute vec3 vBinormal;
|
||||||
|
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying vec3 vViewDirTangent;
|
||||||
|
|
||||||
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
uniform vec3 uViewPos;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = ProjectionModelViewMatrix * vec4(vPosition, 1.0);
|
||||||
|
TexCoord = vTexCoord;
|
||||||
|
|
||||||
|
vec3 viewDirWorld = normalize(uViewPos - vPosition);
|
||||||
|
|
||||||
|
// Строим матрицу перехода из атрибутов
|
||||||
|
// Так как базис ортонормирован, TBN^-1 == TBN_transpose
|
||||||
|
vViewDirTangent = vec3(
|
||||||
|
dot(viewDirWorld, vTangent),
|
||||||
|
dot(viewDirWorld, vBinormal),
|
||||||
|
dot(viewDirWorld, vNormal)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*varying vec2 TexCoord;
|
||||||
|
varying vec3 vViewDirTangent;
|
||||||
|
|
||||||
|
uniform sampler2D Texture; // Нам нужен только Alpha канал (высота)
|
||||||
|
uniform float uHeightScale;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 viewDir = normalize(vViewDirTangent);
|
||||||
|
float height = texture2D(Texture, TexCoord).a;
|
||||||
|
|
||||||
|
// Рассчитываем вектор смещения P
|
||||||
|
//vec2 p = viewDir.xy * (height * uHeightScale) / viewDir.z;
|
||||||
|
//vec2 p = vec2(viewDir.y, -viewDir.x) * (height * uHeightScale);
|
||||||
|
//vec2 p = viewDir.xy * (height * uHeightScale);
|
||||||
|
vec2 p = vec2(viewDir.x, -viewDir.y) * (height * uHeightScale);
|
||||||
|
vec2 finalTexCoord = TexCoord + p;
|
||||||
|
|
||||||
|
// 1. Визуализация сетки по смещенным координатам
|
||||||
|
// Если сетка кривая или ломается на стыках — значит T, B, N векторы не сошлись
|
||||||
|
vec2 grid = fract(finalTexCoord * 20.0); // 20 ячеек сетки
|
||||||
|
float line = (step(0.9, grid.x) + step(0.9, grid.y));
|
||||||
|
|
||||||
|
// 2. Визуализация вектора смещения через цвет
|
||||||
|
// Красный = смещение по U, Зеленый = смещение по V
|
||||||
|
vec3 offsetColor = vec3(p * 10.0 + 0.5, 0.0); // Умножаем на 10 для видимости
|
||||||
|
|
||||||
|
vec3 finalColor = mix(offsetColor, vec3(1.0), line); // Накладываем сетку поверх цвета
|
||||||
|
|
||||||
|
// 3. Подмешиваем карту высот, чтобы видеть "объемы"
|
||||||
|
gl_FragColor = vec4(finalColor * height, 1.0);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying vec3 vViewDirTangent;
|
||||||
|
|
||||||
|
uniform sampler2D Texture;
|
||||||
|
uniform float uHeightScale;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 viewDir = normalize(vViewDirTangent);
|
||||||
|
|
||||||
|
// Получаем высоту из альфа-канала запеченной текстуры
|
||||||
|
float height = texture2D(Texture, TexCoord).a;
|
||||||
|
|
||||||
|
// Смещение. Знак минус используется, если мы хотим "вдавить" камни
|
||||||
|
// Деление на viewDir.z помогает избежать сильных искажений под углом
|
||||||
|
//vec2 p = viewDir.xy * (height * uHeightScale) / viewDir.z;
|
||||||
|
vec2 p = vec2(viewDir.x, -viewDir.y) * (height * uHeightScale);
|
||||||
|
//vec2 p = vec2(0,0);
|
||||||
|
vec2 finalTexCoord = TexCoord + p;
|
||||||
|
|
||||||
|
gl_FragColor = texture2D(Texture, finalTexCoord);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying vec3 vViewDirTangent; // Тот самый вектор из VS
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// 1. Нормализуем входящий вектор
|
||||||
|
vec3 v = normalize(vViewDirTangent);
|
||||||
|
|
||||||
|
// 2. Преобразуем компоненты из [-1, 1] в [0, 1] для визуализации
|
||||||
|
// X -> Red, Y -> Green, Z -> Blue
|
||||||
|
vec3 debugColor = v * 0.5 + 0.5;
|
||||||
|
|
||||||
|
gl_FragColor = vec4(debugColor, 1.0);
|
||||||
|
}*/
|
||||||
@@ -5,8 +5,8 @@ varying vec2 texCoord;
|
|||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec4 color = texture2D(Texture,texCoord).rgba;
|
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;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
uniform samplerCube Texture;
|
||||||
|
|
||||||
|
varying vec3 dir;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
gl_FragColor = textureCube(Texture, normalize(dir));
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
uniform samplerCube Texture;
|
||||||
|
uniform float skyPercent;
|
||||||
|
|
||||||
|
varying vec3 dir;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec4 skyBoxColor = textureCube(Texture, normalize(dir));
|
||||||
|
vec4 skyColor = vec4(0.0, 0.5, 1.0, 1.0);
|
||||||
|
gl_FragColor = skyPercent*skyColor + (1.0 - skyPercent) * skyBoxColor;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
precision mediump float;
|
||||||
|
uniform samplerCube Texture;
|
||||||
|
varying vec3 dir;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
gl_FragColor = textureCube(Texture, normalize(dir));
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// Vertex Shader (Bake Stage)
|
||||||
|
attribute vec3 vPosition;
|
||||||
|
attribute vec2 vTexCoord;
|
||||||
|
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying float vHeight;
|
||||||
|
|
||||||
|
// Данные о плоскости треугольника планеты
|
||||||
|
uniform vec3 uPlanePoint; // Любая вершина треугольника (например, tri.data[0])
|
||||||
|
uniform vec3 uPlaneNormal; // Нормаль треугольника планеты (ось Z из GetRotationForTriangle)
|
||||||
|
uniform float uMaxHeight; // Максимальный размер камня (BASE_SCALE)
|
||||||
|
|
||||||
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// 1. Вычисляем вектор от плоскости до текущей вершины камня
|
||||||
|
vec3 vecToVertex = vPosition - uPlanePoint;
|
||||||
|
|
||||||
|
// 2. Проецируем этот вектор на нормаль плоскости (скалярное произведение)
|
||||||
|
// Это и есть кратчайшее расстояние от точки до плоскости
|
||||||
|
float distance = dot(vecToVertex, uPlaneNormal);
|
||||||
|
|
||||||
|
// 3. Нормализуем высоту для записи в текстуру (0.0 - уровень земли, 1.0 - пик)
|
||||||
|
// Clamp гарантирует, что значения не выйдут за пределы, если камень "утоплен"
|
||||||
|
vHeight = clamp(distance / uMaxHeight, 0.0, 1.0);
|
||||||
|
|
||||||
|
TexCoord = vTexCoord;
|
||||||
|
|
||||||
|
gl_Position = ProjectionModelViewMatrix * vec4(vPosition, 1.0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
varying vec2 TexCoord;
|
||||||
|
varying float vHeight;
|
||||||
|
|
||||||
|
uniform sampler2D Texture;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 stoneColor = texture2D(Texture, TexCoord);
|
||||||
|
|
||||||
|
gl_FragColor = vec4(stoneColor.rgb, vHeight);
|
||||||
|
//gl_FragColor = vec4(vHeight, vHeight, vHeight, vHeight);
|
||||||
|
//gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
attribute vec3 vPosition;
|
||||||
|
attribute vec2 vTexCoord;
|
||||||
|
attribute vec3 vNormal;
|
||||||
|
attribute vec3 vTangent; // Новые атрибуты
|
||||||
|
attribute vec3 vBinormal;
|
||||||
|
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying vec3 vViewDirTangent;
|
||||||
|
varying vec3 worldPosition;
|
||||||
|
|
||||||
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
uniform mat4 ModelViewMatrix;
|
||||||
|
|
||||||
|
uniform vec3 uViewPos;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = ProjectionModelViewMatrix * vec4(vPosition, 1.0);
|
||||||
|
TexCoord = vTexCoord;
|
||||||
|
|
||||||
|
vec3 viewDirWorld = normalize(uViewPos - vPosition);
|
||||||
|
|
||||||
|
// Строим матрицу перехода из атрибутов
|
||||||
|
// Так как базис ортонормирован, TBN^-1 == TBN_transpose
|
||||||
|
vViewDirTangent = vec3(
|
||||||
|
dot(viewDirWorld, vTangent),
|
||||||
|
dot(viewDirWorld, vBinormal),
|
||||||
|
dot(viewDirWorld, vNormal)
|
||||||
|
);
|
||||||
|
vec4 viewPosition = ModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||||
|
|
||||||
|
worldPosition = vPosition;
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
varying vec2 TexCoord;
|
||||||
|
varying vec3 vViewDirTangent;
|
||||||
|
|
||||||
|
uniform sampler2D Texture;
|
||||||
|
uniform sampler2D BakedTexture;
|
||||||
|
uniform float uHeightScale;
|
||||||
|
uniform float uDistanceToPlanetSurface;
|
||||||
|
uniform float uCurrentZFar;
|
||||||
|
varying vec3 worldPosition;
|
||||||
|
|
||||||
|
uniform vec3 uViewPos;
|
||||||
|
const vec4 FOG_COLOR = vec4(0.0, 0.5, 1.0, 1.0); // Синий туман
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 viewDir = normalize(vViewDirTangent);
|
||||||
|
|
||||||
|
// Получаем высоту из альфа-канала запеченной текстуры
|
||||||
|
float height = texture2D(Texture, TexCoord).a;
|
||||||
|
|
||||||
|
// Смещение. Знак минус используется, если мы хотим "вдавить" камни
|
||||||
|
// Деление на viewDir.z помогает избежать сильных искажений под углом
|
||||||
|
//vec2 p = viewDir.xy * (height * uHeightScale) / viewDir.z;
|
||||||
|
vec2 p = vec2(viewDir.x, -viewDir.y) * (height * uHeightScale);
|
||||||
|
//vec2 p = vec2(0,0);
|
||||||
|
vec2 finalTexCoord = TexCoord + p;
|
||||||
|
|
||||||
|
float realDist = distance(worldPosition, uViewPos);
|
||||||
|
|
||||||
|
|
||||||
|
float textureMixFactor = clamp((2000 - realDist) / 500.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
vec4 bakedTextureColor = texture2D(BakedTexture, finalTexCoord);
|
||||||
|
vec4 textureColor = texture2D(Texture, TexCoord);
|
||||||
|
|
||||||
|
vec4 finalColor = textureMixFactor*textureColor + (1 - textureMixFactor) * bakedTextureColor;
|
||||||
|
|
||||||
|
float fogFactor;
|
||||||
|
if (uDistanceToPlanetSurface > 1000)
|
||||||
|
{
|
||||||
|
gl_FragColor = vec4(finalColor.rgb, 1.0);
|
||||||
|
}
|
||||||
|
else if (uDistanceToPlanetSurface > 100)
|
||||||
|
{
|
||||||
|
float t = clamp((uDistanceToPlanetSurface - 100) / 900.0, 0.0, 1.0); // 1 upstairs, 0 downstairs
|
||||||
|
|
||||||
|
fogFactor = clamp((realDist - 2400) / (300.0*(1 + 10*t)), 0.0, 1.0);
|
||||||
|
|
||||||
|
gl_FragColor = mix(vec4(finalColor.rgb, 1.0), FOG_COLOR, fogFactor*(1.0 - t));
|
||||||
|
}
|
||||||
|
else if (uDistanceToPlanetSurface > 40)
|
||||||
|
{
|
||||||
|
//From 100 to 40:
|
||||||
|
//(1000 < realDist < 1800)
|
||||||
|
|
||||||
|
float t = clamp((uDistanceToPlanetSurface - 40) / 60.0, 0.0, 1.0); // 1 upstairs, 0 downstairs
|
||||||
|
|
||||||
|
fogFactor = clamp((realDist - 2400) / 300.0, 0.0, 1.0); // old fog factor
|
||||||
|
|
||||||
|
float fogFactor2 = clamp((realDist - 1000) / 800.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
gl_FragColor = mix(vec4(finalColor.rgb, 1.0), FOG_COLOR, max(fogFactor, fogFactor2*(1.0 - t)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fogFactor = clamp((realDist - 1000) / (800.0), 0.0, 1.0);
|
||||||
|
|
||||||
|
gl_FragColor = mix(vec4(finalColor.rgb, 1.0), FOG_COLOR, fogFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying vec3 vViewDirTangent; // Тот самый вектор из VS
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// 1. Нормализуем входящий вектор
|
||||||
|
vec3 v = normalize(vViewDirTangent);
|
||||||
|
|
||||||
|
// 2. Преобразуем компоненты из [-1, 1] в [0, 1] для визуализации
|
||||||
|
// X -> Red, Y -> Green, Z -> Blue
|
||||||
|
vec3 debugColor = v * 0.5 + 0.5;
|
||||||
|
|
||||||
|
gl_FragColor = vec4(debugColor, 1.0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
varying vec2 TexCoord;
|
||||||
|
varying vec3 vViewDirTangent;
|
||||||
|
|
||||||
|
uniform sampler2D Texture; // Нам нужен только Alpha канал (высота)
|
||||||
|
uniform float uHeightScale;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 viewDir = normalize(vViewDirTangent);
|
||||||
|
float height = texture2D(Texture, TexCoord).a;
|
||||||
|
|
||||||
|
// Рассчитываем вектор смещения P
|
||||||
|
//vec2 p = viewDir.xy * (height * uHeightScale) / viewDir.z;
|
||||||
|
//vec2 p = vec2(viewDir.y, -viewDir.x) * (height * uHeightScale);
|
||||||
|
//vec2 p = viewDir.xy * (height * uHeightScale);
|
||||||
|
vec2 p = vec2(viewDir.x, -viewDir.y) * (height * uHeightScale);
|
||||||
|
vec2 finalTexCoord = TexCoord + p;
|
||||||
|
|
||||||
|
// 1. Визуализация сетки по смещенным координатам
|
||||||
|
// Если сетка кривая или ломается на стыках — значит T, B, N векторы не сошлись
|
||||||
|
vec2 grid = fract(finalTexCoord * 20.0); // 20 ячеек сетки
|
||||||
|
float line = (step(0.9, grid.x) + step(0.9, grid.y));
|
||||||
|
|
||||||
|
// 2. Визуализация вектора смещения через цвет
|
||||||
|
// Красный = смещение по U, Зеленый = смещение по V
|
||||||
|
vec3 offsetColor = vec3(p * 10.0 + 0.5, 0.0); // Умножаем на 10 для видимости
|
||||||
|
|
||||||
|
vec3 finalColor = mix(offsetColor, vec3(1.0), line); // Накладываем сетку поверх цвета
|
||||||
|
|
||||||
|
// 3. Подмешиваем карту высот, чтобы видеть "объемы"
|
||||||
|
gl_FragColor = vec4(finalColor * height, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// Вершинный шейдер (Vertex Shader)
|
||||||
|
|
||||||
|
attribute vec3 vPosition;
|
||||||
|
attribute vec2 vTexCoord;
|
||||||
|
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying float viewZ;
|
||||||
|
varying vec3 pos;
|
||||||
|
varying vec3 worldPosition;
|
||||||
|
|
||||||
|
|
||||||
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
uniform mat4 ModelViewMatrix;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Преобразование позиции в пространство вида (View Space)
|
||||||
|
vec4 viewPosition = ModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||||
|
|
||||||
|
// Сохраняем отрицательную Z-координату. В OpenGL Z-координата (глубина)
|
||||||
|
// в пространстве вида обычно отрицательна, но для расчета тумана
|
||||||
|
// удобнее использовать положительное значение.
|
||||||
|
viewZ = -viewPosition.z;
|
||||||
|
|
||||||
|
pos = vPosition.xyz;
|
||||||
|
|
||||||
|
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||||
|
|
||||||
|
TexCoord = vTexCoord;
|
||||||
|
worldPosition = vPosition;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
// ---Фрагментный шейдер (Fragment Shader)
|
||||||
|
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying float viewZ;
|
||||||
|
varying vec3 pos;
|
||||||
|
|
||||||
|
uniform sampler2D Texture;
|
||||||
|
uniform float uDistanceToPlanetSurface;
|
||||||
|
|
||||||
|
const vec4 FOG_COLOR = vec4(0.0, 0.5, 1.0, 1.0); // Синий туман
|
||||||
|
|
||||||
|
varying vec3 worldPosition;
|
||||||
|
|
||||||
|
uniform vec3 uViewPos;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
|
||||||
|
vec4 textureColor = texture2D(Texture, TexCoord);
|
||||||
|
vec3 finalColor = textureColor.rgb;
|
||||||
|
|
||||||
|
float realDist = distance(worldPosition, uViewPos);
|
||||||
|
|
||||||
|
float alphaFactor = clamp((2000 - realDist) / 500.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
float fogFactor;
|
||||||
|
if (uDistanceToPlanetSurface > 1000)
|
||||||
|
{
|
||||||
|
gl_FragColor = vec4(finalColor.rgb, 1.0);
|
||||||
|
}
|
||||||
|
else if (uDistanceToPlanetSurface > 100)
|
||||||
|
{
|
||||||
|
float t = clamp((uDistanceToPlanetSurface - 100) / 900.0, 0.0, 1.0); // 1 upstairs, 0 downstairs
|
||||||
|
|
||||||
|
fogFactor = clamp((realDist - 2400) / (300.0*(1 + 10*t)), 0.0, 1.0);
|
||||||
|
|
||||||
|
gl_FragColor = mix(vec4(finalColor.rgb, alphaFactor), FOG_COLOR, fogFactor*(1.0 - t));
|
||||||
|
}
|
||||||
|
else if (uDistanceToPlanetSurface > 40)
|
||||||
|
{
|
||||||
|
//From 100 to 40:
|
||||||
|
//(1000 < realDist < 1800)
|
||||||
|
|
||||||
|
float t = clamp((uDistanceToPlanetSurface - 40) / 60.0, 0.0, 1.0); // 1 upstairs, 0 downstairs
|
||||||
|
|
||||||
|
fogFactor = clamp((realDist - 2400) / 300.0, 0.0, 1.0); // old fog factor
|
||||||
|
|
||||||
|
float fogFactor2 = clamp((realDist - 1000) / 800.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
gl_FragColor = mix(vec4(finalColor.rgb, alphaFactor), FOG_COLOR, max(fogFactor, fogFactor2*(1.0 - t)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fogFactor = clamp((realDist - 1000) / (800.0), 0.0, 1.0);
|
||||||
|
|
||||||
|
gl_FragColor = mix(vec4(finalColor.rgb, alphaFactor), FOG_COLOR, fogFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
@@ -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>..\SDL2-2.28.3\include;..\lpng1645\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>libpng16_staticd.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>..\SDL2-2.28.3\lib\x64;..\lpng1645\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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
||||||
Reference in new issue
Block a user