Compare commits
No commits in common. "e04fcbb9bdae8fe70ed2dce2ad13b7bee6cb7673" and "4de8f78ecad8b7e2139d593b95aaf9ef01b25ece" have entirely different histories.
e04fcbb9bd
...
4de8f78eca
BIN
audio/background.wav
(Stored with Git LFS)
Normal file
BIN
audio/background.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
audio/lullaby-music-vol20-186394--online-audio-convert.com.ogg
(Stored with Git LFS)
Normal file
BIN
audio/lullaby-music-vol20-186394--online-audio-convert.com.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -52,7 +52,6 @@ add_library(main SHARED
|
||||
../../../../src/planet/PlanetObject.cpp
|
||||
../../../../src/planet/StoneObject.cpp
|
||||
../../../../src/render/FrameBuffer.cpp
|
||||
../../../../src/render/ShadowMap.cpp
|
||||
../../../../src/render/Renderer.cpp
|
||||
../../../../src/render/ShaderManager.cpp
|
||||
../../../../src/render/TextureManager.cpp
|
||||
|
||||
@ -175,7 +175,6 @@ set(EMSCRIPTEN_LINK_FLAGS
|
||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/loading.png@resources/loading.png"
|
||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/shaders@resources/shaders"
|
||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start.lua@resources/start.lua"
|
||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start2.lua@resources/start2.lua"
|
||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../audio@audio"
|
||||
)
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(witcher001 LANGUAGES C CXX)
|
||||
project(space-game001 LANGUAGES C CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
@ -12,9 +12,9 @@ option(FULLSCREEN "Launch the game in fullscreen mode" OFF)
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ThirdParty.cmake)
|
||||
|
||||
# ===========================================
|
||||
# Основной проект witcher001
|
||||
# Основной проект space-game001
|
||||
# ===========================================
|
||||
add_executable(witcher001
|
||||
add_executable(space-game001
|
||||
../src/main.cpp
|
||||
../src/Game.cpp
|
||||
../src/Game.h
|
||||
@ -32,6 +32,8 @@ add_executable(witcher001
|
||||
../src/TextModel.h
|
||||
../src/AudioPlayerAsync.cpp
|
||||
../src/AudioPlayerAsync.h
|
||||
../src/BoneAnimatedModel.cpp
|
||||
../src/BoneAnimatedModel.h
|
||||
../src/BoneAnimatedModelNew.cpp
|
||||
../src/BoneAnimatedModelNew.h
|
||||
../src/render/OpenGlExtensions.cpp
|
||||
@ -40,6 +42,8 @@ add_executable(witcher001
|
||||
../src/utils/Utils.h
|
||||
../src/SparkEmitter.cpp
|
||||
../src/SparkEmitter.h
|
||||
../src/utils/Perlin.cpp
|
||||
../src/utils/Perlin.h
|
||||
../src/utils/TaskManager.cpp
|
||||
../src/utils/TaskManager.h
|
||||
../src/render/FrameBuffer.cpp
|
||||
@ -81,21 +85,21 @@ add_executable(witcher001
|
||||
)
|
||||
|
||||
# Установка проекта по умолчанию для Visual Studio
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT witcher001)
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT space-game001)
|
||||
|
||||
# include-пути проекта
|
||||
target_include_directories(witcher001 PRIVATE
|
||||
target_include_directories(space-game001 PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src"
|
||||
)
|
||||
|
||||
set_target_properties(witcher001 PROPERTIES
|
||||
OUTPUT_NAME "witcher001"
|
||||
set_target_properties(space-game001 PROPERTIES
|
||||
OUTPUT_NAME "space-game001"
|
||||
)
|
||||
|
||||
# Определения препроцессора:
|
||||
# PNG_ENABLED – включает код PNG в TextureManager
|
||||
# SDL_MAIN_HANDLED – отключает переопределение main -> SDL_main
|
||||
target_compile_definitions(witcher001 PRIVATE
|
||||
target_compile_definitions(space-game001 PRIVATE
|
||||
WIN32_LEAN_AND_MEAN
|
||||
PNG_ENABLED
|
||||
SDL_MAIN_HANDLED
|
||||
@ -104,14 +108,14 @@ target_compile_definitions(witcher001 PRIVATE
|
||||
)
|
||||
|
||||
if(FULLSCREEN)
|
||||
target_compile_definitions(witcher001 PRIVATE FULLSCREEN)
|
||||
target_compile_definitions(space-game001 PRIVATE FULLSCREEN)
|
||||
endif()
|
||||
|
||||
# Линкуем с SDL2main, если он вообще установлен
|
||||
target_link_libraries(witcher001 PRIVATE SDL2main_external_lib)
|
||||
target_link_libraries(space-game001 PRIVATE SDL2main_external_lib)
|
||||
|
||||
# Линкуем сторонние библиотеки
|
||||
target_link_libraries(witcher001 PRIVATE
|
||||
target_link_libraries(space-game001 PRIVATE
|
||||
SDL2_external_lib
|
||||
libpng_external_lib
|
||||
zlib_external_lib
|
||||
@ -126,7 +130,7 @@ target_link_libraries(witcher001 PRIVATE
|
||||
|
||||
# Линкуем OpenGL (Windows)
|
||||
if(WIN32)
|
||||
target_link_libraries(witcher001 PRIVATE opengl32)
|
||||
target_link_libraries(space-game001 PRIVATE opengl32)
|
||||
endif()
|
||||
|
||||
# ===========================================
|
||||
@ -136,19 +140,19 @@ 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:witcher001>/SDL2d.dll,$<TARGET_FILE_DIR:witcher001>/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>")
|
||||
|
||||
set(ZLIB_DLL_SRC "$<IF:$<CONFIG:Debug>,${ZLIB_INSTALL_DIR}/bin/zd.dll,${ZLIB_INSTALL_DIR}/bin/z.dll>")
|
||||
set(ZLIB_DLL_DST "$<IF:$<CONFIG:Debug>,$<TARGET_FILE_DIR:witcher001>/zd.dll,$<TARGET_FILE_DIR:witcher001>/z.dll>")
|
||||
set(ZLIB_DLL_DST "$<IF:$<CONFIG:Debug>,$<TARGET_FILE_DIR:space-game001>/zd.dll,$<TARGET_FILE_DIR:space-game001>/z.dll>")
|
||||
|
||||
set(SDL2TTF_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2TTF_BASE_DIR}-Debug/bin/SDL2_ttfd.dll,${SDL2TTF_BASE_DIR}-Release/bin/SDL2_ttf.dll>")
|
||||
|
||||
set(SDL2MIXER_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2MIXER_BASE_DIR}-Debug/bin/SDL2_mixerd.dll,${SDL2MIXER_BASE_DIR}-Release/bin/SDL2_mixer.dll>")
|
||||
|
||||
add_custom_command(TARGET witcher001 POST_BUILD
|
||||
add_custom_command(TARGET space-game001 POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Copying DLLs to output folder..."
|
||||
|
||||
# Копируем SDL2 (целевое имя всегда SDL2.dll)
|
||||
@ -159,7 +163,7 @@ if (WIN32)
|
||||
# Копируем LIBZIP (целевое имя всегда zip.dll)
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${LIBZIP_DLL_SRC}"
|
||||
"$<TARGET_FILE_DIR:witcher001>/zip.dll"
|
||||
"$<TARGET_FILE_DIR:space-game001>/zip.dll"
|
||||
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${ZLIB_DLL_SRC}"
|
||||
@ -167,11 +171,11 @@ if (WIN32)
|
||||
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${SDL2TTF_DLL_SRC}"
|
||||
"$<TARGET_FILE_DIR:witcher001>"
|
||||
"$<TARGET_FILE_DIR:space-game001>"
|
||||
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/SDL_mixer-release-2.8.0/install-$<CONFIG>/bin/SDL2_mixer$<$<CONFIG:Debug>:d>.dll"
|
||||
"$<TARGET_FILE_DIR:witcher001>/SDL2_mixer$<$<CONFIG:Debug>:d>.dll"
|
||||
"$<TARGET_FILE_DIR:space-game001>/SDL2_mixer$<$<CONFIG:Debug>:d>.dll"
|
||||
)
|
||||
endif()
|
||||
|
||||
@ -187,12 +191,12 @@ set(RUNTIME_RESOURCE_DIRS
|
||||
|
||||
# Копируем ресурсы и шейдеры в папку exe и в корень build/
|
||||
foreach(resdir IN LISTS RUNTIME_RESOURCE_DIRS)
|
||||
add_custom_command(TARGET witcher001 POST_BUILD
|
||||
add_custom_command(TARGET space-game001 POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Copying ${resdir} to runtime folders..."
|
||||
# 1) туда, где лежит exe (build/Debug, build/Release и т.п.)
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/../${resdir}"
|
||||
"$<TARGET_FILE_DIR:witcher001>/${resdir}"
|
||||
"$<TARGET_FILE_DIR:space-game001>/${resdir}"
|
||||
# 2) в корень build, если захочешь запускать из этой папки
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/../${resdir}"
|
||||
|
||||
@ -3,472 +3,175 @@
|
||||
"agentRadius": 0.45,
|
||||
"floorY": 0.0,
|
||||
"objectPadding": 0.25,
|
||||
"boundaryPadding": 0.35,
|
||||
"areas": [
|
||||
{
|
||||
"name": "main_corridor",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
-2.2,
|
||||
0.8
|
||||
],
|
||||
[
|
||||
2.2,
|
||||
0.8
|
||||
],
|
||||
[
|
||||
2.2,
|
||||
-40.8
|
||||
],
|
||||
[
|
||||
-2.2,
|
||||
-40.8
|
||||
]
|
||||
[-2.2, 0.8],
|
||||
[2.2, 0.8],
|
||||
[2.2, -40.8],
|
||||
[-2.2, -40.8]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "left_door_05",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
-3.4,
|
||||
-4.2
|
||||
],
|
||||
[
|
||||
-2.0,
|
||||
-4.2
|
||||
],
|
||||
[
|
||||
-2.0,
|
||||
-5.8
|
||||
],
|
||||
[
|
||||
-3.4,
|
||||
-5.8
|
||||
]
|
||||
[-3.4, -4.2],
|
||||
[-2.0, -4.2],
|
||||
[-2.0, -5.8],
|
||||
[-3.4, -5.8]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "right_door_05",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
2.0,
|
||||
-4.2
|
||||
],
|
||||
[
|
||||
3.4,
|
||||
-4.2
|
||||
],
|
||||
[
|
||||
3.4,
|
||||
-5.8
|
||||
],
|
||||
[
|
||||
2.0,
|
||||
-5.8
|
||||
]
|
||||
[2.0, -4.2],
|
||||
[3.4, -4.2],
|
||||
[3.4, -5.8],
|
||||
[2.0, -5.8]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "left_room_05",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
-8.8,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
-3.0,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
-3.0,
|
||||
-9.0
|
||||
],
|
||||
[
|
||||
-8.8,
|
||||
-9.0
|
||||
]
|
||||
[-8.8, -1.0],
|
||||
[-3.0, -1.0],
|
||||
[-3.0, -9.0],
|
||||
[-8.8, -9.0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "right_room_05",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
3.0,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
8.8,
|
||||
-1.0
|
||||
],
|
||||
[
|
||||
8.8,
|
||||
-9.0
|
||||
],
|
||||
[
|
||||
3.0,
|
||||
-9.0
|
||||
]
|
||||
[3.0, -1.0],
|
||||
[8.8, -1.0],
|
||||
[8.8, -9.0],
|
||||
[3.0, -9.0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "left_door_15",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
-3.4,
|
||||
-14.2
|
||||
],
|
||||
[
|
||||
-2.0,
|
||||
-14.2
|
||||
],
|
||||
[
|
||||
-2.0,
|
||||
-15.8
|
||||
],
|
||||
[
|
||||
-3.4,
|
||||
-15.8
|
||||
]
|
||||
[-3.4, -14.2],
|
||||
[-2.0, -14.2],
|
||||
[-2.0, -15.8],
|
||||
[-3.4, -15.8]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "right_door_15",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
2.0,
|
||||
-14.2
|
||||
],
|
||||
[
|
||||
3.4,
|
||||
-14.2
|
||||
],
|
||||
[
|
||||
3.4,
|
||||
-15.8
|
||||
],
|
||||
[
|
||||
2.0,
|
||||
-15.8
|
||||
]
|
||||
[2.0, -14.2],
|
||||
[3.4, -14.2],
|
||||
[3.4, -15.8],
|
||||
[2.0, -15.8]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "left_room_15",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
-8.8,
|
||||
-11.0
|
||||
],
|
||||
[
|
||||
-3.0,
|
||||
-11.0
|
||||
],
|
||||
[
|
||||
-3.0,
|
||||
-19.0
|
||||
],
|
||||
[
|
||||
-8.8,
|
||||
-19.0
|
||||
]
|
||||
[-8.8, -11.0],
|
||||
[-3.0, -11.0],
|
||||
[-3.0, -19.0],
|
||||
[-8.8, -19.0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "right_room_15",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
3.0,
|
||||
-11.0
|
||||
],
|
||||
[
|
||||
8.8,
|
||||
-11.0
|
||||
],
|
||||
[
|
||||
8.8,
|
||||
-19.0
|
||||
],
|
||||
[
|
||||
3.0,
|
||||
-19.0
|
||||
]
|
||||
[3.0, -11.0],
|
||||
[8.8, -11.0],
|
||||
[8.8, -19.0],
|
||||
[3.0, -19.0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "left_door_25",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
-3.4,
|
||||
-24.2
|
||||
],
|
||||
[
|
||||
-2.0,
|
||||
-24.2
|
||||
],
|
||||
[
|
||||
-2.0,
|
||||
-25.8
|
||||
],
|
||||
[
|
||||
-3.4,
|
||||
-25.8
|
||||
]
|
||||
[-3.4, -24.2],
|
||||
[-2.0, -24.2],
|
||||
[-2.0, -25.8],
|
||||
[-3.4, -25.8]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "right_door_25",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
2.0,
|
||||
-24.2
|
||||
],
|
||||
[
|
||||
3.4,
|
||||
-24.2
|
||||
],
|
||||
[
|
||||
3.4,
|
||||
-25.8
|
||||
],
|
||||
[
|
||||
2.0,
|
||||
-25.8
|
||||
]
|
||||
[2.0, -24.2],
|
||||
[3.4, -24.2],
|
||||
[3.4, -25.8],
|
||||
[2.0, -25.8]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "left_room_25",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
-8.8,
|
||||
-21.0
|
||||
],
|
||||
[
|
||||
-3.0,
|
||||
-21.0
|
||||
],
|
||||
[
|
||||
-3.0,
|
||||
-29.0
|
||||
],
|
||||
[
|
||||
-8.8,
|
||||
-29.0
|
||||
]
|
||||
[-8.8, -21.0],
|
||||
[-3.0, -21.0],
|
||||
[-3.0, -29.0],
|
||||
[-8.8, -29.0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "right_room_25",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
3.0,
|
||||
-21.0
|
||||
],
|
||||
[
|
||||
8.8,
|
||||
-21.0
|
||||
],
|
||||
[
|
||||
8.8,
|
||||
-29.0
|
||||
],
|
||||
[
|
||||
3.0,
|
||||
-29.0
|
||||
]
|
||||
[3.0, -21.0],
|
||||
[8.8, -21.0],
|
||||
[8.8, -29.0],
|
||||
[3.0, -29.0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "left_door_35",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
-3.4,
|
||||
-34.2
|
||||
],
|
||||
[
|
||||
-2.0,
|
||||
-34.2
|
||||
],
|
||||
[
|
||||
-2.0,
|
||||
-35.8
|
||||
],
|
||||
[
|
||||
-3.4,
|
||||
-35.8
|
||||
]
|
||||
[-3.4, -34.2],
|
||||
[-2.0, -34.2],
|
||||
[-2.0, -35.8],
|
||||
[-3.4, -35.8]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "right_door_35",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
2.0,
|
||||
-34.2
|
||||
],
|
||||
[
|
||||
3.4,
|
||||
-34.2
|
||||
],
|
||||
[
|
||||
3.4,
|
||||
-35.8
|
||||
],
|
||||
[
|
||||
2.0,
|
||||
-35.8
|
||||
]
|
||||
[2.0, -34.2],
|
||||
[3.4, -34.2],
|
||||
[3.4, -35.8],
|
||||
[2.0, -35.8]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "left_room_35",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
-8.8,
|
||||
-31.0
|
||||
],
|
||||
[
|
||||
-3.0,
|
||||
-31.0
|
||||
],
|
||||
[
|
||||
-3.0,
|
||||
-39.0
|
||||
],
|
||||
[
|
||||
-8.8,
|
||||
-39.0
|
||||
]
|
||||
[-8.8, -31.0],
|
||||
[-3.0, -31.0],
|
||||
[-3.0, -39.0],
|
||||
[-8.8, -39.0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "right_room_35",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
3.0,
|
||||
-31.0
|
||||
],
|
||||
[
|
||||
8.8,
|
||||
-31.0
|
||||
],
|
||||
[
|
||||
8.8,
|
||||
-39.0
|
||||
],
|
||||
[
|
||||
3.0,
|
||||
-39.0
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"obstacles": [
|
||||
{
|
||||
"name": "firebox",
|
||||
"polygon": [
|
||||
[
|
||||
-2.49468,
|
||||
-32.87888
|
||||
],
|
||||
[
|
||||
-2.05776,
|
||||
-32.87888
|
||||
],
|
||||
[
|
||||
-2.05776,
|
||||
-31.51618
|
||||
],
|
||||
[
|
||||
-2.49468,
|
||||
-31.51618
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bench",
|
||||
"polygon": [
|
||||
[
|
||||
-2.54485,
|
||||
-9.31999
|
||||
],
|
||||
[
|
||||
-2.51786,
|
||||
-9.3557
|
||||
],
|
||||
[
|
||||
-2.48369,
|
||||
-9.37177
|
||||
],
|
||||
[
|
||||
-2.45574,
|
||||
-9.38357
|
||||
],
|
||||
[
|
||||
-2.17907,
|
||||
-9.39566
|
||||
],
|
||||
[
|
||||
-1.80829,
|
||||
-9.40749
|
||||
],
|
||||
[
|
||||
-1.7521,
|
||||
-9.36413
|
||||
],
|
||||
[
|
||||
-1.66462,
|
||||
-9.28728
|
||||
],
|
||||
[
|
||||
-1.65801,
|
||||
-9.14512
|
||||
],
|
||||
[
|
||||
-1.65114,
|
||||
-7.22169
|
||||
],
|
||||
[
|
||||
-1.65535,
|
||||
-6.51944
|
||||
],
|
||||
[
|
||||
-1.72626,
|
||||
-6.42306
|
||||
],
|
||||
[
|
||||
-1.76837,
|
||||
-6.39498
|
||||
],
|
||||
[
|
||||
-2.47166,
|
||||
-6.39746
|
||||
],
|
||||
[
|
||||
-2.5309,
|
||||
-6.44135
|
||||
],
|
||||
[
|
||||
-2.53691,
|
||||
-7.18464
|
||||
]
|
||||
[3.0, -31.0],
|
||||
[8.8, -31.0],
|
||||
[8.8, -39.0],
|
||||
[3.0, -39.0]
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@ -8,668 +8,10 @@
|
||||
"name": "main_corridor",
|
||||
"available": true,
|
||||
"polygon": [
|
||||
[
|
||||
-200,
|
||||
200
|
||||
],
|
||||
[
|
||||
200,
|
||||
200
|
||||
],
|
||||
[
|
||||
200,
|
||||
-200
|
||||
],
|
||||
[
|
||||
-200,
|
||||
-200
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"obstacles": [
|
||||
{
|
||||
"name": "door",
|
||||
"polygon": [
|
||||
[
|
||||
-5.2,
|
||||
7.08001
|
||||
],
|
||||
[
|
||||
-5.19904,
|
||||
7.07025
|
||||
],
|
||||
[
|
||||
-5.19619,
|
||||
7.06087
|
||||
],
|
||||
[
|
||||
-5.19157,
|
||||
7.05223
|
||||
],
|
||||
[
|
||||
-5.18536,
|
||||
7.04465
|
||||
],
|
||||
[
|
||||
-5.17778,
|
||||
7.03843
|
||||
],
|
||||
[
|
||||
-5.16913,
|
||||
7.03381
|
||||
],
|
||||
[
|
||||
-5.15975,
|
||||
7.03097
|
||||
],
|
||||
[
|
||||
-5.15,
|
||||
7.03001
|
||||
],
|
||||
[
|
||||
-3.75,
|
||||
7.13001
|
||||
],
|
||||
[
|
||||
-3.625,
|
||||
7.43001
|
||||
],
|
||||
[
|
||||
-3.625,
|
||||
8.83001
|
||||
],
|
||||
[
|
||||
-3.75,
|
||||
9.13001
|
||||
],
|
||||
[
|
||||
-5.15,
|
||||
9.23001
|
||||
],
|
||||
[
|
||||
-5.15975,
|
||||
9.22905
|
||||
],
|
||||
[
|
||||
-5.16913,
|
||||
9.2262
|
||||
],
|
||||
[
|
||||
-5.17778,
|
||||
9.22158
|
||||
],
|
||||
[
|
||||
-5.18536,
|
||||
9.21536
|
||||
],
|
||||
[
|
||||
-5.19157,
|
||||
9.20778
|
||||
],
|
||||
[
|
||||
-5.19619,
|
||||
9.19914
|
||||
],
|
||||
[
|
||||
-5.19904,
|
||||
9.18976
|
||||
],
|
||||
[
|
||||
-5.2,
|
||||
9.18001
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "inai",
|
||||
"polygon": [
|
||||
[
|
||||
-3.75,
|
||||
-15.0
|
||||
],
|
||||
[
|
||||
3.75,
|
||||
-15.0
|
||||
],
|
||||
[
|
||||
3.75,
|
||||
15.0
|
||||
],
|
||||
[
|
||||
-3.75,
|
||||
15.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tree001",
|
||||
"polygon": [
|
||||
[
|
||||
10.45,
|
||||
12.0
|
||||
],
|
||||
[
|
||||
10.38971,
|
||||
12.225
|
||||
],
|
||||
[
|
||||
10.225,
|
||||
12.38971
|
||||
],
|
||||
[
|
||||
10.0,
|
||||
12.45
|
||||
],
|
||||
[
|
||||
9.775,
|
||||
12.38971
|
||||
],
|
||||
[
|
||||
9.61029,
|
||||
12.225
|
||||
],
|
||||
[
|
||||
9.55,
|
||||
12.0
|
||||
],
|
||||
[
|
||||
9.61029,
|
||||
11.775
|
||||
],
|
||||
[
|
||||
9.775,
|
||||
11.61029
|
||||
],
|
||||
[
|
||||
10.0,
|
||||
11.55
|
||||
],
|
||||
[
|
||||
10.225,
|
||||
11.61029
|
||||
],
|
||||
[
|
||||
10.38971,
|
||||
11.775
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tree002",
|
||||
"polygon": [
|
||||
[
|
||||
-11.55,
|
||||
19.0
|
||||
],
|
||||
[
|
||||
-11.61029,
|
||||
19.225
|
||||
],
|
||||
[
|
||||
-11.775,
|
||||
19.38971
|
||||
],
|
||||
[
|
||||
-12.0,
|
||||
19.45
|
||||
],
|
||||
[
|
||||
-12.225,
|
||||
19.38971
|
||||
],
|
||||
[
|
||||
-12.38971,
|
||||
19.225
|
||||
],
|
||||
[
|
||||
-12.45,
|
||||
19.0
|
||||
],
|
||||
[
|
||||
-12.38971,
|
||||
18.775
|
||||
],
|
||||
[
|
||||
-12.225,
|
||||
18.61029
|
||||
],
|
||||
[
|
||||
-12.0,
|
||||
18.55
|
||||
],
|
||||
[
|
||||
-11.775,
|
||||
18.61029
|
||||
],
|
||||
[
|
||||
-11.61029,
|
||||
18.775
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tree003",
|
||||
"polygon": [
|
||||
[
|
||||
-11.55,
|
||||
8.0
|
||||
],
|
||||
[
|
||||
-11.61029,
|
||||
8.225
|
||||
],
|
||||
[
|
||||
-11.775,
|
||||
8.38971
|
||||
],
|
||||
[
|
||||
-12.0,
|
||||
8.45
|
||||
],
|
||||
[
|
||||
-12.225,
|
||||
8.38971
|
||||
],
|
||||
[
|
||||
-12.38971,
|
||||
8.225
|
||||
],
|
||||
[
|
||||
-12.45,
|
||||
8.0
|
||||
],
|
||||
[
|
||||
-12.38971,
|
||||
7.775
|
||||
],
|
||||
[
|
||||
-12.225,
|
||||
7.61029
|
||||
],
|
||||
[
|
||||
-12.0,
|
||||
7.55
|
||||
],
|
||||
[
|
||||
-11.775,
|
||||
7.61029
|
||||
],
|
||||
[
|
||||
-11.61029,
|
||||
7.775
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tree004",
|
||||
"polygon": [
|
||||
[
|
||||
-11.55,
|
||||
0.0
|
||||
],
|
||||
[
|
||||
-11.61029,
|
||||
0.225
|
||||
],
|
||||
[
|
||||
-11.775,
|
||||
0.38971
|
||||
],
|
||||
[
|
||||
-12.0,
|
||||
0.45
|
||||
],
|
||||
[
|
||||
-12.225,
|
||||
0.38971
|
||||
],
|
||||
[
|
||||
-12.38971,
|
||||
0.225
|
||||
],
|
||||
[
|
||||
-12.45,
|
||||
0.0
|
||||
],
|
||||
[
|
||||
-12.38971,
|
||||
-0.225
|
||||
],
|
||||
[
|
||||
-12.225,
|
||||
-0.38971
|
||||
],
|
||||
[
|
||||
-12.0,
|
||||
-0.45
|
||||
],
|
||||
[
|
||||
-11.775,
|
||||
-0.38971
|
||||
],
|
||||
[
|
||||
-11.61029,
|
||||
-0.225
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tree005",
|
||||
"polygon": [
|
||||
[
|
||||
-11.55,
|
||||
-8.0
|
||||
],
|
||||
[
|
||||
-11.61029,
|
||||
-7.775
|
||||
],
|
||||
[
|
||||
-11.775,
|
||||
-7.61029
|
||||
],
|
||||
[
|
||||
-12.0,
|
||||
-7.55
|
||||
],
|
||||
[
|
||||
-12.225,
|
||||
-7.61029
|
||||
],
|
||||
[
|
||||
-12.38971,
|
||||
-7.775
|
||||
],
|
||||
[
|
||||
-12.45,
|
||||
-8.0
|
||||
],
|
||||
[
|
||||
-12.38971,
|
||||
-8.225
|
||||
],
|
||||
[
|
||||
-12.225,
|
||||
-8.38971
|
||||
],
|
||||
[
|
||||
-12.0,
|
||||
-8.45
|
||||
],
|
||||
[
|
||||
-11.775,
|
||||
-8.38971
|
||||
],
|
||||
[
|
||||
-11.61029,
|
||||
-8.225
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tree006",
|
||||
"polygon": [
|
||||
[
|
||||
8.94915,
|
||||
-2.59884
|
||||
],
|
||||
[
|
||||
8.88886,
|
||||
-2.37384
|
||||
],
|
||||
[
|
||||
8.72415,
|
||||
-2.20913
|
||||
],
|
||||
[
|
||||
8.49915,
|
||||
-2.14884
|
||||
],
|
||||
[
|
||||
8.27415,
|
||||
-2.20913
|
||||
],
|
||||
[
|
||||
8.10944,
|
||||
-2.37384
|
||||
],
|
||||
[
|
||||
8.04915,
|
||||
-2.59884
|
||||
],
|
||||
[
|
||||
8.10944,
|
||||
-2.82384
|
||||
],
|
||||
[
|
||||
8.27415,
|
||||
-2.98855
|
||||
],
|
||||
[
|
||||
8.49915,
|
||||
-3.04884
|
||||
],
|
||||
[
|
||||
8.72415,
|
||||
-2.98855
|
||||
],
|
||||
[
|
||||
8.88886,
|
||||
-2.82384
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tree007",
|
||||
"polygon": [
|
||||
[
|
||||
15.0436,
|
||||
5.3401
|
||||
],
|
||||
[
|
||||
14.98331,
|
||||
5.5651
|
||||
],
|
||||
[
|
||||
14.8186,
|
||||
5.72981
|
||||
],
|
||||
[
|
||||
14.5936,
|
||||
5.7901
|
||||
],
|
||||
[
|
||||
14.3686,
|
||||
5.72981
|
||||
],
|
||||
[
|
||||
14.20389,
|
||||
5.5651
|
||||
],
|
||||
[
|
||||
14.1436,
|
||||
5.3401
|
||||
],
|
||||
[
|
||||
14.20389,
|
||||
5.1151
|
||||
],
|
||||
[
|
||||
14.3686,
|
||||
4.95039
|
||||
],
|
||||
[
|
||||
14.5936,
|
||||
4.8901
|
||||
],
|
||||
[
|
||||
14.8186,
|
||||
4.95039
|
||||
],
|
||||
[
|
||||
14.98331,
|
||||
5.1151
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tree008",
|
||||
"polygon": [
|
||||
[
|
||||
24.3795,
|
||||
9.00583
|
||||
],
|
||||
[
|
||||
24.31921,
|
||||
9.23083
|
||||
],
|
||||
[
|
||||
24.1545,
|
||||
9.39554
|
||||
],
|
||||
[
|
||||
23.9295,
|
||||
9.45583
|
||||
],
|
||||
[
|
||||
23.7045,
|
||||
9.39554
|
||||
],
|
||||
[
|
||||
23.53979,
|
||||
9.23083
|
||||
],
|
||||
[
|
||||
23.4795,
|
||||
9.00583
|
||||
],
|
||||
[
|
||||
23.53979,
|
||||
8.78083
|
||||
],
|
||||
[
|
||||
23.7045,
|
||||
8.61612
|
||||
],
|
||||
[
|
||||
23.9295,
|
||||
8.55583
|
||||
],
|
||||
[
|
||||
24.1545,
|
||||
8.61612
|
||||
],
|
||||
[
|
||||
24.31921,
|
||||
8.78083
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tree009",
|
||||
"polygon": [
|
||||
[
|
||||
30.2628,
|
||||
-1.45278
|
||||
],
|
||||
[
|
||||
30.20251,
|
||||
-1.22778
|
||||
],
|
||||
[
|
||||
30.0378,
|
||||
-1.06307
|
||||
],
|
||||
[
|
||||
29.8128,
|
||||
-1.00278
|
||||
],
|
||||
[
|
||||
29.5878,
|
||||
-1.06307
|
||||
],
|
||||
[
|
||||
29.42309,
|
||||
-1.22778
|
||||
],
|
||||
[
|
||||
29.3628,
|
||||
-1.45278
|
||||
],
|
||||
[
|
||||
29.42309,
|
||||
-1.67778
|
||||
],
|
||||
[
|
||||
29.5878,
|
||||
-1.84249
|
||||
],
|
||||
[
|
||||
29.8128,
|
||||
-1.90278
|
||||
],
|
||||
[
|
||||
30.0378,
|
||||
-1.84249
|
||||
],
|
||||
[
|
||||
30.20251,
|
||||
-1.67778
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tree010",
|
||||
"polygon": [
|
||||
[
|
||||
33.6271,
|
||||
14.609
|
||||
],
|
||||
[
|
||||
33.56681,
|
||||
14.834
|
||||
],
|
||||
[
|
||||
33.4021,
|
||||
14.99871
|
||||
],
|
||||
[
|
||||
33.1771,
|
||||
15.059
|
||||
],
|
||||
[
|
||||
32.9521,
|
||||
14.99871
|
||||
],
|
||||
[
|
||||
32.78739,
|
||||
14.834
|
||||
],
|
||||
[
|
||||
32.7271,
|
||||
14.609
|
||||
],
|
||||
[
|
||||
32.78739,
|
||||
14.384
|
||||
],
|
||||
[
|
||||
32.9521,
|
||||
14.21929
|
||||
],
|
||||
[
|
||||
33.1771,
|
||||
14.159
|
||||
],
|
||||
[
|
||||
33.4021,
|
||||
14.21929
|
||||
],
|
||||
[
|
||||
33.56681,
|
||||
14.384
|
||||
]
|
||||
[-200, 200],
|
||||
[200, 200],
|
||||
[200, -200],
|
||||
[-200, -200]
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
BIN
resources/w/Zombie_BaseColor.png
(Stored with Git LFS)
Normal file
BIN
resources/w/Zombie_BaseColor.png
(Stored with Git LFS)
Normal file
Binary file not shown.
8481
resources/w/bench001opt.txt
Normal file
8481
resources/w/bench001opt.txt
Normal file
File diff suppressed because it is too large
Load Diff
430269
resources/w/default_float001.txt
Normal file
430269
resources/w/default_float001.txt
Normal file
File diff suppressed because it is too large
Load Diff
427767
resources/w/default_float001_cut.txt
Normal file
427767
resources/w/default_float001_cut.txt
Normal file
File diff suppressed because it is too large
Load Diff
434022
resources/w/default_idle002.txt
Normal file
434022
resources/w/default_idle002.txt
Normal file
File diff suppressed because it is too large
Load Diff
432354
resources/w/default_walk001.txt
Normal file
432354
resources/w/default_walk001.txt
Normal file
File diff suppressed because it is too large
Load Diff
BIN
resources/w/exterior/Segmented_Plane — копия.png
(Stored with Git LFS)
Normal file
BIN
resources/w/exterior/Segmented_Plane — копия.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/w/exterior/Segmented_Plane.png
(Stored with Git LFS)
Normal file
BIN
resources/w/exterior/Segmented_Plane.png
(Stored with Git LFS)
Normal file
Binary file not shown.
37
resources/w/exterior/Segmented_Plane.txt
Normal file
37
resources/w/exterior/Segmented_Plane.txt
Normal file
@ -0,0 +1,37 @@
|
||||
===Vertices (Split by UV/Normal): 16
|
||||
V 0: Pos(-33.333332, -100.0, 0.0) Norm(0.0, 0.0, 1.0) UV(0.333333, 0.0)
|
||||
V 1: Pos(-100.0, -33.333332, 0.0) Norm(0.0, 0.0, 1.0) UV(0.0, 0.333333)
|
||||
V 2: Pos(-100.0, -100.0, 0.0) Norm(0.0, 0.0, 1.0) UV(0.0, 0.0)
|
||||
V 3: Pos(33.333336, -100.0, 0.0) Norm(0.0, 0.0, 1.0) UV(0.666667, 0.0)
|
||||
V 4: Pos(-33.333332, -33.333332, 0.0) Norm(0.0, 0.0, 1.0) UV(0.333333, 0.333333)
|
||||
V 5: Pos(100.0, -100.0, 0.0) Norm(0.0, 0.0, 1.0) UV(1.0, 0.0)
|
||||
V 6: Pos(33.333336, -33.333332, 0.0) Norm(0.0, 0.0, 1.0) UV(0.666667, 0.333333)
|
||||
V 7: Pos(-100.0, 33.333336, 0.0) Norm(0.0, 0.0, 1.0) UV(0.0, 0.666667)
|
||||
V 8: Pos(-33.333332, 33.333336, 0.0) Norm(0.0, 0.0, 1.0) UV(0.333333, 0.666667)
|
||||
V 9: Pos(100.0, -33.333332, 0.0) Norm(0.0, 0.0, 1.0) UV(1.0, 0.333333)
|
||||
V 10: Pos(33.333336, 33.333336, 0.0) Norm(0.0, 0.0, 1.0) UV(0.666667, 0.666667)
|
||||
V 11: Pos(-100.0, 100.0, 0.0) Norm(0.0, 0.0, 1.0) UV(0.0, 1.0)
|
||||
V 12: Pos(-33.333332, 100.0, 0.0) Norm(0.0, 0.0, 1.0) UV(0.333333, 1.0)
|
||||
V 13: Pos(100.0, 33.333336, 0.0) Norm(0.0, 0.0, 1.0) UV(1.0, 0.666667)
|
||||
V 14: Pos(33.333336, 100.0, 0.0) Norm(0.0, 0.0, 1.0) UV(0.666667, 1.0)
|
||||
V 15: Pos(100.0, 100.0, 0.0) Norm(0.0, 0.0, 1.0) UV(1.0, 1.0)
|
||||
|
||||
===Triangles (Indices): 18
|
||||
Tri: 0 1 2
|
||||
Tri: 3 4 0
|
||||
Tri: 5 6 3
|
||||
Tri: 4 7 1
|
||||
Tri: 6 8 4
|
||||
Tri: 9 10 6
|
||||
Tri: 8 11 7
|
||||
Tri: 10 12 8
|
||||
Tri: 13 14 10
|
||||
Tri: 0 4 1
|
||||
Tri: 3 6 4
|
||||
Tri: 5 9 6
|
||||
Tri: 4 8 7
|
||||
Tri: 6 10 8
|
||||
Tri: 9 13 10
|
||||
Tri: 8 12 11
|
||||
Tri: 10 14 12
|
||||
Tri: 13 15 14
|
||||
122796
resources/w/exterior/tree001.txt
Normal file
122796
resources/w/exterior/tree001.txt
Normal file
File diff suppressed because it is too large
Load Diff
433188
resources/w/float_attack003.txt
Normal file
433188
resources/w/float_attack003.txt
Normal file
File diff suppressed because it is too large
Load Diff
427767
resources/w/float_attack003_cut.txt
Normal file
427767
resources/w/float_attack003_cut.txt
Normal file
File diff suppressed because it is too large
Load Diff
109260
resources/w/gg/gg_action_attack001.txt
Normal file
109260
resources/w/gg/gg_action_attack001.txt
Normal file
File diff suppressed because it is too large
Load Diff
111869
resources/w/gg/gg_action_chop001.txt
Normal file
111869
resources/w/gg/gg_action_chop001.txt
Normal file
File diff suppressed because it is too large
Load Diff
111364
resources/w/gg/gg_action_idle001.txt
Normal file
111364
resources/w/gg/gg_action_idle001.txt
Normal file
File diff suppressed because it is too large
Load Diff
111364
resources/w/gg/gg_action_idle002.txt
Normal file
111364
resources/w/gg/gg_action_idle002.txt
Normal file
File diff suppressed because it is too large
Load Diff
106819
resources/w/gg/gg_action_stab001.txt
Normal file
106819
resources/w/gg/gg_action_stab001.txt
Normal file
File diff suppressed because it is too large
Load Diff
99361
resources/w/gg/gg_action_to_stand001.txt
Normal file
99361
resources/w/gg/gg_action_to_stand001.txt
Normal file
File diff suppressed because it is too large
Load Diff
214502
resources/w/gg/gg_stand_idle001.txt
Normal file
214502
resources/w/gg/gg_stand_idle001.txt
Normal file
File diff suppressed because it is too large
Load Diff
105613
resources/w/gg/gg_stand_to_action002.txt
Normal file
105613
resources/w/gg/gg_stand_to_action002.txt
Normal file
File diff suppressed because it is too large
Load Diff
100403
resources/w/gg/gg_walking001.txt
Normal file
100403
resources/w/gg/gg_walking001.txt
Normal file
File diff suppressed because it is too large
Load Diff
64
resources/w/gg/knife001.txt
Normal file
64
resources/w/gg/knife001.txt
Normal file
@ -0,0 +1,64 @@
|
||||
===Vertices (Split by UV/Normal): 41
|
||||
V 0: Pos(0.02, 0.15, 0.0) Norm(0.577338, 0.577356, -0.577357) UV(0.77503, 0.750033)
|
||||
V 1: Pos(-0.02, -0.15, 0.0) Norm(-0.577338, -0.577356, -0.577357) UV(0.808365, 0.500022)
|
||||
V 2: Pos(-0.02, 0.15, 0.0) Norm(-0.577347, 0.577357, -0.577347) UV(0.808365, 0.750033)
|
||||
V 3: Pos(0.02, -0.15, 0.6) Norm(0.577338, -0.577356, 0.577357) UV(0.866701, 0.496276)
|
||||
V 4: Pos(-0.02, 0.15, 0.6) Norm(-0.577338, 0.577356, 0.577357) UV(0.833366, 0.746287)
|
||||
V 5: Pos(-0.02, -0.15, 0.6) Norm(-0.577347, -0.577357, 0.577347) UV(0.833366, 0.496276)
|
||||
V 6: Pos(0.02, -0.15, 0.0) Norm(0.577347, -0.577357, -0.577347) UV(0.833366, 0.496276)
|
||||
V 7: Pos(-0.02, -0.15, 0.6) Norm(-0.577347, -0.577357, 0.577347) UV(0.866701, 0.0)
|
||||
V 8: Pos(-0.02, -0.15, 0.0) Norm(-0.577338, -0.577356, -0.577357) UV(0.866701, 0.496276)
|
||||
V 9: Pos(0.02, 0.15, 0.0) Norm(0.577338, 0.577356, -0.577357) UV(0.500022, 0.5)
|
||||
V 10: Pos(0.02, -0.15, 0.6) Norm(0.577338, -0.577356, 0.577357) UV(0.750033, 0.0)
|
||||
V 11: Pos(0.02, -0.15, 0.0) Norm(0.577347, -0.577357, -0.577347) UV(0.750033, 0.5)
|
||||
V 12: Pos(-0.02, 0.15, 0.0) Norm(-0.577347, 0.577357, -0.577347) UV(0.77503, 0.500022)
|
||||
V 13: Pos(0.02, 0.15, 0.6) Norm(0.577347, 0.577357, 0.577347) UV(0.808365, 0.0)
|
||||
V 14: Pos(0.02, 0.15, 0.0) Norm(0.577338, 0.577356, -0.577357) UV(0.808365, 0.500022)
|
||||
V 15: Pos(-0.02, -0.15, 0.0) Norm(-0.577338, -0.577356, -0.577357) UV(0.500022, 1.0)
|
||||
V 16: Pos(-0.02, 0.15, 0.6) Norm(-0.577338, 0.577356, 0.577357) UV(0.750033, 0.5)
|
||||
V 17: Pos(-0.02, 0.15, 0.0) Norm(-0.577347, 0.577357, -0.577347) UV(0.750033, 1.0)
|
||||
V 18: Pos(0.015, 0.15, 0.6) Norm(0.583227, 0.576373, -0.572398) UV(0.8667, 0.250011)
|
||||
V 19: Pos(-0.015, -0.15, 0.6) Norm(-0.570792, -0.648582, -0.503526) UV(0.891702, 0.0)
|
||||
V 20: Pos(-0.015, 0.15, 0.6) Norm(-0.583229, 0.576375, -0.572394) UV(0.891702, 0.250011)
|
||||
V 21: Pos(0.0, 0.05, 1.4) Norm(0.0, -0.417006, 0.908904) UV(0.166674, 0.0)
|
||||
V 22: Pos(-0.015, 0.15, 0.6) Norm(-0.583229, 0.576375, -0.572394) UV(0.250011, 0.666784)
|
||||
V 23: Pos(-0.015, -0.15, 0.6) Norm(-0.570792, -0.648582, -0.503526) UV(0.0, 0.666784)
|
||||
V 24: Pos(0.015, 0.15, 0.6) Norm(0.583227, 0.576373, -0.572398) UV(0.250011, 0.666784)
|
||||
V 25: Pos(0.0, 0.05, 1.4) Norm(0.0, -0.417006, 0.908904) UV(0.333348, 0.0)
|
||||
V 26: Pos(0.015, -0.15, 0.6) Norm(0.570794, -0.648585, -0.50352) UV(0.500022, 0.666784)
|
||||
V 27: Pos(-0.015, -0.15, 0.6) Norm(-0.570792, -0.648582, -0.503526) UV(0.77503, 0.68218)
|
||||
V 28: Pos(0.015, -0.15, 0.6) Norm(0.570794, -0.648585, -0.50352) UV(0.750033, 0.681722)
|
||||
V 29: Pos(0.0, 0.05, 1.4) Norm(0.0, -0.417006, 0.908904) UV(0.77503, 0.0)
|
||||
V 30: Pos(-0.015, 0.15, 0.6) Norm(-0.583229, 0.576375, -0.572394) UV(0.808365, 0.666696)
|
||||
V 31: Pos(0.0, 0.15, 1.4) Norm(0.0, 0.536928, 0.843628) UV(0.820865, 0.0)
|
||||
V 32: Pos(0.015, 0.15, 0.6) Norm(0.583227, 0.576373, -0.572398) UV(0.833366, 0.666696)
|
||||
V 33: Pos(0.02, -0.15, 0.0) Norm(0.577347, -0.577357, -0.577347) UV(0.77503, 0.500022)
|
||||
V 34: Pos(0.02, 0.15, 0.6) Norm(0.577347, 0.577357, 0.577347) UV(0.866701, 0.746287)
|
||||
V 35: Pos(0.02, -0.15, 0.6) Norm(0.577338, -0.577356, 0.577357) UV(0.833366, 0.0)
|
||||
V 36: Pos(0.02, 0.15, 0.6) Norm(0.577347, 0.577357, 0.577347) UV(0.500022, 0.0)
|
||||
V 37: Pos(-0.02, 0.15, 0.6) Norm(-0.577338, 0.577356, 0.577357) UV(0.77503, 0.0)
|
||||
V 38: Pos(-0.02, -0.15, 0.6) Norm(-0.577347, -0.577357, 0.577347) UV(0.500022, 0.5)
|
||||
V 39: Pos(0.015, -0.15, 0.6) Norm(0.570794, -0.648585, -0.50352) UV(0.8667, 0.0)
|
||||
V 40: Pos(0.0, 0.15, 1.4) Norm(0.0, 0.536928, 0.843628) UV(0.250011, 0.0)
|
||||
|
||||
===Triangles (Indices): 20
|
||||
Tri: 0 1 2
|
||||
Tri: 3 4 5
|
||||
Tri: 6 7 8
|
||||
Tri: 9 10 11
|
||||
Tri: 12 13 14
|
||||
Tri: 15 16 17
|
||||
Tri: 18 19 20
|
||||
Tri: 21 22 23
|
||||
Tri: 24 25 26
|
||||
Tri: 27 28 29
|
||||
Tri: 30 31 32
|
||||
Tri: 0 33 1
|
||||
Tri: 3 34 4
|
||||
Tri: 6 35 7
|
||||
Tri: 9 36 10
|
||||
Tri: 12 37 13
|
||||
Tri: 15 38 16
|
||||
Tri: 18 39 19
|
||||
Tri: 21 40 22
|
||||
Tri: 24 40 25
|
||||
111869
resources/w/gg/new/gg_action_to_stand001.txt
Normal file
111869
resources/w/gg/new/gg_action_to_stand001.txt
Normal file
File diff suppressed because it is too large
Load Diff
140654
resources/w/gg/new/gg_die001.txt
Normal file
140654
resources/w/gg/new/gg_die001.txt
Normal file
File diff suppressed because it is too large
Load Diff
86619
resources/w/gg/new/gg_die_idle001.txt
Normal file
86619
resources/w/gg/new/gg_die_idle001.txt
Normal file
File diff suppressed because it is too large
Load Diff
88134
resources/w/gg/new/gg_stand_idle001.txt
Normal file
88134
resources/w/gg/new/gg_stand_idle001.txt
Normal file
File diff suppressed because it is too large
Load Diff
111869
resources/w/gg/new/gg_stand_to_action001.txt
Normal file
111869
resources/w/gg/new/gg_stand_to_action001.txt
Normal file
File diff suppressed because it is too large
Load Diff
104294
resources/w/gg/new/gg_walk001.txt
Normal file
104294
resources/w/gg/new/gg_walk001.txt
Normal file
File diff suppressed because it is too large
Load Diff
296013
resources/w/jam/man_stand_idle001.txt
Normal file
296013
resources/w/jam/man_stand_idle001.txt
Normal file
File diff suppressed because it is too large
Load Diff
296013
resources/w/jam/man_stand_idle002.txt
Normal file
296013
resources/w/jam/man_stand_idle002.txt
Normal file
File diff suppressed because it is too large
Load Diff
265274
resources/w/jam/man_walk001.txt
Normal file
265274
resources/w/jam/man_walk001.txt
Normal file
File diff suppressed because it is too large
Load Diff
265274
resources/w/jam/man_walk002.txt
Normal file
265274
resources/w/jam/man_walk002.txt
Normal file
File diff suppressed because it is too large
Load Diff
244655
resources/w/jam/salesperson_stand_idle003.txt
Normal file
244655
resources/w/jam/salesperson_stand_idle003.txt
Normal file
File diff suppressed because it is too large
Load Diff
244655
resources/w/jam/salesperson_stand_idle004.txt
Normal file
244655
resources/w/jam/salesperson_stand_idle004.txt
Normal file
File diff suppressed because it is too large
Load Diff
213916
resources/w/jam/salesperson_walk001.txt
Normal file
213916
resources/w/jam/salesperson_walk001.txt
Normal file
File diff suppressed because it is too large
Load Diff
490165
resources/w/jam/woman_idle001.txt
Normal file
490165
resources/w/jam/woman_idle001.txt
Normal file
File diff suppressed because it is too large
Load Diff
490165
resources/w/jam/woman_idle002.txt
Normal file
490165
resources/w/jam/woman_idle002.txt
Normal file
File diff suppressed because it is too large
Load Diff
251965
resources/w/jam/woman_walk001.txt
Normal file
251965
resources/w/jam/woman_walk001.txt
Normal file
File diff suppressed because it is too large
Load Diff
248421
resources/w/jam/woman_walk002.txt
Normal file
248421
resources/w/jam/woman_walk002.txt
Normal file
File diff suppressed because it is too large
Load Diff
259354
resources/w/new_anims/gg_run003.txt
Normal file
259354
resources/w/new_anims/gg_run003.txt
Normal file
File diff suppressed because it is too large
Load Diff
424511
resources/w/new_anims/gg_stand_idle003.txt
Normal file
424511
resources/w/new_anims/gg_stand_idle003.txt
Normal file
File diff suppressed because it is too large
Load Diff
2197
resources/w/room001.txt
Normal file
2197
resources/w/room001.txt
Normal file
File diff suppressed because it is too large
Load Diff
1995
resources/w/room002.txt
Normal file
1995
resources/w/room002.txt
Normal file
File diff suppressed because it is too large
Load Diff
BIN
resources/w/zombie002.anim
(Stored with Git LFS)
Normal file
BIN
resources/w/zombie002.anim
(Stored with Git LFS)
Normal file
Binary file not shown.
464463
resources/w/zombie002.txt
Normal file
464463
resources/w/zombie002.txt
Normal file
File diff suppressed because it is too large
Load Diff
BIN
resources/w/zombie_idle001.anim
(Stored with Git LFS)
Normal file
BIN
resources/w/zombie_idle001.anim
(Stored with Git LFS)
Normal file
Binary file not shown.
215507
resources/w/zombie_idle001.txt
Normal file
215507
resources/w/zombie_idle001.txt
Normal file
File diff suppressed because it is too large
Load Diff
1041
src/BoneAnimatedModel.cpp
Normal file
1041
src/BoneAnimatedModel.cpp
Normal file
File diff suppressed because it is too large
Load Diff
103
src/BoneAnimatedModel.h
Normal file
103
src/BoneAnimatedModel.h
Normal file
@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include "render/Renderer.h"
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
namespace ZL
|
||||
{
|
||||
constexpr int MAX_BONE_COUNT = 6;
|
||||
constexpr int MAX_GPU_BONES = 64;
|
||||
struct Bone
|
||||
{
|
||||
Vector3f boneStartWorld;
|
||||
float boneLength;
|
||||
Matrix4f boneMatrixWorld;
|
||||
|
||||
int parent;
|
||||
std::vector<int> children;
|
||||
};
|
||||
|
||||
struct BoneWeight
|
||||
{
|
||||
int boneIndex = -1;
|
||||
float weight = 0;
|
||||
};
|
||||
|
||||
struct AnimationKeyFrame
|
||||
{
|
||||
int frame;
|
||||
std::vector<Bone> bones;
|
||||
};
|
||||
|
||||
struct Animation
|
||||
{
|
||||
std::vector<AnimationKeyFrame> keyFrames;
|
||||
};
|
||||
|
||||
struct GpuBoneData {
|
||||
std::vector<Vector4f> boneIndices0; // bone indices 0-3 per vertex (as float)
|
||||
std::vector<Vector2f> boneIndices1; // bone indices 4-5 per vertex
|
||||
std::vector<Vector4f> boneWeights0; // bone weights 0-3 per vertex
|
||||
std::vector<Vector2f> boneWeights1; // bone weights 4-5 per vertex
|
||||
bool prepared = false;
|
||||
void PrepareGpuSkinningData(const std::vector<std::array<BoneWeight, MAX_BONE_COUNT>>& verticesBoneWeight);
|
||||
};
|
||||
|
||||
struct BoneSystem
|
||||
{
|
||||
VertexDataStruct mesh;
|
||||
VertexDataStruct startMesh;
|
||||
std::vector<std::array<BoneWeight, MAX_BONE_COUNT>> verticesBoneWeight;
|
||||
|
||||
Matrix4f armatureMatrix;
|
||||
|
||||
std::vector<Bone> startBones;
|
||||
std::vector<Bone> currentBones;
|
||||
std::vector<std::string> boneNames;
|
||||
|
||||
std::vector<Animation> animations;
|
||||
int startingFrame = 0;
|
||||
|
||||
void LoadFromFile(const std::string& fileName, const std::string& ZIPFileName = "");
|
||||
void LoadFromBinaryFile(const std::string& fileName, const std::string& ZIPFileName = "");
|
||||
|
||||
void Interpolate(int frame);
|
||||
|
||||
int findBoneIndex(const std::string& name) const;
|
||||
|
||||
// GPU skinning: compute skinning matrices without modifying the mesh
|
||||
//void ComputeSkinningMatrices(int frame, std::vector<Matrix4f>& outMatrices) const;
|
||||
};
|
||||
|
||||
|
||||
struct GpuSkinningShaderData {
|
||||
GpuBoneData gpuBoneData;
|
||||
|
||||
// GPU skinning data (lazily initialized)
|
||||
VertexRenderStruct bindPoseMutable;
|
||||
std::shared_ptr<VBOHolder> boneIndices0VBO;
|
||||
std::shared_ptr<VBOHolder> boneIndices1VBO;
|
||||
std::shared_ptr<VBOHolder> boneWeights0VBO;
|
||||
std::shared_ptr<VBOHolder> boneWeights1VBO;
|
||||
bool gpuSkinningPrepared = false;
|
||||
std::vector<Eigen::Matrix4f> skinningMatrices;
|
||||
|
||||
void prepareGpuSkinningVBOs(BoneSystem& model);
|
||||
void RenderVBO(Renderer& renderer);
|
||||
void ComputeSkinningMatrices(const std::vector<Bone>& startBones, const std::vector<AnimationKeyFrame>& keyFrames, int frame);
|
||||
};
|
||||
|
||||
struct BoneAnimationData {
|
||||
BoneSystem model;
|
||||
float currentFrame = 0.f;
|
||||
int lastFrame = -1;
|
||||
int totalFrames = 1;
|
||||
|
||||
GpuSkinningShaderData gpuSkinningShaderData;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
@ -13,21 +13,7 @@ namespace ZL
|
||||
using std::max;
|
||||
#endif
|
||||
|
||||
int getIndexByValue(const std::string& name, const std::vector<std::string>& words)
|
||||
{
|
||||
for (int i = 0; i < words.size(); i++)
|
||||
{
|
||||
if (words[i] == name)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Bone name not found: " << name << std::endl;
|
||||
throw std::runtime_error("Bone name not found: " + name);
|
||||
|
||||
return -1;
|
||||
}
|
||||
extern int getIndexByValue(const std::string& name, const std::vector<std::string>& words);
|
||||
|
||||
static std::string trimRight(const std::string& s)
|
||||
{
|
||||
@ -37,42 +23,6 @@ namespace ZL
|
||||
return s.substr(0, end);
|
||||
}
|
||||
|
||||
|
||||
void GpuBoneData::PrepareGpuSkinningData(const std::vector<std::array<BoneWeight, MAX_BONE_COUNT>>& verticesBoneWeight)
|
||||
{
|
||||
size_t vertexCount = verticesBoneWeight.size();
|
||||
boneIndices0.resize(vertexCount);
|
||||
boneIndices1.resize(vertexCount);
|
||||
boneWeights0.resize(vertexCount);
|
||||
boneWeights1.resize(vertexCount);
|
||||
|
||||
for (size_t i = 0; i < vertexCount; i++)
|
||||
{
|
||||
boneIndices0[i] = Vector4f(
|
||||
static_cast<float>(max(0, verticesBoneWeight[i][0].boneIndex)),
|
||||
static_cast<float>(max(0, verticesBoneWeight[i][1].boneIndex)),
|
||||
static_cast<float>(max(0, verticesBoneWeight[i][2].boneIndex)),
|
||||
static_cast<float>(max(0, verticesBoneWeight[i][3].boneIndex))
|
||||
);
|
||||
boneIndices1[i] = Vector2f(
|
||||
static_cast<float>(max(0, verticesBoneWeight[i][4].boneIndex)),
|
||||
static_cast<float>(max(0, verticesBoneWeight[i][5].boneIndex))
|
||||
);
|
||||
boneWeights0[i] = Vector4f(
|
||||
verticesBoneWeight[i][0].weight,
|
||||
verticesBoneWeight[i][1].weight,
|
||||
verticesBoneWeight[i][2].weight,
|
||||
verticesBoneWeight[i][3].weight
|
||||
);
|
||||
boneWeights1[i] = Vector2f(
|
||||
verticesBoneWeight[i][4].weight,
|
||||
verticesBoneWeight[i][5].weight
|
||||
);
|
||||
}
|
||||
|
||||
prepared = true;
|
||||
}
|
||||
|
||||
void BoneSystemNew::LoadFromFile(const std::string& fileName, const std::string& ZIPFileName)
|
||||
{
|
||||
std::ifstream filestream;
|
||||
|
||||
@ -1,48 +1,9 @@
|
||||
#pragma once
|
||||
#include "render/Renderer.h"
|
||||
#include "BoneAnimatedModel.h"
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
namespace ZL
|
||||
{
|
||||
constexpr int MAX_BONE_COUNT = 6;
|
||||
constexpr int MAX_GPU_BONES = 64;
|
||||
struct Bone
|
||||
{
|
||||
Eigen::Vector3f boneStartWorld;
|
||||
float boneLength;
|
||||
Eigen::Matrix4f boneMatrixWorld;
|
||||
|
||||
int parent;
|
||||
std::vector<int> children;
|
||||
};
|
||||
|
||||
struct BoneWeight
|
||||
{
|
||||
int boneIndex = -1;
|
||||
float weight = 0;
|
||||
};
|
||||
|
||||
struct AnimationKeyFrame
|
||||
{
|
||||
int frame;
|
||||
std::vector<Bone> bones;
|
||||
};
|
||||
|
||||
struct Animation
|
||||
{
|
||||
std::vector<AnimationKeyFrame> keyFrames;
|
||||
};
|
||||
|
||||
struct GpuBoneData {
|
||||
std::vector<Vector4f> boneIndices0; // bone indices 0-3 per vertex (as float)
|
||||
std::vector<Vector2f> boneIndices1; // bone indices 4-5 per vertex
|
||||
std::vector<Vector4f> boneWeights0; // bone weights 0-3 per vertex
|
||||
std::vector<Vector2f> boneWeights1; // bone weights 4-5 per vertex
|
||||
bool prepared = false;
|
||||
void PrepareGpuSkinningData(const std::vector<std::array<BoneWeight, MAX_BONE_COUNT>>& verticesBoneWeight);
|
||||
};
|
||||
|
||||
struct MeshBoneData
|
||||
{
|
||||
VertexDataStruct mesh;
|
||||
|
||||
@ -78,43 +78,6 @@ void Character::setPathPlanner(PathPlanner planner) {
|
||||
pathPlanner = std::move(planner);
|
||||
}
|
||||
|
||||
bool Character::isMoving() const
|
||||
{
|
||||
Eigen::Vector3f toTarget = walkTarget - position;
|
||||
toTarget.y() = 0.f;
|
||||
return !pathWaypoints.empty() || toTarget.norm() > WALK_THRESHOLD;
|
||||
}
|
||||
|
||||
Eigen::Vector3f Character::getCurrentNavigationTarget() const
|
||||
{
|
||||
if (!pathWaypoints.empty() && currentWaypointIndex < pathWaypoints.size()) {
|
||||
return pathWaypoints[currentWaypointIndex];
|
||||
}
|
||||
return walkTarget;
|
||||
}
|
||||
|
||||
void Character::forceReplan()
|
||||
{
|
||||
if (!pathPlanner) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Eigen::Vector3f normalizedTarget(requestedWalkTarget.x(), 0.f, requestedWalkTarget.z());
|
||||
pathWaypoints = pathPlanner(position, normalizedTarget);
|
||||
currentWaypointIndex = 0;
|
||||
|
||||
if (!pathWaypoints.empty()) {
|
||||
for (Eigen::Vector3f& waypoint : pathWaypoints) {
|
||||
waypoint.y() = 0.f;
|
||||
}
|
||||
walkTarget = pathWaypoints.back();
|
||||
return;
|
||||
}
|
||||
|
||||
walkTarget = Eigen::Vector3f(position.x(), 0.f, position.z());
|
||||
onArrivedCallback = nullptr;
|
||||
}
|
||||
|
||||
void Character::setTexture(std::shared_ptr<ZL::Texture> texture)
|
||||
{
|
||||
for (auto& animEntry : animations) {
|
||||
@ -127,7 +90,15 @@ void Character::setTexture(std::shared_ptr<ZL::Texture> texture)
|
||||
void Character::setTexture(const std::string& meshName, std::shared_ptr<Texture> tex) {
|
||||
meshTextures[meshName] = std::move(tex);
|
||||
}
|
||||
|
||||
/*
|
||||
void Character::setTexture(std::shared_ptr<Texture> tex) {
|
||||
for (auto& animEntry : animations) {
|
||||
for (const auto& name : animEntry.second.model.meshNamesOrdered) {
|
||||
meshTextures[name] = tex;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
AnimationState Character::resolveActiveState() const {
|
||||
|
||||
if (animations.count(currentState)) return currentState;
|
||||
@ -166,6 +137,14 @@ void Character::update(int64_t deltaMs) {
|
||||
deltaMs = static_cast<int64_t>(static_cast<float>(deltaMs) * speedMultiplier);
|
||||
}
|
||||
|
||||
|
||||
//weaponInitialRotation = Eigen::AngleAxisf(x/180.0, Eigen::Vector3f::UnitZ()).toRotationMatrix();
|
||||
//weaponInitialRotation = Eigen::AngleAxisf(-M_PI*0.5, Eigen::Vector3f::UnitZ()).toRotationMatrix();
|
||||
//weaponInitialPosition = Eigen::Vector3f(0, 0.09, 0.016);
|
||||
/*if (deltaMs > 200)
|
||||
{
|
||||
deltaMs = 200;
|
||||
}*/
|
||||
Eigen::Vector3f activeTarget;
|
||||
Eigen::Vector3f lookTarget;
|
||||
|
||||
@ -357,8 +336,14 @@ void Character::update(int64_t deltaMs) {
|
||||
resetAnim = false;
|
||||
anim.currentFrame = 0;
|
||||
}
|
||||
//19
|
||||
int prevFrame = anim.currentFrame;
|
||||
anim.currentFrame += static_cast<float>(deltaMs) / 24.f;
|
||||
/*
|
||||
if (npcId == "ghost_01x")
|
||||
{
|
||||
std::cout << "Current animation frame: " << anim.currentFrame << " / " << anim.totalFrames << " -- " << anim.lastFrame << std::endl;
|
||||
}*/
|
||||
|
||||
if (static_cast<int>(anim.currentFrame) >= 20 && currentState == AnimationState::STAND_TO_ACTION)
|
||||
{
|
||||
@ -414,21 +399,25 @@ void Character::update(int64_t deltaMs) {
|
||||
if (currentState == AnimationState::STAND_TO_ACTION)
|
||||
{
|
||||
currentState = AnimationState::ACTION_IDLE;
|
||||
//resetAnim = true;
|
||||
}
|
||||
if (currentState == AnimationState::ACTION_TO_STAND)
|
||||
{
|
||||
currentState = AnimationState::STAND;
|
||||
//resetAnim = true;
|
||||
}
|
||||
|
||||
if (currentState == AnimationState::ACTION_ATTACK)
|
||||
{
|
||||
currentState = AnimationState::ACTION_IDLE;
|
||||
//resetAnim = true;
|
||||
attack = 0;
|
||||
}
|
||||
|
||||
if (currentState == AnimationState::ACTION_TO_DEATH)
|
||||
{
|
||||
currentState = AnimationState::DEATH_IDLE;
|
||||
//resetAnim = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -53,21 +53,11 @@ public:
|
||||
void drawShadowDepth(Renderer& renderer);
|
||||
void drawWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera);
|
||||
|
||||
// Character-to-character collision (XZ-plane). Used by Location to keep
|
||||
// player/NPCs from walking through each other.
|
||||
float collisionRadius = 0.45f;
|
||||
|
||||
// Movement/path introspection used for dynamic replanning.
|
||||
bool isMoving() const;
|
||||
const Eigen::Vector3f& getRequestedWalkTarget() const { return requestedWalkTarget; }
|
||||
Eigen::Vector3f getCurrentNavigationTarget() const;
|
||||
void forceReplan();
|
||||
|
||||
|
||||
// attackDirection is a world-space horizontal vector pointing from the
|
||||
// attacker toward this character — i.e. the direction the hit pushes
|
||||
// them. A zero vector disables directional sparks (isotropic burst).
|
||||
void applyDamage(float damageAmount, const Eigen::Vector3f& attackDirection = Eigen::Vector3f::Zero());
|
||||
// attackDirection is a world-space horizontal vector pointing from the
|
||||
// attacker toward this character — i.e. the direction the hit pushes
|
||||
// them. A zero vector disables directional sparks (isotropic burst).
|
||||
void applyDamage(float damageAmount, const Eigen::Vector3f& attackDirection = Eigen::Vector3f::Zero());
|
||||
|
||||
// Configures the per-character hit-spark emitter with the shared spark
|
||||
// texture. Safe to call once per character after construction.
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include "Game.h"
|
||||
#include "AnimatedModel.h"
|
||||
#include "BoneAnimatedModel.h"
|
||||
#include "utils/Utils.h"
|
||||
#include "render/OpenGlExtensions.h"
|
||||
#include <iostream>
|
||||
@ -661,16 +662,16 @@ namespace ZL
|
||||
if (event.type == SDL_KEYDOWN && event.key.repeat == 0) {
|
||||
switch (event.key.keysym.sym) {
|
||||
case SDLK_1:
|
||||
//if (audioPlayer) audioPlayer->playSoundAsync("audio/background.wav");
|
||||
if (audioPlayer) audioPlayer->playSoundAsync("audio/background.wav");
|
||||
break;
|
||||
case SDLK_2:
|
||||
//if (audioPlayer) audioPlayer->playMusicAsync("audio/lullaby-music-vol20-186394--online-audio-convert.com.ogg");
|
||||
if (audioPlayer) audioPlayer->playMusicAsync("audio/lullaby-music-vol20-186394--online-audio-convert.com.ogg");
|
||||
break;
|
||||
case SDLK_3:
|
||||
//if (audioPlayer) audioPlayer->stopMusicAsync();
|
||||
if (audioPlayer) audioPlayer->stopMusicAsync();
|
||||
break;
|
||||
case SDLK_f:
|
||||
//currentLocation->dialogueSystem.startDialogue("test_choice_dialogue");
|
||||
currentLocation->dialogueSystem.startDialogue("test_choice_dialogue");
|
||||
break;
|
||||
|
||||
case SDLK_e:
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "Character.h"
|
||||
#include "BoneAnimatedModel.h"
|
||||
#include "render/Renderer.h"
|
||||
#include "Environment.h"
|
||||
#include "render/TextureManager.h"
|
||||
@ -106,6 +107,9 @@ namespace ZL {
|
||||
void updatePinchZoom();
|
||||
void endPinch();
|
||||
int countNonUiPointers() const;
|
||||
void handleDown(int64_t fingerId, int mx, int my);
|
||||
void handleUp(int64_t fingerId, int mx, int my);
|
||||
void handleMotion(int64_t fingerId, int mx, int my);
|
||||
|
||||
void setupQuestJournalUi();
|
||||
void toggleQuestJournal();
|
||||
|
||||
225
src/Location.cpp
225
src/Location.cpp
@ -23,23 +23,6 @@ namespace ZL
|
||||
// on_npc_interact callback fires and the conversation begins.
|
||||
static constexpr float NPC_TALK_DISTANCE = 1.25f;
|
||||
|
||||
static float distancePointToSegmentXZ(const Eigen::Vector3f& p,
|
||||
const Eigen::Vector3f& a,
|
||||
const Eigen::Vector3f& b)
|
||||
{
|
||||
const Eigen::Vector2f p2(p.x(), p.z());
|
||||
const Eigen::Vector2f a2(a.x(), a.z());
|
||||
const Eigen::Vector2f b2(b.x(), b.z());
|
||||
const Eigen::Vector2f ab = b2 - a2;
|
||||
const float abLenSq = ab.squaredNorm();
|
||||
if (abLenSq <= 1e-8f) {
|
||||
return (p2 - a2).norm();
|
||||
}
|
||||
const float t = std::clamp((p2 - a2).dot(ab) / abLenSq, 0.0f, 1.0f);
|
||||
const Eigen::Vector2f closest = a2 + ab * t;
|
||||
return (p2 - closest).norm();
|
||||
}
|
||||
|
||||
Location::Location(Renderer& iRenderer, Inventory& iInventory)
|
||||
: renderer(iRenderer)
|
||||
, inventory(iInventory)
|
||||
@ -198,51 +181,38 @@ namespace ZL
|
||||
|
||||
void Location::setupNavigation(const std::string& navigationJsonPath)
|
||||
{
|
||||
// Static navigation blockers are defined in the navigation JSON as polygons.
|
||||
// NPC + player are handled as dynamic obstacles, so they are intentionally NOT in JSON.
|
||||
navigation.build({}, navigationJsonPath, CONST_ZIP_FILE);
|
||||
std::vector<PathFinder::ObstacleMesh> obstacles;
|
||||
obstacles.reserve(gameObjects.size() + interactiveObjects.size());
|
||||
|
||||
for (const auto& item : gameObjects) {
|
||||
const LoadedGameObject& gameObj = item.second;
|
||||
obstacles.push_back({ &gameObj.mesh.data, Eigen::Vector3f::Zero() });
|
||||
}
|
||||
|
||||
for (const InteractiveObject& intObj : interactiveObjects) {
|
||||
if (!intObj.isActive) {
|
||||
continue;
|
||||
}
|
||||
obstacles.push_back({ &intObj.mesh.data, intObj.position });
|
||||
}
|
||||
|
||||
navigation.build(obstacles, navigationJsonPath, CONST_ZIP_FILE);
|
||||
|
||||
#ifdef SHOW_PATH
|
||||
buildDebugNavMeshes();
|
||||
#endif
|
||||
|
||||
static constexpr float kDynamicObstacleInfluenceDist = 6.0f;
|
||||
|
||||
auto makePlanner = [this](const Character* self) {
|
||||
return [this, self](const Eigen::Vector3f& start, const Eigen::Vector3f& end) {
|
||||
std::vector<PathFinder::DynamicObstacle> dynamicObstacles;
|
||||
dynamicObstacles.reserve(npcs.size() + 1);
|
||||
|
||||
const auto addCharacter = [&](const Character* other) {
|
||||
if (!other || other == self) return;
|
||||
if (other->hp <= 0.f) return;
|
||||
|
||||
if (distancePointToSegmentXZ(other->position, start, end) > kDynamicObstacleInfluenceDist) {
|
||||
return;
|
||||
}
|
||||
|
||||
PathFinder::DynamicObstacle obs;
|
||||
obs.position = Eigen::Vector3f(other->position.x(), navigation.getFloorY(), other->position.z());
|
||||
obs.radius = (std::max)(0.0f, other->collisionRadius);
|
||||
dynamicObstacles.push_back(obs);
|
||||
};
|
||||
|
||||
addCharacter(player.get());
|
||||
for (const auto& npc : npcs) {
|
||||
addCharacter(npc.get());
|
||||
}
|
||||
|
||||
return navigation.findPath(start, end, dynamicObstacles);
|
||||
auto planner = [this](const Eigen::Vector3f& start, const Eigen::Vector3f& end) {
|
||||
return navigation.findPath(start, end);
|
||||
};
|
||||
};
|
||||
|
||||
if (player) {
|
||||
player->setPathPlanner(makePlanner(player.get()));
|
||||
player->setPathPlanner(planner);
|
||||
}
|
||||
|
||||
for (auto& npc : npcs) {
|
||||
if (npc) {
|
||||
npc->setPathPlanner(makePlanner(npc.get()));
|
||||
npc->setPathPlanner(planner);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -671,156 +641,6 @@ namespace ZL
|
||||
return navigation.setAreaAvailable(areaName, available);
|
||||
}
|
||||
|
||||
void Location::resolveCharacterCollisions()
|
||||
{
|
||||
std::vector<Character*> characters;
|
||||
characters.reserve(npcs.size() + 1);
|
||||
|
||||
if (player) {
|
||||
characters.push_back(player.get());
|
||||
}
|
||||
for (auto& npc : npcs) {
|
||||
if (npc) {
|
||||
characters.push_back(npc.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (characters.size() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
static constexpr int kIterations = 3;
|
||||
static constexpr float kMinSeparationEps = 1e-4f;
|
||||
|
||||
for (int iter = 0; iter < kIterations; ++iter) {
|
||||
for (size_t i = 0; i < characters.size(); ++i) {
|
||||
for (size_t j = i + 1; j < characters.size(); ++j) {
|
||||
Character* a = characters[i];
|
||||
Character* b = characters[j];
|
||||
if (!a || !b) continue;
|
||||
if (a->hp <= 0.f || b->hp <= 0.f) continue;
|
||||
|
||||
const float minDist = a->collisionRadius + b->collisionRadius;
|
||||
if (minDist <= 0.f) continue;
|
||||
|
||||
const Eigen::Vector2f pa(a->position.x(), a->position.z());
|
||||
const Eigen::Vector2f pb(b->position.x(), b->position.z());
|
||||
const Eigen::Vector2f delta = pb - pa;
|
||||
const float dist = delta.norm();
|
||||
|
||||
if (dist >= minDist) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Eigen::Vector2f normal(1.f, 0.f);
|
||||
if (dist > kMinSeparationEps) {
|
||||
normal = delta / dist;
|
||||
}
|
||||
|
||||
const float penetration = (minDist - dist);
|
||||
const float push = penetration * 0.5f;
|
||||
|
||||
Eigen::Vector3f newA = a->position;
|
||||
Eigen::Vector3f newB = b->position;
|
||||
newA.x() -= normal.x() * push;
|
||||
newA.z() -= normal.y() * push;
|
||||
newA.y() = 0.f;
|
||||
newB.x() += normal.x() * push;
|
||||
newB.z() += normal.y() * push;
|
||||
newB.y() = 0.f;
|
||||
|
||||
if (navigation.isReady()) {
|
||||
const bool aOk = navigation.isWalkable(newA);
|
||||
const bool bOk = navigation.isWalkable(newB);
|
||||
|
||||
if (aOk && bOk) {
|
||||
a->position = newA;
|
||||
b->position = newB;
|
||||
}
|
||||
else if (aOk && !bOk) {
|
||||
a->position = newA;
|
||||
}
|
||||
else if (!aOk && bOk) {
|
||||
b->position = newB;
|
||||
}
|
||||
}
|
||||
else {
|
||||
a->position = newA;
|
||||
b->position = newB;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Location::updateDynamicReplans(int64_t deltaMs)
|
||||
{
|
||||
static constexpr float kMovedEps = 0.05f;
|
||||
static constexpr float kReplanTriggerDist = 1.1f;
|
||||
static constexpr int64_t kReplanCooldownMs = 300;
|
||||
|
||||
for (auto it = replanCooldownRemainingMs.begin(); it != replanCooldownRemainingMs.end();) {
|
||||
it->second -= deltaMs;
|
||||
if (it->second <= 0) {
|
||||
it = replanCooldownRemainingMs.erase(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Character*> characters;
|
||||
characters.reserve(npcs.size() + 1);
|
||||
if (player) characters.push_back(player.get());
|
||||
for (auto& npc : npcs) if (npc) characters.push_back(npc.get());
|
||||
|
||||
std::vector<Character*> movers;
|
||||
movers.reserve(characters.size());
|
||||
for (Character* c : characters) {
|
||||
if (!c) continue;
|
||||
auto it = lastCharacterPositions.find(c);
|
||||
if (it == lastCharacterPositions.end()) {
|
||||
lastCharacterPositions[c] = c->position;
|
||||
continue;
|
||||
}
|
||||
|
||||
const Eigen::Vector3f prev = it->second;
|
||||
const float moved = (c->position - prev).norm();
|
||||
it->second = c->position;
|
||||
|
||||
if (moved > kMovedEps) {
|
||||
movers.push_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (movers.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Character* mover : movers) {
|
||||
if (!mover) continue;
|
||||
|
||||
for (Character* walker : characters) {
|
||||
if (!walker || walker == mover) continue;
|
||||
if (walker->hp <= 0.f) continue;
|
||||
if (!walker->isMoving()) continue;
|
||||
|
||||
if (replanCooldownRemainingMs.find(walker) != replanCooldownRemainingMs.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Eigen::Vector3f nextTarget = walker->getCurrentNavigationTarget();
|
||||
const float distToSegment = distancePointToSegmentXZ(mover->position, walker->position, nextTarget);
|
||||
if (distToSegment > kReplanTriggerDist) {
|
||||
continue;
|
||||
}
|
||||
|
||||
walker->forceReplan();
|
||||
replanCooldownRemainingMs[walker] = kReplanCooldownMs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Location::update(int64_t delta)
|
||||
{
|
||||
if (player) {
|
||||
@ -832,9 +652,6 @@ namespace ZL
|
||||
npc->update(delta);
|
||||
}
|
||||
|
||||
resolveCharacterCollisions();
|
||||
updateDynamicReplans(delta);
|
||||
|
||||
// Check if player reached target interactive object
|
||||
if (targetInteractiveObject && player) {
|
||||
float distToObject = (player->position - targetInteractiveObject->position).norm();
|
||||
@ -1071,4 +888,4 @@ namespace ZL
|
||||
}
|
||||
|
||||
|
||||
} // namespace ZL
|
||||
} // namespace ZL
|
||||
@ -13,8 +13,6 @@
|
||||
#include "dialogue/DialogueSystem.h"
|
||||
#include "SparkEmitter.h"
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
namespace ZL
|
||||
{
|
||||
|
||||
@ -114,13 +112,6 @@ namespace ZL
|
||||
protected:
|
||||
Renderer& renderer;
|
||||
Inventory& inventory;
|
||||
|
||||
private:
|
||||
void resolveCharacterCollisions();
|
||||
void updateDynamicReplans(int64_t deltaMs);
|
||||
|
||||
std::unordered_map<Character*, Eigen::Vector3f> lastCharacterPositions;
|
||||
std::unordered_map<Character*, int64_t> replanCooldownRemainingMs;
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
} // namespace ZL
|
||||
@ -10,6 +10,219 @@
|
||||
namespace ZL
|
||||
{
|
||||
|
||||
|
||||
VertexDataStruct LoadFromTextFile(const std::string& fileName, const std::string& ZIPFileName)
|
||||
{
|
||||
VertexDataStruct result;
|
||||
std::ifstream filestream;
|
||||
std::istringstream zipStream;
|
||||
|
||||
if (!ZIPFileName.empty())
|
||||
{
|
||||
std::vector<char> fileData = readFileFromZIP(fileName, ZIPFileName);
|
||||
std::string fileContents(fileData.begin(), fileData.end());
|
||||
zipStream.str(fileContents);
|
||||
}
|
||||
else
|
||||
{
|
||||
filestream.open(fileName);
|
||||
}
|
||||
|
||||
// Создаем ссылку f на нужный поток – после этого код ниже остается без изменений
|
||||
std::istream& f = (!ZIPFileName.empty()) ? static_cast<std::istream&>(zipStream) : static_cast<std::istream&>(filestream);
|
||||
|
||||
|
||||
//Skip first 5 lines
|
||||
std::string tempLine;
|
||||
|
||||
std::getline(f, tempLine);
|
||||
|
||||
static const std::regex pattern_count(R"(\d+)");
|
||||
static const std::regex pattern_float(R"([-]?\d+\.\d+)");
|
||||
static const std::regex pattern_int(R"([-]?\d+)");
|
||||
|
||||
|
||||
std::smatch match;
|
||||
|
||||
int numberVertices;
|
||||
|
||||
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||
std::string number_str = match.str();
|
||||
numberVertices = std::stoi(number_str);
|
||||
}
|
||||
else {
|
||||
std::cout << "No number found in the input string: " << tempLine << std::endl;
|
||||
throw std::runtime_error("No number found in the input string.");
|
||||
}
|
||||
|
||||
std::vector<Vector3f> vertices;
|
||||
|
||||
vertices.resize(numberVertices);
|
||||
for (int i = 0; i < numberVertices; i++)
|
||||
{
|
||||
std::getline(f, tempLine);
|
||||
|
||||
std::vector<float> floatValues;
|
||||
|
||||
auto b = tempLine.cbegin();
|
||||
auto e = tempLine.cend();
|
||||
while (std::regex_search(b, e, match, pattern_float)) {
|
||||
floatValues.push_back(std::stof(match.str()));
|
||||
b = match.suffix().first;
|
||||
}
|
||||
|
||||
vertices[i] = Vector3f{ floatValues[0], floatValues[1], floatValues[2] };
|
||||
}
|
||||
|
||||
std::cout << "UV Coordinates" << std::endl;
|
||||
|
||||
std::getline(f, tempLine); //===UV Coordinates:
|
||||
|
||||
std::getline(f, tempLine); //triangle count
|
||||
int numberTriangles;
|
||||
|
||||
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||
std::string number_str = match.str();
|
||||
numberTriangles = std::stoi(number_str);
|
||||
}
|
||||
else {
|
||||
std::cout << "-No number found in the input string: " << tempLine << std::endl;
|
||||
throw std::runtime_error("-No number found in the input string.");
|
||||
}
|
||||
|
||||
|
||||
// Now process UVs
|
||||
std::vector<std::array<Vector2f, 3>> uvCoords;
|
||||
|
||||
uvCoords.resize(numberTriangles);
|
||||
|
||||
for (int i = 0; i < numberTriangles; i++)
|
||||
{
|
||||
std::getline(f, tempLine); //Face 0
|
||||
|
||||
int uvCount;
|
||||
std::getline(f, tempLine);
|
||||
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||
std::string number_str = match.str();
|
||||
uvCount = std::stoi(number_str);
|
||||
}
|
||||
else {
|
||||
std::cout << "2 No number found in the input string: " << tempLine << std::endl;
|
||||
throw std::runtime_error("2 No number found in the input string.");
|
||||
}
|
||||
|
||||
if (uvCount != 3)
|
||||
{
|
||||
std::cout << "UV count is not 3 for triangle " << i << ": " << uvCount << std::endl;
|
||||
throw std::runtime_error("more than 3 uvs");
|
||||
}
|
||||
|
||||
std::vector<float> floatValues;
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
std::getline(f, tempLine); //UV <Vector (-0.3661, -1.1665)>
|
||||
|
||||
auto b = tempLine.cbegin();
|
||||
auto e = tempLine.cend();
|
||||
floatValues.clear();
|
||||
while (std::regex_search(b, e, match, pattern_float)) {
|
||||
floatValues.push_back(std::stof(match.str()));
|
||||
b = match.suffix().first;
|
||||
}
|
||||
|
||||
if (floatValues.size() != 2)
|
||||
{
|
||||
std::cout << "UV count is not 2: " << j << " " << floatValues.size() << std::endl;
|
||||
throw std::runtime_error("more than 2 uvs---");
|
||||
}
|
||||
|
||||
uvCoords[i][j] = Vector2f{ floatValues[0],floatValues[1] };
|
||||
}
|
||||
}
|
||||
|
||||
//std::cout << "Normals go" << std::endl;
|
||||
|
||||
std::getline(f, tempLine); //===Normals:
|
||||
|
||||
|
||||
std::vector<Vector3f> normals;
|
||||
|
||||
normals.resize(numberVertices);
|
||||
for (int i = 0; i < numberVertices; i++)
|
||||
{
|
||||
std::getline(f, tempLine);
|
||||
|
||||
std::vector<float> floatValues;
|
||||
|
||||
auto b = tempLine.cbegin();
|
||||
auto e = tempLine.cend();
|
||||
while (std::regex_search(b, e, match, pattern_float)) {
|
||||
floatValues.push_back(std::stof(match.str()));
|
||||
b = match.suffix().first;
|
||||
}
|
||||
|
||||
normals[i] = Vector3f{ floatValues[0], floatValues[1], floatValues[2] };
|
||||
}
|
||||
|
||||
//std::cout << "Triangles go:" << std::endl;
|
||||
|
||||
std::getline(f, tempLine); //===Triangles: 3974
|
||||
|
||||
|
||||
std::vector<std::array<int, 3>> triangles;
|
||||
|
||||
triangles.resize(numberTriangles);
|
||||
for (int i = 0; i < numberTriangles; i++)
|
||||
{
|
||||
std::getline(f, tempLine);
|
||||
|
||||
std::vector<int> intValues;
|
||||
|
||||
auto b = tempLine.cbegin();
|
||||
auto e = tempLine.cend();
|
||||
while (std::regex_search(b, e, match, pattern_int)) {
|
||||
intValues.push_back(std::stoi(match.str()));
|
||||
b = match.suffix().first;
|
||||
}
|
||||
|
||||
triangles[i] = { intValues[0], intValues[1], intValues[2] };
|
||||
}
|
||||
|
||||
|
||||
std::cout << "Process vertices" << std::endl;
|
||||
|
||||
|
||||
|
||||
// Now let's process vertices
|
||||
|
||||
for (int i = 0; i < numberTriangles; i++)
|
||||
{
|
||||
|
||||
result.PositionData.push_back(vertices[triangles[i][0]]);
|
||||
result.PositionData.push_back(vertices[triangles[i][1]]);
|
||||
result.PositionData.push_back(vertices[triangles[i][2]]);
|
||||
|
||||
result.TexCoordData.push_back(uvCoords[i][0]);
|
||||
result.TexCoordData.push_back(uvCoords[i][1]);
|
||||
result.TexCoordData.push_back(uvCoords[i][2]);
|
||||
|
||||
}
|
||||
|
||||
//Swap from Blender format to OpenGL format
|
||||
for (int i = 0; i < result.PositionData.size(); i++)
|
||||
{
|
||||
Vector3f tempVec = result.PositionData[i];
|
||||
result.PositionData[i](0) = tempVec(1);
|
||||
result.PositionData[i](1) = tempVec(2);
|
||||
result.PositionData[i](2) = tempVec(0);
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
VertexDataStruct LoadFromTextFile02(const std::string& fileName, const std::string& ZIPFileName)
|
||||
{
|
||||
VertexDataStruct result;
|
||||
|
||||
@ -6,5 +6,6 @@
|
||||
|
||||
namespace ZL
|
||||
{
|
||||
VertexDataStruct LoadFromTextFile(const std::string& fileName, const std::string& ZIPFileName = "");
|
||||
VertexDataStruct LoadFromTextFile02(const std::string& fileName, const std::string& ZIPFileName = "");
|
||||
}
|
||||
@ -205,7 +205,11 @@ void DialogueOverlay::drawDialogue(Renderer& renderer, const PresentationModel&
|
||||
nameRenderer->drawText(model.speaker, nameX, nameY, 1.0f, false, { 1.0f, 0.88f, 0.45f, 1.0f });
|
||||
}
|
||||
|
||||
|
||||
// const std::string wrappedBody = wrapText(model.visibleText, 90);
|
||||
// bodyRenderer->drawText(wrappedBody, bodyX, bodyY, 1.0f, false, { 1.0f, 1.0f, 1.0f, 1.0f });
|
||||
// const std::string wrappedBody = wrapText(model.visibleText, 56);
|
||||
// bodyRenderer->drawText(wrappedBody, bodyX, bodyY, 1.0f, false, { 1.0f, 1.0f, 1.0f, 1.0f });
|
||||
|
||||
const float bodyTextScale = 1.0f;
|
||||
const float bodyMaxWidthPx = textboxRect.w - 48.0f;
|
||||
|
||||
|
||||
@ -7,9 +7,14 @@
|
||||
#include "external/nlohmann/json.hpp"
|
||||
#include "TextModel.h"
|
||||
#include "InteractiveObject.h"
|
||||
//#include "Character.h"
|
||||
//#include "render/TextureManager.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
|
||||
//struct Texture;
|
||||
//struct VertexRenderStruct;
|
||||
//class Renderer;
|
||||
class Character;
|
||||
|
||||
struct GameObjectData {
|
||||
|
||||
@ -38,52 +38,6 @@ namespace {
|
||||
|
||||
return polygon;
|
||||
}
|
||||
|
||||
float distancePointToSegment2D(const Eigen::Vector2f& p,
|
||||
const Eigen::Vector2f& a,
|
||||
const Eigen::Vector2f& b)
|
||||
{
|
||||
const Eigen::Vector2f ab = b - a;
|
||||
const float abLenSq = ab.squaredNorm();
|
||||
if (abLenSq <= 1e-8f) {
|
||||
return (p - a).norm();
|
||||
}
|
||||
float t = (p - a).dot(ab) / abLenSq;
|
||||
t = (std::max)(0.0f, (std::min)(1.0f, t));
|
||||
const Eigen::Vector2f proj = a + t * ab;
|
||||
return (p - proj).norm();
|
||||
}
|
||||
|
||||
Eigen::Vector2f closestPointOnSegment2D(const Eigen::Vector2f& p,
|
||||
const Eigen::Vector2f& a,
|
||||
const Eigen::Vector2f& b)
|
||||
{
|
||||
const Eigen::Vector2f ab = b - a;
|
||||
const float abLenSq = ab.squaredNorm();
|
||||
if (abLenSq <= 1e-8f) {
|
||||
return a;
|
||||
}
|
||||
|
||||
float t = (p - a).dot(ab) / abLenSq;
|
||||
t = (std::max)(0.0f, (std::min)(1.0f, t));
|
||||
return a + t * ab;
|
||||
}
|
||||
|
||||
float distancePointToPolygonEdges(const Eigen::Vector2f& p,
|
||||
const std::vector<Eigen::Vector2f>& polygon)
|
||||
{
|
||||
if (polygon.size() < 2) {
|
||||
return (std::numeric_limits<float>::max)();
|
||||
}
|
||||
|
||||
float best = (std::numeric_limits<float>::max)();
|
||||
for (size_t i = 0; i < polygon.size(); ++i) {
|
||||
const Eigen::Vector2f& a = polygon[i];
|
||||
const Eigen::Vector2f& b = polygon[(i + 1) % polygon.size()];
|
||||
best = (std::min)(best, distancePointToSegment2D(p, a, b));
|
||||
}
|
||||
return best;
|
||||
}
|
||||
}
|
||||
|
||||
void PathFinder::build(const std::vector<ObstacleMesh>& obstacleMeshes,
|
||||
@ -120,8 +74,8 @@ std::vector<Eigen::Vector3f> PathFinder::findPath(const Eigen::Vector3f& start,
|
||||
|
||||
Cell startCell;
|
||||
Cell endCell;
|
||||
if (!findNearestWalkableCell(start, startCell, walkable) ||
|
||||
!findNearestWalkableCell(end, endCell, walkable)) {
|
||||
if (!findNearestWalkableCell(start, startCell) ||
|
||||
!findNearestWalkableCell(end, endCell)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -167,7 +121,7 @@ std::vector<Eigen::Vector3f> PathFinder::findPath(const Eigen::Vector3f& start,
|
||||
|
||||
for (const auto& offset : offsets) {
|
||||
Cell next{ currentCell.x + offset[0], currentCell.z + offset[1] };
|
||||
if (!isCellWalkable(next, walkable)) {
|
||||
if (!isCellWalkable(next)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -175,7 +129,7 @@ std::vector<Eigen::Vector3f> PathFinder::findPath(const Eigen::Vector3f& start,
|
||||
if (diagonal) {
|
||||
Cell horizontal{ currentCell.x + offset[0], currentCell.z };
|
||||
Cell vertical{ currentCell.x, currentCell.z + offset[1] };
|
||||
if (!isCellWalkable(horizontal, walkable) || !isCellWalkable(vertical, walkable)) {
|
||||
if (!isCellWalkable(horizontal) || !isCellWalkable(vertical)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -206,161 +160,7 @@ std::vector<Eigen::Vector3f> PathFinder::findPath(const Eigen::Vector3f& start,
|
||||
}
|
||||
}
|
||||
std::reverse(cells.begin(), cells.end());
|
||||
cells = smoothCells(cells, walkable);
|
||||
|
||||
std::vector<Eigen::Vector3f> path;
|
||||
path.reserve(cells.size());
|
||||
for (const Cell& cell : cells) {
|
||||
path.push_back(cellCenter(cell));
|
||||
}
|
||||
|
||||
if (!path.empty() && (path.front() - Eigen::Vector3f(start.x(), floorY, start.z())).norm() < cellSize * 0.75f) {
|
||||
path.erase(path.begin());
|
||||
}
|
||||
|
||||
if (!path.empty()) {
|
||||
Cell requestedEndCell;
|
||||
if (worldToCell(end, requestedEndCell) &&
|
||||
requestedEndCell.x == endCell.x &&
|
||||
requestedEndCell.z == endCell.z) {
|
||||
path.back() = Eigen::Vector3f(end.x(), floorY, end.z());
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
std::vector<Eigen::Vector3f> PathFinder::findPath(const Eigen::Vector3f& start,
|
||||
const Eigen::Vector3f& end,
|
||||
const std::vector<DynamicObstacle>& dynamicObstacles) const
|
||||
{
|
||||
if (!ready || walkable.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<unsigned char> walkableGrid = walkable;
|
||||
if (!dynamicObstacles.empty()) {
|
||||
for (const DynamicObstacle& obstacle : dynamicObstacles) {
|
||||
const float radius = obstacle.radius + agentRadius;
|
||||
if (radius <= 0.0f) continue;
|
||||
|
||||
const float minWorldX = obstacle.position.x() - radius;
|
||||
const float maxWorldX = obstacle.position.x() + radius;
|
||||
const float minWorldZ = obstacle.position.z() - radius;
|
||||
const float maxWorldZ = obstacle.position.z() + radius;
|
||||
|
||||
const int minCellX = (std::max)(0, static_cast<int>(std::floor((minWorldX - minX) / cellSize)));
|
||||
const int maxCellX = (std::min)(gridWidth - 1, static_cast<int>(std::floor((maxWorldX - minX) / cellSize)));
|
||||
const int minCellZ = (std::max)(0, static_cast<int>(std::floor((minWorldZ - minZ) / cellSize)));
|
||||
const int maxCellZ = (std::min)(gridDepth - 1, static_cast<int>(std::floor((maxWorldZ - minZ) / cellSize)));
|
||||
|
||||
const float radiusSq = radius * radius;
|
||||
for (int z = minCellZ; z <= maxCellZ; ++z) {
|
||||
for (int x = minCellX; x <= maxCellX; ++x) {
|
||||
const Cell cell{ x, z };
|
||||
const Eigen::Vector3f center = cellCenter(cell);
|
||||
const float dx = center.x() - obstacle.position.x();
|
||||
const float dz = center.z() - obstacle.position.z();
|
||||
if (dx * dx + dz * dz <= radiusSq) {
|
||||
const int idx = indexOf(cell);
|
||||
if (idx >= 0 && idx < static_cast<int>(walkableGrid.size())) {
|
||||
walkableGrid[static_cast<size_t>(idx)] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cell startCell;
|
||||
Cell endCell;
|
||||
if (!findNearestWalkableCell(start, startCell, walkableGrid) ||
|
||||
!findNearestWalkableCell(end, endCell, walkableGrid)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (startCell.x == endCell.x && startCell.z == endCell.z) {
|
||||
return { cellCenter(endCell) };
|
||||
}
|
||||
|
||||
struct QueueNode {
|
||||
int index = 0;
|
||||
float priority = 0.0f;
|
||||
|
||||
bool operator<(const QueueNode& other) const
|
||||
{
|
||||
return priority > other.priority;
|
||||
}
|
||||
};
|
||||
|
||||
const int cellCount = gridWidth * gridDepth;
|
||||
std::vector<float> cost(static_cast<size_t>(cellCount), INF_COST);
|
||||
std::vector<int> cameFrom(static_cast<size_t>(cellCount), -1);
|
||||
std::priority_queue<QueueNode> open;
|
||||
|
||||
const int startIndex = indexOf(startCell);
|
||||
const int endIndex = indexOf(endCell);
|
||||
|
||||
cost[static_cast<size_t>(startIndex)] = 0.0f;
|
||||
open.push({ startIndex, 0.0f });
|
||||
|
||||
static const int offsets[8][2] = {
|
||||
{ 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 },
|
||||
{ 1, 1 }, { 1, -1 }, { -1, 1 }, { -1, -1 }
|
||||
};
|
||||
|
||||
while (!open.empty()) {
|
||||
const QueueNode current = open.top();
|
||||
open.pop();
|
||||
|
||||
if (current.index == endIndex) {
|
||||
break;
|
||||
}
|
||||
|
||||
const Cell currentCell{ current.index % gridWidth, current.index / gridWidth };
|
||||
|
||||
for (const auto& offset : offsets) {
|
||||
Cell next{ currentCell.x + offset[0], currentCell.z + offset[1] };
|
||||
if (!isCellWalkable(next, walkableGrid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool diagonal = offset[0] != 0 && offset[1] != 0;
|
||||
if (diagonal) {
|
||||
Cell horizontal{ currentCell.x + offset[0], currentCell.z };
|
||||
Cell vertical{ currentCell.x, currentCell.z + offset[1] };
|
||||
if (!isCellWalkable(horizontal, walkableGrid) || !isCellWalkable(vertical, walkableGrid)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const int nextIndex = indexOf(next);
|
||||
const float stepCost = diagonal ? 1.41421356f : 1.0f;
|
||||
const float newCost = cost[static_cast<size_t>(current.index)] + stepCost;
|
||||
if (newCost >= cost[static_cast<size_t>(nextIndex)]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cost[static_cast<size_t>(nextIndex)] = newCost;
|
||||
cameFrom[static_cast<size_t>(nextIndex)] = current.index;
|
||||
const float priority = newCost + distanceCells(next, endCell);
|
||||
open.push({ nextIndex, priority });
|
||||
}
|
||||
}
|
||||
|
||||
if (cameFrom[static_cast<size_t>(endIndex)] == -1) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<Cell> cells;
|
||||
for (int current = endIndex; current != -1; current = cameFrom[static_cast<size_t>(current)]) {
|
||||
cells.push_back({ current % gridWidth, current / gridWidth });
|
||||
if (current == startIndex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::reverse(cells.begin(), cells.end());
|
||||
cells = smoothCells(cells, walkableGrid);
|
||||
cells = smoothCells(cells);
|
||||
|
||||
std::vector<Eigen::Vector3f> path;
|
||||
path.reserve(cells.size());
|
||||
@ -406,7 +206,7 @@ bool PathFinder::setAreaAvailable(const std::string& areaName, bool available)
|
||||
bool PathFinder::isWalkable(const Eigen::Vector3f& point) const
|
||||
{
|
||||
Cell cell;
|
||||
return worldToCell(point, cell) && isCellWalkable(cell, walkable);
|
||||
return worldToCell(point, cell) && isCellWalkable(cell);
|
||||
}
|
||||
|
||||
void PathFinder::loadConfig(const std::string& configPath, const std::string& zipPath)
|
||||
@ -415,9 +215,7 @@ void PathFinder::loadConfig(const std::string& configPath, const std::string& zi
|
||||
agentRadius = 0.45f;
|
||||
floorY = 0.0f;
|
||||
objectPadding = 0.25f;
|
||||
boundaryPadding = 0.0f;
|
||||
areas.clear();
|
||||
obstaclePolygons.clear();
|
||||
|
||||
try {
|
||||
std::string content;
|
||||
@ -438,7 +236,6 @@ void PathFinder::loadConfig(const std::string& configPath, const std::string& zi
|
||||
agentRadius = root.value("agentRadius", agentRadius);
|
||||
floorY = root.value("floorY", floorY);
|
||||
objectPadding = root.value("objectPadding", objectPadding);
|
||||
boundaryPadding = root.value("boundaryPadding", boundaryPadding);
|
||||
|
||||
if (!root.contains("areas") || !root["areas"].is_array()) {
|
||||
std::cerr << "[nav] Navigation config has no 'areas' array: " << configPath << "\n";
|
||||
@ -462,18 +259,6 @@ void PathFinder::loadConfig(const std::string& configPath, const std::string& zi
|
||||
|
||||
areas.push_back(area);
|
||||
}
|
||||
|
||||
if (root.contains("obstacles") && root["obstacles"].is_array()) {
|
||||
for (const auto& item : root["obstacles"]) {
|
||||
ObstaclePolygon obstacle;
|
||||
obstacle.name = item.value("name", "");
|
||||
obstacle.polygon = readPolygon(item);
|
||||
if (obstacle.polygon.size() < 3) {
|
||||
continue;
|
||||
}
|
||||
obstaclePolygons.push_back(std::move(obstacle));
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "[nav] Failed to load config '" << configPath << "': " << e.what() << "\n";
|
||||
}
|
||||
@ -481,7 +266,6 @@ void PathFinder::loadConfig(const std::string& configPath, const std::string& zi
|
||||
cellSize = (std::max)(cellSize, 0.1f);
|
||||
agentRadius = (std::max)(agentRadius, 0.0f);
|
||||
objectPadding = (std::max)(objectPadding, 0.0f);
|
||||
boundaryPadding = (std::max)(boundaryPadding, 0.0f);
|
||||
}
|
||||
|
||||
void PathFinder::resetGridBounds()
|
||||
@ -520,12 +304,6 @@ void PathFinder::resetGridBounds()
|
||||
}
|
||||
}
|
||||
|
||||
for (const ObstaclePolygon& obstacle : obstaclePolygons) {
|
||||
for (const Eigen::Vector2f& point : obstacle.polygon) {
|
||||
includePoint(point.x(), point.y());
|
||||
}
|
||||
}
|
||||
|
||||
const float padding = cellSize * 2.0f + agentRadius + objectPadding;
|
||||
minX -= padding;
|
||||
minZ -= padding;
|
||||
@ -541,75 +319,20 @@ void PathFinder::rebuildWalkableGrid()
|
||||
walkable.assign(static_cast<size_t>(gridWidth * gridDepth), 0);
|
||||
markAvailableAreasWalkable();
|
||||
markObstacleMeshesBlocked();
|
||||
markObstaclePolygonsBlocked();
|
||||
}
|
||||
|
||||
void PathFinder::markAvailableAreasWalkable()
|
||||
{
|
||||
const auto insideAvailableArea = [this](const Eigen::Vector2f& point) {
|
||||
for (const NavigationArea& area : areas) {
|
||||
if (!area.available) {
|
||||
continue;
|
||||
}
|
||||
if (pointInPolygon(point.x(), point.y(), area.polygon)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const auto externalBoundaryDistance = [this, &insideAvailableArea](const Eigen::Vector2f& point) {
|
||||
if (boundaryPadding <= 0.0f) {
|
||||
return (std::numeric_limits<float>::max)();
|
||||
}
|
||||
|
||||
const float sampleOffset = (std::max)(cellSize * 0.25f, 0.05f);
|
||||
float best = (std::numeric_limits<float>::max)();
|
||||
|
||||
for (const NavigationArea& area : areas) {
|
||||
if (!area.available || area.polygon.size() < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < area.polygon.size(); ++i) {
|
||||
const Eigen::Vector2f& a = area.polygon[i];
|
||||
const Eigen::Vector2f& b = area.polygon[(i + 1) % area.polygon.size()];
|
||||
const Eigen::Vector2f edge = b - a;
|
||||
if (edge.squaredNorm() <= 1e-8f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Eigen::Vector2f closest = closestPointOnSegment2D(point, a, b);
|
||||
Eigen::Vector2f normal(-edge.y(), edge.x());
|
||||
normal.normalize();
|
||||
|
||||
const bool sideAInside = insideAvailableArea(closest + normal * sampleOffset);
|
||||
const bool sideBInside = insideAvailableArea(closest - normal * sampleOffset);
|
||||
if (sideAInside && sideBInside) {
|
||||
continue;
|
||||
}
|
||||
|
||||
best = (std::min)(best, distancePointToSegment2D(point, a, b));
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
};
|
||||
|
||||
for (int z = 0; z < gridDepth; ++z) {
|
||||
for (int x = 0; x < gridWidth; ++x) {
|
||||
const Cell cell{ x, z };
|
||||
const Eigen::Vector3f center = cellCenter(cell);
|
||||
const Eigen::Vector2f point(center.x(), center.z());
|
||||
|
||||
for (const NavigationArea& area : areas) {
|
||||
if (!area.available) {
|
||||
continue;
|
||||
}
|
||||
if (pointInPolygon(center.x(), center.z(), area.polygon)) {
|
||||
if (boundaryPadding > 0.0f && externalBoundaryDistance(point) < boundaryPadding) {
|
||||
continue;
|
||||
}
|
||||
walkable[static_cast<size_t>(indexOf(cell))] = 1;
|
||||
break;
|
||||
}
|
||||
@ -618,51 +341,8 @@ void PathFinder::markAvailableAreasWalkable()
|
||||
}
|
||||
}
|
||||
|
||||
void PathFinder::markObstaclePolygonsBlocked()
|
||||
{
|
||||
if (obstaclePolygons.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float padding = agentRadius + objectPadding;
|
||||
|
||||
for (int z = 0; z < gridDepth; ++z) {
|
||||
for (int x = 0; x < gridWidth; ++x) {
|
||||
const Cell cell{ x, z };
|
||||
const int idx = indexOf(cell);
|
||||
if (idx < 0 || idx >= static_cast<int>(walkable.size())) {
|
||||
continue;
|
||||
}
|
||||
if (!walkable[static_cast<size_t>(idx)]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Eigen::Vector3f center3 = cellCenter(cell);
|
||||
const Eigen::Vector2f center(center3.x(), center3.z());
|
||||
|
||||
for (const ObstaclePolygon& obstacle : obstaclePolygons) {
|
||||
if (pointInPolygon(center.x(), center.y(), obstacle.polygon)) {
|
||||
walkable[static_cast<size_t>(idx)] = 0;
|
||||
break;
|
||||
}
|
||||
if (padding > 0.0f &&
|
||||
distancePointToPolygonEdges(center, obstacle.polygon) <= padding) {
|
||||
walkable[static_cast<size_t>(idx)] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PathFinder::markObstacleMeshesBlocked()
|
||||
{
|
||||
if (!obstaclePolygons.empty()) {
|
||||
// Prefer JSON-defined obstacle polygons over mesh-derived blockers.
|
||||
// Mesh blockers tend to over-block (e.g. tree crowns) and are harder to author/tune.
|
||||
return;
|
||||
}
|
||||
|
||||
const float padding = agentRadius + objectPadding;
|
||||
|
||||
for (const ObstacleMesh& obstacle : obstacles) {
|
||||
@ -726,16 +406,7 @@ bool PathFinder::isInsideGrid(const Cell& cell) const
|
||||
|
||||
bool PathFinder::isCellWalkable(const Cell& cell) const
|
||||
{
|
||||
return isCellWalkable(cell, walkable);
|
||||
}
|
||||
|
||||
bool PathFinder::isCellWalkable(const Cell& cell, const std::vector<unsigned char>& walkableGrid) const
|
||||
{
|
||||
const int idx = indexOf(cell);
|
||||
return isInsideGrid(cell) &&
|
||||
idx >= 0 &&
|
||||
idx < static_cast<int>(walkableGrid.size()) &&
|
||||
walkableGrid[static_cast<size_t>(idx)] != 0;
|
||||
return isInsideGrid(cell) && walkable[static_cast<size_t>(indexOf(cell))] != 0;
|
||||
}
|
||||
|
||||
int PathFinder::indexOf(const Cell& cell) const
|
||||
@ -744,11 +415,6 @@ int PathFinder::indexOf(const Cell& cell) const
|
||||
}
|
||||
|
||||
bool PathFinder::findNearestWalkableCell(const Eigen::Vector3f& point, Cell& out) const
|
||||
{
|
||||
return findNearestWalkableCell(point, out, walkable);
|
||||
}
|
||||
|
||||
bool PathFinder::findNearestWalkableCell(const Eigen::Vector3f& point, Cell& out, const std::vector<unsigned char>& walkableGrid) const
|
||||
{
|
||||
Cell origin;
|
||||
if (!worldToCell(point, origin)) {
|
||||
@ -758,7 +424,7 @@ bool PathFinder::findNearestWalkableCell(const Eigen::Vector3f& point, Cell& out
|
||||
origin.z = (std::min)((std::max)(z, 0), gridDepth - 1);
|
||||
}
|
||||
|
||||
if (isCellWalkable(origin, walkableGrid)) {
|
||||
if (isCellWalkable(origin)) {
|
||||
out = origin;
|
||||
return true;
|
||||
}
|
||||
@ -772,7 +438,7 @@ bool PathFinder::findNearestWalkableCell(const Eigen::Vector3f& point, Cell& out
|
||||
}
|
||||
|
||||
Cell candidate{ origin.x + dx, origin.z + dz };
|
||||
if (isCellWalkable(candidate, walkableGrid)) {
|
||||
if (isCellWalkable(candidate)) {
|
||||
out = candidate;
|
||||
return true;
|
||||
}
|
||||
@ -784,11 +450,6 @@ bool PathFinder::findNearestWalkableCell(const Eigen::Vector3f& point, Cell& out
|
||||
}
|
||||
|
||||
bool PathFinder::hasLineOfSight(const Cell& from, const Cell& to) const
|
||||
{
|
||||
return hasLineOfSight(from, to, walkable);
|
||||
}
|
||||
|
||||
bool PathFinder::hasLineOfSight(const Cell& from, const Cell& to, const std::vector<unsigned char>& walkableGrid) const
|
||||
{
|
||||
const Eigen::Vector3f a = cellCenter(from);
|
||||
const Eigen::Vector3f b = cellCenter(to);
|
||||
@ -799,7 +460,7 @@ bool PathFinder::hasLineOfSight(const Cell& from, const Cell& to, const std::vec
|
||||
const float t = static_cast<float>(i) / static_cast<float>(steps);
|
||||
const Eigen::Vector3f p = a * (1.0f - t) + b * t;
|
||||
Cell cell;
|
||||
if (!worldToCell(p, cell) || !isCellWalkable(cell, walkableGrid)) {
|
||||
if (!worldToCell(p, cell) || !isCellWalkable(cell)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -808,11 +469,6 @@ bool PathFinder::hasLineOfSight(const Cell& from, const Cell& to, const std::vec
|
||||
}
|
||||
|
||||
std::vector<PathFinder::Cell> PathFinder::smoothCells(const std::vector<Cell>& cells) const
|
||||
{
|
||||
return smoothCells(cells, walkable);
|
||||
}
|
||||
|
||||
std::vector<PathFinder::Cell> PathFinder::smoothCells(const std::vector<Cell>& cells, const std::vector<unsigned char>& walkableGrid) const
|
||||
{
|
||||
if (cells.size() <= 2) {
|
||||
return cells;
|
||||
@ -824,7 +480,7 @@ std::vector<PathFinder::Cell> PathFinder::smoothCells(const std::vector<Cell>& c
|
||||
|
||||
while (anchor < cells.size() - 1) {
|
||||
size_t next = cells.size() - 1;
|
||||
while (next > anchor + 1 && !hasLineOfSight(cells[anchor], cells[next], walkableGrid)) {
|
||||
while (next > anchor + 1 && !hasLineOfSight(cells[anchor], cells[next])) {
|
||||
--next;
|
||||
}
|
||||
|
||||
|
||||
@ -14,16 +14,6 @@ public:
|
||||
Eigen::Vector3f offset = Eigen::Vector3f::Zero();
|
||||
};
|
||||
|
||||
struct ObstaclePolygon {
|
||||
std::string name;
|
||||
std::vector<Eigen::Vector2f> polygon;
|
||||
};
|
||||
|
||||
struct DynamicObstacle {
|
||||
Eigen::Vector3f position = Eigen::Vector3f::Zero();
|
||||
float radius = 0.0f;
|
||||
};
|
||||
|
||||
struct Cell {
|
||||
int x = 0;
|
||||
int z = 0;
|
||||
@ -42,10 +32,6 @@ public:
|
||||
std::vector<Eigen::Vector3f> findPath(const Eigen::Vector3f& start,
|
||||
const Eigen::Vector3f& end) const;
|
||||
|
||||
std::vector<Eigen::Vector3f> findPath(const Eigen::Vector3f& start,
|
||||
const Eigen::Vector3f& end,
|
||||
const std::vector<DynamicObstacle>& dynamicObstacles) const;
|
||||
|
||||
bool setAreaAvailable(const std::string& areaName, bool available);
|
||||
bool isReady() const { return ready; }
|
||||
bool isWalkable(const Eigen::Vector3f& point) const;
|
||||
@ -58,7 +44,6 @@ private:
|
||||
float agentRadius = 0.45f;
|
||||
float floorY = 0.0f;
|
||||
float objectPadding = 0.25f;
|
||||
float boundaryPadding = 0.0f;
|
||||
|
||||
float minX = 0.0f;
|
||||
float minZ = 0.0f;
|
||||
@ -69,7 +54,6 @@ private:
|
||||
std::string loadedConfigPath;
|
||||
std::string loadedZipPath;
|
||||
std::vector<ObstacleMesh> obstacles;
|
||||
std::vector<ObstaclePolygon> obstaclePolygons;
|
||||
std::vector<unsigned char> walkable;
|
||||
std::vector<NavigationArea> areas;
|
||||
|
||||
@ -78,7 +62,6 @@ private:
|
||||
void rebuildWalkableGrid();
|
||||
void markAvailableAreasWalkable();
|
||||
void markObstacleMeshesBlocked();
|
||||
void markObstaclePolygonsBlocked();
|
||||
|
||||
bool worldToCell(const Eigen::Vector3f& point, Cell& out) const;
|
||||
Eigen::Vector3f cellCenter(const Cell& cell) const;
|
||||
@ -91,11 +74,6 @@ private:
|
||||
std::vector<Cell> smoothCells(const std::vector<Cell>& cells) const;
|
||||
|
||||
static bool pointInPolygon(float x, float z, const std::vector<Eigen::Vector2f>& polygon);
|
||||
|
||||
bool isCellWalkable(const Cell& cell, const std::vector<unsigned char>& walkableGrid) const;
|
||||
bool findNearestWalkableCell(const Eigen::Vector3f& point, Cell& out, const std::vector<unsigned char>& walkableGrid) const;
|
||||
bool hasLineOfSight(const Cell& from, const Cell& to, const std::vector<unsigned char>& walkableGrid) const;
|
||||
std::vector<Cell> smoothCells(const std::vector<Cell>& cells, const std::vector<unsigned char>& walkableGrid) const;
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
|
||||
@ -9,9 +9,10 @@ namespace ZL {
|
||||
GLuint fbo = 0;
|
||||
GLuint textureID = 0;
|
||||
int width, height;
|
||||
bool useMipmaps;
|
||||
bool useMipmaps; // <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>-<2D><><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
public:
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> false
|
||||
FrameBuffer(int w, int h, bool useMipmaps = false);
|
||||
~FrameBuffer();
|
||||
|
||||
@ -21,6 +22,7 @@ namespace ZL {
|
||||
void Bind();
|
||||
void Unbind();
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>-<2D><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
void GenerateMipmaps();
|
||||
|
||||
GLuint getTextureID() const { return textureID; }
|
||||
|
||||
@ -14,6 +14,8 @@ namespace ZL {
|
||||
GLuint shaderProgram;
|
||||
|
||||
std::unordered_map<std::string, GLuint> uniformList;
|
||||
|
||||
//std::unordered_map<std::string, std::pair<bool, size_t>> UniformList;
|
||||
std::map<std::string, GLuint> attribList;
|
||||
|
||||
|
||||
|
||||
@ -298,6 +298,34 @@ bool TextRenderer::loadGlyphs(const std::string& ttfPath, int pixelSize, const s
|
||||
rowHeight = max(rowHeight, gb.height);
|
||||
}
|
||||
|
||||
// // Проходим по стандартным ASCII символам
|
||||
// for (unsigned char c = 32; c < 128; ++c) {
|
||||
//
|
||||
// FT_Load_Char(face, c, FT_LOAD_RENDER);
|
||||
|
||||
// TextureDataStruct glyphData;
|
||||
// glyphData.width = face->glyph->bitmap.width;
|
||||
// glyphData.height = face->glyph->bitmap.rows;
|
||||
// glyphData.format = TextureDataStruct::R8;
|
||||
// glyphData.mipmap = TextureDataStruct::NONE;
|
||||
|
||||
// // Копируем буфер FreeType в вектор данных
|
||||
// size_t dataSize = glyphData.width * glyphData.height;
|
||||
// glyphData.data.assign(face->glyph->bitmap.buffer, face->glyph->bitmap.buffer + dataSize);
|
||||
|
||||
// // Теперь создание текстуры — это одна строка!
|
||||
// auto tex = std::make_shared<Texture>(glyphData);
|
||||
|
||||
//GlyphInfo g;
|
||||
// g.texture = tex;
|
||||
// g.size = Eigen::Vector2f((float)face->glyph->bitmap.width, (float)face->glyph->bitmap.rows);
|
||||
// g.bearing = Eigen::Vector2f((float)face->glyph->bitmap_left, (float)face->glyph->bitmap_top);
|
||||
// // Advance во FreeType измеряется в 1/64 пикселя
|
||||
// g.advance = (unsigned int)face->glyph->advance.x;
|
||||
|
||||
// glyphs.emplace((char)c, g);
|
||||
// }
|
||||
|
||||
// Создаём Texture из atlasData (R8)
|
||||
TextureDataStruct atlasTex;
|
||||
atlasTex.width = atlasWidth;
|
||||
@ -438,9 +466,12 @@ void TextRenderer::drawText(const std::string& text, float x, float y, float sca
|
||||
// Примечание: для текста лучше использовать GL_DYNAMIC_DRAW,
|
||||
// но RefreshVBO сейчас жестко зашит на GL_STATIC_DRAW.
|
||||
// Для UI это обычно не критично, если строк не тысячи.
|
||||
// textMesh.AssignFrom(textData);
|
||||
|
||||
// 4. Рендеринг
|
||||
r->shaderManager.PushShader(shaderName);
|
||||
//r->PushMatrix();
|
||||
//r->LoadIdentity();
|
||||
|
||||
// Матрица проекции — используем виртуальные проекционные размеры,
|
||||
// чтобы координаты текста были независимы от физического разрешения экрана.
|
||||
@ -467,7 +498,24 @@ void TextRenderer::drawText(const std::string& text, float x, float y, float sca
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
//for (size_t i = 0; i < text.length(); ++i) {
|
||||
// auto it = glyphs.find(text[i]);
|
||||
// if (it == glyphs.end()) continue;
|
||||
|
||||
// glBindTexture(GL_TEXTURE_2D, it->second.texture->getTexID());
|
||||
|
||||
// // Отрисовываем по 6 вершин за раз
|
||||
// // Нам нужно вручную биндить VBO, так как DrawVertexRenderStruct рисует всё сразу
|
||||
// glBindBuffer(GL_ARRAY_BUFFER, textMesh.positionVBO->getBuffer());
|
||||
// r->VertexAttribPointer3fv("vPosition", 0, (const char*)(i * 6 * sizeof(Vector3f)));
|
||||
|
||||
// glBindBuffer(GL_ARRAY_BUFFER, textMesh.texCoordVBO->getBuffer());
|
||||
// r->VertexAttribPointer2fv("vTexCoord", 0, (const char*)(i * 6 * sizeof(Vector2f)));
|
||||
|
||||
// glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
//}
|
||||
r->DrawVertexRenderStruct(cached.mesh);
|
||||
//r->PopMatrix();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
namespace ZL {
|
||||
|
||||
struct GlyphInfo {
|
||||
// std::shared_ptr<Texture> texture; // Texture for glyph
|
||||
Eigen::Vector2f uv; // u,v координата левого верхнего угла в атласе (0..1)
|
||||
Eigen::Vector2f uvSize; // ширина/высота в UV (0..1)
|
||||
|
||||
@ -41,6 +42,10 @@ private:
|
||||
|
||||
std::unordered_map<uint32_t, GlyphInfo> glyphs;
|
||||
|
||||
// OpenGL objects for a dynamic quad
|
||||
//unsigned int vao = 0;
|
||||
//unsigned int vbo = 0;
|
||||
|
||||
// единый атлас для всех глифов
|
||||
std::shared_ptr<Texture> atlasTexture;
|
||||
size_t atlasWidth = 0;
|
||||
|
||||
73
src/utils/Perlin.cpp
Normal file
73
src/utils/Perlin.cpp
Normal file
@ -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(Eigen::Vector3f pos, float noiseCoeff) {
|
||||
// Частота шума (чем больше, тем больше "холмов")
|
||||
float frequency = 7.0f;
|
||||
|
||||
// Получаем значение шума (обычно от -1 до 1)
|
||||
float noiseValue = noise(pos(0) * frequency, pos(1) * frequency, pos(2) * frequency);
|
||||
|
||||
// Масштабируем: хотим отклонение от 1.0 до 1.1 (примерно)
|
||||
float height = 1.0f + (noiseValue * noiseCoeff);
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
24
src/utils/Perlin.h
Normal file
24
src/utils/Perlin.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <Eigen/Dense>
|
||||
|
||||
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(Eigen::Vector3f pos, float noiseCoeff);
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
Loading…
Reference in New Issue
Block a user