Compare commits
3 Commits
272e202774
...
cd91174f5d
| Author | SHA1 | Date | |
|---|---|---|---|
| cd91174f5d | |||
| 4b24d85123 | |||
| f86e7fd96c |
@@ -77,6 +77,7 @@ add_subdirectory(src/tests)
|
||||
add_subdirectory(src/physics)
|
||||
add_subdirectory(src/editor)
|
||||
add_subdirectory(assets/blender/buildings/parts)
|
||||
add_subdirectory(resources)
|
||||
|
||||
add_executable(Game Game.cpp ${WATER_SRC})
|
||||
target_include_directories(Game PRIVATE src/gamedata)
|
||||
@@ -203,34 +204,8 @@ add_custom_target(stage_stories ALL DEPENDS stage_lua_scripts ${CMAKE_BINARY_DIR
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_BINARY_DIR}/resources.cfg
|
||||
COMMAND cp ${CMAKE_SOURCE_DIR}/resources.cfg ${CMAKE_BINARY_DIR}/resources.cfg
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/resources/main
|
||||
${CMAKE_BINARY_DIR}/resources/main
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/resources/shaderlib
|
||||
${CMAKE_BINARY_DIR}/resources/shaderlib
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/resources/terrain
|
||||
${CMAKE_BINARY_DIR}/resources/terrain
|
||||
# COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/lua-scripts
|
||||
# ${CMAKE_BINARY_DIR}/lua-scripts
|
||||
# COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/skybox
|
||||
# ${CMAKE_BINARY_DIR}/skybox
|
||||
# COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/resources/debug
|
||||
# ${CMAKE_BINARY_DIR}/resources/debug
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/resources.cfg ${CMAKE_BINARY_DIR}/resources.cfg
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/resources.cfg)
|
||||
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/resources/terrain/world_map.png
|
||||
COMMAND unzip -o ${CMAKE_SOURCE_DIR}/world_map.kra mergedimage.png -d ${CMAKE_BINARY_DIR}/world_map
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_BINARY_DIR}/world_map/mergedimage.png
|
||||
${CMAKE_BINARY_DIR}/resources/terrain/world_map.png
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/world_map
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/world_map.kra)
|
||||
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/resources/terrain/brushes.png
|
||||
COMMAND unzip -o ${CMAKE_SOURCE_DIR}/brushes.kra mergedimage.png -d ${CMAKE_BINARY_DIR}/brushes
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_BINARY_DIR}/brushes/mergedimage.png
|
||||
${CMAKE_BINARY_DIR}/resources/terrain/brushes.png
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/brushes
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/brushes.kra)
|
||||
|
||||
set(SKYBOX_SRC
|
||||
early_morning_bk.jpg
|
||||
@@ -356,29 +331,11 @@ add_custom_command(
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${CHARACTER_GLBS}
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_models.py ${VRM_IMPORTED_BLENDS} ${EDITED_BLEND_TARGETS}
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
#add_custom_command(
|
||||
# OUTPUT ${CMAKE_SOURCE_DIR}/characters/female/vroid-normal-female.scene
|
||||
# ${CMAKE_SOURCE_DIR}/characters/male/vroid-normal-male.scene
|
||||
# ${CMAKE_SOURCE_DIR}/assets/blender/vrm-vroid-normal-female.blend
|
||||
# ${CMAKE_SOURCE_DIR}/assets/blender/vrm-vroid-normal-male.blend
|
||||
# ${CMAKE_SOURCE_DIR}/assets/blender/shapes/male/vrm-vroid-normal-male-chibi.blend
|
||||
# COMMAND mkdir -p ${CREATE_DIRECTORIES}
|
||||
# COMMAND ${BLENDER} -b -Y -P ${CMAKE_SOURCE_DIR}/assets/blender/scripts/import_vrm.py
|
||||
# COMMAND ${BLENDER} -b -Y -P ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_models.py
|
||||
## COMMAND ${BLENDER} -b -Y -P ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_ogre_scene.py
|
||||
# COMMAND echo rm -Rf ${CMAKE_SOURCE_DIR}/characters/male/*.material ${CMAKE_SOURCE_DIR}/characters/female/*.material
|
||||
# COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/characters
|
||||
# ${CMAKE_BINARY_DIR}/characters
|
||||
# DEPENDS ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_models.py ${CMAKE_SOURCE_DIR}/assets/blender/scripts/import_vrm.py
|
||||
# ${CMAKE_SOURCE_DIR}/assets/vroid/buch1.vrm
|
||||
# ${CMAKE_SOURCE_DIR}/assets/vroid/buch1-chibi.vrm
|
||||
# ${CMAKE_SOURCE_DIR}/assets/vroid/jane2-dress.vrm
|
||||
# WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
|
||||
add_custom_target(stage_files ALL DEPENDS ${CMAKE_BINARY_DIR}/resources.cfg ${MATERIALS_OUTPUT}
|
||||
${CMAKE_BINARY_DIR}/resources/terrain/world_map.png
|
||||
${CMAKE_BINARY_DIR}/resources/terrain/brushes.png
|
||||
edited-blends)
|
||||
edited-blends stage_resources)
|
||||
|
||||
add_custom_target(remove_scenes COMMAND rm -f ${VRM_SOURCE} ${VRM_IMPORTED_BLENDS} ${CHARACTER_GLBS})
|
||||
|
||||
|
||||
38
Game.cpp
38
Game.cpp
@@ -15,7 +15,7 @@
|
||||
#include "Components.h"
|
||||
#include "CharacterModule.h"
|
||||
#include "TerrainModule.h"
|
||||
#include "GUIModule.h"
|
||||
#include "GUIModuleCommon.h"
|
||||
#include "AppModule.h"
|
||||
#include "sound.h"
|
||||
class App;
|
||||
@@ -236,15 +236,14 @@ public:
|
||||
else if (key == 'f')
|
||||
control |= 64;
|
||||
if (key == 'w' || key == 'a' || key == 's' || key == 'd' ||
|
||||
key == 'e' || key == OgreBites::SDLK_LSHIFT)
|
||||
key == 'e' || key == OgreBites::SDLK_LSHIFT || key == 'e' ||
|
||||
key == 'f')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool keyReleased(const OgreBites::KeyboardEvent &evt) override
|
||||
{
|
||||
OgreBites::Keycode key = evt.keysym.sym;
|
||||
if (isGuiEnabled())
|
||||
return false;
|
||||
if (key == 'w')
|
||||
control &= ~1;
|
||||
else if (key == 'a')
|
||||
@@ -255,8 +254,14 @@ public:
|
||||
control &= ~8;
|
||||
else if (key == OgreBites::SDLK_LSHIFT)
|
||||
control &= ~16;
|
||||
if (key == 'w' || key == 'a' || key == 's' || key == 'd' ||
|
||||
key == OgreBites::SDLK_LSHIFT)
|
||||
else if (key == 'e')
|
||||
control &= ~32;
|
||||
else if (key == 'f')
|
||||
control &= ~64;
|
||||
if (isGuiEnabled())
|
||||
return false;
|
||||
if (key == 'w' || key == 'a' || key == 's' || key == 'd' ||
|
||||
key == OgreBites::SDLK_LSHIFT || key == 'e' || key == 'f')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -474,14 +479,19 @@ public:
|
||||
mDynWorld->getBtWorld()->stepSimulation(delta, 3);
|
||||
#endif
|
||||
if (!ECS::get().has<ECS::GUI>())
|
||||
return;
|
||||
/* Update window grab */
|
||||
ECS::GUI &gui = ECS::get().get_mut<ECS::GUI>();
|
||||
if (gui.grabChanged) {
|
||||
setWindowGrab(gui.grab);
|
||||
gui.grabChanged = false;
|
||||
ECS::get().modified<ECS::GUI>();
|
||||
}
|
||||
goto end;
|
||||
{
|
||||
/* Update window grab */
|
||||
ECS::GUI &gui = ECS::get().get_mut<ECS::GUI>();
|
||||
if (gui.grabChanged) {
|
||||
setWindowGrab(gui.grab);
|
||||
gui.grabChanged = false;
|
||||
ECS::get().modified<ECS::GUI>();
|
||||
std::cout << "updateWorld " << gui.grabChanged
|
||||
<< " " << gui.grab << std::endl;
|
||||
}
|
||||
}
|
||||
end:
|
||||
ECS::update(delta);
|
||||
|
||||
#if 0
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
project(building-parts)
|
||||
set(PARTS_FILES pier.blend)
|
||||
set(FURNITURE_FILES furniture.blend furniture-sofa.blend)
|
||||
set(PARTS_OUTPUT_DIRS)
|
||||
foreach(PARTS_FILE ${PARTS_FILES})
|
||||
get_filename_component(FILE_NAME ${PARTS_FILE} NAME_WE)
|
||||
@@ -14,4 +15,17 @@ foreach(PARTS_FILE ${PARTS_FILES})
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${PARTS_FILE} ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_building_parts.py)
|
||||
list(APPEND PARTS_OUTPUT_DIRS ${PARTS_OUTPUT_DIR})
|
||||
endforeach()
|
||||
foreach(FURNITURE_FILE ${FURNITURE_FILES})
|
||||
get_filename_component(FILE_NAME ${FURNITURE_FILE} NAME_WE)
|
||||
set(PARTS_OUTPUT_DIR ${CMAKE_BINARY_DIR}/resources/buildings/parts/${FILE_NAME})
|
||||
add_custom_command(
|
||||
OUTPUT ${PARTS_OUTPUT_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${PARTS_OUTPUT_DIR}
|
||||
COMMAND ${BLENDER} ${CMAKE_CURRENT_SOURCE_DIR}/${FURNITURE_FILE}
|
||||
-b -Y -P
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/export_furniture_parts.py
|
||||
-- ${PARTS_OUTPUT_DIR}
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${PARTS_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/export_furniture_parts.py)
|
||||
list(APPEND PARTS_OUTPUT_DIRS ${PARTS_OUTPUT_DIR})
|
||||
endforeach()
|
||||
add_custom_target(import_building_parts ALL DEPENDS ${PARTS_OUTPUT_DIRS})
|
||||
|
||||
182
assets/blender/buildings/parts/export_furniture_parts.py
Normal file
182
assets/blender/buildings/parts/export_furniture_parts.py
Normal file
@@ -0,0 +1,182 @@
|
||||
import bpy
|
||||
import os, sys, time
|
||||
import json
|
||||
from mathutils import Matrix, Quaternion
|
||||
argv = sys.argv
|
||||
argv = argv[argv.index("--") + 1:]
|
||||
|
||||
incpath = os.path.dirname(__file__)
|
||||
|
||||
sys.path.insert(0, incpath)
|
||||
outdir = argv[0]
|
||||
|
||||
basis_change = Matrix((
|
||||
(1, 0, 0, 0),
|
||||
(0, 0, 1, 0),
|
||||
(0, -1, 0, 0),
|
||||
(0, 0, 0, 1)
|
||||
))
|
||||
|
||||
def export_root_objects_to_gltf(output_dir):
|
||||
# Ensure the output directory exists
|
||||
if not os.path.exists(output_dir):
|
||||
os.makedirs(output_dir)
|
||||
|
||||
# Deselect all objects
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
|
||||
# Iterate through all objects in the scene
|
||||
for obj in bpy.context.scene.objects:
|
||||
# Check if the object has no parent and has children
|
||||
# The original request specifies "objects having no parent with children".
|
||||
# This condition captures those that are explicitly root objects of a hierarchy.
|
||||
if obj.parent is None:
|
||||
# Select the root object and all its children
|
||||
|
||||
print(obj.name)
|
||||
if not obj.name.startswith("furniture-"):
|
||||
continue
|
||||
desc = {}
|
||||
desc["name"] = obj.name.replace("furniture-","")
|
||||
desc["mesh"] = obj.name + ".glb"
|
||||
if "furniture_tags" in obj:
|
||||
mtags = obj["furniture_tags"]
|
||||
if "," in mtags:
|
||||
atags = [m.strip() for m in mtags.split(",")]
|
||||
desc["tags"] = atags
|
||||
else:
|
||||
desc["tags"] = [mtags]
|
||||
else:
|
||||
desc["tags"] = []
|
||||
desc["sensors"] = []
|
||||
desc["actions"] = []
|
||||
desc["positions"] = []
|
||||
for child in obj.children:
|
||||
if child.name.startswith("action-"):
|
||||
if not "action" in child:
|
||||
continue
|
||||
if not "height" in child:
|
||||
continue
|
||||
if not "radius" in child:
|
||||
continue
|
||||
local_matrix = child.matrix_local
|
||||
ogre_local_matrix = basis_change @ local_matrix @ basis_change.inverted()
|
||||
local_pos_d = ogre_local_matrix.to_translation()
|
||||
local_rot_d = ogre_local_matrix.to_quaternion()
|
||||
local_pos = [round(x, 4) for x in local_pos_d]
|
||||
local_rot = [round(x, 4) for x in local_rot_d]
|
||||
action = {}
|
||||
action["position_x"] = local_pos[0]
|
||||
action["position_y"] = local_pos[1]
|
||||
action["position_z"] = local_pos[2]
|
||||
action["rotation_w"] = local_rot[0]
|
||||
action["rotation_x"] = local_rot[1]
|
||||
action["rotation_y"] = local_rot[2]
|
||||
action["rotation_z"] = local_rot[3]
|
||||
action["height"] = child["height"]
|
||||
action["radius"] = child["radius"]
|
||||
action["action"] = child["action"]
|
||||
if "action_text" in child:
|
||||
action["action_text"] = child["action_text"]
|
||||
else:
|
||||
action["action_text"] = child["action"].capitalize()
|
||||
if "name" in child:
|
||||
action["name"] = child["name"]
|
||||
else:
|
||||
action["name"] = desc["name"] + "_" + str(len(desc["actions"]))
|
||||
action["furniture"] = {}
|
||||
action["furniture"]["name"] = desc["name"]
|
||||
action["furniture"]["tags"] = desc["tags"]
|
||||
action["positions"] = []
|
||||
for schild in child.children:
|
||||
if schild.name.startswith("position-"):
|
||||
local_matrix = schild.matrix_local
|
||||
ogre_local_matrix = basis_change @ local_matrix @ basis_change.inverted()
|
||||
local_pos_d = ogre_local_matrix.to_translation()
|
||||
local_rot_d = ogre_local_matrix.to_quaternion()
|
||||
local_pos = [round(x, 4) for x in local_pos_d]
|
||||
local_rot = [round(x, 4) for x in local_rot_d]
|
||||
position = {}
|
||||
if "name" in schild:
|
||||
position["name"] = schild["name"]
|
||||
if "type" in schild:
|
||||
position["type"] = schild["type"]
|
||||
position["position_x"] = local_pos[0]
|
||||
position["position_y"] = local_pos[2]
|
||||
position["position_z"] = local_pos[1]
|
||||
position["rotation_w"] = local_rot[0]
|
||||
position["rotation_x"] = local_rot[1]
|
||||
position["rotation_y"] = local_rot[2]
|
||||
position["rotation_z"] = local_rot[3]
|
||||
action["positions"].append(position)
|
||||
desc["actions"].append(action)
|
||||
if child.name.startswith("position-"):
|
||||
local_matrix = child.matrix_local
|
||||
ogre_local_matrix = basis_change @ local_matrix @ basis_change.inverted()
|
||||
local_pos_d = ogre_local_matrix.to_translation()
|
||||
local_rot_d = ogre_local_matrix.to_quaternion()
|
||||
local_pos = [round(x, 4) for x in local_pos_d]
|
||||
local_rot = [round(x, 4) for x in local_rot_d]
|
||||
position = {}
|
||||
if "name" in child:
|
||||
position["name"] = child["name"]
|
||||
if "type" in child:
|
||||
position["type"] = child["type"]
|
||||
position["position_x"] = local_pos[0]
|
||||
position["position_y"] = local_pos[2]
|
||||
position["position_z"] = local_pos[1]
|
||||
position["rotation_w"] = local_rot[0]
|
||||
position["rotation_x"] = local_rot[1]
|
||||
position["rotation_y"] = local_rot[2]
|
||||
position["rotation_z"] = local_rot[3]
|
||||
desc["positions"].append(position)
|
||||
|
||||
obj.select_set(True)
|
||||
for child in obj.children_recursive:
|
||||
child.select_set(True)
|
||||
|
||||
obj.location = (0.0, 0.0, 0.0)
|
||||
|
||||
# Set the root object as the active object for the export operator
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
|
||||
# Define the output file path
|
||||
file_path = os.path.join(output_dir, f"{obj.name}.glb")
|
||||
|
||||
# Export the selected objects to a glTF file
|
||||
bpy.ops.export_scene.gltf(filepath=file_path,
|
||||
use_selection=True,
|
||||
check_existing=False,
|
||||
export_format='GLB',
|
||||
export_texture_dir='textures', export_texcoords=True,
|
||||
export_normals=True,
|
||||
export_tangents=True,
|
||||
export_materials='EXPORT',
|
||||
export_colors=True,
|
||||
use_mesh_edges=False,
|
||||
use_mesh_vertices=False,
|
||||
export_cameras=False,
|
||||
use_visible=False,
|
||||
use_renderable=False,
|
||||
export_yup=True,
|
||||
export_apply=True,
|
||||
export_animations=True,
|
||||
export_force_sampling=True,
|
||||
export_def_bones=False,
|
||||
export_current_frame=False,
|
||||
export_morph=True,
|
||||
export_morph_animation=False,
|
||||
export_morph_normal=True,
|
||||
export_morph_tangent=True,
|
||||
export_lights=False,
|
||||
export_skins=True)
|
||||
|
||||
# Deselect all objects for the next iteration
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
|
||||
print(f"Exported {obj.name} and its children to {file_path}")
|
||||
with open(file_path + ".json", "w") as json_data:
|
||||
json.dump(desc, json_data)
|
||||
|
||||
export_root_objects_to_gltf(outdir)
|
||||
|
||||
BIN
assets/blender/buildings/parts/furniture-full.blend
LFS
Normal file
BIN
assets/blender/buildings/parts/furniture-full.blend
LFS
Normal file
Binary file not shown.
BIN
assets/blender/buildings/parts/furniture-sofa.blend
LFS
Normal file
BIN
assets/blender/buildings/parts/furniture-sofa.blend
LFS
Normal file
Binary file not shown.
BIN
assets/blender/buildings/parts/furniture.blend
LFS
Normal file
BIN
assets/blender/buildings/parts/furniture.blend
LFS
Normal file
Binary file not shown.
71
assets/blender/scripts/export_building_parts.py
Normal file
71
assets/blender/scripts/export_building_parts.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import bpy
|
||||
import os, sys, time
|
||||
argv = sys.argv
|
||||
argv = argv[argv.index("--") + 1:]
|
||||
|
||||
incpath = os.path.dirname(__file__)
|
||||
|
||||
sys.path.insert(0, incpath)
|
||||
outdir = argv[0]
|
||||
|
||||
def export_root_objects_to_gltf(output_dir):
|
||||
# Ensure the output directory exists
|
||||
if not os.path.exists(output_dir):
|
||||
os.makedirs(output_dir)
|
||||
|
||||
# Deselect all objects
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
|
||||
# Iterate through all objects in the scene
|
||||
for obj in bpy.context.scene.objects:
|
||||
# Check if the object has no parent and has children
|
||||
# The original request specifies "objects having no parent with children".
|
||||
# This condition captures those that are explicitly root objects of a hierarchy.
|
||||
if obj.parent is None:
|
||||
# Select the root object and all its children
|
||||
print(obj.name)
|
||||
obj.select_set(True)
|
||||
for child in obj.children_recursive:
|
||||
child.select_set(True)
|
||||
|
||||
# Set the root object as the active object for the export operator
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
|
||||
# Define the output file path
|
||||
file_path = os.path.join(output_dir, f"{obj.name}.glb")
|
||||
|
||||
# Export the selected objects to a glTF file
|
||||
bpy.ops.export_scene.gltf(filepath=file_path,
|
||||
use_selection=True,
|
||||
check_existing=False,
|
||||
export_format='GLB',
|
||||
export_texture_dir='textures', export_texcoords=True,
|
||||
export_normals=True,
|
||||
export_tangents=True,
|
||||
export_materials='EXPORT',
|
||||
export_colors=True,
|
||||
use_mesh_edges=False,
|
||||
use_mesh_vertices=False,
|
||||
export_cameras=False,
|
||||
use_visible=False,
|
||||
use_renderable=False,
|
||||
export_yup=True,
|
||||
export_apply=True,
|
||||
export_animations=True,
|
||||
export_force_sampling=True,
|
||||
export_def_bones=False,
|
||||
export_current_frame=False,
|
||||
export_morph=True,
|
||||
export_morph_animation=False,
|
||||
export_morph_normal=True,
|
||||
export_morph_tangent=True,
|
||||
export_lights=False,
|
||||
export_skins=True)
|
||||
|
||||
# Deselect all objects for the next iteration
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
|
||||
print(f"Exported {obj.name} and its children to {file_path}")
|
||||
|
||||
export_root_objects_to_gltf(outdir)
|
||||
|
||||
@@ -655,3 +655,54 @@ setup_handler(function(event, trigger_entity, what_entity)
|
||||
--]]
|
||||
end
|
||||
end)
|
||||
|
||||
--[[
|
||||
active_dialogues = {}
|
||||
setup_action_handler("talk", function(town, index, word)
|
||||
local ret = ""
|
||||
local choices = {}
|
||||
local have_choice = false
|
||||
local have_paragraph = false
|
||||
local book = narrator.parse_file('stories.talk')
|
||||
local story = narrator.init_story(book)
|
||||
if story == nil then
|
||||
crash()
|
||||
end
|
||||
story:begin()
|
||||
narrate("Boo!!!!")
|
||||
if story.can_continue() then
|
||||
local paragraph = story:continue(1)
|
||||
print(dump(paragraph))
|
||||
if story:can_choose() then
|
||||
have_choice = true
|
||||
local ch = story:get_choices()
|
||||
for i, choice in ipairs(ch) do
|
||||
table.insert(choices, choice.text)
|
||||
print(i, dump(choice))
|
||||
end
|
||||
if #choices == 1 and choices[1] == "Ascend" then
|
||||
story:choose(1)
|
||||
choices = {}
|
||||
end
|
||||
if #choices == 1 and choices[1] == "Continue" then
|
||||
this.story:choose(1)
|
||||
choices = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
if (#choices > 0) then
|
||||
print("choices!!!")
|
||||
narrate(ret, choices)
|
||||
else
|
||||
narrate(ret)
|
||||
end
|
||||
if not have_choice and not have_paragraph then
|
||||
-- complete
|
||||
crash()
|
||||
else
|
||||
print("can continue")
|
||||
end
|
||||
|
||||
end)
|
||||
]]--
|
||||
|
||||
|
||||
6
lua-scripts/stories/talk.ink
Normal file
6
lua-scripts/stories/talk.ink
Normal file
@@ -0,0 +1,6 @@
|
||||
Dialogue...
|
||||
Whatever...
|
||||
* [Ascend]
|
||||
~ crash()
|
||||
- ->END
|
||||
|
||||
@@ -21,6 +21,7 @@ FileSystem=resources/terrain
|
||||
FileSystem=skybox
|
||||
FileSystem=resources/buildings
|
||||
FileSystem=resources/buildings/parts/pier
|
||||
FileSystem=resources/buildings/parts/furniture
|
||||
FileSystem=resources/vehicles
|
||||
FileSystem=resources/debug
|
||||
FileSystem=resources/fonts
|
||||
|
||||
34
resources/CMakeLists.txt
Normal file
34
resources/CMakeLists.txt
Normal file
@@ -0,0 +1,34 @@
|
||||
project(resources)
|
||||
set(DIRECTORY_LIST
|
||||
main
|
||||
shaderlib
|
||||
terrain
|
||||
)
|
||||
set(TARGET_PATHS)
|
||||
foreach(DIR_NAME ${DIRECTORY_LIST})
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DIR_NAME}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/${DIR_NAME}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${DIR_NAME}
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${DIR_NAME})
|
||||
list(APPEND TARGET_PATHS ${CMAKE_CURRENT_BINARY_DIR}/${DIR_NAME})
|
||||
endforeach()
|
||||
|
||||
#add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/terrain/world_map.png
|
||||
# COMMAND unzip -o ${CMAKE_CURRENT_SOURCE_DIR}/world_map.kra mergedimage.png -d ${CMAKE_CURRENT_BINARY_DIR}/world_map
|
||||
# COMMAND ${CMAKE_COMMAND} -E copy
|
||||
# ${CMAKE_BINARY_DIR}/world_map/mergedimage.png
|
||||
# ${CMAKE_BINARY_DIR}/resources/terrain/world_map.png
|
||||
# COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/world_map
|
||||
# DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/world_map.kra)
|
||||
#list(APPEND TARGET_PATHS ${CMAKE_CURRENT_BINARY_DIR}/terrain/world_map.png)
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/terrain/brushes.png
|
||||
COMMAND unzip -o ${CMAKE_CURRENT_SOURCE_DIR}/brushes.kra mergedimage.png -d ${CMAKE_CURRENT_BINARY_DIR}/brushes
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_CURRENT_BINARY_DIR}/brushes/mergedimage.png
|
||||
${CMAKE_CURRENT_BINARY_DIR}/terrain/brushes.png
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/brushes
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/brushes.kra)
|
||||
list(APPEND TARGET_PATHS ${CMAKE_CURRENT_BINARY_DIR}/terrain/brushes.png)
|
||||
|
||||
add_custom_target(stage_resources ALL DEPENDS ${TARGET_PATHS})
|
||||
16
resources/shaderlib/RTSLib_Colour.glsl
Normal file
16
resources/shaderlib/RTSLib_Colour.glsl
Normal file
@@ -0,0 +1,16 @@
|
||||
// This file is part of the OGRE project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at https://www.ogre3d.org/licensing.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifdef USE_LINEAR_COLOURS
|
||||
#define ENABLE_LINEAR_COLOUR(colour) colour.rgb = pow(colour.rgb, vec3_splat(2.2))
|
||||
#else
|
||||
#define ENABLE_LINEAR_COLOUR(colour)
|
||||
#endif
|
||||
|
||||
#if defined(USE_LINEAR_COLOURS) && !defined(TARGET_CONSUMES_LINEAR)
|
||||
#define COLOUR_TRANSFER(colour) colour.rgb = pow(colour.rgb, vec3_splat(1.0/2.2))
|
||||
#else
|
||||
#define COLOUR_TRANSFER(colour)
|
||||
#endif
|
||||
BIN
resources/terrain/world_map.png
Normal file
BIN
resources/terrain/world_map.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
2586
src/FastNoiseLite/FastNoiseLite.h
Normal file
2586
src/FastNoiseLite/FastNoiseLite.h
Normal file
File diff suppressed because it is too large
Load Diff
22
src/FastNoiseLite/LICENSE
Normal file
22
src/FastNoiseLite/LICENSE
Normal file
@@ -0,0 +1,22 @@
|
||||
MIT License
|
||||
|
||||
Copyright(c) 2020 Jordan Peck (jordan.me2@gmail.com)
|
||||
Copyright(c) 2020 Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
23
src/FastNoiseLite/README.md
Normal file
23
src/FastNoiseLite/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
## Getting Started
|
||||
|
||||
Here's an example for creating a 128x128 array of OpenSimplex2 noise
|
||||
|
||||
```cpp
|
||||
// Create and configure FastNoise object
|
||||
FastNoiseLite noise;
|
||||
noise.SetNoiseType(FastNoiseLite::NoiseType_OpenSimplex2);
|
||||
|
||||
// Gather noise data
|
||||
std::vector<float> noiseData(128 * 128);
|
||||
int index = 0;
|
||||
|
||||
for (int y = 0; y < 128; y++)
|
||||
{
|
||||
for (int x = 0; x < 128; x++)
|
||||
{
|
||||
noiseData[index++] = noise.GetNoise((float)x, (float)y);
|
||||
}
|
||||
}
|
||||
|
||||
// Do something with this data...
|
||||
```
|
||||
@@ -9,7 +9,7 @@ find_package(OgreProcedural REQUIRED CONFIG)
|
||||
find_package(pugixml REQUIRED CONFIG)
|
||||
find_package(flecs REQUIRED CONFIG)
|
||||
|
||||
set(COPY_DIRECTORIES resources skybox water resources/buildings/parts)
|
||||
set(COPY_DIRECTORIES characters resources skybox water resources/buildings/parts)
|
||||
set(INSTALL_DEPS ${CMAKE_CURRENT_BINARY_DIR}/resources.cfg)
|
||||
foreach(DIR_NAME ${COPY_DIRECTORIES})
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DIR_NAME}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "Components.h"
|
||||
#include "CharacterModule.h"
|
||||
#include "TerrainModule.h"
|
||||
#include "GUIModule.h"
|
||||
#include "GUIModuleCommon.h"
|
||||
#include "AppModule.h"
|
||||
#include "EditorGizmoModule.h"
|
||||
#include "EditorInputModule.h"
|
||||
|
||||
@@ -6,9 +6,10 @@ find_package(nlohmann_json REQUIRED)
|
||||
find_package(OgreProcedural REQUIRED CONFIG)
|
||||
add_subdirectory(items)
|
||||
add_library(GameData STATIC GameData.cpp CharacterModule.cpp WaterModule.cpp SunModule.cpp TerrainModule.cpp
|
||||
GUIModule.cpp LuaData.cpp WorldMapModule.cpp BoatModule.cpp EventTriggerModule.cpp
|
||||
GUIModule.cpp EditorGUIModule.cpp LuaData.cpp WorldMapModule.cpp BoatModule.cpp EventTriggerModule.cpp
|
||||
CharacterAnimationModule.cpp PhysicsModule.cpp EventModule.cpp CharacterManagerModule.cpp
|
||||
VehicleManagerModule.cpp AppModule.cpp StaticGeometryModule.cpp SmartObject.cpp SlotsModule.cpp goap.cpp)
|
||||
VehicleManagerModule.cpp AppModule.cpp StaticGeometryModule.cpp SmartObject.cpp SlotsModule.cpp
|
||||
PlayerActionModule.cpp goap.cpp)
|
||||
target_link_libraries(GameData PUBLIC
|
||||
lua
|
||||
flecs::flecs_static
|
||||
|
||||
@@ -22,38 +22,28 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, const CharacterBase &ch,
|
||||
AnimationControl &anim) {
|
||||
if (!anim.configured && ch.mSkeleton) {
|
||||
if (!anim.configured) {
|
||||
int i, j;
|
||||
e.set<EventData>({});
|
||||
ch.mSkeleton->setBlendMode(
|
||||
ch.mBodyEnt->getSkeleton()->setBlendMode(
|
||||
Ogre::ANIMBLEND_CUMULATIVE);
|
||||
Ogre::String animNames[] = {
|
||||
"idle",
|
||||
"walking",
|
||||
"running",
|
||||
"treading_water",
|
||||
"swimming",
|
||||
"hanging-idle",
|
||||
"hanging-climb",
|
||||
"swimming-hold-edge",
|
||||
"swimming-edge-climb",
|
||||
"character-talk",
|
||||
"pass-character",
|
||||
"idle-act",
|
||||
"sitting-chair",
|
||||
"sitting-ground"
|
||||
};
|
||||
int state_count = sizeof(animNames) /
|
||||
sizeof(animNames[0]);
|
||||
anim.mAnimationSystem =
|
||||
new AnimationSystem(false);
|
||||
for (i = 0; i < state_count; i++) {
|
||||
Ogre::AnimationStateSet *animStateSet =
|
||||
ch.mBodyEnt->getAllAnimationStates();
|
||||
const Ogre::AnimationStateMap &animMap =
|
||||
animStateSet->getAnimationStates();
|
||||
anim.mAnimationSystem =
|
||||
new AnimationSystem(false);
|
||||
ch.mBodyEnt->getSkeleton()
|
||||
->getBone("Root")
|
||||
->removeAllChildren();
|
||||
for (auto it = animMap.begin();
|
||||
it != animMap.end(); it++) {
|
||||
Animation *animation = new Animation(
|
||||
ch.mSkeleton,
|
||||
ch.mBodyEnt->getAnimationState(
|
||||
animNames[i]),
|
||||
ch.mSkeleton->getAnimation(
|
||||
animNames[i]),
|
||||
ch.mBodyEnt->getSkeleton(),
|
||||
it->second,
|
||||
ch.mBodyEnt->getSkeleton()
|
||||
->getAnimation(
|
||||
it->first),
|
||||
e);
|
||||
#ifdef VDEBUG
|
||||
std::cout
|
||||
@@ -62,7 +52,7 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
#endif
|
||||
animation->setLoop(true);
|
||||
anim.mAnimationSystem->add_animation(
|
||||
animNames[i], animation);
|
||||
it->first, animation);
|
||||
}
|
||||
anim.mAnimationSystem
|
||||
->builder()
|
||||
@@ -157,10 +147,39 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
CharacterBase &ch, AnimationControl &anim) {
|
||||
float delta = eng.delta;
|
||||
// ch.mBoneMotion = Ogre::Vector3::ZERO;
|
||||
bool result = anim.mAnimationSystem->addTime(delta);
|
||||
if (!ch.mRootBone)
|
||||
if (!anim.mAnimationSystem)
|
||||
return;
|
||||
// The value we get is interpolated value. When result is true it is new step
|
||||
#if 0
|
||||
ch.mBodyEnt->getSkeleton()->getBone("Root")->reset();
|
||||
ch.mBodyEnt->getSkeleton()->getBone("Root")->setPosition(
|
||||
Ogre::Vector3::ZERO);
|
||||
#endif
|
||||
bool result = anim.mAnimationSystem->addTime(delta);
|
||||
Ogre::Vector3 rootMotion =
|
||||
anim.mAnimationSystem->getRootMotionDelta();
|
||||
ch.mBonePrevMotion = ch.mBoneMotion;
|
||||
ch.mBoneMotion = rootMotion;
|
||||
ch.mBodyEnt->_updateAnimation();
|
||||
ch.mBodyEnt->getSkeleton()->getBone("Root")->setPosition(
|
||||
Ogre::Vector3::ZERO);
|
||||
#if 0
|
||||
Ogre::Vector3 deltaMotion;
|
||||
ch.mBodyEnt->_updateAnimation();
|
||||
std::cout << "motion: " << ch.mBoneMotion << " "
|
||||
<< rootMotion << " " << ch.mBonePrevMotion
|
||||
<< std::endl;
|
||||
rootMotion = ch.mBodyEnt->getSkeleton()
|
||||
->getBone("Root")
|
||||
->getPosition();
|
||||
if (rootMotion.squaredLength() <
|
||||
ch.mBoneMotion.squaredLength())
|
||||
deltaMotion = rootMotion;
|
||||
else
|
||||
deltaMotion = rootMotion - ch.mBoneMotion;
|
||||
ch.mBonePrevMotion = ch.mBoneMotion;
|
||||
ch.mBoneMotion = deltaMotion;
|
||||
#endif
|
||||
// The value we get is interpolated value. When result is true it is new step
|
||||
#if 0
|
||||
Ogre::Vector3 offset = ch.mRootBone->getPosition();
|
||||
ch.mBoneMotion = static_cast<RootMotionListener *>(
|
||||
@@ -302,54 +321,7 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
Ogre::Vector3 colNormal;
|
||||
bool is_on_floor = false;
|
||||
bool penetration = false;
|
||||
#if 0
|
||||
if (eng.startupDelay < 0.0f) {
|
||||
if (body.mController) {
|
||||
Ogre::Vector3 rotMotion =
|
||||
v.velocity * eng.delta;
|
||||
rotMotion.x = Ogre::Math::Clamp(
|
||||
rotMotion.x, -0.04f, 0.04f);
|
||||
rotMotion.y = Ogre::Math::Clamp(
|
||||
rotMotion.y, -0.025f, 0.1f);
|
||||
rotMotion.z = Ogre::Math::Clamp(
|
||||
rotMotion.z, -0.04f, 0.04f);
|
||||
btVector3 currentPosition =
|
||||
body.mGhostObject
|
||||
->getWorldTransform()
|
||||
.getOrigin();
|
||||
is_on_floor =
|
||||
body.mController->isOnFloor();
|
||||
penetration = body.mController
|
||||
->isPenetrating();
|
||||
if (is_on_floor)
|
||||
v.gvelocity =
|
||||
Ogre::Vector3::ZERO;
|
||||
|
||||
btTransform from(
|
||||
Ogre::Bullet::convert(
|
||||
ch.mBodyNode
|
||||
->getOrientation()),
|
||||
Ogre::Bullet::convert(
|
||||
ch.mBodyNode
|
||||
->getPosition()));
|
||||
ch.mBodyNode->_setDerivedPosition(
|
||||
ch.mBodyNode
|
||||
->_getDerivedPosition() +
|
||||
rotMotion);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
});
|
||||
#if 0
|
||||
ecs.system<CharacterVelocity, CharacterBase>("HandleRootMotionEnd")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, CharacterVelocity &v,
|
||||
CharacterBase &ch) {
|
||||
// zero the velocity;
|
||||
// v.velocity = Ogre::Vector3::ZERO;
|
||||
// ch.mBoneMotion = Ogre::Vector3::ZERO;
|
||||
});
|
||||
#endif
|
||||
|
||||
ecs.system<const Input, const CharacterBase, AnimationControl>(
|
||||
"HandleNPCAnimations")
|
||||
@@ -360,6 +332,8 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
const CharacterBase &ch, AnimationControl &anim) {
|
||||
if (!anim.configured)
|
||||
return;
|
||||
if (!anim.mAnimationSystem)
|
||||
return;
|
||||
AnimationNodeStateMachine *state_machine =
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
@@ -405,6 +379,8 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
AnimationControl &anim) {
|
||||
if (!anim.configured)
|
||||
return;
|
||||
if (!anim.mAnimationSystem)
|
||||
return;
|
||||
AnimationNodeStateMachine *main_sm =
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
@@ -568,15 +544,6 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
act.prevMotion.z = input.motion.z;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!controls_idle) {
|
||||
if (Ogre::Math::Abs(input.motion.z - act.prevMotion.z) > 0.001f) {
|
||||
if (input.motion.z < 0)
|
||||
ECS::get_mut<LuaData>().call_handler("actuator_forward", e);
|
||||
}
|
||||
ECS::get_mut<LuaData>().call_handler("actuator_controls_update");
|
||||
}
|
||||
#endif
|
||||
act.prevMotion = input.motion;
|
||||
});
|
||||
ecs.system<EventData>("UpdateEvents")
|
||||
@@ -616,87 +583,6 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
<< "h=" << ch.mBodyNode->_getDerivedPosition().y
|
||||
<< std::endl;
|
||||
});
|
||||
#endif
|
||||
#if 0
|
||||
ecs.system<const EngineData, const CharacterBase, CharacterBody>(
|
||||
"UpdateBodyCast")
|
||||
.kind(flecs::OnUpdate)
|
||||
.without<CharacterInActuator>()
|
||||
.each([](flecs::entity e, const EngineData &eng,
|
||||
const CharacterBase &ch, CharacterBody &body) {
|
||||
struct ResultCallback
|
||||
: public btCollisionWorld::RayResultCallback {
|
||||
btCollisionObject *m_me;
|
||||
btVector3 m_from, m_to, m_hitNormalWorld,
|
||||
m_hitPointWorld;
|
||||
ResultCallback(btCollisionObject *me,
|
||||
const btVector3 &from,
|
||||
const btVector3 &to)
|
||||
: m_me(me)
|
||||
, m_from(from)
|
||||
, m_to(to)
|
||||
{
|
||||
}
|
||||
btScalar addSingleResult(
|
||||
btCollisionWorld::LocalRayResult
|
||||
&rayResult,
|
||||
bool normalInWorldSpace) override
|
||||
{
|
||||
if (rayResult.m_collisionObject == m_me)
|
||||
return 1.0f;
|
||||
if (!btPairCachingGhostObject::upcast(
|
||||
rayResult.m_collisionObject))
|
||||
return 1.0f;
|
||||
if (!(rayResult.m_collisionObject
|
||||
->getCollisionFlags() &
|
||||
btCollisionObject::
|
||||
CF_CHARACTER_OBJECT))
|
||||
return 1.0f;
|
||||
m_closestHitFraction =
|
||||
rayResult.m_hitFraction;
|
||||
m_collisionObject =
|
||||
rayResult.m_collisionObject;
|
||||
if (normalInWorldSpace)
|
||||
m_hitNormalWorld =
|
||||
rayResult
|
||||
.m_hitNormalLocal;
|
||||
else
|
||||
m_hitNormalWorld =
|
||||
m_collisionObject
|
||||
->getWorldTransform()
|
||||
.getBasis() *
|
||||
rayResult
|
||||
.m_hitNormalLocal;
|
||||
m_hitPointWorld.setInterpolate3(
|
||||
m_from, m_to,
|
||||
rayResult.m_hitFraction);
|
||||
return rayResult.m_hitFraction;
|
||||
}
|
||||
};
|
||||
Ogre::Vector3 offset(0.0f, 0.5f, 0.0f);
|
||||
float dist = 0.5f;
|
||||
btVector3 a = Ogre::Bullet::convert(
|
||||
ch.mBodyNode->getPosition() + offset),
|
||||
b(Ogre::Bullet::convert(
|
||||
ch.mBodyNode->getPosition() +
|
||||
ch.mBodyNode->getOrientation() *
|
||||
Ogre::Vector3(0, 0, dist) +
|
||||
offset));
|
||||
ResultCallback result(body.mGhostObject, a, b);
|
||||
// body.mGhostObject->rayTest(a, b, result);
|
||||
eng.mWorld->getBtWorld()->rayTest(a, b, result);
|
||||
if (result.hasHit()) {
|
||||
std::cout << "Hit!!! " << result.m_hitPointWorld
|
||||
<< std::endl;
|
||||
e.set<CharacterInActuator>(
|
||||
{ "idle", { 0, 0, 0 } });
|
||||
ECS::get<LuaBase>().mLua->call_handler(
|
||||
"character_enter", e,
|
||||
ECS::get<Body2Entity>().entities.at(
|
||||
const_cast<btCollisionObject *>(
|
||||
result.m_collisionObject)));
|
||||
}
|
||||
});
|
||||
#endif
|
||||
struct AnimationSetCommand : public GameWorld::Command {
|
||||
int operator()(const std::vector<GameWorld::Parameter *> &args)
|
||||
|
||||
@@ -9,22 +9,16 @@
|
||||
namespace ECS
|
||||
{
|
||||
class RootMotionListener : public Ogre::NodeAnimationTrack::Listener {
|
||||
Ogre::Vector3 prevTranslation;
|
||||
mutable Ogre::Vector3 deltaMotion;
|
||||
flecs::entity e;
|
||||
|
||||
public:
|
||||
RootMotionListener(flecs::entity e)
|
||||
: Ogre::NodeAnimationTrack::Listener()
|
||||
, e(e)
|
||||
, prevTranslation(Ogre::Vector3::ZERO)
|
||||
, deltaMotion(Ogre::Vector3::ZERO)
|
||||
{
|
||||
}
|
||||
bool getInterpolatedKeyFrame(const Ogre::AnimationTrack *t,
|
||||
const Ogre::TimeIndex &timeIndex,
|
||||
Ogre::KeyFrame *kf) override
|
||||
{
|
||||
#if 0
|
||||
Ogre::TransformKeyFrame *vkf =
|
||||
static_cast<Ogre::TransformKeyFrame *>(kf);
|
||||
Ogre::KeyFrame *kf1, *kf2;
|
||||
@@ -36,14 +30,12 @@ public:
|
||||
k2 = static_cast<Ogre::TransformKeyFrame *>(kf2);
|
||||
Ogre::Vector3 translation;
|
||||
Ogre::Quaternion rotation;
|
||||
if (tm == 0.0f) {
|
||||
Ogre::Vector3 deltaMotion;
|
||||
Ogre::Vector3 prevMotion;
|
||||
if (tm == 0.0f) {
|
||||
rotation = k1->getRotation();
|
||||
translation = k1->getTranslate();
|
||||
deltaMotion = translation;
|
||||
|
||||
// vkf->setRotation(k1->getRotation());
|
||||
// vkf->setTranslate(k1->getTranslate());
|
||||
// vkf->setScale(k1->getScale());
|
||||
} else {
|
||||
rotation = Ogre::Quaternion::nlerp(
|
||||
tm, k1->getRotation(), k2->getRotation(), true);
|
||||
@@ -55,14 +47,7 @@ public:
|
||||
translation.squaredLength())
|
||||
deltaMotion = translation;
|
||||
}
|
||||
#if 0
|
||||
std::cout << "time: " << tm
|
||||
<< " Position: " << deltaMotion;
|
||||
std::cout << " Quaternion: " << rotation;
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
vkf->setTranslate(deltaMotion);
|
||||
// vkf->setTranslate(translation);
|
||||
vkf->setRotation(rotation);
|
||||
vkf->setScale(Ogre::Vector3(1, 1, 1));
|
||||
prevTranslation = translation;
|
||||
@@ -70,7 +55,9 @@ public:
|
||||
e.get_mut<CharacterBase>().mBonePrevMotion = prevTranslation;
|
||||
e.modified<CharacterBase>();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
};
|
||||
struct AnimationTrigger;
|
||||
struct AnimationTriggerSubscriber {
|
||||
@@ -126,46 +113,66 @@ struct AnimationTrigger {
|
||||
{
|
||||
}
|
||||
};
|
||||
struct SetupTracks {
|
||||
Ogre::NodeAnimationTrack *mHipsTrack;
|
||||
Ogre::NodeAnimationTrack *mRootTrack;
|
||||
RootMotionListener *mListener;
|
||||
Ogre::Vector3 mRootTranslation;
|
||||
SetupTracks(flecs::entity e, Ogre::Skeleton *skeleton,
|
||||
Ogre::Animation *animation)
|
||||
: mListener(OGRE_NEW RootMotionListener(e))
|
||||
{
|
||||
mHipsTrack = nullptr;
|
||||
mRootTrack = nullptr;
|
||||
for (const auto &it : animation->_getNodeTrackList()) {
|
||||
Ogre::NodeAnimationTrack *track = it.second;
|
||||
Ogre::String trackName =
|
||||
track->getAssociatedNode()->getName();
|
||||
if (trackName == "mixamorig:Hips") {
|
||||
mHipsTrack = track;
|
||||
} else if (trackName == "Root") {
|
||||
mRootTrack = track;
|
||||
// mRootTracks[i]->removeAllKeyFrames();
|
||||
}
|
||||
}
|
||||
if (!mRootTrack) {
|
||||
Ogre::Bone *bone = skeleton->getBone("Root");
|
||||
mRootTrack = animation->createNodeTrack(
|
||||
bone->getHandle(), bone);
|
||||
Ogre::TransformKeyFrame *kf =
|
||||
mRootTrack->createNodeKeyFrame(0.0f);
|
||||
kf->setTranslate(Ogre::Vector3::ZERO);
|
||||
kf->setRotation(Ogre::Quaternion::IDENTITY);
|
||||
}
|
||||
// if (e.has<Player>()) // FIXME
|
||||
// mRootTrack->setListener(mListener);
|
||||
Ogre::TransformKeyFrame *tkfBeg =
|
||||
(Ogre::TransformKeyFrame *)mRootTrack->getKeyFrame(0);
|
||||
Ogre::TransformKeyFrame *tkfEnd =
|
||||
(Ogre::TransformKeyFrame *)mRootTrack->getKeyFrame(
|
||||
mRootTrack->getNumKeyFrames() - 1);
|
||||
mRootTranslation =
|
||||
tkfEnd->getTranslate() - tkfBeg->getTranslate();
|
||||
}
|
||||
};
|
||||
struct Animation {
|
||||
Ogre::AnimationState *mAnimationState;
|
||||
Ogre::Animation *mSkelAnimation;
|
||||
Ogre::NodeAnimationTrack *mHipsTrack;
|
||||
Ogre::NodeAnimationTrack *mRootTrack;
|
||||
RootMotionListener *mListener;
|
||||
SetupTracks *mTracks;
|
||||
float m_weight;
|
||||
float m_accWeight;
|
||||
flecs::entity e;
|
||||
Ogre::Skeleton *mSkeleton;
|
||||
Animation(Ogre::Skeleton *skeleton, Ogre::AnimationState *animState,
|
||||
Ogre::Animation *skelAnimation, flecs::entity e)
|
||||
: mAnimationState(animState)
|
||||
: mTracks(OGRE_NEW SetupTracks(e, skeleton, skelAnimation))
|
||||
, mAnimationState(animState)
|
||||
, mSkelAnimation(skelAnimation)
|
||||
, mListener(OGRE_NEW RootMotionListener(e))
|
||||
, m_weight(0)
|
||||
, m_accWeight(0)
|
||||
, e(e)
|
||||
, mSkeleton(skeleton)
|
||||
{
|
||||
int j;
|
||||
mRootTrack = nullptr;
|
||||
mHipsTrack = nullptr;
|
||||
for (const auto &it : mSkelAnimation->_getNodeTrackList()) {
|
||||
Ogre::NodeAnimationTrack *track = it.second;
|
||||
Ogre::String trackName =
|
||||
track->getAssociatedNode()->getName();
|
||||
if (trackName == "mixamorig:Hips") {
|
||||
mHipsTrack = track;
|
||||
} else if (trackName == "Root") {
|
||||
mRootTrack = track;
|
||||
// mRootTracks[i]->removeAllKeyFrames();
|
||||
}
|
||||
}
|
||||
if (!mRootTrack) {
|
||||
Ogre::Bone *bone = skeleton->getBone("Root");
|
||||
mRootTrack = mSkelAnimation->createNodeTrack(
|
||||
bone->getHandle(), bone);
|
||||
Ogre::TransformKeyFrame *kf =
|
||||
mRootTrack->createNodeKeyFrame(0.0f);
|
||||
kf->setTranslate(Ogre::Vector3::ZERO);
|
||||
kf->setRotation(Ogre::Quaternion::IDENTITY);
|
||||
}
|
||||
mRootTrack->setListener(mListener);
|
||||
}
|
||||
Ogre::String getName()
|
||||
{
|
||||
@@ -198,22 +205,134 @@ struct Animation {
|
||||
{
|
||||
return m_weight;
|
||||
}
|
||||
bool addTime(float time)
|
||||
Ogre::Vector3 rootMotion;
|
||||
Ogre::Vector3 getRootMotionDelta()
|
||||
{
|
||||
#if 0
|
||||
Ogre::KeyFrame *kf1, *kf2;
|
||||
Ogre::TransformKeyFrame *k1, *k2;
|
||||
unsigned short firstKeyIndex;
|
||||
Ogre::Real timePos = mAnimationState->getTimePosition();
|
||||
Ogre::TimeIndex index = mSkelAnimation->_getTimeIndex(timePos);
|
||||
float tm = mTracks->mRootTrack->getKeyFramesAtTime(
|
||||
index, &kf1, &kf2, &firstKeyIndex);
|
||||
k1 = static_cast<Ogre::TransformKeyFrame *>(kf1);
|
||||
k2 = static_cast<Ogre::TransformKeyFrame *>(kf2);
|
||||
Ogre::Vector3 translation;
|
||||
Ogre::Quaternion rotation;
|
||||
if (tm == 0.0f) {
|
||||
rotation = k1->getRotation();
|
||||
translation = k1->getTranslate();
|
||||
} else {
|
||||
rotation = Ogre::Quaternion::nlerp(
|
||||
tm, k1->getRotation(),
|
||||
k2->getRotation(), true);
|
||||
translation = k1->getTranslate() +
|
||||
(k2->getTranslate() -
|
||||
k1->getTranslate()) *
|
||||
tm;
|
||||
}
|
||||
return translation * mAnimationState->getWeight();
|
||||
#endif
|
||||
if (mAnimationState->getEnabled())
|
||||
return rootMotion * mAnimationState->getWeight();
|
||||
else
|
||||
return Ogre::Vector3(0, 0, 0);
|
||||
}
|
||||
#if 0
|
||||
void updateRootMotion(Ogre::Real timePos)
|
||||
{
|
||||
Ogre::KeyFrame *kf1, *kf2;
|
||||
Ogre::TransformKeyFrame *k1, *k2;
|
||||
unsigned short firstKeyIndex;
|
||||
mSkeleton->getBone("Root")->setManuallyControlled(true);
|
||||
Ogre::TimeIndex index = mSkelAnimation->_getTimeIndex(timePos);
|
||||
float tm = mTracks->mRootTrack->getKeyFramesAtTime(
|
||||
index, &kf1, &kf2, &firstKeyIndex);
|
||||
k1 = static_cast<Ogre::TransformKeyFrame *>(kf1);
|
||||
k2 = static_cast<Ogre::TransformKeyFrame *>(kf2);
|
||||
Ogre::Vector3 translation;
|
||||
Ogre::Quaternion rotation;
|
||||
Ogre::Vector3 deltaMotion =
|
||||
e.get_mut<CharacterBase>().mBoneMotion;
|
||||
Ogre::Vector3 prevTranslation =
|
||||
e.get_mut<CharacterBase>().mBonePrevMotion;
|
||||
if (tm == 0.0f) {
|
||||
rotation = k1->getRotation() * m_weight;
|
||||
translation = k1->getTranslate() * m_weight;
|
||||
deltaMotion = translation;
|
||||
} else {
|
||||
rotation = Ogre::Quaternion::nlerp(
|
||||
tm, k1->getRotation() * m_weight,
|
||||
k2->getRotation() * m_weight, true);
|
||||
translation = k1->getTranslate() * m_weight +
|
||||
(k2->getTranslate() * m_weight -
|
||||
k1->getTranslate() * m_weight) *
|
||||
tm;
|
||||
deltaMotion = translation - prevTranslation;
|
||||
if (deltaMotion.squaredLength() >
|
||||
translation.squaredLength())
|
||||
deltaMotion = translation;
|
||||
}
|
||||
e.get_mut<CharacterBase>().mBoneMotion = deltaMotion;
|
||||
e.get_mut<CharacterBase>().mBonePrevMotion = prevTranslation;
|
||||
e.modified<CharacterBase>();
|
||||
#if 1
|
||||
if (timePos > 0.5f && m_weight > 0.2 && translation.squaredLength() > 0.0f) {
|
||||
std::cout << timePos << " " << m_weight << " "
|
||||
<< e.get<CharacterBase>()
|
||||
.mBodyEnt->getMesh()
|
||||
->getName()
|
||||
<< " " << deltaMotion << " "
|
||||
<< prevTranslation << std::endl;
|
||||
std::cout << translation << " " << rotation << std::endl;
|
||||
// OgreAssert(false, "updateRootMotion");
|
||||
}
|
||||
#endif
|
||||
mTracks->mRootTrack->getAssociatedNode()->setPosition(
|
||||
Ogre::Vector3());
|
||||
mSkeleton->getBone("Root")->reset();
|
||||
}
|
||||
#endif
|
||||
void getKeyframeIndices(Ogre::Real timePos, unsigned short *pindex)
|
||||
{
|
||||
Ogre::TimeIndex index = mSkelAnimation->_getTimeIndex(timePos);
|
||||
Ogre::KeyFrame *kf1, *kf2;
|
||||
mTracks->mRootTrack->getKeyFramesAtTime(index, &kf1, &kf2, pindex);
|
||||
|
||||
}
|
||||
bool addTime(float time)
|
||||
{
|
||||
bool result = mAnimationState->getEnabled();
|
||||
if (!result)
|
||||
return result;
|
||||
Ogre::TimeIndex index = mSkelAnimation->_getTimeIndex(
|
||||
mAnimationState->getTimePosition());
|
||||
Ogre::KeyFrame *kf1, *kf2;
|
||||
unsigned short prev_index, next_index;
|
||||
mRootTrack->getKeyFramesAtTime(index, &kf1, &kf2, &prev_index);
|
||||
unsigned short prev_index, next_index;
|
||||
Ogre::TimeIndex index = mSkelAnimation->_getTimeIndex(mAnimationState->getTimePosition());
|
||||
getKeyframeIndices(mAnimationState->getTimePosition(), &prev_index);
|
||||
unsigned int previous_frame = index.getKeyIndex();
|
||||
float lastTime = mAnimationState->getTimePosition();
|
||||
mAnimationState->addTime(time);
|
||||
index = mSkelAnimation->_getTimeIndex(
|
||||
mAnimationState->getTimePosition());
|
||||
mRootTrack->getKeyFramesAtTime(index, &kf1, &kf2, &next_index);
|
||||
return prev_index != next_index;
|
||||
float thisTime = mAnimationState->getTimePosition();
|
||||
float length = mAnimationState->getLength();
|
||||
bool loop = mAnimationState->getLoop();
|
||||
int loops = loop ? (int)std::round((lastTime + time - thisTime) / length) : 0;
|
||||
Ogre::TransformKeyFrame tkf(0, 0);
|
||||
mTracks->mRootTrack->getInterpolatedKeyFrame(lastTime, &tkf);
|
||||
Ogre::Vector3 lastRootPos = tkf.getTranslate();
|
||||
mTracks->mRootTrack->getInterpolatedKeyFrame(thisTime, &tkf);
|
||||
Ogre::Vector3 thisRootPos = tkf.getTranslate();
|
||||
#if 0
|
||||
if (thisTime > lastTime)
|
||||
rootMotion = thisRootPos - lastRootPos;
|
||||
else
|
||||
rootMotion = mTracks->mRootTranslation + thisRootPos - lastRootPos;
|
||||
#else
|
||||
rootMotion = (thisRootPos - lastRootPos) + (loops * mTracks->mRootTranslation);
|
||||
|
||||
#endif
|
||||
getKeyframeIndices(mAnimationState->getTimePosition(), &next_index);
|
||||
// updateRootMotion(mAnimationState->getTimePosition());
|
||||
return prev_index != next_index;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
@@ -827,6 +946,14 @@ struct AnimationSystem : AnimationNode {
|
||||
}
|
||||
};
|
||||
AnimationSystemBuilder m_builder;
|
||||
Ogre::Vector3 getRootMotionDelta()
|
||||
{
|
||||
Ogre::Vector3 motionDelta(0, 0, 0);
|
||||
int i;
|
||||
for (i = 0; i < vanimation_list.size(); i++)
|
||||
motionDelta += vanimation_list[i]->getRootMotionDelta();
|
||||
return motionDelta;
|
||||
}
|
||||
bool addTime(float time)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -4,15 +4,190 @@
|
||||
#include "Components.h"
|
||||
#include "CharacterModule.h"
|
||||
#include "CharacterAnimationModule.h"
|
||||
#include "StaticGeometryModule.h"
|
||||
#include "PhysicsModule.h"
|
||||
#include "PlayerActionModule.h"
|
||||
#include "items.h"
|
||||
#include "CharacterManagerModule.h"
|
||||
|
||||
namespace ECS
|
||||
{
|
||||
struct TownNPCs {
|
||||
struct NPCData {
|
||||
flecs::entity e;
|
||||
nlohmann::json props;
|
||||
Ogre::Vector3 position;
|
||||
Ogre::Quaternion orientation;
|
||||
Ogre::String model;
|
||||
};
|
||||
|
||||
std::map<int, NPCData> npcs;
|
||||
};
|
||||
struct LivesIn {};
|
||||
void createNPCActionNodes(flecs::entity town, flecs::entity e, int index)
|
||||
{
|
||||
NPCActionNodes &anodes = e.get_mut<NPCActionNodes>();
|
||||
const CharacterBase &ch = e.get<CharacterBase>();
|
||||
Ogre::Vector3 characterPos = ch.mBodyNode->_getDerivedPosition();
|
||||
Ogre::Quaternion characterRot = ch.mBodyNode->_getDerivedOrientation();
|
||||
if (anodes.anodes.size() > 0) {
|
||||
int i;
|
||||
for (i = 0; i < anodes.anodes.size(); i++) {
|
||||
auto &anode = anodes.anodes[i];
|
||||
Ogre::Vector3 offset = Ogre::Vector3::UNIT_Z * 0.3f +
|
||||
Ogre::Vector3::UNIT_Y;
|
||||
if (i == 1)
|
||||
offset = Ogre::Vector3::NEGATIVE_UNIT_Z * 0.3f +
|
||||
Ogre::Vector3::UNIT_Y;
|
||||
anode.position = characterPos + characterRot * offset;
|
||||
anode.rotation = characterRot;
|
||||
to_json(anode.props["position"], anode.position);
|
||||
to_json(anode.props["rotation"], anode.rotation);
|
||||
}
|
||||
e.modified<NPCActionNodes>();
|
||||
return;
|
||||
}
|
||||
{
|
||||
ActionNodeList::ActionNode anode;
|
||||
anode.props["action"] = "talk";
|
||||
anode.props["action_text"] = "Talk";
|
||||
anode.action = "talk";
|
||||
anode.action_text = "Talk";
|
||||
Ogre::Vector3 offset = Ogre::Vector3::UNIT_Z * 0.25f +
|
||||
Ogre::Vector3::UNIT_Y * 1.5f;
|
||||
anode.position = characterPos + characterRot * offset;
|
||||
anode.rotation = characterRot;
|
||||
anode.radius = 0.6f;
|
||||
anode.height = 1.0f;
|
||||
to_json(anode.props["position"], anode.position);
|
||||
to_json(anode.props["rotation"], anode.rotation);
|
||||
|
||||
anode.props["radius"] = anode.radius;
|
||||
anode.props["height"] = anode.height;
|
||||
anode.props["town"] = town.id();
|
||||
anode.props["index"] = index;
|
||||
anodes.anodes.push_back(anode);
|
||||
}
|
||||
{
|
||||
ActionNodeList::ActionNode anode;
|
||||
anode.props["action"] = "action";
|
||||
anode.props["action_text"] = "Action";
|
||||
anode.action = "action";
|
||||
anode.action_text = "Action";
|
||||
Ogre::Vector3 offset = Ogre::Vector3::NEGATIVE_UNIT_Z * 0.2f +
|
||||
Ogre::Vector3::UNIT_Y;
|
||||
anode.position = characterPos + characterRot * offset;
|
||||
anode.rotation = characterRot;
|
||||
anode.radius = 0.3f;
|
||||
anode.height = 1.0f;
|
||||
to_json(anode.props["position"], anode.position);
|
||||
to_json(anode.props["rotation"], anode.rotation);
|
||||
anode.props["radius"] = anode.radius;
|
||||
anode.props["height"] = anode.height;
|
||||
anode.props["town"] = town.id();
|
||||
anode.props["index"] = index;
|
||||
anodes.anodes.push_back(anode);
|
||||
}
|
||||
e.modified<NPCActionNodes>();
|
||||
}
|
||||
CharacterManagerModule::CharacterManagerModule(flecs::world &ecs)
|
||||
{
|
||||
ecs.module<CharacterManagerModule>();
|
||||
ecs.import <CharacterModule>();
|
||||
ecs.import <CharacterAnimationModule>();
|
||||
ecs.import <PhysicsModule>();
|
||||
ecs.import <PlayerActionModule>();
|
||||
ecs.component<TownCharacterHolder>();
|
||||
ecs.component<TownNPCs>();
|
||||
ecs.component<LivesIn>();
|
||||
ecs.component<NPCActionNodes>().on_add(
|
||||
[](flecs::entity e, NPCActionNodes &anodes) {
|
||||
anodes.anodes.clear();
|
||||
});
|
||||
ecs.system<TerrainItem, TownNPCs>("UpdateCharacters")
|
||||
.immediate()
|
||||
.kind(flecs::OnUpdate)
|
||||
.interval(1.0f)
|
||||
.write<CharacterBase>()
|
||||
.write<NPCActionNodes>()
|
||||
.write<CharacterLocation>()
|
||||
.write<CharacterConf>()
|
||||
.write<Character>()
|
||||
.write<LivesIn>()
|
||||
.each([this](flecs::entity town, TerrainItem &item,
|
||||
TownNPCs &npcs) {
|
||||
if (!player.is_valid())
|
||||
return;
|
||||
if (!player.has<CharacterBase>())
|
||||
return;
|
||||
ECS::get().defer_suspend();
|
||||
Ogre::Vector3 cameraPos =
|
||||
player.get<CharacterBase>()
|
||||
.mBodyNode->_getDerivedPosition();
|
||||
for (auto &npc : npcs.npcs) {
|
||||
int index = npc.first;
|
||||
TownNPCs::NPCData &data = npc.second;
|
||||
Ogre::Vector3 npcPosition = data.position;
|
||||
Ogre::Quaternion npcOrientation =
|
||||
data.orientation;
|
||||
if (cameraPos.squaredDistance(npcPosition) <
|
||||
10000.0f) {
|
||||
if (!data.e.is_valid()) {
|
||||
data.e = createCharacterData(
|
||||
data.model,
|
||||
data.position,
|
||||
data.orientation);
|
||||
data.e.add<LivesIn>(town);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cameraPos.squaredDistance(npcPosition) >
|
||||
22500.0f) {
|
||||
if (data.e.is_valid()) {
|
||||
data.e.destruct();
|
||||
data.e = flecs::entity();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ECS::get().defer_resume();
|
||||
});
|
||||
ecs.system<TerrainItem, TownNPCs>("UpdateCharacters2")
|
||||
.immediate()
|
||||
.kind(flecs::OnUpdate)
|
||||
.write<CharacterBase>()
|
||||
.write<NPCActionNodes>()
|
||||
.write<CharacterLocation>()
|
||||
.write<CharacterConf>()
|
||||
.write<Character>()
|
||||
.write<LivesIn>()
|
||||
.each([this](flecs::entity town, TerrainItem &item,
|
||||
TownNPCs &npcs) {
|
||||
if (!player.is_valid())
|
||||
return;
|
||||
if (!player.has<CharacterBase>())
|
||||
return;
|
||||
Ogre::Vector3 cameraPos =
|
||||
player.get<CharacterBase>()
|
||||
.mBodyNode->_getDerivedPosition();
|
||||
for (auto &npc : npcs.npcs) {
|
||||
int index = npc.first;
|
||||
TownNPCs::NPCData &data = npc.second;
|
||||
Ogre::Vector3 npcPosition = data.position;
|
||||
Ogre::Quaternion npcOrientation =
|
||||
data.orientation;
|
||||
if (cameraPos.squaredDistance(npcPosition) <
|
||||
10000.0f) {
|
||||
if (data.e.is_valid()) {
|
||||
if (data.e.has<CharacterBase>() &&
|
||||
data.e.has<LivesIn>(town))
|
||||
createNPCActionNodes(
|
||||
town, data.e,
|
||||
index);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
flecs::entity
|
||||
CharacterManagerModule::createPlayer(const Ogre::Vector3 &position,
|
||||
@@ -43,7 +218,44 @@ CharacterManagerModule::createCharacterData(const Ogre::String model,
|
||||
.entity()
|
||||
.set<CharacterLocation>({ rotation, position })
|
||||
.set<CharacterConf>({ model })
|
||||
.add<Character>();
|
||||
return e;
|
||||
.add<Character>()
|
||||
.add<NPCActionNodes>();
|
||||
return e;
|
||||
}
|
||||
|
||||
void CharacterManagerModule::registerTownCharacters(flecs::entity town)
|
||||
{
|
||||
Ogre::MeshManager::getSingleton().load("normal-male.glb", "General");
|
||||
Ogre::MeshManager::getSingleton().load("normal-female.glb", "General");
|
||||
Ogre::String props = StaticGeometryModule::getItemProperties(town);
|
||||
nlohmann::json j = nlohmann::json::parse(props);
|
||||
nlohmann::json npcs = nlohmann::json::array();
|
||||
if (town.has<TownNPCs>())
|
||||
return;
|
||||
if (j.find("npcs") != j.end())
|
||||
npcs = j["npcs"];
|
||||
std::cout << npcs.dump(4) << std::endl;
|
||||
int index = 0;
|
||||
std::map<int, TownNPCs::NPCData> npcMap;
|
||||
for (auto &npc : npcs) {
|
||||
const char *models[] = { "normal-male.glb",
|
||||
"normal-female.glb" };
|
||||
int sex = npc["sex"].get<int>();
|
||||
Ogre::Vector3 npcPosition;
|
||||
Ogre::Quaternion npcOrientation;
|
||||
from_json(npc["position"], npcPosition);
|
||||
from_json(npc["orientation"], npcOrientation);
|
||||
Ogre::String model = models[sex];
|
||||
TownNPCs::NPCData npcData;
|
||||
npcData.e = flecs::entity();
|
||||
npcData.model = model;
|
||||
npcData.orientation = npcOrientation;
|
||||
npcData.position = npcPosition;
|
||||
npcData.props = npc;
|
||||
npcMap[index] = npcData;
|
||||
index++;
|
||||
}
|
||||
town.set<TownNPCs>({ npcMap });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <flecs.h>
|
||||
namespace ECS
|
||||
{
|
||||
struct TownCharacterHolder{int index;};
|
||||
struct CharacterManagerModule {
|
||||
std::set<flecs::entity> characters;
|
||||
flecs::entity player;
|
||||
@@ -17,6 +18,10 @@ struct CharacterManagerModule {
|
||||
{
|
||||
return player;
|
||||
}
|
||||
void registerTownCharacters(flecs::entity town);
|
||||
void setTownCharacter(flecs::entity town, int index, bool enable);
|
||||
CharacterManagerModule(CharacterManagerModule &&) = delete;
|
||||
CharacterManagerModule &operator=(CharacterManagerModule&&) = delete;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -282,13 +282,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
ch.mBodyNode->setOrientation(loc.orientation);
|
||||
ch.mBodyNode->setPosition(loc.position);
|
||||
ch.mBodyNode->attachObject(ch.mBodyEnt);
|
||||
ch.mSkeleton = ch.mBodyEnt->getSkeleton();
|
||||
OgreAssert(ch.mBodyEnt->getSkeleton()->hasBone("Root"),
|
||||
"No root bone");
|
||||
OgreAssert(ch.mSkeleton->hasBone("Root"),
|
||||
"No root bone");
|
||||
ch.mRootBone = ch.mSkeleton->getBone("Root");
|
||||
OgreAssert(ch.mRootBone, "No root bone");
|
||||
ch.mBoneMotion = Ogre::Vector3::ZERO;
|
||||
ch.mBonePrevMotion = Ogre::Vector3::ZERO;
|
||||
});
|
||||
|
||||
@@ -21,8 +21,6 @@ struct CharacterBase {
|
||||
float mTimer;
|
||||
Ogre::SceneNode *mBodyNode;
|
||||
Ogre::Entity *mBodyEnt;
|
||||
Ogre::Skeleton *mSkeleton;
|
||||
Ogre::Node *mRootBone;
|
||||
Ogre::Vector3 mBoneMotion;
|
||||
Ogre::Vector3 mBonePrevMotion;
|
||||
Ogre::Vector3 mGoalDirection; // actual intended direction in world-space
|
||||
|
||||
1421
src/gamedata/EditorGUIModule.cpp
Normal file
1421
src/gamedata/EditorGUIModule.cpp
Normal file
File diff suppressed because it is too large
Load Diff
9
src/gamedata/EditorGUIModule.h
Normal file
9
src/gamedata/EditorGUIModule.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef __EDITORGUIMODULE_H__
|
||||
#define __EDITORGUIMODULE_H__
|
||||
|
||||
namespace ECS {
|
||||
struct EditorGUIModule {
|
||||
EditorGUIModule(flecs::world &ecs);
|
||||
};
|
||||
}
|
||||
#endif // EDITORGUIMODULE_H
|
||||
@@ -26,4 +26,4 @@ struct EventModule {
|
||||
flecs::entity to);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,40 +6,9 @@ namespace OgreBites
|
||||
}
|
||||
namespace ECS
|
||||
{
|
||||
struct GUI {
|
||||
bool enabled;
|
||||
bool grab;
|
||||
bool grabChanged;
|
||||
bool narrationBox;
|
||||
bool mainMenu;
|
||||
Ogre::String narrationText;
|
||||
std::vector<Ogre::String> choices;
|
||||
int narration_answer;
|
||||
static void setWindowGrab(bool g = true)
|
||||
{
|
||||
ECS::GUI &gui = ECS::get().get_mut<GUI>();
|
||||
if (gui.grab != g) {
|
||||
gui.grab = g;
|
||||
gui.grabChanged = true;
|
||||
ECS::get().modified<GUI>();
|
||||
}
|
||||
}
|
||||
static void finish()
|
||||
{
|
||||
ECS::GUI &gui = ECS::get().get_mut<ECS::GUI>();
|
||||
gui.enabled = false;
|
||||
gui.mainMenu = false;
|
||||
gui.narrationBox = false;
|
||||
ECS::get().modified<ECS::GUI>();
|
||||
setWindowGrab(true);
|
||||
}
|
||||
};
|
||||
struct GUIModule {
|
||||
flecs::entity ui_wait;
|
||||
GUIModule(flecs::world &ecs);
|
||||
};
|
||||
struct EditorGUIModule {
|
||||
EditorGUIModule(flecs::world &ecs);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
127
src/gamedata/GUIModuleCommon.h
Normal file
127
src/gamedata/GUIModuleCommon.h
Normal file
@@ -0,0 +1,127 @@
|
||||
#ifndef __GUIMODULECOMMON_H__
|
||||
#define __GUIMODULECOMMON_H__
|
||||
#include <iostream>
|
||||
#include <Ogre.h>
|
||||
#include "Components.h"
|
||||
#include "GameData.h"
|
||||
namespace ECS
|
||||
{
|
||||
|
||||
struct GUI {
|
||||
bool enabled;
|
||||
bool grab;
|
||||
bool grabChanged;
|
||||
bool narrationBox;
|
||||
bool mainMenu;
|
||||
Ogre::String narrationText;
|
||||
std::vector<Ogre::String> choices;
|
||||
int narration_answer;
|
||||
struct NarrationHandler {
|
||||
private:
|
||||
Ogre::String mnarrationText;
|
||||
std::vector<Ogre::String> mchoices;
|
||||
int narration_answer;
|
||||
|
||||
private:
|
||||
bool complete;
|
||||
bool active;
|
||||
public:
|
||||
bool is_complete()
|
||||
{
|
||||
return complete;
|
||||
}
|
||||
bool is_active()
|
||||
{
|
||||
return active;
|
||||
}
|
||||
const Ogre::String &getNarrationText() const
|
||||
{
|
||||
return mnarrationText;
|
||||
}
|
||||
const std::vector<Ogre::String> &getChoices() const
|
||||
{
|
||||
return mchoices;
|
||||
}
|
||||
void progress()
|
||||
{
|
||||
_event("narration_progress");
|
||||
}
|
||||
void setNarrationAnswer(int answer)
|
||||
{
|
||||
narration_answer = answer;
|
||||
_event("narration_answered");
|
||||
}
|
||||
int getNarrationAnswer() const
|
||||
{
|
||||
return narration_answer;
|
||||
}
|
||||
|
||||
NarrationHandler(): complete(false), active(false) {}
|
||||
private:
|
||||
virtual void finish() = 0;
|
||||
virtual void activate() = 0;
|
||||
virtual void event(const Ogre::String &event) = 0;
|
||||
protected:
|
||||
void _activate()
|
||||
{
|
||||
activate();
|
||||
active = true;
|
||||
}
|
||||
void _finish()
|
||||
{
|
||||
finish();
|
||||
complete = true;
|
||||
}
|
||||
void _narration(const Ogre::String &text, const std::vector<Ogre::String> &choices)
|
||||
{
|
||||
mnarrationText = text;
|
||||
mchoices = choices;
|
||||
|
||||
}
|
||||
void _clear_narration()
|
||||
{
|
||||
mnarrationText = "";
|
||||
mchoices.clear();
|
||||
}
|
||||
public:
|
||||
void _event(const Ogre::String &ev)
|
||||
{
|
||||
if (!active && !complete)
|
||||
_activate();
|
||||
event(ev);
|
||||
}
|
||||
virtual ~NarrationHandler() {}
|
||||
};
|
||||
|
||||
static void setWindowGrab(bool g = true)
|
||||
{
|
||||
ECS::GUI &gui = ECS::get().get_mut<GUI>();
|
||||
if (gui.grab != g) {
|
||||
gui.grab = g;
|
||||
gui.grabChanged = true;
|
||||
ECS::get().modified<GUI>();
|
||||
}
|
||||
}
|
||||
static void finish()
|
||||
{
|
||||
ECS::GUI &gui = ECS::get().get_mut<ECS::GUI>();
|
||||
gui.enabled = false;
|
||||
gui.mainMenu = false;
|
||||
gui.narrationBox = false;
|
||||
ECS::get().modified<ECS::GUI>();
|
||||
setWindowGrab(true);
|
||||
}
|
||||
std::vector<NarrationHandler *> narrationHandlers;
|
||||
void addNarrationHandler(struct NarrationHandler *handler)
|
||||
{
|
||||
narrationHandlers.push_back(handler);
|
||||
}
|
||||
void removeNarrationHandler(struct NarrationHandler *handler)
|
||||
{
|
||||
auto it = std::find(narrationHandlers.begin(), narrationHandlers.end(), handler);
|
||||
narrationHandlers.erase(it);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // GUIMODULECOMMON_H
|
||||
@@ -10,7 +10,9 @@
|
||||
#include "WaterModule.h"
|
||||
#include "TerrainModule.h"
|
||||
#include "SunModule.h"
|
||||
#include "GUIModuleCommon.h"
|
||||
#include "GUIModule.h"
|
||||
#include "EditorGUIModule.h"
|
||||
#include "LuaData.h"
|
||||
#include "WorldMapModule.h"
|
||||
#include "BoatModule.h"
|
||||
@@ -20,6 +22,7 @@
|
||||
#include "EventModule.h"
|
||||
#include "CharacterManagerModule.h"
|
||||
#include "VehicleManagerModule.h"
|
||||
#include "PlayerActionModule.h"
|
||||
#include "AppModule.h"
|
||||
#include "world-build.h"
|
||||
|
||||
@@ -42,7 +45,7 @@ void setup_minimal()
|
||||
ecs.component<Body2Entity>().add(flecs::Singleton);
|
||||
}
|
||||
void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window)
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window)
|
||||
{
|
||||
std::cout << "Setup GameData\n";
|
||||
setup_minimal();
|
||||
@@ -53,11 +56,13 @@ void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
ecs.import <WaterModule>();
|
||||
ecs.import <SunModule>();
|
||||
ecs.import <TerrainModule>();
|
||||
ecs.import <GUIModule>();
|
||||
ecs.import <GUIModule>();
|
||||
ecs.import <EventTriggerModule>();
|
||||
ecs.import <LuaModule>();
|
||||
ecs.import <WorldMapModule>();
|
||||
ecs.import <CharacterAnimationModule>();
|
||||
ecs.import <PlayerActionModule>();
|
||||
ecs.add<ActionNodeList>();
|
||||
|
||||
ecs.system<EngineData>("UpdateDelta")
|
||||
.kind(flecs::OnUpdate)
|
||||
@@ -90,7 +95,7 @@ void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
#endif
|
||||
});
|
||||
ecs.set<EngineData>({ scnMgr, 0.0f, 5.0f, (int)window->getWidth(),
|
||||
(int)window->getHeight(), false });
|
||||
(int)window->getHeight(), false });
|
||||
ecs.set<Camera>({ cameraNode, camera, false });
|
||||
ecs.add<GameData>();
|
||||
ecs.add<Input>();
|
||||
@@ -168,7 +173,7 @@ void setupInventoryScene(Ogre::SceneManager *scnMgr,
|
||||
}
|
||||
|
||||
void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window)
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window)
|
||||
{
|
||||
std::cout << "Setup Editor\n";
|
||||
setup_minimal();
|
||||
@@ -185,6 +190,8 @@ void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
ecs.import <LuaModule>();
|
||||
// ecs.import <WorldMapModule>();
|
||||
ecs.import <CharacterAnimationModule>();
|
||||
ecs.import <PlayerActionModule>();
|
||||
ecs.add<ActionNodeList>();
|
||||
|
||||
ecs.system<EngineData>("UpdateDelta")
|
||||
.kind(flecs::OnUpdate)
|
||||
@@ -217,7 +224,7 @@ void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
#endif
|
||||
});
|
||||
ecs.set<EngineData>({ scnMgr, 0.0f, 5.0f, (int)window->getWidth(),
|
||||
(int)window->getHeight(), false });
|
||||
(int)window->getHeight(), false });
|
||||
ecs.set<Camera>({ cameraNode, camera, false });
|
||||
#if 0
|
||||
ecs.set<EditorSceneSwitch>({ 0 });
|
||||
|
||||
@@ -6,13 +6,13 @@ namespace ECS
|
||||
extern flecs::entity player;
|
||||
void setup_minimal();
|
||||
void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window);
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window);
|
||||
void setupInteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window);
|
||||
void setupInventoryScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window);
|
||||
void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window);
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window);
|
||||
void setupEditorAlt(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window);
|
||||
void update(float delta);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <OgreFileSystemLayer.h>
|
||||
#include "GameData.h"
|
||||
#include "Components.h"
|
||||
#include "GUIModule.h"
|
||||
#include "GUIModuleCommon.h"
|
||||
#include "PhysicsModule.h"
|
||||
#include "CharacterModule.h"
|
||||
#include "CharacterAnimationModule.h"
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "EventTriggerModule.h"
|
||||
#include "SlotsModule.h"
|
||||
#include "world-build.h"
|
||||
#include "PlayerActionModule.h"
|
||||
#include "LuaData.h"
|
||||
#include "luaaa.hpp"
|
||||
extern "C" {
|
||||
@@ -299,7 +300,20 @@ LuaData::LuaData()
|
||||
return 0;
|
||||
});
|
||||
lua_setglobal(L, "setup_handler");
|
||||
lua_pushcfunction(L, [](lua_State *L) -> int {
|
||||
lua_pushcfunction(L, [](lua_State *L) -> int {
|
||||
luaL_checktype(L, 1, LUA_TSTRING);
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||
ECS::get_mut<PlayerActionModule>().setupLuaActionHandler(L);
|
||||
ECS::modified<PlayerActionModule>();
|
||||
return 0;
|
||||
});
|
||||
lua_setglobal(L, "setup_action_handler");
|
||||
lua_pushcfunction(L, [](lua_State *L) -> int {
|
||||
// FIXME
|
||||
return 0;
|
||||
});
|
||||
lua_setglobal(L, "setup_narration_handler");
|
||||
lua_pushcfunction(L, [](lua_State *L) -> int {
|
||||
int args = lua_gettop(L);
|
||||
if (args < 1)
|
||||
return 0;
|
||||
@@ -846,6 +860,7 @@ LuaModule::LuaModule(flecs::world &ecs)
|
||||
ecs.module<LuaModule>();
|
||||
ecs.import <SlotsModule>();
|
||||
ecs.import <VehicleManagerModule>();
|
||||
ecs.import <PlayerActionModule>();
|
||||
ecs.component<LuaChildEventTrigger>();
|
||||
ecs.component<LuaBase>()
|
||||
.on_add([](LuaBase &lua) {
|
||||
@@ -911,4 +926,4 @@ LuaModule::LuaModule(flecs::world &ecs)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ struct LuaData {
|
||||
lua_State *L;
|
||||
std::vector<int> setup_handlers;
|
||||
int setup_handler();
|
||||
int call_handler(const Ogre::String &event);
|
||||
int call_handler(const Ogre::String &event);
|
||||
int call_handler(const Ogre::String &event, flecs::entity e,
|
||||
flecs::entity o);
|
||||
|
||||
|
||||
@@ -172,14 +172,18 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.event(flecs::OnRemove)
|
||||
.each([&](flecs::entity e, const JPH::BodyID &id) {
|
||||
JoltPhysicsWrapper::getSingleton().removeBody(id);
|
||||
JoltPhysicsWrapper::getSingleton().destroyBody(id);
|
||||
if (e.has<CharacterBase>() || e.has<Character>())
|
||||
return;
|
||||
JoltPhysicsWrapper::getSingleton().destroyBody(id);
|
||||
std::cout << "body destroyed" << std::endl;
|
||||
});
|
||||
ecs.observer<const EngineData, const CharacterBase>("SetupCharacterPh")
|
||||
.event(flecs::OnSet)
|
||||
ecs.system<const EngineData, const CharacterBase>("SetupCharacterPh")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<Character>()
|
||||
.without<CharacterBody>()
|
||||
.write<CharacterBody>()
|
||||
.without<CharacterBody>()
|
||||
.without<JPH::BodyID>()
|
||||
.write<CharacterBody>()
|
||||
.write<JPH::BodyID>()
|
||||
.each([](flecs::entity e, const EngineData &eng,
|
||||
const CharacterBase &base) {
|
||||
CharacterBody &b = e.ensure<CharacterBody>();
|
||||
|
||||
320
src/gamedata/PlayerActionModule.cpp
Normal file
320
src/gamedata/PlayerActionModule.cpp
Normal file
@@ -0,0 +1,320 @@
|
||||
#include <nanoflann.hpp>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <flecs.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "Components.h"
|
||||
#include "GameData.h"
|
||||
#include "CharacterManagerModule.h"
|
||||
#include "CharacterModule.h"
|
||||
#include "items.h"
|
||||
#include "GUIModule.h"
|
||||
#include "GUIModuleCommon.h"
|
||||
#include "LuaData.h"
|
||||
#include "PlayerActionModule.h"
|
||||
|
||||
namespace ECS
|
||||
{
|
||||
struct OgreVector3Adaptor {
|
||||
const std::vector<ActionNodeList::ActionNode> &nodes;
|
||||
|
||||
OgreVector3Adaptor(const std::vector<ActionNodeList::ActionNode> &nodes)
|
||||
: nodes(nodes)
|
||||
{
|
||||
}
|
||||
|
||||
// Required by nanoflann: Number of data points
|
||||
inline size_t kdtree_get_point_count() const
|
||||
{
|
||||
return nodes.size();
|
||||
}
|
||||
|
||||
// Required by nanoflann: Returns the distance between the vector and a point
|
||||
// Using squared distance is standard for performance
|
||||
inline float kdtree_get_pt(const size_t idx, const size_t dim) const
|
||||
{
|
||||
return nodes[idx].position[dim];
|
||||
}
|
||||
|
||||
// Optional: bounding box optimization (return false if not implemented)
|
||||
template <class BBOX> bool kdtree_get_bbox(BBOX & /*bb*/) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
typedef nanoflann::KDTreeSingleIndexAdaptor<
|
||||
nanoflann::L2_Simple_Adaptor<float, OgreVector3Adaptor>,
|
||||
OgreVector3Adaptor, 3 /* dimensionality */
|
||||
>
|
||||
OgreKDTree;
|
||||
struct ActionNodeList::indexObject {
|
||||
OgreVector3Adaptor adaptor;
|
||||
OgreKDTree index;
|
||||
indexObject(const std::vector<ActionNodeList::ActionNode> &nodes)
|
||||
: adaptor(nodes)
|
||||
, index(3, adaptor,
|
||||
nanoflann::KDTreeSingleIndexAdaptorParams(10))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct TestNarrativeHandler : GUI::NarrationHandler {
|
||||
int count;
|
||||
TestNarrativeHandler()
|
||||
: GUI::NarrationHandler()
|
||||
, count(0)
|
||||
{
|
||||
}
|
||||
void finish() override
|
||||
{
|
||||
_clear_narration();
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
_narration("Dialogue...", {});
|
||||
count = 0;
|
||||
}
|
||||
void event(const Ogre::String &evt) override
|
||||
{
|
||||
if (evt == "narration_progress" ||
|
||||
evt == "narration_answered") {
|
||||
count++;
|
||||
if (count == 1) {
|
||||
_narration(
|
||||
"Question..." +
|
||||
Ogre::StringConverter::toString(
|
||||
count),
|
||||
{ "Answer1", "Answer2" });
|
||||
} else {
|
||||
_narration(
|
||||
"Whatever..." +
|
||||
Ogre::StringConverter::toString(
|
||||
count),
|
||||
{});
|
||||
}
|
||||
if (count > 5)
|
||||
_finish();
|
||||
}
|
||||
if (evt == "narration_answered")
|
||||
std::cout << "answer: " << getNarrationAnswer()
|
||||
<< std::endl;
|
||||
}
|
||||
};
|
||||
struct SimpleWordHandler : PlayerActionModule::ActionWordHandler {
|
||||
void operator()(flecs::entity town, int index,
|
||||
const Ogre::String &word) override
|
||||
{
|
||||
TestNarrativeHandler *handle = OGRE_NEW TestNarrativeHandler();
|
||||
ECS::get_mut<GUI>().addNarrationHandler(handle);
|
||||
ECS::modified<GUI>();
|
||||
}
|
||||
};
|
||||
|
||||
PlayerActionModule::PlayerActionModule(flecs::world &ecs)
|
||||
{
|
||||
ecs.module<PlayerActionModule>();
|
||||
ecs.import <CharacterManagerModule>();
|
||||
ecs.component<ActionNodeList>()
|
||||
.on_add([](flecs::entity e, ActionNodeList &alist) {
|
||||
alist.dirty = true;
|
||||
alist.nodes.reserve(1000);
|
||||
alist.dynamicNodes.reserve(1000);
|
||||
alist.selected = -1;
|
||||
alist.busy = false;
|
||||
})
|
||||
.add(flecs::Singleton);
|
||||
#if 0
|
||||
ecs.system<ActionNodeList>("testNodeList")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([](ActionNodeList &list) {
|
||||
if (list.nodes.size() > 0) {
|
||||
Ogre::Vector3 queryPos =
|
||||
ECS::get<Camera>()
|
||||
.mCameraNode
|
||||
->_getDerivedPosition();
|
||||
std::vector<size_t> points;
|
||||
list.query(queryPos, points);
|
||||
for (auto &p : points)
|
||||
std::cout << p << std::endl
|
||||
<< list.nodes[p].props.dump()
|
||||
<< std::endl;
|
||||
OgreAssert(points.size() == 0, "got result");
|
||||
}
|
||||
});
|
||||
#endif
|
||||
ecs.system<ActionNodeList>("updateNodeList")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([](ActionNodeList &list) {
|
||||
if (list.busy)
|
||||
return;
|
||||
if (list.nodes.size() > 0) {
|
||||
Ogre::SceneNode *cameraNode =
|
||||
ECS::get<Camera>().mCameraNode;
|
||||
Ogre::Vector3 cameraPos =
|
||||
cameraNode->_getDerivedPosition();
|
||||
flecs::entity player =
|
||||
ECS::get<CharacterManagerModule>()
|
||||
.getPlayer();
|
||||
if (player.is_valid()) {
|
||||
Ogre::Vector3 playerPos =
|
||||
player.get<CharacterBase>()
|
||||
.mBodyNode
|
||||
->_getDerivedPosition();
|
||||
list.query(playerPos, list.points,
|
||||
list.distances);
|
||||
} else {
|
||||
list.query(cameraPos, list.points,
|
||||
list.distances);
|
||||
}
|
||||
}
|
||||
});
|
||||
ecs.system<ActionNodeList, const Input>("ActivateActionNode")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](ActionNodeList &list, const Input &input) {
|
||||
if (input.control & 32)
|
||||
std::cout << "act pressed" << std::endl;
|
||||
if (list.busy)
|
||||
return;
|
||||
if (input.act_pressed && list.selected >= 0) {
|
||||
std::cout << list.dynamicNodes[list.selected]
|
||||
.props.dump(4)
|
||||
<< std::endl;
|
||||
flecs::entity_t townid =
|
||||
list.dynamicNodes[list.selected]
|
||||
.props["town"]
|
||||
.get<flecs::entity_t>();
|
||||
flecs::entity town = ECS::get().entity(townid);
|
||||
int index = list.dynamicNodes[list.selected]
|
||||
.props["index"]
|
||||
.get<int>();
|
||||
for (auto it = actionWords.begin();
|
||||
it != actionWords.end(); it++) {
|
||||
if (it->first ==
|
||||
list.dynamicNodes[list.selected]
|
||||
.action) {
|
||||
(*it->second)(
|
||||
town, index,
|
||||
list.dynamicNodes
|
||||
[list.selected]
|
||||
.action);
|
||||
list.busy = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ECS::get<GUI>().enabled)
|
||||
list.busy = false;
|
||||
});
|
||||
SimpleWordHandler *handler = OGRE_NEW SimpleWordHandler;
|
||||
addWordHandler("talk", handler);
|
||||
}
|
||||
|
||||
void PlayerActionModule::addWordHandler(const Ogre::String &word,
|
||||
ActionWordHandler *handler)
|
||||
{
|
||||
actionWords.insert({ word, handler });
|
||||
}
|
||||
|
||||
void PlayerActionModule::removeWordHandler(const Ogre::String &word,
|
||||
ActionWordHandler *handler)
|
||||
{
|
||||
for (auto it = actionWords.begin(); it != actionWords.end();) {
|
||||
if (it->first == word && it->second == handler)
|
||||
it = actionWords.erase(it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
struct LuaWordHandler : PlayerActionModule::ActionWordHandler {
|
||||
lua_State *L;
|
||||
int ref;
|
||||
void operator()(flecs::entity town, int index,
|
||||
const Ogre::String &word) override
|
||||
{
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
lua_pushinteger(L, town.id());
|
||||
lua_pushinteger(L, index);
|
||||
lua_pushstring(L, word.c_str());
|
||||
if (lua_pcall(L, 3, 0, 0)) {
|
||||
Ogre::LogManager::getSingleton().stream()
|
||||
<< lua_tostring(L, -1);
|
||||
OgreAssert(false, "Lua error");
|
||||
}
|
||||
}
|
||||
};
|
||||
void PlayerActionModule::addLuaWordHandler(const Ogre::String &word,
|
||||
lua_State *L, int ref)
|
||||
{
|
||||
struct LuaWordHandler *handler = OGRE_NEW LuaWordHandler;
|
||||
handler->L = L;
|
||||
handler->ref = ref;
|
||||
addWordHandler(word, handler);
|
||||
}
|
||||
|
||||
void PlayerActionModule::removeLuaWordHandler(const Ogre::String &word,
|
||||
lua_State *L, int ref)
|
||||
{
|
||||
for (auto it = actionWords.begin(); it != actionWords.end();) {
|
||||
LuaWordHandler *handler =
|
||||
static_cast<LuaWordHandler *>(it->second);
|
||||
if (it->first == word && handler->L == L && handler->ref == ref)
|
||||
it = actionWords.erase(it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
int PlayerActionModule::setupLuaActionHandler(lua_State *L)
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TSTRING);
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||
Ogre::String word = lua_tostring(L, 1);
|
||||
lua_pushvalue(L, 2);
|
||||
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
addLuaWordHandler(word, L, ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ActionNodeList::build()
|
||||
{
|
||||
dynamicNodes.clear();
|
||||
dynamicNodes.insert(dynamicNodes.end(), nodes.begin(), nodes.end());
|
||||
ECS::get().query_builder<const NPCActionNodes>().each(
|
||||
[&](flecs::entity e, const NPCActionNodes &anodes) {
|
||||
dynamicNodes.insert(dynamicNodes.end(),
|
||||
anodes.anodes.begin(),
|
||||
anodes.anodes.end());
|
||||
});
|
||||
|
||||
indexObj = std::make_shared<ActionNodeList::indexObject>(dynamicNodes);
|
||||
indexObj->index.buildIndex();
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
bool ActionNodeList::query(const Ogre::Vector3 &position,
|
||||
std::vector<size_t> &points,
|
||||
std::vector<float> &distances)
|
||||
{
|
||||
build();
|
||||
std::vector<size_t> tmppoints;
|
||||
std::vector<float> tmpdistances;
|
||||
points.clear();
|
||||
points.reserve(4);
|
||||
distances.clear();
|
||||
distances.reserve(4);
|
||||
tmppoints.resize(4);
|
||||
tmpdistances.resize(4);
|
||||
nanoflann::KNNResultSet<float> resultSet(4);
|
||||
resultSet.init(tmppoints.data(), tmpdistances.data());
|
||||
bool ret = indexObj->index.findNeighbors(resultSet, &position.x,
|
||||
nanoflann::SearchParameters());
|
||||
int i;
|
||||
for (i = 0; i < resultSet.size(); i++)
|
||||
if (tmpdistances[i] < 25.0f) {
|
||||
points.push_back(tmppoints[i]);
|
||||
distances.push_back(tmpdistances[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
63
src/gamedata/PlayerActionModule.h
Normal file
63
src/gamedata/PlayerActionModule.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef PLAYERACTIONMODULE_H
|
||||
#define PLAYERACTIONMODULE_H
|
||||
#include <flecs.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <lua.h>
|
||||
#include <Ogre.h>
|
||||
|
||||
namespace ECS {
|
||||
|
||||
struct ActionNodeList {
|
||||
struct indexObject;
|
||||
struct ActionNode {
|
||||
Ogre::String action;
|
||||
Ogre::String action_text;
|
||||
Ogre::Vector3 position;
|
||||
Ogre::Quaternion rotation;
|
||||
float height;
|
||||
float radius;
|
||||
nlohmann::json props;
|
||||
};
|
||||
std::vector<ActionNode> nodes, dynamicNodes;
|
||||
std::shared_ptr<indexObject> indexObj;
|
||||
std::vector<size_t> points;
|
||||
std::vector<float> distances;
|
||||
int selected;
|
||||
bool dirty;
|
||||
bool busy;
|
||||
void build();
|
||||
bool query(const Ogre::Vector3 &position, std::vector<size_t> &points, std::vector<float> &distances);
|
||||
int addNode(struct ActionNodeList::ActionNode &node)
|
||||
{
|
||||
int index = nodes.size();
|
||||
nodes.push_back(node);
|
||||
dirty = true;
|
||||
return index;
|
||||
}
|
||||
void removeNode(int index)
|
||||
{
|
||||
nodes.erase(nodes.begin() + index);
|
||||
}
|
||||
};
|
||||
struct NPCActionNodes {
|
||||
std::vector<ActionNodeList::ActionNode> anodes;
|
||||
};
|
||||
struct PlayerActionModule {
|
||||
struct ActionWordHandler {
|
||||
virtual void operator()(flecs::entity town, int index,
|
||||
const Ogre::String &word) = 0;
|
||||
};
|
||||
|
||||
std::multimap<Ogre::String, ActionWordHandler *>
|
||||
actionWords;
|
||||
|
||||
PlayerActionModule(flecs::world &ecs);
|
||||
void addWordHandler(const Ogre::String &word, ActionWordHandler *handler);
|
||||
void removeWordHandler(const Ogre::String &word, ActionWordHandler *handler);
|
||||
void addLuaWordHandler(const Ogre::String &word, lua_State *L, int ref);
|
||||
void removeLuaWordHandler(const Ogre::String &word, lua_State *L, int ref);
|
||||
int setupLuaActionHandler(lua_State *L);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // PLAYERACTIONMODULE_H
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <OgreRTShaderSystem.h>
|
||||
#include <OgreStaticGeometry.h>
|
||||
#include <OgreMeshLodGenerator.h>
|
||||
#include <OgreWorkQueue.h>
|
||||
#include <Procedural.h>
|
||||
#include "Components.h"
|
||||
#include "GameData.h"
|
||||
@@ -19,13 +20,42 @@ namespace ECS
|
||||
{
|
||||
|
||||
static bool itemsLoaded = false;
|
||||
static bool furnitureLoaded = false;
|
||||
static bool templatesLoaded = false;
|
||||
static std::list<std::pair<long, long> > addQueue;
|
||||
StaticGeometryModule::StaticGeometryModule(flecs::world &ecs)
|
||||
{
|
||||
ecs.module<StaticGeometryModule>();
|
||||
ecs.component<TerrainSlotParent>();
|
||||
ecs.component<TerrainItem>();
|
||||
ecs.component<TerrainItemNode>().on_remove([](flecs::entity e,
|
||||
ecs.component<FurnitureItem>();
|
||||
ecs.component<FurnitureInstance>()
|
||||
.on_remove([](flecs::entity e, FurnitureInstance &instance) {
|
||||
if (instance.furniture) {
|
||||
instance.furniture
|
||||
->destroyAllChildrenAndObjects();
|
||||
instance.furniture->getCreator()
|
||||
->destroySceneNode(instance.furniture);
|
||||
instance.furniture = nullptr;
|
||||
}
|
||||
})
|
||||
.on_set([](flecs::entity e, FurnitureInstance &instance) {
|
||||
if (instance.furniture !=
|
||||
e.get<FurnitureInstance>().furniture) {
|
||||
FurnitureInstance &f =
|
||||
e.get_mut<FurnitureInstance>();
|
||||
if (f.furniture) {
|
||||
f.furniture
|
||||
->destroyAllChildrenAndObjects();
|
||||
f.furniture->getCreator()
|
||||
->destroySceneNode(f.furniture);
|
||||
}
|
||||
}
|
||||
})
|
||||
.on_add([](flecs::entity e, FurnitureInstance &instance) {
|
||||
instance.furniture = nullptr;
|
||||
});
|
||||
ecs.component<TerrainItemNode>().on_remove([](flecs::entity e,
|
||||
TerrainItemNode &item) {
|
||||
if (item.itemNode) {
|
||||
item.itemNode->destroyAllChildrenAndObjects();
|
||||
@@ -40,6 +70,7 @@ StaticGeometryModule::StaticGeometryModule(flecs::world &ecs)
|
||||
}
|
||||
});
|
||||
ecs.component<TerrainItemMeshNode>();
|
||||
ecs.component<GeometryUpdateItem>();
|
||||
ecs.import <TerrainModule>();
|
||||
ecs.observer<const Terrain>("LoadTerrainItems")
|
||||
.event(flecs::OnSet)
|
||||
@@ -60,6 +91,14 @@ StaticGeometryModule::StaticGeometryModule(flecs::world &ecs)
|
||||
itemsLoaded = true;
|
||||
return;
|
||||
}
|
||||
if (!furnitureLoaded) {
|
||||
loadFurniture();
|
||||
furnitureLoaded = true;
|
||||
}
|
||||
if (!templatesLoaded) {
|
||||
loadTemplates();
|
||||
templatesLoaded = true;
|
||||
}
|
||||
std::list<std::pair<long, long> > output;
|
||||
while (!addQueue.empty()) {
|
||||
std::pair<long, long> item = addQueue.front();
|
||||
@@ -157,8 +196,48 @@ void StaticGeometryModule::setItemProperties(flecs::entity id,
|
||||
const Ogre::String &StaticGeometryModule::getItemProperties(flecs::entity id)
|
||||
{
|
||||
OgreAssert(id.is_valid(), "bad id");
|
||||
return id.get<TerrainItem>().properties;
|
||||
return id.get<TerrainItem>().properties;
|
||||
}
|
||||
|
||||
nlohmann::json templates;
|
||||
void StaticGeometryModule::loadTemplates()
|
||||
{
|
||||
if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(
|
||||
"templates.list"))
|
||||
return;
|
||||
Ogre::String group =
|
||||
Ogre::ResourceGroupManager::getSingleton()
|
||||
.findGroupContainingResource("templates.list");
|
||||
Ogre::DataStreamPtr stream =
|
||||
Ogre::ResourceGroupManager::getSingleton().openResource(
|
||||
"templates.list", group);
|
||||
Ogre::String json = stream->getAsString();
|
||||
nlohmann::json jtemplates = nlohmann::json::parse(json);
|
||||
templates = jtemplates;
|
||||
}
|
||||
|
||||
void StaticGeometryModule::saveTemplates()
|
||||
{
|
||||
Ogre::String path = "resources/buildings/templates.list";
|
||||
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(
|
||||
"templates.list")) {
|
||||
Ogre::String group =
|
||||
Ogre::ResourceGroupManager::getSingleton()
|
||||
.findGroupContainingResource("templates.list");
|
||||
Ogre::FileInfoListPtr fileInfoList(
|
||||
Ogre::ResourceGroupManager::getSingleton()
|
||||
.findResourceFileInfo(group, "templates.list"));
|
||||
OgreAssert(fileInfoList->size() == 1,
|
||||
"templates.list should be there and only once");
|
||||
path = fileInfoList->at(0).archive->getName() + "/" +
|
||||
"templates.list";
|
||||
Ogre::FileSystemLayer::removeFile(path);
|
||||
}
|
||||
std::fstream fout(path.c_str(), std::ios::out);
|
||||
fout << templates.dump();
|
||||
fout.close();
|
||||
}
|
||||
|
||||
void StaticGeometryModule::saveItems()
|
||||
{
|
||||
Ogre::String path = "resources/buildings/items.list";
|
||||
@@ -271,463 +350,457 @@ void StaticGeometryModule::loadItems()
|
||||
<< std::endl;
|
||||
std::cout << "position: " << item.id() << " " << position
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StaticGeometryModule::saveFurniture()
|
||||
{
|
||||
/* No saving - furniture is generated by blender */
|
||||
}
|
||||
|
||||
void StaticGeometryModule::loadFurniture()
|
||||
{
|
||||
ECS::get().delete_with<FurnitureItem>();
|
||||
static std::vector<Ogre::String> glb_names;
|
||||
const std::vector<Ogre::String> &groups =
|
||||
Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
|
||||
if (glb_names.size() == 0) {
|
||||
int i;
|
||||
for (i = 0; i < groups.size(); i++) {
|
||||
std::vector<Ogre::String> names =
|
||||
*Ogre::ResourceGroupManager::getSingleton()
|
||||
.findResourceNames(
|
||||
groups[i],
|
||||
"furniture-*.glb.json");
|
||||
glb_names.insert(glb_names.end(), names.begin(),
|
||||
names.end());
|
||||
}
|
||||
}
|
||||
for (auto &g : glb_names) {
|
||||
Ogre::String group = Ogre::ResourceGroupManager::getSingleton()
|
||||
.findGroupContainingResource(g);
|
||||
Ogre::DataStreamPtr stream =
|
||||
Ogre::ResourceGroupManager::getSingleton().openResource(
|
||||
g, group);
|
||||
Ogre::String json = stream->getAsString();
|
||||
nlohmann::json jdata = nlohmann::json::parse(json);
|
||||
std::vector<Ogre::String> tags;
|
||||
for (auto &tag : jdata["tags"]) {
|
||||
Ogre::String stag = tag.get<Ogre::String>();
|
||||
tags.push_back(stag);
|
||||
}
|
||||
Ogre::String meshName = jdata["mesh"].get<Ogre::String>();
|
||||
Ogre::MeshPtr mesh =
|
||||
Ogre::MeshManager::getSingleton().getByName(meshName);
|
||||
if (mesh) {
|
||||
Ogre::LodConfig meshconf(mesh);
|
||||
Geometry::setupLods(meshconf);
|
||||
}
|
||||
ECS::get().entity().set<FurnitureItem>({ json, tags });
|
||||
std::cout << "path: " << g << std::endl;
|
||||
}
|
||||
}
|
||||
void StaticGeometryModule::getItemPositionPerSlot(
|
||||
long x, long y, std::list<Ogre::Vector3> *positions)
|
||||
long x, long y, std::list<Ogre::Vector3> *positions)
|
||||
{
|
||||
std::pair<long, long> pos{ x, y };
|
||||
if (!positions)
|
||||
return;
|
||||
flecs::entity slot =
|
||||
ECS::get().query_builder<const TerrainSlotParent>().build().find(
|
||||
[&](const TerrainSlotParent &slot) -> bool {
|
||||
return slot.slot == pos;
|
||||
std::pair<long, long> pos{ x, y };
|
||||
if (!positions)
|
||||
return;
|
||||
flecs::entity slot =
|
||||
ECS::get().query_builder<const TerrainSlotParent>().build().find(
|
||||
[&](const TerrainSlotParent &slot) -> bool {
|
||||
return slot.slot == pos;
|
||||
});
|
||||
if (!slot.is_valid())
|
||||
return;
|
||||
ECS::get()
|
||||
.query_builder<const TerrainItem>()
|
||||
.with(flecs::ChildOf, slot)
|
||||
.build()
|
||||
.each([&](flecs::entity e, const TerrainItem &item) {
|
||||
positions->push_back(item.position);
|
||||
});
|
||||
if (!slot.is_valid())
|
||||
return;
|
||||
ECS::get()
|
||||
.query_builder<const TerrainItem>()
|
||||
.with(flecs::ChildOf, slot)
|
||||
.build()
|
||||
.each([&](flecs::entity e, const TerrainItem &item) {
|
||||
positions->push_back(item.position);
|
||||
});
|
||||
}
|
||||
void StaticGeometryModule::getItemPositions(std::list<Ogre::Vector3> *positions)
|
||||
{
|
||||
ECS::get().query_builder<const TerrainItem>().build().each(
|
||||
[&](flecs::entity e, const TerrainItem &item) {
|
||||
positions->push_back(item.position);
|
||||
});
|
||||
ECS::get().query_builder<const TerrainItem>().build().each(
|
||||
[&](flecs::entity e, const TerrainItem &item) {
|
||||
positions->push_back(item.position);
|
||||
});
|
||||
}
|
||||
void StaticGeometryModule::getItemPositionAndRotation(
|
||||
flecs::entity e, Ogre::Vector3 &position, Ogre::Quaternion &orientation)
|
||||
flecs::entity e, Ogre::Vector3 &position, Ogre::Quaternion &orientation)
|
||||
{
|
||||
position = e.get<TerrainItem>().position;
|
||||
orientation = e.get<TerrainItem>().orientation;
|
||||
position = e.get<TerrainItem>().position;
|
||||
orientation = e.get<TerrainItem>().orientation;
|
||||
}
|
||||
void StaticGeometryModule::getItemsProperties(
|
||||
std::list<std::pair<flecs::entity, Ogre::String> > *items)
|
||||
std::list<std::pair<flecs::entity, Ogre::String> > *items)
|
||||
{
|
||||
ECS::get().query_builder<const TerrainItem>().build().each(
|
||||
[&](flecs::entity e, const TerrainItem &item) {
|
||||
items->push_back({ e, item.properties });
|
||||
});
|
||||
ECS::get().query_builder<const TerrainItem>().build().each(
|
||||
[&](flecs::entity e, const TerrainItem &item) {
|
||||
items->push_back({ e, item.properties });
|
||||
});
|
||||
}
|
||||
void StaticGeometryModule::createItemGeometry(flecs::entity e)
|
||||
{
|
||||
Geometry::createItemGeometry(e);
|
||||
Geometry::createItemGeometry(e);
|
||||
}
|
||||
|
||||
void StaticGeometryModule::destroyItemGeometry(flecs::entity e)
|
||||
{
|
||||
Geometry::destroyItemGeometry(e);
|
||||
Geometry::destroyItemGeometry(e);
|
||||
}
|
||||
|
||||
nlohmann::json &StaticGeometryModule::getTemplates()
|
||||
{
|
||||
return templates;
|
||||
}
|
||||
|
||||
void StaticGeometryModule::updateItemGeometry(flecs::entity e)
|
||||
{
|
||||
if (e.has<GeometryUpdateItem>())
|
||||
return;
|
||||
e.add<GeometryUpdateItem>();
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask([e]() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask(
|
||||
[e]() {
|
||||
Geometry::updateItemGeometry(e);
|
||||
e.remove<GeometryUpdateItem>();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void StaticGeometryModule::addTriangleBufferWork(
|
||||
const Ogre::String &meshName, Ogre::StaticGeometry *geo,
|
||||
const Ogre::Vector3 &position, const Ogre::Quaternion &rotation,
|
||||
const Procedural::TriangleBuffer &tb)
|
||||
{
|
||||
struct WorkData {
|
||||
Ogre::String meshName;
|
||||
Ogre::StaticGeometry *geo;
|
||||
Ogre::Vector3 position;
|
||||
Ogre::Quaternion rotation;
|
||||
Procedural::TriangleBuffer tb;
|
||||
};
|
||||
WorkData data = { meshName, geo, position, rotation, tb };
|
||||
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask([captData = std::move(
|
||||
data)]() {
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask(
|
||||
[captData]() {
|
||||
Ogre::MeshPtr mesh =
|
||||
captData.tb.transformToMesh(
|
||||
captData.meshName);
|
||||
Ogre::Entity *ent =
|
||||
ECS::get<EngineData>()
|
||||
.mScnMgr->createEntity(mesh);
|
||||
captData.geo->addEntity(ent, captData.position,
|
||||
captData.rotation);
|
||||
ECS::get<EngineData>().mScnMgr->destroyEntity(
|
||||
ent);
|
||||
});
|
||||
});
|
||||
}
|
||||
struct TiledMeshes {
|
||||
struct Tile {
|
||||
Ogre::String materialName;
|
||||
std::shared_ptr<Ogre::VertexData> vertexData;
|
||||
std::shared_ptr<Ogre::IndexData> indexData;
|
||||
std::set<uint32_t> positions;
|
||||
};
|
||||
std::map<Ogre::String, Tile> tiles;
|
||||
uint32_t packKey(const Ogre::Vector3i &position)
|
||||
struct Tile {
|
||||
Ogre::String materialName;
|
||||
std::shared_ptr<Ogre::VertexData> vertexData;
|
||||
std::shared_ptr<Ogre::IndexData> indexData;
|
||||
std::set<uint32_t> positions;
|
||||
};
|
||||
std::map<Ogre::String, Tile> tiles;
|
||||
uint32_t packKey(const Ogre::Vector3i &position)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
key |= (uint32_t)(position[2] + 512) << 20;
|
||||
key |= (uint32_t)(position[1] + 512) << 10;
|
||||
key |= (uint32_t)(position[0] + 512) << 0;
|
||||
return key;
|
||||
uint32_t key = 0;
|
||||
key |= (uint32_t)(position[2] + 512) << 20;
|
||||
key |= (uint32_t)(position[1] + 512) << 10;
|
||||
key |= (uint32_t)(position[0] + 512) << 0;
|
||||
return key;
|
||||
}
|
||||
void unpackKey(uint32_t key, Ogre::Vector3i &position)
|
||||
void unpackKey(uint32_t key, Ogre::Vector3i &position)
|
||||
{
|
||||
uint32_t mask = 0x3ff;
|
||||
position[0] = (int)(key & mask) - 512;
|
||||
position[1] = (int)((key >> 10) & mask) - 512;
|
||||
position[2] = (int)((key >> 20) & mask) - 512;
|
||||
uint32_t mask = 0x3ff;
|
||||
position[0] = (int)(key & mask) - 512;
|
||||
position[1] = (int)((key >> 10) & mask) - 512;
|
||||
position[2] = (int)((key >> 20) & mask) - 512;
|
||||
}
|
||||
void setTile(const Ogre::String &name, const Ogre::Vector3i &position)
|
||||
void setTile(const Ogre::String &name, const Ogre::Vector3i &position)
|
||||
{
|
||||
if (tiles.find(name) == tiles.end())
|
||||
return;
|
||||
tiles[name].positions.insert(packKey(position));
|
||||
if (tiles.find(name) == tiles.end())
|
||||
return;
|
||||
tiles[name].positions.insert(packKey(position));
|
||||
}
|
||||
void clearTile(const Ogre::String &name, const Ogre::Vector3i &position)
|
||||
void clearTile(const Ogre::String &name, const Ogre::Vector3i &position)
|
||||
{
|
||||
if (tiles.find(name) == tiles.end())
|
||||
return;
|
||||
tiles[name].positions.erase(packKey(position));
|
||||
#if 0
|
||||
auto pos = std::find(tiles[name].positions.begin(),
|
||||
tiles[name].positions.end(),
|
||||
packKey(position));
|
||||
if (pos != tiles[name].positions.end())
|
||||
tiles[name].positions.erase(pos);
|
||||
#endif
|
||||
}
|
||||
void addTile(const Ogre::String &name, Ogre::MeshPtr mesh)
|
||||
{
|
||||
if (mesh->getSubMeshes().size() != 1)
|
||||
return;
|
||||
Ogre::SubMesh *submesh = mesh->getSubMesh(0);
|
||||
Ogre::VertexData *vertexData;
|
||||
if (submesh->useSharedVertices)
|
||||
vertexData = mesh->sharedVertexData->clone();
|
||||
else
|
||||
vertexData = submesh->vertexData->clone();
|
||||
tiles[name] = { submesh->getMaterialName(),
|
||||
std::shared_ptr<Ogre::VertexData>(vertexData),
|
||||
std::shared_ptr<Ogre::IndexData>(
|
||||
submesh->indexData->clone()),
|
||||
{} };
|
||||
#if 0
|
||||
std::vector<Ogre::Vector3> vertices;
|
||||
std::vector<uint32_t> indices;
|
||||
int count = mesh->getNumSubMeshes();
|
||||
int i, j;
|
||||
int indexCount = 0;
|
||||
int vertexCount = 0;
|
||||
int sharedVertexOffset = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
Ogre::SubMesh *submesh = mesh->getSubMesh(i);
|
||||
indexCount += submesh->indexData->indexCount;
|
||||
if (submesh->useSharedVertices)
|
||||
vertexCount +=
|
||||
mesh->sharedVertexData->vertexCount;
|
||||
else
|
||||
vertexCount += submesh->vertexData->vertexCount;
|
||||
}
|
||||
indices.reserve(indexCount);
|
||||
vertices.reserve(vertexCount);
|
||||
size_t currentVertexOffset = 0;
|
||||
bool added_shared = false;
|
||||
for (i = 0; i < count; i++) {
|
||||
Ogre::SubMesh *submesh = mesh->getSubMesh(i);
|
||||
Ogre::VertexData *vertex_data =
|
||||
submesh->useSharedVertices ?
|
||||
mesh->sharedVertexData :
|
||||
submesh->vertexData;
|
||||
bool add_vertices =
|
||||
(submesh->useSharedVertices && !added_shared) ||
|
||||
!submesh->useSharedVertices;
|
||||
if (add_vertices) {
|
||||
if (submesh->useSharedVertices)
|
||||
sharedVertexOffset = vertices.size();
|
||||
const Ogre::VertexDeclaration *decl =
|
||||
vertex_data->vertexDeclaration;
|
||||
const Ogre::VertexBufferBinding *bind =
|
||||
vertex_data->vertexBufferBinding;
|
||||
const Ogre::VertexElement *position_element =
|
||||
decl->findElementBySemantic(
|
||||
Ogre::VES_POSITION);
|
||||
if (!position_element)
|
||||
continue;
|
||||
Ogre::HardwareVertexBufferSharedPtr vbuf =
|
||||
bind->getBuffer(
|
||||
position_element->getSource());
|
||||
unsigned char *vertex_buffer = static_cast<
|
||||
unsigned char *>(vbuf->lock(
|
||||
Ogre::HardwareBuffer::HBL_READ_ONLY));
|
||||
int vertexSize = vbuf->getVertexSize();
|
||||
for (j = 0; j < vertex_data->vertexCount; j++) {
|
||||
float *position_data;
|
||||
position_element
|
||||
->baseVertexPointerToElement(
|
||||
vertex_buffer,
|
||||
&position_data);
|
||||
vertices.push_back(
|
||||
{ position_data[0],
|
||||
position_data[1],
|
||||
position_data[2] });
|
||||
vertex_buffer += vertexSize;
|
||||
}
|
||||
if (submesh->useSharedVertices)
|
||||
added_shared = true;
|
||||
vbuf->unlock();
|
||||
}
|
||||
Ogre::HardwareIndexBufferSharedPtr ibuf =
|
||||
submesh->indexData->indexBuffer;
|
||||
size_t numIndices = submesh->indexData->indexCount;
|
||||
size_t vertexOffset = submesh->useSharedVertices ?
|
||||
sharedVertexOffset :
|
||||
currentVertexOffset;
|
||||
if (ibuf->getType() ==
|
||||
Ogre::HardwareIndexBuffer::IT_32BIT) {
|
||||
unsigned int *pIndices = static_cast<
|
||||
unsigned int *>(ibuf->lock(
|
||||
Ogre::HardwareBuffer::HBL_READ_ONLY));
|
||||
for (j = 0; j < numIndices; j++) {
|
||||
indices.push_back(
|
||||
(uint32_t)pIndices[j] +
|
||||
vertexOffset);
|
||||
}
|
||||
ibuf->unlock();
|
||||
} else {
|
||||
unsigned short *pIndices = static_cast<
|
||||
unsigned short *>(ibuf->lock(
|
||||
Ogre::HardwareBuffer::HBL_READ_ONLY));
|
||||
for (j = 0; j < numIndices; j++) {
|
||||
indices.push_back(
|
||||
(uint32_t)pIndices[j] +
|
||||
vertexOffset);
|
||||
}
|
||||
ibuf->unlock();
|
||||
}
|
||||
currentVertexOffset = vertices.size();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
struct buildSettings {
|
||||
Ogre::String meshName;
|
||||
Ogre::String materialName;
|
||||
Ogre::MeshPtr mesh;
|
||||
Ogre::SubMesh *sm;
|
||||
int vertexCount, vertexOffset;
|
||||
int indexCount, indexOffset;
|
||||
Ogre::VertexDeclaration *vdecl;
|
||||
Ogre::HardwareVertexBufferSharedPtr vbuf;
|
||||
Ogre::AxisAlignedBox bounds;
|
||||
bool setBounds;
|
||||
};
|
||||
void configureSettings(struct buildSettings &settings)
|
||||
{
|
||||
settings.mesh = Ogre::MeshManager::getSingleton().createManual(
|
||||
settings.meshName,
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||
settings.mesh->createVertexData();
|
||||
settings.sm = settings.mesh->createSubMesh();
|
||||
settings.vertexCount = 0;
|
||||
settings.indexCount = 0;
|
||||
settings.vdecl = nullptr;
|
||||
for (const auto &tile : tiles) {
|
||||
settings.vertexCount +=
|
||||
tile.second.vertexData->vertexCount *
|
||||
tile.second.positions.size();
|
||||
settings.indexCount +=
|
||||
tile.second.indexData->indexCount *
|
||||
tile.second.positions.size();
|
||||
if (!settings.vdecl) {
|
||||
settings.vdecl =
|
||||
tile.second.vertexData
|
||||
->vertexDeclaration->clone();
|
||||
settings.materialName =
|
||||
tile.second.materialName;
|
||||
if (tiles.find(name) == tiles.end())
|
||||
return;
|
||||
tiles[name].positions.erase(packKey(position));
|
||||
}
|
||||
void addTile(const Ogre::String &name, Ogre::MeshPtr mesh)
|
||||
{
|
||||
if (mesh->getSubMeshes().size() != 1)
|
||||
return;
|
||||
Ogre::SubMesh *submesh = mesh->getSubMesh(0);
|
||||
Ogre::VertexData *vertexData;
|
||||
if (submesh->useSharedVertices)
|
||||
vertexData = mesh->sharedVertexData->clone();
|
||||
else
|
||||
vertexData = submesh->vertexData->clone();
|
||||
tiles[name] = { submesh->getMaterialName(),
|
||||
std::shared_ptr<Ogre::VertexData>(vertexData),
|
||||
std::shared_ptr<Ogre::IndexData>(
|
||||
submesh->indexData->clone()),
|
||||
{} };
|
||||
}
|
||||
struct buildSettings {
|
||||
Ogre::String meshName;
|
||||
Ogre::String materialName;
|
||||
Ogre::MeshPtr mesh;
|
||||
Ogre::SubMesh *sm;
|
||||
int vertexCount, vertexOffset;
|
||||
int indexCount, indexOffset;
|
||||
Ogre::VertexDeclaration *vdecl;
|
||||
Ogre::HardwareVertexBufferSharedPtr vbuf;
|
||||
Ogre::AxisAlignedBox bounds;
|
||||
bool setBounds;
|
||||
};
|
||||
void configureSettings(struct buildSettings &settings)
|
||||
{
|
||||
settings.mesh = Ogre::MeshManager::getSingleton().createManual(
|
||||
settings.meshName,
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||
settings.mesh->createVertexData();
|
||||
settings.sm = settings.mesh->createSubMesh();
|
||||
settings.vertexCount = 0;
|
||||
settings.indexCount = 0;
|
||||
settings.vdecl = nullptr;
|
||||
for (const auto &tile : tiles) {
|
||||
settings.vertexCount +=
|
||||
tile.second.vertexData->vertexCount *
|
||||
tile.second.positions.size();
|
||||
settings.indexCount +=
|
||||
tile.second.indexData->indexCount *
|
||||
tile.second.positions.size();
|
||||
if (!settings.vdecl) {
|
||||
settings.vdecl =
|
||||
tile.second.vertexData
|
||||
->vertexDeclaration->clone();
|
||||
settings.materialName =
|
||||
tile.second.materialName;
|
||||
}
|
||||
}
|
||||
settings.mesh->sharedVertexData->vertexStart = 0;
|
||||
settings.mesh->sharedVertexData->vertexCount =
|
||||
settings.vertexCount;
|
||||
settings.mesh->sharedVertexData->vertexDeclaration =
|
||||
settings.vdecl;
|
||||
settings.vbuf =
|
||||
Ogre::HardwareBufferManager::getSingleton()
|
||||
.createVertexBuffer(
|
||||
settings.vdecl->getVertexSize(0),
|
||||
settings.vertexCount,
|
||||
Ogre::HBU_GPU_ONLY);
|
||||
settings.mesh->sharedVertexData->vertexBufferBinding->setBinding(
|
||||
0, settings.vbuf);
|
||||
settings.sm->indexData->indexStart = 0;
|
||||
settings.sm->indexData->indexCount = settings.indexCount;
|
||||
settings.sm->indexData->indexBuffer =
|
||||
Ogre::HardwareBufferManager::getSingleton()
|
||||
.createIndexBuffer(
|
||||
Ogre::HardwareIndexBuffer::IT_32BIT,
|
||||
settings.sm->indexData->indexCount * 8,
|
||||
Ogre::HBU_GPU_ONLY);
|
||||
settings.sm->setMaterialName(settings.materialName);
|
||||
settings.setBounds = true;
|
||||
}
|
||||
void processIndex(struct buildSettings &settings,
|
||||
const struct Tile &tile, unsigned int *dstIndices)
|
||||
{
|
||||
int j;
|
||||
std::shared_ptr<Ogre::IndexData> srcIndexData = tile.indexData;
|
||||
int srcIndexCount = srcIndexData->indexCount;
|
||||
std::shared_ptr<Ogre::VertexData> srcVertexData =
|
||||
tile.vertexData;
|
||||
int srcVertexCount = srcVertexData->vertexCount;
|
||||
Ogre::HardwareIndexBufferSharedPtr srcIbuf =
|
||||
srcIndexData->indexBuffer;
|
||||
Ogre::HardwareBufferLockGuard srcIndexLock(
|
||||
srcIbuf, Ogre::HardwareBuffer::HBL_READ_ONLY);
|
||||
if (srcIndexData->indexBuffer->getType() ==
|
||||
Ogre::HardwareIndexBuffer::IT_32BIT) {
|
||||
unsigned int *indices =
|
||||
static_cast<unsigned int *>(srcIndexLock.pData);
|
||||
for (j = 0; j < srcIndexCount; j++)
|
||||
dstIndices[settings.indexOffset + j] =
|
||||
indices[j] + settings.vertexOffset;
|
||||
} else if (srcIndexData->indexBuffer->getType() ==
|
||||
Ogre::HardwareIndexBuffer::IT_16BIT) {
|
||||
unsigned short *indices = static_cast<unsigned short *>(
|
||||
srcIndexLock.pData);
|
||||
for (j = 0; j < srcIndexCount; j++)
|
||||
dstIndices[settings.indexOffset + j] =
|
||||
indices[j] + settings.vertexOffset;
|
||||
}
|
||||
}
|
||||
void processSingleVertex(
|
||||
struct buildSettings &settings,
|
||||
const Ogre::VertexDeclaration::VertexElementList &srcElements,
|
||||
uint32_t offset, unsigned char *srcData, unsigned char *dstData)
|
||||
{
|
||||
for (const auto &srcElement : srcElements) {
|
||||
unsigned char *srcPtr, *dstPtr;
|
||||
const Ogre::VertexElement *destElement =
|
||||
settings.vdecl->findElementBySemantic(
|
||||
srcElement.getSemantic(),
|
||||
srcElement.getIndex());
|
||||
if (!destElement)
|
||||
goto out;
|
||||
if (srcElement.getType() != destElement->getType() ||
|
||||
srcElement.getSize() != destElement->getSize())
|
||||
goto out;
|
||||
srcPtr = srcData + srcElement.getOffset();
|
||||
dstPtr = dstData + destElement->getOffset();
|
||||
if (destElement->getSemantic() == Ogre::VES_POSITION) {
|
||||
float *srcPositionData =
|
||||
reinterpret_cast<float *>(srcPtr);
|
||||
float *dstPositionData =
|
||||
reinterpret_cast<float *>(dstPtr);
|
||||
Ogre::Vector3 position(srcPositionData[0],
|
||||
srcPositionData[1],
|
||||
srcPositionData[2]);
|
||||
Ogre::Vector3i offsetv;
|
||||
unpackKey(offset, offsetv);
|
||||
position.x += (float)offsetv[0];
|
||||
position.y += (float)offsetv[1];
|
||||
position.z += (float)offsetv[2];
|
||||
dstPositionData[0] = position.x;
|
||||
dstPositionData[1] = position.y;
|
||||
dstPositionData[2] = position.z;
|
||||
if (settings.setBounds) {
|
||||
settings.bounds.setMinimum(position);
|
||||
settings.bounds.setMaximum(position);
|
||||
settings.setBounds = false;
|
||||
settings.mesh->sharedVertexData->vertexStart = 0;
|
||||
settings.mesh->sharedVertexData->vertexCount =
|
||||
settings.vertexCount;
|
||||
settings.mesh->sharedVertexData->vertexDeclaration =
|
||||
settings.vdecl;
|
||||
settings.vbuf =
|
||||
Ogre::HardwareBufferManager::getSingleton()
|
||||
.createVertexBuffer(
|
||||
settings.vdecl->getVertexSize(0),
|
||||
settings.vertexCount,
|
||||
Ogre::HBU_GPU_ONLY);
|
||||
settings.mesh->sharedVertexData->vertexBufferBinding->setBinding(
|
||||
0, settings.vbuf);
|
||||
settings.sm->indexData->indexStart = 0;
|
||||
settings.sm->indexData->indexCount = settings.indexCount;
|
||||
settings.sm->indexData->indexBuffer =
|
||||
Ogre::HardwareBufferManager::getSingleton()
|
||||
.createIndexBuffer(
|
||||
Ogre::HardwareIndexBuffer::IT_32BIT,
|
||||
settings.sm->indexData->indexCount * 8,
|
||||
Ogre::HBU_GPU_ONLY);
|
||||
settings.sm->setMaterialName(settings.materialName);
|
||||
settings.setBounds = true;
|
||||
}
|
||||
void processIndex(struct buildSettings &settings,
|
||||
const struct Tile &tile, unsigned int *dstIndices)
|
||||
{
|
||||
int j;
|
||||
std::shared_ptr<Ogre::IndexData> srcIndexData = tile.indexData;
|
||||
int srcIndexCount = srcIndexData->indexCount;
|
||||
std::shared_ptr<Ogre::VertexData> srcVertexData =
|
||||
tile.vertexData;
|
||||
int srcVertexCount = srcVertexData->vertexCount;
|
||||
Ogre::HardwareIndexBufferSharedPtr srcIbuf =
|
||||
srcIndexData->indexBuffer;
|
||||
Ogre::HardwareBufferLockGuard srcIndexLock(
|
||||
srcIbuf, Ogre::HardwareBuffer::HBL_READ_ONLY);
|
||||
if (srcIndexData->indexBuffer->getType() ==
|
||||
Ogre::HardwareIndexBuffer::IT_32BIT) {
|
||||
unsigned int *indices =
|
||||
static_cast<unsigned int *>(srcIndexLock.pData);
|
||||
for (j = 0; j < srcIndexCount; j++)
|
||||
dstIndices[settings.indexOffset + j] =
|
||||
indices[j] + settings.vertexOffset;
|
||||
} else if (srcIndexData->indexBuffer->getType() ==
|
||||
Ogre::HardwareIndexBuffer::IT_16BIT) {
|
||||
unsigned short *indices = static_cast<unsigned short *>(
|
||||
srcIndexLock.pData);
|
||||
for (j = 0; j < srcIndexCount; j++)
|
||||
dstIndices[settings.indexOffset + j] =
|
||||
indices[j] + settings.vertexOffset;
|
||||
}
|
||||
}
|
||||
void processSingleVertex(
|
||||
struct buildSettings &settings,
|
||||
const Ogre::VertexDeclaration::VertexElementList &srcElements,
|
||||
uint32_t offset, unsigned char *srcData, unsigned char *dstData)
|
||||
{
|
||||
for (const auto &srcElement : srcElements) {
|
||||
unsigned char *srcPtr, *dstPtr;
|
||||
const Ogre::VertexElement *destElement =
|
||||
settings.vdecl->findElementBySemantic(
|
||||
srcElement.getSemantic(),
|
||||
srcElement.getIndex());
|
||||
if (!destElement)
|
||||
goto out;
|
||||
if (srcElement.getType() != destElement->getType() ||
|
||||
srcElement.getSize() != destElement->getSize())
|
||||
goto out;
|
||||
srcPtr = srcData + srcElement.getOffset();
|
||||
dstPtr = dstData + destElement->getOffset();
|
||||
if (destElement->getSemantic() == Ogre::VES_POSITION) {
|
||||
float *srcPositionData =
|
||||
reinterpret_cast<float *>(srcPtr);
|
||||
float *dstPositionData =
|
||||
reinterpret_cast<float *>(dstPtr);
|
||||
Ogre::Vector3 position(srcPositionData[0],
|
||||
srcPositionData[1],
|
||||
srcPositionData[2]);
|
||||
Ogre::Vector3i offsetv;
|
||||
unpackKey(offset, offsetv);
|
||||
position.x += (float)offsetv[0];
|
||||
position.y += (float)offsetv[1];
|
||||
position.z += (float)offsetv[2];
|
||||
dstPositionData[0] = position.x;
|
||||
dstPositionData[1] = position.y;
|
||||
dstPositionData[2] = position.z;
|
||||
if (settings.setBounds) {
|
||||
settings.bounds.setMinimum(position);
|
||||
settings.bounds.setMaximum(position);
|
||||
settings.setBounds = false;
|
||||
} else
|
||||
settings.bounds.merge(position);
|
||||
} else if (destElement->getSemantic() ==
|
||||
Ogre::VES_NORMAL) {
|
||||
float *srcNormalData =
|
||||
reinterpret_cast<float *>(srcPtr);
|
||||
float *dstNormalData =
|
||||
reinterpret_cast<float *>(dstPtr);
|
||||
Ogre::Vector3 normal(srcNormalData[0],
|
||||
srcNormalData[1],
|
||||
srcNormalData[2]);
|
||||
dstNormalData[0] = normal.x;
|
||||
dstNormalData[1] = normal.y;
|
||||
dstNormalData[2] = normal.z;
|
||||
} else
|
||||
memcpy(dstPtr, srcPtr, srcElement.getSize());
|
||||
settings.bounds.merge(position);
|
||||
} else if (destElement->getSemantic() ==
|
||||
Ogre::VES_NORMAL) {
|
||||
float *srcNormalData =
|
||||
reinterpret_cast<float *>(srcPtr);
|
||||
float *dstNormalData =
|
||||
reinterpret_cast<float *>(dstPtr);
|
||||
Ogre::Vector3 normal(srcNormalData[0],
|
||||
srcNormalData[1],
|
||||
srcNormalData[2]);
|
||||
dstNormalData[0] = normal.x;
|
||||
dstNormalData[1] = normal.y;
|
||||
dstNormalData[2] = normal.z;
|
||||
} else
|
||||
memcpy(dstPtr, srcPtr, srcElement.getSize());
|
||||
out:;
|
||||
}
|
||||
}
|
||||
void processTile(struct buildSettings &settings,
|
||||
const struct Tile &tile, uint32_t position,
|
||||
unsigned char *dstpData)
|
||||
{
|
||||
std::shared_ptr<Ogre::VertexData> srcVertexData =
|
||||
tile.vertexData;
|
||||
const Ogre::VertexDeclaration *srcDecl =
|
||||
srcVertexData->vertexDeclaration;
|
||||
const Ogre::VertexBufferBinding *srcBind =
|
||||
srcVertexData->vertexBufferBinding;
|
||||
int srcVertexCount = srcVertexData->vertexCount;
|
||||
Ogre::HardwareVertexBufferSharedPtr srcVbuf =
|
||||
srcBind->getBuffer(0);
|
||||
std::shared_ptr<Ogre::IndexData> srcIndexData = tile.indexData;
|
||||
int srcIndexCount = srcIndexData->indexCount;
|
||||
}
|
||||
}
|
||||
void processTile(struct buildSettings &settings,
|
||||
const struct Tile &tile, uint32_t position,
|
||||
unsigned char *dstpData)
|
||||
{
|
||||
std::shared_ptr<Ogre::VertexData> srcVertexData =
|
||||
tile.vertexData;
|
||||
const Ogre::VertexDeclaration *srcDecl =
|
||||
srcVertexData->vertexDeclaration;
|
||||
const Ogre::VertexBufferBinding *srcBind =
|
||||
srcVertexData->vertexBufferBinding;
|
||||
int srcVertexCount = srcVertexData->vertexCount;
|
||||
Ogre::HardwareVertexBufferSharedPtr srcVbuf =
|
||||
srcBind->getBuffer(0);
|
||||
std::shared_ptr<Ogre::IndexData> srcIndexData = tile.indexData;
|
||||
int srcIndexCount = srcIndexData->indexCount;
|
||||
|
||||
Ogre::HardwareBufferLockGuard srcVertexLock(
|
||||
srcVbuf, 0, srcVertexCount * srcDecl->getVertexSize(0),
|
||||
Ogre::HardwareBuffer::HBL_READ_ONLY);
|
||||
const Ogre::VertexDeclaration::VertexElementList &srcElements =
|
||||
srcDecl->getElements();
|
||||
int j;
|
||||
unsigned char *srcpData =
|
||||
static_cast<unsigned char *>(srcVertexLock.pData);
|
||||
Ogre::HardwareBufferLockGuard srcVertexLock(
|
||||
srcVbuf, 0, srcVertexCount * srcDecl->getVertexSize(0),
|
||||
Ogre::HardwareBuffer::HBL_READ_ONLY);
|
||||
const Ogre::VertexDeclaration::VertexElementList &srcElements =
|
||||
srcDecl->getElements();
|
||||
int j;
|
||||
unsigned char *srcpData =
|
||||
static_cast<unsigned char *>(srcVertexLock.pData);
|
||||
|
||||
for (j = 0; j < srcVertexCount; j++) {
|
||||
unsigned char *srcData =
|
||||
srcpData + j * srcVbuf->getVertexSize();
|
||||
unsigned char *dstData =
|
||||
dstpData + (settings.vertexOffset +
|
||||
j) * settings.vbuf->getVertexSize();
|
||||
processSingleVertex(settings, srcElements, position,
|
||||
srcData, dstData);
|
||||
for (j = 0; j < srcVertexCount; j++) {
|
||||
unsigned char *srcData =
|
||||
srcpData + j * srcVbuf->getVertexSize();
|
||||
unsigned char *dstData =
|
||||
dstpData + (settings.vertexOffset +
|
||||
j) * settings.vbuf->getVertexSize();
|
||||
processSingleVertex(settings, srcElements, position,
|
||||
srcData, dstData);
|
||||
}
|
||||
}
|
||||
Ogre::MeshPtr build(const Ogre::String &meshName)
|
||||
{
|
||||
buildSettings settings;
|
||||
settings.meshName = meshName;
|
||||
configureSettings(settings);
|
||||
}
|
||||
Ogre::MeshPtr build(const Ogre::String &meshName)
|
||||
{
|
||||
buildSettings settings;
|
||||
settings.meshName = meshName;
|
||||
configureSettings(settings);
|
||||
{
|
||||
Ogre::HardwareBufferLockGuard vertexLock(
|
||||
settings.vbuf, 0,
|
||||
settings.vertexCount *
|
||||
settings.vdecl->getVertexSize(0),
|
||||
Ogre::HardwareBuffer::HBL_NO_OVERWRITE);
|
||||
Ogre::HardwareBufferLockGuard indexLock(
|
||||
settings.sm->indexData->indexBuffer,
|
||||
Ogre::HardwareBuffer::HBL_NO_OVERWRITE);
|
||||
settings.vertexOffset = 0;
|
||||
settings.indexOffset = 0;
|
||||
unsigned char *dstpData =
|
||||
static_cast<unsigned char *>(vertexLock.pData);
|
||||
unsigned int *dstIndices =
|
||||
static_cast<unsigned int *>(indexLock.pData);
|
||||
Ogre::HardwareBufferLockGuard vertexLock(
|
||||
settings.vbuf, 0,
|
||||
settings.vertexCount *
|
||||
settings.vdecl->getVertexSize(0),
|
||||
Ogre::HardwareBuffer::HBL_NO_OVERWRITE);
|
||||
Ogre::HardwareBufferLockGuard indexLock(
|
||||
settings.sm->indexData->indexBuffer,
|
||||
Ogre::HardwareBuffer::HBL_NO_OVERWRITE);
|
||||
settings.vertexOffset = 0;
|
||||
settings.indexOffset = 0;
|
||||
unsigned char *dstpData =
|
||||
static_cast<unsigned char *>(vertexLock.pData);
|
||||
unsigned int *dstIndices =
|
||||
static_cast<unsigned int *>(indexLock.pData);
|
||||
|
||||
for (const auto &tile : tiles) {
|
||||
std::shared_ptr<Ogre::IndexData> srcIndexData =
|
||||
tile.second.indexData;
|
||||
int srcIndexCount = srcIndexData->indexCount;
|
||||
std::shared_ptr<Ogre::VertexData> srcVertexData =
|
||||
tile.second.vertexData;
|
||||
int srcVertexCount = srcVertexData->vertexCount;
|
||||
for (const auto &position :
|
||||
tile.second.positions) {
|
||||
processTile(settings, tile.second,
|
||||
position, dstpData);
|
||||
processIndex(settings, tile.second,
|
||||
dstIndices);
|
||||
settings.vertexOffset += srcVertexCount;
|
||||
settings.indexOffset += srcIndexCount;
|
||||
Ogre::Vector3i vposition;
|
||||
unpackKey(position, vposition);
|
||||
std::cout << "position: " << position
|
||||
<< " " << vposition
|
||||
<< std::endl;
|
||||
for (const auto &tile : tiles) {
|
||||
std::shared_ptr<Ogre::IndexData> srcIndexData =
|
||||
tile.second.indexData;
|
||||
int srcIndexCount = srcIndexData->indexCount;
|
||||
std::shared_ptr<Ogre::VertexData> srcVertexData =
|
||||
tile.second.vertexData;
|
||||
int srcVertexCount = srcVertexData->vertexCount;
|
||||
for (const auto &position :
|
||||
tile.second.positions) {
|
||||
processTile(settings, tile.second,
|
||||
position, dstpData);
|
||||
processIndex(settings, tile.second,
|
||||
dstIndices);
|
||||
settings.vertexOffset += srcVertexCount;
|
||||
settings.indexOffset += srcIndexCount;
|
||||
Ogre::Vector3i vposition;
|
||||
unpackKey(position, vposition);
|
||||
std::cout << "position: " << position
|
||||
<< " " << vposition
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
settings.mesh->_setBounds(settings.bounds);
|
||||
}
|
||||
Ogre::LodConfig config(settings.mesh);
|
||||
// config.advanced.useCompression = false;
|
||||
// config.advanced.useVertexNormals = true;
|
||||
config.advanced.preventPunchingHoles = true;
|
||||
config.advanced.preventBreakingLines = true;
|
||||
config.createGeneratedLodLevel(2, 0.15f);
|
||||
config.createGeneratedLodLevel(20, 0.49f);
|
||||
#if 0
|
||||
}
|
||||
settings.mesh->_setBounds(settings.bounds);
|
||||
}
|
||||
Ogre::LodConfig config(settings.mesh);
|
||||
// config.advanced.useCompression = false;
|
||||
// config.advanced.useVertexNormals = true;
|
||||
config.advanced.preventPunchingHoles = true;
|
||||
config.advanced.preventBreakingLines = true;
|
||||
config.createGeneratedLodLevel(2, 0.15f);
|
||||
config.createGeneratedLodLevel(20, 0.49f);
|
||||
config.createGeneratedLodLevel(15, 0.49f);
|
||||
config.createGeneratedLodLevel(150, 0.75f);
|
||||
#endif
|
||||
config.advanced.useBackgroundQueue = false;
|
||||
Ogre::MeshLodGenerator::getSingleton().generateLodLevels(
|
||||
config);
|
||||
return settings.mesh;
|
||||
}
|
||||
void removeTile(const Ogre::String &name)
|
||||
{
|
||||
tiles.erase(name);
|
||||
}
|
||||
TiledMeshes()
|
||||
{
|
||||
}
|
||||
config.advanced.useBackgroundQueue = false;
|
||||
Ogre::MeshLodGenerator::getSingleton().generateLodLevels(
|
||||
config);
|
||||
return settings.mesh;
|
||||
}
|
||||
void removeTile(const Ogre::String &name)
|
||||
{
|
||||
tiles.erase(name);
|
||||
}
|
||||
TiledMeshes()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
#include <flecs.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <Ogre.h>
|
||||
namespace Procedural
|
||||
{
|
||||
class TriangleBuffer;
|
||||
}
|
||||
namespace Ogre
|
||||
{
|
||||
struct LodConfig;
|
||||
@@ -25,6 +29,15 @@ struct TerrainItemMeshNode {
|
||||
Ogre::SceneNode *itemNode;
|
||||
Ogre::StaticGeometry *geo;
|
||||
};
|
||||
struct FurnitureItem {
|
||||
Ogre::String properties;
|
||||
std::vector<Ogre::String> tags;
|
||||
};
|
||||
struct FurnitureInstance {
|
||||
Ogre::SceneNode *furniture;
|
||||
};
|
||||
struct GeometryUpdateItem {};
|
||||
|
||||
struct TownCollider {};
|
||||
|
||||
struct StaticGeometryModule {
|
||||
@@ -37,8 +50,12 @@ struct StaticGeometryModule {
|
||||
static void setItemProperties(flecs::entity id,
|
||||
Ogre::String properties);
|
||||
static const Ogre::String &getItemProperties(flecs::entity id);
|
||||
static void saveItems();
|
||||
static void loadTemplates();
|
||||
static void saveTemplates();
|
||||
static void saveItems();
|
||||
static void loadItems();
|
||||
static void saveFurniture();
|
||||
static void loadFurniture();
|
||||
static void getItemPositionPerSlot(long x, long y,
|
||||
std::list<Ogre::Vector3> *positions);
|
||||
static void getItemPositions(std::list<Ogre::Vector3> *positions);
|
||||
@@ -49,6 +66,13 @@ struct StaticGeometryModule {
|
||||
std::list<std::pair<flecs::entity, Ogre::String> > *items);
|
||||
static void createItemGeometry(flecs::entity e);
|
||||
static void destroyItemGeometry(flecs::entity e);
|
||||
static nlohmann::json &getTemplates();
|
||||
static void updateItemGeometry(flecs::entity e);
|
||||
static void addTriangleBufferWork(const Ogre::String &meshName,
|
||||
Ogre::StaticGeometry *geo,
|
||||
const Ogre::Vector3 &position,
|
||||
const Ogre::Quaternion &rotation,
|
||||
const Procedural::TriangleBuffer &tb);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@ find_package(Bullet REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
find_package(OgreProcedural REQUIRED CONFIG)
|
||||
add_library(items STATIC items.cpp harbour.cpp temple.cpp town.cpp)
|
||||
target_include_directories(items PUBLIC .)
|
||||
target_include_directories(items PUBLIC . ${CMAKE_SOURCE_DIR}/src/FastNoiseLite)
|
||||
target_link_libraries(items PRIVATE
|
||||
flecs::flecs_static
|
||||
nlohmann_json::nlohmann_json
|
||||
@@ -13,4 +13,4 @@ target_link_libraries(items PRIVATE
|
||||
OgreBites
|
||||
editor
|
||||
physics
|
||||
)
|
||||
)
|
||||
|
||||
@@ -22,6 +22,22 @@ namespace ECS
|
||||
{
|
||||
namespace Items
|
||||
{
|
||||
void runScriptsForAllTowns()
|
||||
{
|
||||
std::pair<flecs::entity, Ogre::String> selected_item;
|
||||
std::list<std::pair<flecs::entity, Ogre::String> > items;
|
||||
StaticGeometryModule::getItemsProperties(&items);
|
||||
for (const auto &item : items) {
|
||||
nlohmann::json j = nlohmann::json::parse(item.second);
|
||||
Ogre::String itemType = j["type"].get<Ogre::String>();
|
||||
if (itemType == "town") {
|
||||
Items::runAllScriptsForTown(item.first);
|
||||
if (item.first.has<TerrainItemNode>())
|
||||
Geometry::updateItemGeometry(item.first);
|
||||
}
|
||||
}
|
||||
StaticGeometryModule::saveItems();
|
||||
}
|
||||
void showItemPopup(const std::pair<flecs::entity, Ogre::String> &item)
|
||||
{
|
||||
Ogre::String popupLabel =
|
||||
@@ -131,8 +147,7 @@ void showItemPopup(const std::pair<flecs::entity, Ogre::String> &item)
|
||||
orientation;
|
||||
item.first.modified<TerrainItem>();
|
||||
StaticGeometryModule::saveItems();
|
||||
StaticGeometryModule::destroyItemGeometry(item.first);
|
||||
StaticGeometryModule::createItemGeometry(item.first);
|
||||
StaticGeometryModule::updateItemGeometry(item.first);
|
||||
}
|
||||
if (itemType == "harbour")
|
||||
createHarbourPopup(item);
|
||||
@@ -194,17 +209,39 @@ namespace Geometry
|
||||
{
|
||||
void setupLods(Ogre::LodConfig &config)
|
||||
{
|
||||
int count = 0;
|
||||
// config.advanced.useCompression = false;
|
||||
config.advanced.useVertexNormals = true;
|
||||
config.advanced.preventPunchingHoles = true;
|
||||
config.advanced.preventBreakingLines = true;
|
||||
config.createGeneratedLodLevel(10, 0.15f);
|
||||
config.createGeneratedLodLevel(50, 0.25f);
|
||||
config.createGeneratedLodLevel(100, 0.36f);
|
||||
config.createGeneratedLodLevel(200, 0.50f);
|
||||
// config.createGeneratedLodLevel(50, 0.25f);
|
||||
// config.createGeneratedLodLevel(100, 0.36f);
|
||||
// config.createGeneratedLodLevel(200, 0.50f);
|
||||
config.createGeneratedLodLevel(500, 0.85f);
|
||||
config.advanced.useBackgroundQueue = false;
|
||||
Ogre::MeshLodGenerator::getSingleton().generateLodLevels(config);
|
||||
std::cout << "mesh name: " << config.mesh->getName() << std::endl;
|
||||
bool crash = false;
|
||||
for (count = 0; count < config.mesh->getSubMeshes().size(); count++) {
|
||||
Ogre::SubMesh *submesh = config.mesh->getSubMeshes()[count];
|
||||
std::cout << "unprocessed submesh: " << count << " " << submesh
|
||||
<< std::endl;
|
||||
if (submesh)
|
||||
submesh->parent = config.mesh.get();
|
||||
else
|
||||
crash = true;
|
||||
}
|
||||
Ogre::MeshLodGenerator::getSingleton().generateLodLevels(config);
|
||||
for (count = 0; count < config.mesh->getSubMeshes().size(); count++) {
|
||||
Ogre::SubMesh *submesh = config.mesh->getSubMeshes()[count];
|
||||
std::cout << "submesh: " << count << " " << submesh
|
||||
<< std::endl;
|
||||
if (submesh)
|
||||
submesh->parent = config.mesh.get();
|
||||
else
|
||||
crash = true;
|
||||
}
|
||||
OgreAssert(!crash, "no submesh");
|
||||
}
|
||||
|
||||
Ogre::StaticGeometry *createStaticGeometry(flecs::entity e)
|
||||
@@ -294,6 +331,14 @@ void destroyItemGeometry(flecs::entity e)
|
||||
#endif
|
||||
e.remove<TerrainItemNode>();
|
||||
}
|
||||
void updateItemGeometry(flecs::entity e)
|
||||
{
|
||||
OgreAssert(e.has<TerrainItem>(), "not terrain item");
|
||||
if (e.has<TerrainItemNode>())
|
||||
destroyItemGeometry(e);
|
||||
createItemGeometry(e);
|
||||
}
|
||||
|
||||
flecs::entity createMeshGeometry(const Ogre::String &meshName,
|
||||
flecs::entity parente,
|
||||
Ogre::SceneNode *sceneNode,
|
||||
@@ -322,7 +367,7 @@ flecs::entity createMeshGeometry(const Ogre::String &meshName,
|
||||
.set<TerrainItemMeshNode>({ sceneNode, geo });
|
||||
JoltPhysicsWrapper::getSingleton().addBody(id,
|
||||
JPH::EActivation::Activate);
|
||||
return e;
|
||||
return e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Items
|
||||
void showItemPopup(const std::pair<flecs::entity, Ogre::String> &item);
|
||||
void showItemButtons(const std::pair<flecs::entity, Ogre::String> &item);
|
||||
void createItemsMenu();
|
||||
void runScriptsForAllTowns();
|
||||
}
|
||||
namespace Geometry
|
||||
{
|
||||
@@ -53,6 +54,7 @@ struct harbourMaker {
|
||||
};
|
||||
void createItemGeometry(flecs::entity e);
|
||||
void destroyItemGeometry(flecs::entity e);
|
||||
void updateItemGeometry(flecs::entity e);
|
||||
flecs::entity createMeshGeometry(const Ogre::String &meshName,
|
||||
flecs::entity parente,
|
||||
Ogre::SceneNode *sceneNode,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,25 +12,15 @@ namespace Items
|
||||
void createTownItem();
|
||||
void createTownMenu();
|
||||
void createTownPopup(const std::pair<flecs::entity, Ogre::String> item);
|
||||
void runAllScriptsForTown(flecs::entity e);
|
||||
}
|
||||
namespace Geometry
|
||||
{
|
||||
void clampUV(flecs::entity e, Procedural::TriangleBuffer &tb,
|
||||
const Ogre::String &rectKey);
|
||||
Ogre::MaterialPtr createTownMaterial(flecs::entity e, bool force = false);
|
||||
void createCells(flecs::entity e, const nlohmann::json &jdistrict, int index,
|
||||
Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo);
|
||||
void createTown(flecs::entity e, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo);
|
||||
void createTownPlazza(flecs::entity e, const nlohmann::json &jdistrict,
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo);
|
||||
void createTownLots(flecs::entity e, const nlohmann::json &jdistrict,
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo);
|
||||
void createTownRoofs(flecs::entity e, const nlohmann::json &jdistrict,
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -90,7 +90,10 @@ public:
|
||||
Layers::MOVING; // Non moving only collides with moving
|
||||
case Layers::MOVING:
|
||||
return true; // Moving collides with everything
|
||||
default:
|
||||
case Layers::SENSORS:
|
||||
return inObject2 ==
|
||||
Layers::MOVING; // Non moving only collides with moving
|
||||
default:
|
||||
JPH_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
@@ -107,7 +110,8 @@ public:
|
||||
mObjectToBroadPhase[Layers::NON_MOVING] =
|
||||
BroadPhaseLayers::NON_MOVING;
|
||||
mObjectToBroadPhase[Layers::MOVING] = BroadPhaseLayers::MOVING;
|
||||
}
|
||||
mObjectToBroadPhase[Layers::SENSORS] = BroadPhaseLayers::MOVING;
|
||||
}
|
||||
|
||||
virtual uint GetNumBroadPhaseLayers() const override
|
||||
{
|
||||
@@ -1330,7 +1334,18 @@ public:
|
||||
OgreAssert(result.Get(), "Can not create com offset shape");
|
||||
return result.Get();
|
||||
}
|
||||
void applyBuoyancyImpulse(JPH::BodyID id,
|
||||
JPH::ShapeRefC
|
||||
createRotatedTranslatedShape(const Ogre::Vector3 &offset,
|
||||
const Ogre::Quaternion rotation,
|
||||
JPH::ShapeRefC shape)
|
||||
{
|
||||
return JPH::RotatedTranslatedShapeSettings(
|
||||
JoltPhysics::convert(offset),
|
||||
JoltPhysics::convert(rotation), shape)
|
||||
.Create()
|
||||
.Get();
|
||||
}
|
||||
void applyBuoyancyImpulse(JPH::BodyID id,
|
||||
const Ogre::Vector3 &surfacePosition,
|
||||
const Ogre::Vector3 &surfaceNormal,
|
||||
float buoyancy, float linearDrag,
|
||||
@@ -1597,7 +1612,14 @@ JPH::ShapeRefC
|
||||
JoltPhysicsWrapper::createOffsetCenterOfMassShape(const Ogre::Vector3 &offset,
|
||||
JPH::ShapeRefC shape)
|
||||
{
|
||||
return phys->createOffsetCenterOfMassShape(offset, shape);
|
||||
return phys->createOffsetCenterOfMassShape(offset, shape);
|
||||
}
|
||||
|
||||
JPH::ShapeRefC JoltPhysicsWrapper::createRotatedTranslatedShape(
|
||||
const Ogre::Vector3 &offset, const Ogre::Quaternion rotation,
|
||||
JPH::ShapeRefC shape)
|
||||
{
|
||||
return phys->createRotatedTranslatedShape(offset, rotation, shape);
|
||||
}
|
||||
|
||||
JPH::BodyID
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace Layers
|
||||
{
|
||||
static constexpr JPH::ObjectLayer NON_MOVING = 0;
|
||||
static constexpr JPH::ObjectLayer MOVING = 1;
|
||||
static constexpr JPH::ObjectLayer NUM_LAYERS = 2;
|
||||
static constexpr JPH::ObjectLayer SENSORS = 2;
|
||||
static constexpr JPH::ObjectLayer NUM_LAYERS = 3;
|
||||
};
|
||||
|
||||
// Each broadphase layer results in a separate bounding volume tree in the broad phase. You at least want to have
|
||||
@@ -134,7 +135,10 @@ public:
|
||||
JPH::ShapeRefC
|
||||
createOffsetCenterOfMassShape(const Ogre::Vector3 &offset,
|
||||
JPH::ShapeRefC shape);
|
||||
JPH::BodyID createBody(const JPH::BodyCreationSettings &settings);
|
||||
JPH::ShapeRefC
|
||||
createRotatedTranslatedShape(const Ogre::Vector3 &offset, const Ogre::Quaternion rotation,
|
||||
JPH::ShapeRefC shape);
|
||||
JPH::BodyID createBody(const JPH::BodyCreationSettings &settings);
|
||||
JPH::BodyID createBody(const JPH::Shape *shape, float mass,
|
||||
const Ogre::Vector3 &position,
|
||||
const Ogre::Quaternion &rotation,
|
||||
|
||||
Reference in New Issue
Block a user