Compare commits
6 Commits
bf25ef1a80
...
884a310033
| Author | SHA1 | Date | |
|---|---|---|---|
| 884a310033 | |||
| b363742507 | |||
| a85152a675 | |||
| 71b7f47bcd | |||
| 74a1adfb27 | |||
| 7947690e80 |
@@ -29,6 +29,7 @@ find_package(assimp REQUIRED CONFIG)
|
||||
find_package(OgreProcedural REQUIRED CONFIG)
|
||||
find_package(pugixml REQUIRED CONFIG)
|
||||
find_package(flecs REQUIRED CONFIG)
|
||||
find_package(Tracy REQUIRED CONFIG)
|
||||
|
||||
add_library(fix::assimp INTERFACE IMPORTED)
|
||||
set_target_properties(fix::assimp PROPERTIES
|
||||
@@ -81,11 +82,12 @@ add_executable(Game Game.cpp ${WATER_SRC})
|
||||
target_include_directories(Game PRIVATE src/gamedata)
|
||||
target_link_libraries(Game OgreBites OgrePaging OgreTerrain OgreMeshLodGenerator
|
||||
OgreProcedural::OgreProcedural
|
||||
OgreCrowd
|
||||
GameData
|
||||
sound
|
||||
sceneloader physics
|
||||
OgreCrowd
|
||||
sceneloader physics lua
|
||||
flecs::flecs_static
|
||||
Tracy::TracyClient
|
||||
-Wl,--as-needed
|
||||
)
|
||||
if(OGRE_STATIC)
|
||||
@@ -244,7 +246,7 @@ add_custom_target(stage_files ALL DEPENDS ${CMAKE_BINARY_DIR}/resources.cfg ${MA
|
||||
|
||||
add_custom_target(remove_scenes COMMAND rm -f ${VRM_SOURCE} ${VRM_IMPORTED_BLENDS} ${CHARACTER_GLBS})
|
||||
|
||||
target_compile_definitions(Game PRIVATE FLECS_CPP_NO_AUTO_REGISTRATION JPH_PROFILE_ENABLED)
|
||||
target_compile_definitions(Game PRIVATE FLECS_CPP_NO_AUTO_REGISTRATION JPH_PROFILE_ENABLED JPH_DEBUG_RENDERER JPH_PROFILE_ENABLED JPH_DOUBLE_PRECISION)
|
||||
|
||||
install(TARGETS Game DESTINATION bin)
|
||||
install(TARGETS Editor DESTINATION bin)
|
||||
|
||||
97
Game.cpp
97
Game.cpp
@@ -10,7 +10,6 @@
|
||||
#include <OgreTimer.h>
|
||||
#include <OgreMeshLodGenerator.h>
|
||||
|
||||
// #include "water/water.h"
|
||||
#include "GameData.h"
|
||||
#include "Components.h"
|
||||
#include "CharacterModule.h"
|
||||
@@ -21,6 +20,7 @@
|
||||
#include "PhysicsModule.h"
|
||||
#include "physics.h"
|
||||
#include "sound.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
class App;
|
||||
class SkyRenderer : public Ogre::SceneManager::Listener {
|
||||
protected:
|
||||
@@ -477,6 +477,7 @@ public:
|
||||
}
|
||||
void updateWorld(float delta)
|
||||
{
|
||||
ZoneScoped;
|
||||
if (!ECS::get().has<ECS::GUI>())
|
||||
goto end;
|
||||
{
|
||||
@@ -628,11 +629,11 @@ end:
|
||||
void setupInput()
|
||||
{
|
||||
}
|
||||
JoltPhysicsWrapper *mJolt;
|
||||
JoltPhysicsWrapper *mJolt;
|
||||
void createContent()
|
||||
{
|
||||
int i;
|
||||
mJolt = new JoltPhysicsWrapper(mScnMgr, mCameraNode);
|
||||
mJolt = new JoltPhysicsWrapper(mScnMgr, mCameraNode);
|
||||
|
||||
sky = new SkyBoxRenderer(getSceneManager());
|
||||
bool drawFirst = true;
|
||||
@@ -738,40 +739,50 @@ end:
|
||||
};
|
||||
void KeyboardListener::frameRendered(const Ogre::FrameEvent &evt)
|
||||
{
|
||||
if (fps_timer.getMilliseconds() > 1000.0f) {
|
||||
std::cout << "FPS: "
|
||||
<< mApp->getRenderWindow()->getStatistics().lastFPS
|
||||
<< " ";
|
||||
std::cout << "Draw calls: "
|
||||
<< mApp->getRenderWindow()->getStatistics().batchCount
|
||||
<< " ";
|
||||
fps_timer.reset();
|
||||
std::cout << "Drops: "
|
||||
<< mApp->getRenderWindow()
|
||||
->getStatistics()
|
||||
.vBlankMissCount
|
||||
<< "\n";
|
||||
fps_timer.reset();
|
||||
}
|
||||
if (!isGuiEnabled() ||
|
||||
(isGuiEnabled() && ECS::get<ECS::GUI>().narrationBox)) {
|
||||
mApp->updateWorld(evt.timeSinceLastFrame);
|
||||
if (mInitDelay >= 0.0f)
|
||||
mInitDelay -= evt.timeSinceLastFrame;
|
||||
}
|
||||
{
|
||||
ZoneScopedN("frameRendered");
|
||||
if (fps_timer.getMilliseconds() > 1000.0f) {
|
||||
std::cout << "FPS: "
|
||||
<< mApp->getRenderWindow()
|
||||
->getStatistics()
|
||||
.lastFPS
|
||||
<< " ";
|
||||
std::cout << "Draw calls: "
|
||||
<< mApp->getRenderWindow()
|
||||
->getStatistics()
|
||||
.batchCount
|
||||
<< " ";
|
||||
fps_timer.reset();
|
||||
std::cout << "Drops: "
|
||||
<< mApp->getRenderWindow()
|
||||
->getStatistics()
|
||||
.vBlankMissCount
|
||||
<< "\n";
|
||||
fps_timer.reset();
|
||||
}
|
||||
if (!isGuiEnabled() ||
|
||||
(isGuiEnabled() && ECS::get<ECS::GUI>().narrationBox)) {
|
||||
mApp->updateWorld(evt.timeSinceLastFrame);
|
||||
if (mInitDelay >= 0.0f)
|
||||
mInitDelay -= evt.timeSinceLastFrame;
|
||||
}
|
||||
|
||||
if (!isGuiEnabled() && ECS::get().has<ECS::Input>()) {
|
||||
ECS::Input &input = ECS::get().get_mut<ECS::Input>();
|
||||
input.control = control;
|
||||
input.mouse = mouse;
|
||||
input.mouse_abs = mouse_abs;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
if (!isGuiEnabled() && ECS::get().has<ECS::Input>()) {
|
||||
ECS::Input &input = ECS::get().get_mut<ECS::Input>();
|
||||
input.control = control;
|
||||
input.mouse = mouse;
|
||||
input.mouse_abs = mouse_abs;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
}
|
||||
}
|
||||
#ifdef USE_RENDER_LOOP
|
||||
FrameMark;
|
||||
#endif
|
||||
}
|
||||
|
||||
int main()
|
||||
@@ -784,7 +795,23 @@ int main()
|
||||
// KeyHandler keyHandler;
|
||||
// ctx.addInputListener(&keyHandler);
|
||||
ctx.enableDbgDraw(false);
|
||||
#ifdef USE_RENDER_LOOP
|
||||
ctx.getRoot()->startRendering();
|
||||
#else
|
||||
auto renderSystem = Ogre::Root::getSingleton().getRenderSystem();
|
||||
OgreAssert(renderSystem, "no RenderSystem");
|
||||
renderSystem->_initRenderTargets();
|
||||
Ogre::Root::getSingleton().clearEventTimes();
|
||||
Ogre::Root::getSingleton().queueEndRendering(false);
|
||||
while (!Ogre::Root::getSingleton().endRenderingQueued()) {
|
||||
{
|
||||
ZoneScopedN("render");
|
||||
if (!Ogre::Root::getSingleton().renderOneFrame())
|
||||
break;
|
||||
}
|
||||
FrameMark;
|
||||
}
|
||||
#endif
|
||||
ctx.setWindowGrab(false);
|
||||
ctx.closeApp();
|
||||
return 0;
|
||||
|
||||
@@ -18,14 +18,20 @@ 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 ${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_baked.blend
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${FURNITURE_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${FURNITURE_FILE}
|
||||
COMMAND ${BLENDER} -b ${CMAKE_CURRENT_BINARY_DIR}/${FURNITURE_FILE} -Y -P
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bake_furniture.py
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${FURNITURE_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/bake_furniture.py)
|
||||
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
|
||||
COMMAND ${BLENDER} -b ${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_baked.blend
|
||||
-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)
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_baked.blend ${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})
|
||||
|
||||
125
assets/blender/buildings/parts/bake_furniture.py
Normal file
125
assets/blender/buildings/parts/bake_furniture.py
Normal file
@@ -0,0 +1,125 @@
|
||||
import bpy
|
||||
|
||||
def get_all_children_recursive(obj, mesh_list):
|
||||
"""Recursively finds all mesh objects in the hierarchy."""
|
||||
for child in obj.children:
|
||||
if child.type == 'MESH' and child.data.uv_layers:
|
||||
mesh_list.append(child)
|
||||
get_all_children_recursive(child, mesh_list)
|
||||
|
||||
def setup_furniture_atlas():
|
||||
# 1. Gather valid objects: Children of empties starting with "furniture-"
|
||||
|
||||
furniture_meshes = []
|
||||
roots = [o for o in bpy.data.objects if o.name.startswith("furniture-")]
|
||||
|
||||
for root in roots:
|
||||
# If the root itself is a mesh with UVs, add it
|
||||
if root.type == 'MESH' and root.data.uv_layers:
|
||||
furniture_meshes.append(root)
|
||||
# Find all nested children
|
||||
get_all_children_recursive(root, furniture_meshes)
|
||||
|
||||
# Remove duplicates if any (in case of complex parenting)
|
||||
furniture_meshes = list(set(furniture_meshes))
|
||||
|
||||
if not furniture_meshes:
|
||||
print("No recursive mesh objects found with UVs.")
|
||||
return
|
||||
|
||||
furniture_objs = furniture_meshes
|
||||
|
||||
if not furniture_objs:
|
||||
print("No valid furniture mesh objects found with UVs.")
|
||||
return
|
||||
|
||||
# 2. Manage the Atlas Image (FurnitureColor)
|
||||
image_name = "FurnitureColor"
|
||||
if image_name in bpy.data.images:
|
||||
atlas_img = bpy.data.images[image_name]
|
||||
else:
|
||||
atlas_img = bpy.data.images.new(image_name, width=2048, height=2048)
|
||||
|
||||
# 3. Setup Materials & Nodes
|
||||
processed_mats = set()
|
||||
for obj in furniture_objs:
|
||||
for slot in obj.material_slots:
|
||||
mat = slot.material
|
||||
if mat and mat not in processed_mats:
|
||||
mat.use_nodes = True
|
||||
nodes = mat.node_tree.nodes
|
||||
|
||||
# Find or create the target node
|
||||
bake_node = nodes.get("ATLAS_TARGET")
|
||||
if not bake_node:
|
||||
bake_node = nodes.new('ShaderNodeTexImage')
|
||||
bake_node.name = "ATLAS_TARGET"
|
||||
|
||||
bake_node.image = atlas_img
|
||||
nodes.active = bake_node # Essential for the Bake operator
|
||||
processed_mats.add(mat)
|
||||
|
||||
# 4. Selection & Context Setup
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
for obj in furniture_objs:
|
||||
obj.select_set(True)
|
||||
bpy.context.view_layer.objects.active = furniture_objs[0]
|
||||
|
||||
# 5. Bake Configuration (Cycles, Diffuse, Color only)
|
||||
scene = bpy.context.scene
|
||||
scene.render.engine = 'CYCLES'
|
||||
scene.cycles.device = 'CPU'
|
||||
scene.cycles.samples = 10
|
||||
scene.render.bake.use_pass_direct = False
|
||||
scene.render.bake.use_pass_indirect = False
|
||||
scene.render.bake.use_pass_color = True
|
||||
scene.render.bake.target = 'IMAGE_TEXTURES'
|
||||
|
||||
print("Baking Furniture Atlas...")
|
||||
override = {
|
||||
'active_object': bpy.context.view_layer.objects.active,
|
||||
'selected_objects': bpy.context.selected_objects,
|
||||
}
|
||||
|
||||
with bpy.context.temp_override(**override):
|
||||
bpy.ops.object.bake(type='DIFFUSE', margin=2)
|
||||
atlas_img.pack()
|
||||
|
||||
# 6. Create and Assign Final Atlas Material
|
||||
atlas_mat_name = "M_Furniture_Atlas"
|
||||
if atlas_mat_name in bpy.data.materials:
|
||||
atlas_mat = bpy.data.materials[atlas_mat_name]
|
||||
else:
|
||||
atlas_mat = bpy.data.materials.new(name=atlas_mat_name)
|
||||
atlas_mat.use_nodes = True
|
||||
bsdf = atlas_mat.node_tree.nodes.get("Principled BSDF")
|
||||
tex_node = atlas_mat.node_tree.nodes.new('ShaderNodeTexImage')
|
||||
tex_node.image = atlas_img
|
||||
atlas_mat.node_tree.links.new(tex_node.outputs['Color'], bsdf.inputs['Base Color'])
|
||||
nodes = atlas_mat.node_tree.nodes
|
||||
bsdf = nodes.get("Principled BSDF")
|
||||
if bsdf:
|
||||
bsdf.inputs['Roughness'].default_value = 1.0
|
||||
|
||||
# Reassign all valid objects to the new material
|
||||
for obj in furniture_objs:
|
||||
obj.data.materials.clear()
|
||||
obj.data.materials.append(atlas_mat)
|
||||
|
||||
print("Process Complete. Atlas material applied.")
|
||||
for mat in bpy.data.materials:
|
||||
if mat.users == 0:
|
||||
bpy.data.materials.remove(mat)
|
||||
bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)
|
||||
|
||||
scene.render.engine = 'BLENDER_EEVEE'
|
||||
current_path = bpy.data.filepath
|
||||
if current_path:
|
||||
new_path = current_path.replace(".blend", "_baked.blend")
|
||||
bpy.ops.wm.save_as_mainfile(filepath=new_path)
|
||||
print(f"File saved to: {new_path}")
|
||||
else:
|
||||
print("Warning: File not saved (unsaved blend file).")
|
||||
|
||||
setup_furniture_atlas()
|
||||
|
||||
@@ -81,7 +81,7 @@ class TEST_PT_ObjectPanel(bpy.types.Panel):
|
||||
# Link button with preset arguments
|
||||
row = layout.row(align=True)
|
||||
op = row.operator("test.link_and_play", text="Link & Sit", icon='PLAY')
|
||||
op.filepath = "//../../edited-normal-male.blend" # SET YOUR FILEPATH
|
||||
op.filepath = "//../../characters/edited-normal-male.blend" # SET YOUR FILEPATH
|
||||
op.rig_name = "male" # SET YOUR RIG NAME
|
||||
op.action_name = "sitting-chair" # SET YOUR ACTION NAME
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -11,18 +11,24 @@ add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/edited-normal-${EDITED_BLEND}.blend
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/edited-normal-${EDITED_BLEND}.blend
|
||||
${CMAKE_BINARY_DIR}/assets/blender/vrm-vroid-normal-${EDITED_BLEND}.blend
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/copy_animations.py
|
||||
${CMAKE_BINARY_DIR}/assets/blender/mixamo
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-E copy ${CMAKE_CURRENT_SOURCE_DIR}/edited-normal-${EDITED_BLEND}.blend
|
||||
${CMAKE_CURRENT_BINARY_DIR}/edited-normal-${EDITED_BLEND}.blend
|
||||
COMMAND ${BLENDER} -b -Y
|
||||
${CMAKE_CURRENT_BINARY_DIR}/edited-normal-${EDITED_BLEND}.blend
|
||||
-P ${CMAKE_SOURCE_DIR}/assets/blender/scripts/copy_animations.py --
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/copy_animations.py --
|
||||
${CMAKE_BINARY_DIR}/assets/blender/vrm-vroid-normal-${EDITED_BLEND}.blend ${EDITED_BLEND}
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
list(APPEND EDITED_BLEND_TARGETS ${CMAKE_BINARY_DIR}/assets/blender/characters/edited-normal-${EDITED_BLEND}.blend)
|
||||
list(APPEND CHARACTER_GLBS ${CMAKE_BINARY_DIR}/characters/${EDITED_BLEND}/normal-${EDITED_BLEND}.glb)
|
||||
endforeach()
|
||||
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/assets/blender/mixamo
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/assets/blender/mixamo ${CMAKE_BINARY_DIR}/assets/blender/mixamo
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/assets/blender/mixamo
|
||||
)
|
||||
|
||||
set(VRM_IMPORTED_BLENDS
|
||||
${CMAKE_BINARY_DIR}/assets/blender/vrm-vroid-normal-female.blend
|
||||
@@ -30,16 +36,48 @@ set(VRM_IMPORTED_BLENDS
|
||||
${CMAKE_BINARY_DIR}/assets/blender/shapes/male/vrm-vroid-normal-male-chibi.blend
|
||||
)
|
||||
|
||||
#add_custom_command(
|
||||
# OUTPUT ${CHARACTER_GLBS}
|
||||
# COMMAND ${CMAKE_COMMAND} -E make_directory ${CREATE_DIRECTORIES}
|
||||
# COMMAND ${BLENDER} -b -Y -P ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_models.py
|
||||
# COMMAND ${CMAKE_COMMAND} -D FILE=${CMAKE_BINARY_DIR}/characters/male/normal-male.glb -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_file_size.cmake
|
||||
# COMMAND ${CMAKE_COMMAND} -D FILE=${CMAKE_BINARY_DIR}/characters/female/normal-female.glb -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_file_size.cmake
|
||||
# COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${CHARACTER_GLBS}
|
||||
# DEPENDS ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_models.py ${VRM_IMPORTED_BLENDS} ${EDITED_BLEND_TARGETS}
|
||||
# WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(FEMALE_OBJECTS "Body;Hair;Face;BackHair;Tops;Bottoms;Shoes;Accessory")
|
||||
set(MALE_OBJECTS "Body;Hair;Face;BackHair;Tops;Bottoms;Shoes;Accessory")
|
||||
add_custom_command(
|
||||
OUTPUT ${CHARACTER_GLBS}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CREATE_DIRECTORIES}
|
||||
COMMAND ${BLENDER} -b -Y -P ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_models.py
|
||||
COMMAND ${CMAKE_COMMAND} -D FILE=${CMAKE_BINARY_DIR}/characters/male/normal-male.glb -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_file_size.cmake
|
||||
COMMAND ${CMAKE_COMMAND} -D FILE=${CMAKE_BINARY_DIR}/characters/female/normal-female.glb -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_file_size.cmake
|
||||
COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${CHARACTER_GLBS}
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_models.py ${VRM_IMPORTED_BLENDS} ${EDITED_BLEND_TARGETS}
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
OUTPUT ${CMAKE_BINARY_DIR}/characters/male/normal-male.glb
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CREATE_DIRECTORIES}
|
||||
COMMAND ${BLENDER} -b -Y -P ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_models2.py --
|
||||
${CMAKE_CURRENT_BINARY_DIR}/edited-normal-male.blend
|
||||
${CMAKE_BINARY_DIR}/characters/male/normal-male.glb
|
||||
"${MALE_OBJECTS}"
|
||||
"male"
|
||||
tmp-edited-male.blend
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_models2.py
|
||||
${VRM_IMPORTED_BLENDS}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/edited-normal-male.blend
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_BINARY_DIR}/characters/female/normal-female.glb
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CREATE_DIRECTORIES}
|
||||
COMMAND ${BLENDER} -b -Y -P ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_models2.py --
|
||||
${CMAKE_CURRENT_BINARY_DIR}/edited-normal-female.blend
|
||||
${CMAKE_BINARY_DIR}/characters/female/normal-female.glb
|
||||
"${FEMALE_OBJECTS}"
|
||||
"female"
|
||||
tmp-edited-female.blend
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_models2.py
|
||||
${VRM_IMPORTED_BLENDS}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/edited-normal-female.blend
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
set(VRM_SOURCE)
|
||||
|
||||
@@ -84,7 +122,7 @@ function(blender_import_vrm BLEND VRM EDITABLE RIG)
|
||||
get_filename_component(VRM_NAME ${VRM} NAME_WE)
|
||||
add_custom_command(OUTPUT ${BLEND}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CREATE_DIRECTORIES}
|
||||
COMMAND ${BLENDER} -b -Y -P ${CMAKE_SOURCE_DIR}/assets/blender/scripts/import_vrm2.py -- ${VRM_NAME}.vrm ${TARGET_NAME}.blend ${EDITABLE} ${RIG}
|
||||
COMMAND ${BLENDER} -b -Y -P ${CMAKE_SOURCE_DIR}/assets/blender/scripts/import_vrm2.py -- ${VRM_NAME}.vrm ${BLEND} ${EDITABLE} ${RIG}
|
||||
COMMAND ${CMAKE_COMMAND} -D FILE=${BLEND} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_file_size.cmake
|
||||
COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${BLEND}
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/assets/blender/scripts/import_vrm2.py
|
||||
|
||||
64
assets/blender/characters/copy_animations.py
Normal file
64
assets/blender/characters/copy_animations.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import bpy
|
||||
import sys
|
||||
import os
|
||||
|
||||
argv = sys.argv
|
||||
argv = argv[argv.index("--") + 1:]
|
||||
|
||||
sys.path.insert(0, os.getcwd() + "/assets/blender/scripts")
|
||||
|
||||
source_filepath = argv[0]
|
||||
armature_name = argv[1]
|
||||
|
||||
print("starting...")
|
||||
|
||||
def copy_actions_and_create_nla_tracks(source_filepath, target_object_name):
|
||||
"""
|
||||
Copies actions from a source Blender file that do not exist in the current
|
||||
file, creates NLA tracks for them on a target object, and saves the file.
|
||||
|
||||
Args:
|
||||
source_filepath (str): The full path to the source Blender file.
|
||||
target_object_name (str): The name of the object in the current file
|
||||
to which the actions and NLA tracks will be applied.
|
||||
"""
|
||||
|
||||
# 1. Link or Append Actions from the Source File
|
||||
with bpy.data.libraries.load(source_filepath, link=False) as (data_from, data_to):
|
||||
source_action_names = data_from.actions
|
||||
current_action_names = {action.name for action in bpy.data.actions}
|
||||
actions_to_append = [name for name in source_action_names if name not in current_action_names]
|
||||
data_to.actions = actions_to_append
|
||||
print(actions_to_append)
|
||||
|
||||
# Get the target object
|
||||
target_object = bpy.data.objects.get(target_object_name)
|
||||
if not target_object:
|
||||
print(f"Error: Object '{target_object_name}' not found in the current file.")
|
||||
return
|
||||
|
||||
# Ensure the object has an NLA editor
|
||||
if not target_object.animation_data:
|
||||
target_object.animation_data_create()
|
||||
|
||||
# 2. Iterate through newly imported actions and create NLA tracks
|
||||
for action in data_to.actions:
|
||||
# Check if an action with the same name already exists in the current file
|
||||
# Add the action to the NLA editor as a strip
|
||||
nla_track = target_object.animation_data.nla_tracks.new()
|
||||
nla_track.name = f"NLA_Track_{action.name}"
|
||||
nla_track.strips.new(name=action.name, start=1, action=action)
|
||||
print(f"Created NLA track for action: {action.name}")
|
||||
|
||||
# 3. Save the current Blender file
|
||||
bpy.ops.wm.save_as_mainfile(filepath=bpy.context.blend_data.filepath)
|
||||
print(f"File saved: {bpy.context.blend_data.filepath}")
|
||||
|
||||
# --- Usage Example ---
|
||||
if __name__ == "__main__":
|
||||
# Replace with your actual source file path and target object name
|
||||
source_file = source_filepath
|
||||
target_obj = armature_name
|
||||
|
||||
copy_actions_and_create_nla_tracks(source_file, target_obj)
|
||||
|
||||
@@ -18,7 +18,10 @@ sys.path.insert(1, incpath + "/blender2ogre")
|
||||
|
||||
|
||||
import io_ogre
|
||||
io_ogre.register()
|
||||
try:
|
||||
io_ogre.register()
|
||||
except:
|
||||
pass
|
||||
|
||||
gltf_file = argv[0]
|
||||
print("Exporting to " + gltf_file)
|
||||
|
||||
296
assets/blender/scripts/export_models2.py
Normal file
296
assets/blender/scripts/export_models2.py
Normal file
@@ -0,0 +1,296 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os, sys, time
|
||||
import bpy
|
||||
from math import pi
|
||||
import glob
|
||||
import shutil
|
||||
from mathutils import Vector, Matrix
|
||||
from math import radians, pi
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
#from settings import ExportMappingFemale, ExportMappingMale, ExportMappingMaleBabyShape, ExportMappingMaleEdited, ExportMappingFemaleEdited, ExportMappingMaleTestShapeEdited, ExportMappingMaleBaseShapeEdited
|
||||
|
||||
argv = sys.argv
|
||||
argv = argv[argv.index("--") + 1:]
|
||||
|
||||
|
||||
basepath = os.getcwd()
|
||||
def check_bone(bname):
|
||||
ok = True
|
||||
baddie = ["ctrl_", "mch_", "MCH_", "Ctrl_", "Mch_"]
|
||||
for bd in baddie:
|
||||
if bname.startswith(bd):
|
||||
ok = False
|
||||
break
|
||||
return ok
|
||||
|
||||
def prepare_armature(mapping):
|
||||
print("Preparing...")
|
||||
bpy.ops.object.armature_add(enter_editmode=False)
|
||||
new_armature = bpy.context.object
|
||||
orig_armature = bpy.data.objects[mapping.armature_name]
|
||||
armature_name = orig_armature.name
|
||||
orig_armature.name = orig_armature.name + "_orig"
|
||||
new_armature.name = armature_name
|
||||
queue = []
|
||||
if new_armature.animation_data is None:
|
||||
new_armature.animation_data_create()
|
||||
bpy.context.view_layer.objects.active = new_armature
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
for b in new_armature.data.edit_bones:
|
||||
new_armature.data.edit_bones.remove(b)
|
||||
bpy.context.view_layer.objects.active = orig_armature
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
for b in orig_armature.data.edit_bones:
|
||||
print(b.name)
|
||||
if b.parent is None:
|
||||
queue.append(b.name)
|
||||
print("Copying bones...")
|
||||
while len(queue) > 0:
|
||||
item = queue.pop(0)
|
||||
print(item)
|
||||
itemb = orig_armature.data.edit_bones[item]
|
||||
if not itemb.use_deform and not check_bone(item):
|
||||
continue
|
||||
for cb in orig_armature.data.edit_bones:
|
||||
if cb.parent == itemb:
|
||||
queue.append(cb.name)
|
||||
nb = new_armature.data.edit_bones.new(item)
|
||||
nb.name = item
|
||||
nb.head = itemb.head
|
||||
nb.tail = itemb.tail
|
||||
nb.matrix = itemb.matrix
|
||||
nb.use_deform = itemb.use_deform
|
||||
if itemb.parent is not None:
|
||||
ok = True
|
||||
pname = itemb.parent.name
|
||||
while not check_bone(pname):
|
||||
bparent = itemb.parent.parent
|
||||
if bparent is None:
|
||||
ok = False
|
||||
break
|
||||
pname = bparent.name
|
||||
if ok:
|
||||
nb.parent = new_armature.data.edit_bones[itemb.parent.name]
|
||||
else:
|
||||
nb.parent = None
|
||||
else:
|
||||
nb.parent = None
|
||||
nb.use_connect = itemb.use_connect
|
||||
# drivers_data = new_armature.animation_data.drivers
|
||||
print("Creating constraints...")
|
||||
bpy.context.view_layer.objects.active = new_armature
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
bpy.context.view_layer.objects.active = orig_armature
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
for b in new_armature.pose.bones:
|
||||
print(b.name)
|
||||
c = b.constraints.new(type='COPY_TRANSFORMS')
|
||||
c.target = orig_armature
|
||||
c.subtarget = b.name
|
||||
for obj in bpy.data.objects:
|
||||
if obj.parent == orig_armature:
|
||||
obj.parent = new_armature
|
||||
for mod in obj.modifiers:
|
||||
if mod.type == 'ARMATURE':
|
||||
mod.object = new_armature
|
||||
print("Baking actions...")
|
||||
bpy.context.view_layer.objects.active = new_armature
|
||||
bpy.ops.object.mode_set(mode='POSE')
|
||||
for track in orig_armature.animation_data.nla_tracks:
|
||||
print(track.name)
|
||||
for s in track.strips:
|
||||
action = s.action
|
||||
print(action.name)
|
||||
orig_armature.animation_data.action = action
|
||||
new_armature.animation_data.action = None
|
||||
bpy.context.view_layer.objects.active = new_armature
|
||||
firstFrame = int(s.action_frame_start)
|
||||
lastFrame = int(s.action_frame_end)
|
||||
bpy.ops.nla.bake(frame_start=firstFrame, frame_end=lastFrame, step=5, only_selected=False, visual_keying=True, clear_constraints=False, clean_curves=True, use_current_action=False, bake_types={'POSE'})
|
||||
aname = orig_armature.animation_data.action.name
|
||||
orig_armature.animation_data.action.name = "bake_" + aname
|
||||
new_armature.animation_data.action.name = aname
|
||||
track = new_armature.animation_data.nla_tracks.new()
|
||||
track.name = aname
|
||||
track.strips.new(track.name, int(new_armature.animation_data.action.frame_range[0]), new_armature.animation_data.action)
|
||||
track.mute = True
|
||||
track.lock = True
|
||||
print("Removing constraints...")
|
||||
for b in new_armature.pose.bones:
|
||||
for c in b.constraints:
|
||||
b.constraints.remove(c)
|
||||
new_armature.animation_data.action = bpy.data.actions[mapping.default_action]
|
||||
bpy.context.view_layer.objects.active = new_armature
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# track = new_armature.animation_data.nla_tracks.new()
|
||||
# track.name = action.name
|
||||
|
||||
|
||||
def clamp_angle_deg(angle, min_angle_deg, max_angle_deg):
|
||||
min_angle = radians(min_angle_deg)
|
||||
max_angle = radians(max_angle_deg)
|
||||
if angle < min_angle:
|
||||
angle = min_angle
|
||||
if angle > max_angle:
|
||||
angle = max_angle
|
||||
return angle
|
||||
def angle_to_linear(angle, divider):
|
||||
if angle < 0.0:
|
||||
return angle / divider
|
||||
else:
|
||||
return 0.0
|
||||
def angle_to_linear_x(bone, angle):
|
||||
skel = bpy.data.objects["skeleton_orig"]
|
||||
left_base = "ctrl_base_upperleg.L.001"
|
||||
right_base = "ctrl_base_upperleg.R.001"
|
||||
base = ""
|
||||
if base == "":
|
||||
for e in ["_R", ".R"]:
|
||||
if bone.name.endswith(e):
|
||||
base = right_base
|
||||
break
|
||||
if base == "":
|
||||
for e in ["_L", ".L"]:
|
||||
if bone.name.endswith(e):
|
||||
base = left_base
|
||||
break
|
||||
if base == "":
|
||||
for e in ["_R.", ".R."]:
|
||||
if bone.name.find(e) >= 0:
|
||||
base = right_base
|
||||
break
|
||||
if base == "":
|
||||
for e in ["_L.", ".L."]:
|
||||
if bone.name.find(e) >= 0:
|
||||
base = left_base
|
||||
break
|
||||
mul = skel.pose.bones[base]["to_linear_x_base"]
|
||||
offset = skel.pose.bones[base]["angle_offset"]
|
||||
# print("bone: ", bone.name, "base: ", base, "mul: ", mul)
|
||||
# print("angle: ", angle, " angle_offset: ", offset, " angle_sum: ", angle + offset)
|
||||
print("offset: ", mul * (angle + offset), "bone: ", base, "angle: ", angle)
|
||||
return (angle + offset) * mul
|
||||
def extra_linear(angle, offset):
|
||||
ret = 0.0
|
||||
offt = offset * angle * 2.0 / -radians(-90)
|
||||
if angle * 2.0 < -radians(65):
|
||||
if angle * 2.0 > -radians(65):
|
||||
ret += offset
|
||||
else:
|
||||
ret += offt
|
||||
return ret
|
||||
|
||||
mapping_blend_path = argv[0]
|
||||
mapping_gltf_path = argv[1]
|
||||
mapping_objects = argv[2]
|
||||
mapping_armature_name = argv[3]
|
||||
mapping_outfile = argv[4]
|
||||
|
||||
#for mapping in [ExportMappingFemale(), ExportMappingMale(), ExportMappingMaleBabyShape(), ExportMappingMaleEdited(), ExportMappingFemaleEdited(), ExportMappingMaleTestShapeEdited(), ExportMappingMaleBaseShapeEdited()]:
|
||||
class CommandLineMapping:
|
||||
blend_path = mapping_blend_path
|
||||
gltf_path = mapping_gltf_path
|
||||
# ogre_scene = "characters/female/vroid-normal-female.scene"
|
||||
inner_path = "Object"
|
||||
# objs = ["male", "Body", "Hair", "Face", "BackHair", "Tops", "Bottoms", "Shoes", "Accessory"]
|
||||
# objs = ["female", "Body", "Hair", "Face", "BackHair", "Tops", "Bottoms", "Shoes", "Accessory"]
|
||||
objs = []
|
||||
armature_name = mapping_armature_name
|
||||
outfile = mapping_outfile
|
||||
default_action = 'default'
|
||||
def __init__(self):
|
||||
self.objs = [mapping_armature_name]
|
||||
if len(mapping_objects) > 0:
|
||||
self.objs += [o.strip() for o in mapping_objects.split(";")]
|
||||
self.files = []
|
||||
for fobj in self.objs:
|
||||
self.files.append({"name": fobj})
|
||||
|
||||
for mapping in[CommandLineMapping()]:
|
||||
if not os.path.exists(mapping.blend_path):
|
||||
print("Skipping mapping: " + mapping.blend_path)
|
||||
continue
|
||||
print("Processing mapping: from: " + mapping.blend_path + " to: " + mapping.gltf_path)
|
||||
print("Initializing...")
|
||||
bpy.ops.wm.read_homefile(use_empty=True)
|
||||
print("Preparing driver setup...")
|
||||
bpy.app.driver_namespace["clamp_angle_deg"] = clamp_angle_deg
|
||||
bpy.app.driver_namespace["angle_to_linear"] = angle_to_linear
|
||||
bpy.app.driver_namespace["extra_linear"] = extra_linear
|
||||
bpy.app.driver_namespace["angle_to_linear_x"] = angle_to_linear_x
|
||||
print("Driver setup done...")
|
||||
|
||||
bpy.ops.wm.append(
|
||||
filepath=os.path.join(mapping.blend_path, mapping.inner_path),
|
||||
directory=os.path.join(mapping.blend_path, mapping.inner_path),
|
||||
files=mapping.files)
|
||||
print("Append done...")
|
||||
|
||||
prepare_armature(mapping)
|
||||
print("Armature done...")
|
||||
|
||||
print("Remove junk...")
|
||||
for ob in bpy.data.objects:
|
||||
if ob.name.startswith("cs_"):
|
||||
bpy.data.objects.remove(ob)
|
||||
elif ob.name.startswith("Face") and ob.name != "Face":
|
||||
bpy.data.objects.remove(ob)
|
||||
|
||||
print("Removing original armature and actions...")
|
||||
orig_arm = bpy.data.objects[mapping.armature_name + '_orig']
|
||||
bpy.data.objects.remove(orig_arm)
|
||||
for act in bpy.data.actions:
|
||||
if act.name.startswith("bake_"):
|
||||
act.name = act.name + "-noimp"
|
||||
for act in bpy.data.actions:
|
||||
if act.name.startswith("bake_"):
|
||||
bpy.data.actions.remove(act)
|
||||
for act in bpy.data.actions:
|
||||
if act.name.startswith("bake_"):
|
||||
bpy.data.actions.remove(act)
|
||||
for obj in bpy.data.objects:
|
||||
if obj.type == 'MESH':
|
||||
if not obj.name in mapping.objs and obj.parent is None:
|
||||
if not obj.name.endswith("-noimp"):
|
||||
obj.name = obj.name + "-noimp"
|
||||
bpy.ops.wm.save_as_mainfile(filepath=(basepath + "/assets/blender/scripts/" + mapping.outfile))
|
||||
|
||||
os.makedirs(os.path.dirname(mapping.gltf_path), exist_ok=True)
|
||||
bpy.ops.export_scene.gltf(filepath=mapping.gltf_path,
|
||||
use_selection=False,
|
||||
check_existing=False,
|
||||
# export_format='GLTF_SEPARATE',
|
||||
export_format='GLB',
|
||||
export_texture_dir='textures', export_texcoords=True,
|
||||
export_animation_mode='NLA_TRACKS',
|
||||
export_normals=True,
|
||||
export_tangents=True,
|
||||
export_materials='EXPORT',
|
||||
# export_all_vertex_colors=True,
|
||||
# colors_type='SRGB',
|
||||
# export_vertex_colors=True,
|
||||
export_colors=True,
|
||||
use_mesh_edges=False,
|
||||
use_mesh_vertices=False,
|
||||
export_cameras=False,
|
||||
use_visible=False,
|
||||
use_renderable=False,
|
||||
export_yup=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)
|
||||
print("exported to: " + mapping.gltf_path)
|
||||
|
||||
bpy.ops.wm.read_homefile(use_empty=True)
|
||||
time.sleep(2)
|
||||
bpy.ops.wm.quit_blender()
|
||||
@@ -207,5 +207,5 @@ main_armature.animation_data.action = default_action
|
||||
|
||||
main_armature.select_set(False)
|
||||
bpy.context.view_layer.objects.active = None
|
||||
bpy.ops.wm.save_as_mainfile(filepath=(basepath + "/assets/blender/" + imp.outfile))
|
||||
bpy.ops.wm.save_as_mainfile(filepath=(imp.outfile))
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ target_link_libraries(Editor PRIVATE
|
||||
physics
|
||||
lua
|
||||
flecs::flecs_static
|
||||
Tracy::TracyClient
|
||||
)
|
||||
if(OGRE_STATIC)
|
||||
target_link_options(Editor PRIVATE -static-libstdc++ -static-libgcc)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "PhysicsModule.h"
|
||||
#include "physics.h"
|
||||
#include "sound.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
class App;
|
||||
class SkyRenderer : public Ogre::SceneManager::Listener {
|
||||
@@ -683,52 +684,60 @@ public:
|
||||
};
|
||||
void KeyboardListener::frameRendered(const Ogre::FrameEvent &evt)
|
||||
{
|
||||
if (fps_timer.getMilliseconds() > 1000.0f) {
|
||||
std::cout << "FPS: "
|
||||
<< mApp->getRenderWindow()->getStatistics().lastFPS
|
||||
<< " ";
|
||||
std::cout << "Draw calls: "
|
||||
<< mApp->getRenderWindow()->getStatistics().batchCount
|
||||
<< " ";
|
||||
fps_timer.reset();
|
||||
std::cout << "Drops: "
|
||||
<< mApp->getRenderWindow()
|
||||
->getStatistics()
|
||||
.vBlankMissCount
|
||||
<< "\n";
|
||||
fps_timer.reset();
|
||||
}
|
||||
/* for editor we always update world */
|
||||
/* TODO: implement pause */
|
||||
mApp->updateWorld(evt.timeSinceLastFrame);
|
||||
if (mInitDelay >= 0.0f)
|
||||
mInitDelay -= evt.timeSinceLastFrame;
|
||||
{
|
||||
ZoneScopedN("frameRendered");
|
||||
if (fps_timer.getMilliseconds() > 1000.0f) {
|
||||
std::cout << "FPS: "
|
||||
<< mApp->getRenderWindow()
|
||||
->getStatistics()
|
||||
.lastFPS
|
||||
<< " ";
|
||||
std::cout << "Draw calls: "
|
||||
<< mApp->getRenderWindow()
|
||||
->getStatistics()
|
||||
.batchCount
|
||||
<< " ";
|
||||
fps_timer.reset();
|
||||
std::cout << "Drops: "
|
||||
<< mApp->getRenderWindow()
|
||||
->getStatistics()
|
||||
.vBlankMissCount
|
||||
<< "\n";
|
||||
fps_timer.reset();
|
||||
}
|
||||
/* for editor we always update world */
|
||||
/* TODO: implement pause */
|
||||
mApp->updateWorld(evt.timeSinceLastFrame);
|
||||
if (mInitDelay >= 0.0f)
|
||||
mInitDelay -= evt.timeSinceLastFrame;
|
||||
|
||||
if (!isGuiEnabled() && ECS::get().has<ECS::Input>()) {
|
||||
ECS::Input &input = ECS::get().get_mut<ECS::Input>();
|
||||
input.control = control;
|
||||
input.mouse = mouse;
|
||||
input.mouse_abs = mouse_abs;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
ECS::modified<ECS::Input>();
|
||||
} else {
|
||||
ECS::Input &input = ECS::get().get_mut<ECS::Input>();
|
||||
input.control = control;
|
||||
input.mouse = mouse;
|
||||
input.mouse_abs = mouse_abs;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
ECS::modified<ECS::Input>();
|
||||
if (!isGuiEnabled() && ECS::get().has<ECS::Input>()) {
|
||||
ECS::Input &input = ECS::get().get_mut<ECS::Input>();
|
||||
input.control = control;
|
||||
input.mouse = mouse;
|
||||
input.mouse_abs = mouse_abs;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
ECS::modified<ECS::Input>();
|
||||
} else {
|
||||
ECS::Input &input = ECS::get().get_mut<ECS::Input>();
|
||||
input.control = control;
|
||||
input.mouse = mouse;
|
||||
input.mouse_abs = mouse_abs;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
ECS::modified<ECS::Input>();
|
||||
}
|
||||
}
|
||||
FrameMark;
|
||||
}
|
||||
|
||||
int main()
|
||||
|
||||
68
src/gamedata/AnimationSystem.cpp
Normal file
68
src/gamedata/AnimationSystem.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include <iostream>
|
||||
#include "AnimationSystem.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
namespace AnimationSystem
|
||||
{
|
||||
|
||||
bool AnimationSystem::addTime(float time)
|
||||
{
|
||||
int i;
|
||||
ZoneScopedN("AnimationSystem::addTime");
|
||||
preUpdateTriggers();
|
||||
bool ret = m_builder.animation_nodes[0]->addTime(time);
|
||||
for (i = 0; i < m_builder.animationNodeList.size(); i++) {
|
||||
ZoneScoped;
|
||||
AnimationNodeAnimation *anim = m_builder.animationNodeList[i];
|
||||
OgreAssert(anim->mAnimation, "No animation");
|
||||
float weight = anim->getWeight();
|
||||
anim->mAnimation->increaseAccWeight(weight);
|
||||
#ifdef VDEBUG
|
||||
if (debug)
|
||||
std::cout << i
|
||||
<< " node: " << anim->mAnimation->getName()
|
||||
<< " " << weight << std::endl;
|
||||
#endif
|
||||
if (anim->getWeight() > 0.01f) {
|
||||
ZoneScoped;
|
||||
ZoneText("builder", strlen("builder"));
|
||||
ZoneText(anim->mAnimation->getName().c_str(),
|
||||
anim->mAnimation->getName().length());
|
||||
ZoneValue(anim->getWeight() * 100.0f);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < vanimation_list.size(); i++) {
|
||||
ZoneScoped;
|
||||
float weight = vanimation_list[i]->getAccWeight();
|
||||
vanimation_list[i]->setWeight(weight);
|
||||
vanimation_list[i]->resetAccWeight();
|
||||
// #define VDEBUG
|
||||
#ifdef VDEBUG
|
||||
if (debug && vanimation_list[i]->getEnabled())
|
||||
std::cout << i << " animation: "
|
||||
<< vanimation_list[i]->getName() << " "
|
||||
<< weight << std::endl;
|
||||
#endif
|
||||
#undef VDEBUG
|
||||
if (vanimation_list[i]->mAnimationState->getEnabled()) {
|
||||
ZoneScoped;
|
||||
ZoneText("animation", strlen("animation"));
|
||||
ZoneText(vanimation_list[i]->getName().c_str(),
|
||||
vanimation_list[i]->getName().length());
|
||||
ZoneValue(vanimation_list[i]->getWeight() * 100.0f);
|
||||
}
|
||||
}
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
Ogre::Vector3 AnimationSystem::getRootMotionDelta()
|
||||
{
|
||||
ZoneScopedN("AnimationSystem::getRootMotionDelta");
|
||||
Ogre::Vector3 motionDelta(0, 0, 0);
|
||||
int i;
|
||||
for (i = 0; i < vanimation_list.size(); i++)
|
||||
motionDelta += vanimation_list[i]->getRootMotionDelta();
|
||||
return motionDelta;
|
||||
}
|
||||
|
||||
}
|
||||
900
src/gamedata/AnimationSystem.h
Normal file
900
src/gamedata/AnimationSystem.h
Normal file
@@ -0,0 +1,900 @@
|
||||
#ifndef ANIMATIONSYSTEM_H
|
||||
#define ANIMATIONSYSTEM_H
|
||||
|
||||
#include <iostream>
|
||||
#include <Ogre.h>
|
||||
#include <flecs.h>
|
||||
#include <tracy/Tracy.hpp>
|
||||
#include "GameData.h"
|
||||
#include "EventModule.h"
|
||||
|
||||
namespace AnimationSystem
|
||||
{
|
||||
struct AnimationTrigger;
|
||||
struct AnimationTriggerSubscriber {
|
||||
virtual void operator()(const AnimationTrigger *trigger) = 0;
|
||||
};
|
||||
class RootMotionListener : public Ogre::NodeAnimationTrack::Listener {
|
||||
public:
|
||||
RootMotionListener()
|
||||
: Ogre::NodeAnimationTrack::Listener()
|
||||
{
|
||||
}
|
||||
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;
|
||||
Ogre::TransformKeyFrame *k1, *k2;
|
||||
unsigned short firstKeyIndex;
|
||||
float tm = t->getKeyFramesAtTime(timeIndex, &kf1, &kf2,
|
||||
&firstKeyIndex);
|
||||
k1 = static_cast<Ogre::TransformKeyFrame *>(kf1);
|
||||
k2 = static_cast<Ogre::TransformKeyFrame *>(kf2);
|
||||
Ogre::Vector3 translation;
|
||||
Ogre::Quaternion rotation;
|
||||
Ogre::Vector3 deltaMotion;
|
||||
Ogre::Vector3 prevMotion;
|
||||
if (tm == 0.0f) {
|
||||
rotation = k1->getRotation();
|
||||
translation = k1->getTranslate();
|
||||
deltaMotion = translation;
|
||||
} else {
|
||||
rotation = Ogre::Quaternion::nlerp(
|
||||
tm, k1->getRotation(), k2->getRotation(), true);
|
||||
translation =
|
||||
k1->getTranslate() +
|
||||
(k2->getTranslate() - k1->getTranslate()) * tm;
|
||||
deltaMotion = translation - prevTranslation;
|
||||
if (deltaMotion.squaredLength() >
|
||||
translation.squaredLength())
|
||||
deltaMotion = translation;
|
||||
}
|
||||
vkf->setTranslate(deltaMotion);
|
||||
vkf->setRotation(rotation);
|
||||
vkf->setScale(Ogre::Vector3(1, 1, 1));
|
||||
prevTranslation = translation;
|
||||
e.get_mut<CharacterBase>().mBoneMotion = deltaMotion;
|
||||
e.get_mut<CharacterBase>().mBonePrevMotion = prevTranslation;
|
||||
e.modified<CharacterBase>();
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
};
|
||||
struct AnimationTrigger {
|
||||
Ogre::String name;
|
||||
float time;
|
||||
float weight;
|
||||
std::vector<AnimationTriggerSubscriber *> subscriber_list;
|
||||
float getTriggerTime() const
|
||||
{
|
||||
return time;
|
||||
}
|
||||
float getMinWeight() const
|
||||
{
|
||||
return weight;
|
||||
}
|
||||
const Ogre::String &getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
void notify(float weight)
|
||||
{
|
||||
int i;
|
||||
if (weight < this->weight)
|
||||
return;
|
||||
for (i = 0; i < subscriber_list.size(); i++)
|
||||
(*subscriber_list[i])(this);
|
||||
}
|
||||
void addSubscriber(AnimationTriggerSubscriber *sub)
|
||||
{
|
||||
if (std::find(subscriber_list.begin(), subscriber_list.end(),
|
||||
sub) != subscriber_list.end())
|
||||
return;
|
||||
subscriber_list.push_back(sub);
|
||||
}
|
||||
void removeSubscriber(AnimationTriggerSubscriber *sub)
|
||||
{
|
||||
auto it = std::find(subscriber_list.begin(),
|
||||
subscriber_list.end(), sub);
|
||||
if (it != subscriber_list.end())
|
||||
subscriber_list.erase(it);
|
||||
}
|
||||
void clearSubscribers()
|
||||
{
|
||||
subscriber_list.clear();
|
||||
}
|
||||
AnimationTrigger(const Ogre::String name, float time, float weight)
|
||||
: name(name)
|
||||
, time(time)
|
||||
, weight(weight)
|
||||
{
|
||||
}
|
||||
};
|
||||
struct Animation {
|
||||
struct SetupTracks {
|
||||
Ogre::NodeAnimationTrack *mHipsTrack;
|
||||
Ogre::NodeAnimationTrack *mRootTrack;
|
||||
RootMotionListener *mListener;
|
||||
Ogre::Vector3 mRootTranslation;
|
||||
SetupTracks(Ogre::Skeleton *skeleton,
|
||||
Ogre::Animation *animation)
|
||||
: mListener(OGRE_NEW RootMotionListener())
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
Ogre::TransformKeyFrame *tkfBeg =
|
||||
(Ogre::TransformKeyFrame *)
|
||||
mRootTrack->getKeyFrame(0);
|
||||
Ogre::TransformKeyFrame *tkfEnd =
|
||||
(Ogre::TransformKeyFrame *)
|
||||
mRootTrack->getKeyFrame(
|
||||
mRootTrack->getNumKeyFrames() -
|
||||
1);
|
||||
mRootTranslation =
|
||||
tkfEnd->getTranslate() - tkfBeg->getTranslate();
|
||||
}
|
||||
};
|
||||
Ogre::AnimationState *mAnimationState;
|
||||
Ogre::Animation *mSkelAnimation;
|
||||
SetupTracks *mTracks;
|
||||
float m_weight;
|
||||
float m_accWeight;
|
||||
Ogre::Skeleton *mSkeleton;
|
||||
Animation(Ogre::Skeleton *skeleton, Ogre::AnimationState *animState,
|
||||
Ogre::Animation *skelAnimation)
|
||||
: mTracks(OGRE_NEW SetupTracks(skeleton, skelAnimation))
|
||||
, mAnimationState(animState)
|
||||
, mSkelAnimation(skelAnimation)
|
||||
, m_weight(0)
|
||||
, m_accWeight(0)
|
||||
, mSkeleton(skeleton)
|
||||
{
|
||||
}
|
||||
Ogre::String getName()
|
||||
{
|
||||
return mAnimationState->getAnimationName();
|
||||
}
|
||||
void setLoop(bool loop)
|
||||
{
|
||||
mAnimationState->setLoop(loop);
|
||||
}
|
||||
bool getLoop() const
|
||||
{
|
||||
return mAnimationState->getLoop();
|
||||
}
|
||||
void setEnabled(bool enabled)
|
||||
{
|
||||
mAnimationState->setEnabled(enabled);
|
||||
}
|
||||
bool getEnabled() const
|
||||
{
|
||||
return mAnimationState->getEnabled();
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
bool enabled = weight > 0.001f;
|
||||
setEnabled(enabled);
|
||||
mAnimationState->setWeight(weight);
|
||||
m_weight = weight;
|
||||
}
|
||||
float getWeight() const
|
||||
{
|
||||
return m_weight;
|
||||
}
|
||||
Ogre::Vector3 rootMotion;
|
||||
Ogre::Vector3 getRootMotionDelta()
|
||||
{
|
||||
if (mAnimationState->getEnabled())
|
||||
return rootMotion * mAnimationState->getWeight();
|
||||
else
|
||||
return Ogre::Vector3(0, 0, 0);
|
||||
}
|
||||
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;
|
||||
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);
|
||||
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();
|
||||
rootMotion = (thisRootPos - lastRootPos) +
|
||||
(loops * mTracks->mRootTranslation);
|
||||
|
||||
getKeyframeIndices(mAnimationState->getTimePosition(),
|
||||
&next_index);
|
||||
// updateRootMotion(mAnimationState->getTimePosition());
|
||||
return prev_index != next_index;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
mAnimationState->setTimePosition(0);
|
||||
}
|
||||
void resetAccWeight()
|
||||
{
|
||||
m_accWeight = 0;
|
||||
}
|
||||
void increaseAccWeight(float weight)
|
||||
{
|
||||
m_accWeight += weight;
|
||||
}
|
||||
float getAccWeight() const
|
||||
{
|
||||
return m_accWeight;
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
return mAnimationState->getLength();
|
||||
if (getEnabled())
|
||||
return mAnimationState->getLength();
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
return mAnimationState->getTimePosition();
|
||||
if (getEnabled())
|
||||
return mAnimationState->getTimePosition();
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
};
|
||||
|
||||
struct AnimationNode {
|
||||
std::vector<AnimationNode *> children;
|
||||
float m_weight;
|
||||
Ogre::String m_name;
|
||||
std::multimap<float, AnimationTrigger *> trigger_list;
|
||||
AnimationNode()
|
||||
: m_weight(0)
|
||||
{
|
||||
}
|
||||
virtual bool addTime(float time) = 0;
|
||||
virtual void setWeight(float weight) = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual float getLength() const = 0;
|
||||
virtual float getTimePosition() const = 0;
|
||||
float getWeight()
|
||||
{
|
||||
return m_weight;
|
||||
}
|
||||
const Ogre::String &getName()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
void setName(const Ogre::String &name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
virtual float getTime() const
|
||||
{
|
||||
float l = getLength();
|
||||
if (l > 0.0f)
|
||||
return getTimePosition() / l;
|
||||
return 0.0f;
|
||||
}
|
||||
void addTrigger(AnimationTrigger *trigger)
|
||||
{
|
||||
trigger_list.insert(std::pair<float, AnimationTrigger *>(
|
||||
trigger->getTriggerTime(), trigger));
|
||||
}
|
||||
void clearTriggers()
|
||||
{
|
||||
auto it = trigger_list.begin();
|
||||
while (it != trigger_list.end()) {
|
||||
delete it->second;
|
||||
it++;
|
||||
}
|
||||
trigger_list.clear();
|
||||
}
|
||||
float mpreUpdateTime;
|
||||
void preUpdateTriggers()
|
||||
{
|
||||
mpreUpdateTime = getTime();
|
||||
}
|
||||
void postUpdateTriggers(float delta)
|
||||
{
|
||||
float postUpdateTime = getTime();
|
||||
bool positive = delta >= 0.0f;
|
||||
if (positive)
|
||||
updateTriggers(mpreUpdateTime, postUpdateTime);
|
||||
else
|
||||
updateTriggers(postUpdateTime, mpreUpdateTime);
|
||||
}
|
||||
void updateTriggers(float currentTime, float nextTime)
|
||||
{
|
||||
int i;
|
||||
float weight = getWeight();
|
||||
if (currentTime <= nextTime) {
|
||||
auto it = trigger_list.lower_bound(currentTime);
|
||||
while (it != trigger_list.end()) {
|
||||
if (nextTime <=
|
||||
it->second->getTriggerTime()) // in future, sorrted by time
|
||||
return;
|
||||
it->second->notify(weight);
|
||||
it++;
|
||||
}
|
||||
} else {
|
||||
updateTriggers(currentTime, 1);
|
||||
updateTriggers(0, nextTime);
|
||||
}
|
||||
}
|
||||
};
|
||||
struct AnimationNodeAnimation : AnimationNode {
|
||||
Animation *mAnimation;
|
||||
bool enabled;
|
||||
AnimationNodeAnimation(Animation *animation)
|
||||
: AnimationNode()
|
||||
, mAnimation(animation)
|
||||
{
|
||||
}
|
||||
bool addTime(float time)
|
||||
{
|
||||
bool ret;
|
||||
preUpdateTriggers();
|
||||
ret = mAnimation->addTime(time);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
m_weight = weight;
|
||||
enabled = weight > 0.001f;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
mAnimation->reset();
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
return mAnimation->getLength();
|
||||
if (enabled)
|
||||
return mAnimation->getLength();
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
return mAnimation->getTimePosition();
|
||||
if (enabled)
|
||||
return mAnimation->getTimePosition();
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
};
|
||||
struct AnimationNodeStateMachineState : AnimationNode {
|
||||
AnimationNodeStateMachineState()
|
||||
: AnimationNode()
|
||||
{
|
||||
}
|
||||
bool addTime(float time)
|
||||
{
|
||||
bool ret;
|
||||
preUpdateTriggers();
|
||||
ret = children[0]->addTime(time);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
m_weight = weight;
|
||||
bool enabled = weight > 0.001f;
|
||||
children[0]->setWeight(weight);
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
children[0]->reset();
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
return children[0]->getLength();
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
return children[0]->getTimePosition();
|
||||
}
|
||||
};
|
||||
struct AnimationNodeSpeed : AnimationNode {
|
||||
float m_speed;
|
||||
bool enabled;
|
||||
AnimationNodeSpeed(float speed)
|
||||
: AnimationNode()
|
||||
, m_speed(speed)
|
||||
, enabled(false)
|
||||
{
|
||||
}
|
||||
bool addTime(float time)
|
||||
{
|
||||
bool ret;
|
||||
preUpdateTriggers();
|
||||
ret = children[0]->addTime(time * m_speed);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
m_weight = weight;
|
||||
children[0]->setWeight(weight);
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
children[0]->reset();
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
if (m_speed > 0.0f || m_speed < 0.0f)
|
||||
return children[0]->getLength() / m_speed;
|
||||
return 0.0f;
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
if (m_speed > 0.0f || m_speed < 0.0f)
|
||||
return children[0]->getTimePosition() / m_speed;
|
||||
return 0.0f;
|
||||
}
|
||||
float getTime() const override
|
||||
{
|
||||
float l = children[0]->getLength();
|
||||
if (l > 0.0f)
|
||||
return children[0]->getTimePosition() / l;
|
||||
return 0.0f;
|
||||
}
|
||||
};
|
||||
struct AnimationNodeStateMachine : AnimationNode {
|
||||
std::map<Ogre::String, AnimationNode *> stateMap;
|
||||
std::set<AnimationNode *> fade_in, fade_out;
|
||||
AnimationNode *currentAnim, *nextAnim;
|
||||
float fade_speed;
|
||||
Ogre::String mCurrentStateName;
|
||||
bool configured;
|
||||
bool debug;
|
||||
AnimationNodeStateMachine(float fade_speed, bool debug = false)
|
||||
: AnimationNode()
|
||||
, currentAnim(nullptr)
|
||||
, nextAnim(nullptr)
|
||||
, fade_speed(fade_speed)
|
||||
, mCurrentStateName("")
|
||||
, configured(false)
|
||||
, debug(debug)
|
||||
{
|
||||
m_weight = 1.0f;
|
||||
}
|
||||
bool addTime(float time)
|
||||
{
|
||||
int i;
|
||||
preUpdateTriggers();
|
||||
if (!configured) {
|
||||
configure();
|
||||
configured = true;
|
||||
}
|
||||
#ifdef VDEBUG
|
||||
if (debug) {
|
||||
std::cout << "state machine addTime" << std::endl;
|
||||
std::cout
|
||||
<< "state machine children: " << children.size()
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < children.size(); i++) {
|
||||
#ifdef VDEBUG
|
||||
if (debug)
|
||||
std::cout << "child weight: " << i << " "
|
||||
<< children[i]->getWeight()
|
||||
<< std::endl;
|
||||
#endif
|
||||
AnimationNode *child = children[i];
|
||||
if (fade_in.find(child) != fade_in.end()) {
|
||||
Ogre::Real newWeight =
|
||||
child->getWeight() + time * fade_speed;
|
||||
child->setWeight(Ogre::Math::Clamp<Ogre::Real>(
|
||||
newWeight * m_weight, 0, m_weight));
|
||||
#ifdef VDEBUG
|
||||
if (debug) {
|
||||
std::cout << "fade in: " << newWeight
|
||||
<< std::endl;
|
||||
std::cout << "m_weight: " << m_weight
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
if (newWeight >= 1)
|
||||
fade_in.erase(child);
|
||||
}
|
||||
if (fade_out.find(child) != fade_out.end()) {
|
||||
Ogre::Real newWeight =
|
||||
child->getWeight() - time * fade_speed;
|
||||
child->setWeight(Ogre::Math::Clamp<Ogre::Real>(
|
||||
newWeight * m_weight, 0, 1));
|
||||
if (newWeight <= 0)
|
||||
fade_out.erase(child);
|
||||
}
|
||||
}
|
||||
OgreAssert(currentAnim, "bad current anim");
|
||||
bool ret = false;
|
||||
if (currentAnim)
|
||||
ret = currentAnim->addTime(time);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
int i;
|
||||
if (weight > m_weight && currentAnim)
|
||||
fade_in.insert(currentAnim);
|
||||
if (weight < m_weight && currentAnim &&
|
||||
currentAnim->getWeight() > weight)
|
||||
currentAnim->setWeight(weight);
|
||||
m_weight = weight;
|
||||
bool enabled = weight > 0.001f;
|
||||
/* do not update child state yet */
|
||||
}
|
||||
void addState(AnimationNode *state)
|
||||
{
|
||||
const Ogre::String &name = state->getName();
|
||||
stateMap[name] = state;
|
||||
state->setWeight(0);
|
||||
fade_in.erase(state);
|
||||
fade_out.erase(state);
|
||||
std::cout << "registered state: " << name << std::endl;
|
||||
}
|
||||
void configure()
|
||||
{
|
||||
int i;
|
||||
if (debug)
|
||||
std::cout << "children: " << children.size()
|
||||
<< std::endl;
|
||||
for (i = 0; i < children.size(); i++)
|
||||
addState(children[i]);
|
||||
if (debug)
|
||||
std::cout << "configure called" << std::endl;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < children.size(); i++)
|
||||
children[i]->reset();
|
||||
}
|
||||
void setAnimation(const Ogre::String &anim_state, bool reset = false)
|
||||
{
|
||||
if (!configured) {
|
||||
configure();
|
||||
configured = true;
|
||||
}
|
||||
OgreAssert(stateMap.find(anim_state) != stateMap.end(),
|
||||
"Bad animation state: " + anim_state);
|
||||
nextAnim = stateMap[anim_state];
|
||||
if (nextAnim == currentAnim)
|
||||
return;
|
||||
if (currentAnim != nullptr) {
|
||||
fade_out.insert(currentAnim);
|
||||
fade_in.erase(currentAnim);
|
||||
}
|
||||
fade_out.erase(nextAnim);
|
||||
fade_in.insert(nextAnim);
|
||||
nextAnim->setWeight(0);
|
||||
if (reset)
|
||||
nextAnim->reset();
|
||||
currentAnim = nextAnim;
|
||||
mCurrentStateName = anim_state;
|
||||
}
|
||||
const Ogre::String &getCurrentState() const
|
||||
{
|
||||
return mCurrentStateName;
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
if (currentAnim)
|
||||
return currentAnim->getLength();
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
if (currentAnim)
|
||||
return currentAnim->getTimePosition();
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
};
|
||||
struct AnimationSystem : AnimationNode {
|
||||
bool debug;
|
||||
|
||||
#define ANIM_FADE_SPEED \
|
||||
7.5f // animation crossfade speed in % of full weight per second
|
||||
|
||||
struct AnimationNodeOutput : AnimationNode {
|
||||
float m_weight;
|
||||
float m_speed;
|
||||
AnimationNodeOutput()
|
||||
: AnimationNode()
|
||||
, m_weight(1.0f)
|
||||
, m_speed(1.0f)
|
||||
{
|
||||
}
|
||||
bool addTime(float time)
|
||||
{
|
||||
bool ret;
|
||||
preUpdateTriggers();
|
||||
ret = children[0]->addTime(time * m_speed);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
m_weight = weight;
|
||||
bool enabled = weight > 0.001f;
|
||||
children[0]->setWeight(weight);
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
children[0]->reset();
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
return children[0]->getLength();
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
return children[0]->getTimePosition();
|
||||
}
|
||||
};
|
||||
|
||||
AnimationSystem(bool debug = false)
|
||||
: debug(debug)
|
||||
, m_builder(this, debug)
|
||||
{
|
||||
}
|
||||
std::unordered_map<Ogre::String, Animation *> animation_list;
|
||||
std::vector<Animation *> vanimation_list;
|
||||
void add_animation(const Ogre::String &name, Animation *animation)
|
||||
{
|
||||
OgreAssert(animation, "No animation " + name);
|
||||
animation_list[name] = animation;
|
||||
vanimation_list.push_back(animation);
|
||||
}
|
||||
void clear_animations()
|
||||
{
|
||||
animation_list.clear();
|
||||
vanimation_list.clear();
|
||||
}
|
||||
struct AnimationSystemBuilder {
|
||||
AnimationSystem *mAnimationSystem;
|
||||
std::vector<AnimationNode *> animation_nodes;
|
||||
AnimationNode *parent;
|
||||
std::list<AnimationNode *> parent_stack;
|
||||
std::unordered_map<Ogre::String, AnimationNode *> nodeMap;
|
||||
std::vector<AnimationNodeAnimation *> animationNodeList;
|
||||
bool debug;
|
||||
AnimationSystemBuilder(AnimationSystem *animationSystem,
|
||||
bool debug = false)
|
||||
: mAnimationSystem(animationSystem)
|
||||
, debug(debug)
|
||||
{
|
||||
}
|
||||
AnimationSystemBuilder *output()
|
||||
{
|
||||
AnimationNodeOutput *onode = new AnimationNodeOutput();
|
||||
animation_nodes.push_back(onode);
|
||||
parent = onode;
|
||||
return this;
|
||||
}
|
||||
AnimationSystemBuilder *
|
||||
animation(const Ogre::String &animation_name)
|
||||
{
|
||||
OgreAssert(parent, "bad parent");
|
||||
Animation *animation =
|
||||
mAnimationSystem->animation_list[animation_name];
|
||||
OgreAssert(animation,
|
||||
"bad animation " + animation_name);
|
||||
AnimationNodeAnimation *onode =
|
||||
new AnimationNodeAnimation(animation);
|
||||
OgreAssert(onode, "bad animation");
|
||||
OgreAssert(onode->mAnimation, "bad animation");
|
||||
animation_nodes.push_back(onode);
|
||||
parent->children.push_back(onode);
|
||||
animationNodeList.push_back(onode);
|
||||
return this;
|
||||
}
|
||||
/* FIXME: need to remove flecs dependency */
|
||||
AnimationSystemBuilder *
|
||||
trigger_entity(flecs::entity e, const Ogre::String &name,
|
||||
float time, const Ogre::String &event)
|
||||
{
|
||||
struct EntityEventSubscriber
|
||||
: AnimationTriggerSubscriber {
|
||||
Ogre::String event;
|
||||
flecs::entity ent;
|
||||
void operator()(const AnimationTrigger *trigger)
|
||||
{
|
||||
ent.get_mut<ECS::EventData>().add(
|
||||
ent, event, ent, ent);
|
||||
}
|
||||
EntityEventSubscriber(flecs::entity e,
|
||||
const Ogre::String &event)
|
||||
: event(event)
|
||||
, ent(e)
|
||||
{
|
||||
}
|
||||
};
|
||||
OgreAssert(parent, "bad parent");
|
||||
AnimationTrigger *trigger =
|
||||
new AnimationTrigger(name, time, 0.1f);
|
||||
EntityEventSubscriber *sub =
|
||||
new EntityEventSubscriber(e, event);
|
||||
trigger->addSubscriber(sub);
|
||||
parent->addTrigger(trigger);
|
||||
return this;
|
||||
} // leaf too...
|
||||
AnimationSystemBuilder *
|
||||
transition_end(const Ogre::String &state_from,
|
||||
const Ogre::String &state_to)
|
||||
{
|
||||
struct EndTransitionSubscriber
|
||||
: AnimationTriggerSubscriber {
|
||||
AnimationNodeStateMachine *sm;
|
||||
Ogre::String next_state;
|
||||
bool reset;
|
||||
void operator()(const AnimationTrigger *trigger)
|
||||
{
|
||||
sm->setAnimation(next_state, reset);
|
||||
}
|
||||
EndTransitionSubscriber(
|
||||
AnimationNodeStateMachine *sm,
|
||||
const Ogre::String &next_state,
|
||||
bool reset = true)
|
||||
: sm(sm)
|
||||
, next_state(next_state)
|
||||
, reset(reset)
|
||||
{
|
||||
}
|
||||
};
|
||||
OgreAssert(parent, "no parent");
|
||||
AnimationNodeStateMachine *sm =
|
||||
static_cast<AnimationNodeStateMachine *>(
|
||||
parent);
|
||||
OgreAssert(sm, "no state machine");
|
||||
AnimationTrigger *trigger = new AnimationTrigger(
|
||||
"transition:" + state_from + "_" + state_to,
|
||||
0.99f, 0.1f);
|
||||
EndTransitionSubscriber *sub =
|
||||
new EndTransitionSubscriber(sm, state_to);
|
||||
int i;
|
||||
bool ok = false;
|
||||
for (i = 0; i < sm->children.size(); i++) {
|
||||
if (sm->children[i]->getName() == state_from) {
|
||||
trigger->addSubscriber(sub);
|
||||
sm->children[i]->addTrigger(trigger);
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
OgreAssert(ok, "Failed to set transition");
|
||||
return this;
|
||||
}
|
||||
AnimationSystemBuilder *speed(float speed,
|
||||
const Ogre::String &anchor = "")
|
||||
{
|
||||
OgreAssert(parent, "bad parent");
|
||||
AnimationNodeSpeed *onode =
|
||||
new AnimationNodeSpeed(speed);
|
||||
animation_nodes.push_back(onode);
|
||||
parent->children.push_back(onode);
|
||||
parent_stack.push_back(parent);
|
||||
parent = onode;
|
||||
if (anchor.length() > 0)
|
||||
nodeMap[anchor] = onode;
|
||||
return this;
|
||||
}
|
||||
AnimationSystemBuilder *
|
||||
state_machine(float fade_time = ANIM_FADE_SPEED,
|
||||
const Ogre::String &anchor = "")
|
||||
{
|
||||
OgreAssert(parent, "bad parent");
|
||||
AnimationNodeStateMachine *onode =
|
||||
new AnimationNodeStateMachine(fade_time, debug);
|
||||
animation_nodes.push_back(onode);
|
||||
parent->children.push_back(onode);
|
||||
parent_stack.push_back(parent);
|
||||
parent = onode;
|
||||
if (anchor.length() > 0)
|
||||
nodeMap[anchor] = onode;
|
||||
return this;
|
||||
}
|
||||
AnimationSystemBuilder *state(const Ogre::String &state_name)
|
||||
{
|
||||
OgreAssert(parent, "bad parent");
|
||||
AnimationNodeStateMachineState *onode =
|
||||
new AnimationNodeStateMachineState;
|
||||
animation_nodes.push_back(onode);
|
||||
parent->children.push_back(onode);
|
||||
parent_stack.push_back(parent);
|
||||
parent = onode;
|
||||
onode->setName(state_name);
|
||||
return this;
|
||||
}
|
||||
AnimationSystemBuilder *end()
|
||||
{
|
||||
parent = parent_stack.back();
|
||||
parent_stack.pop_back();
|
||||
return this;
|
||||
}
|
||||
};
|
||||
AnimationSystemBuilder m_builder;
|
||||
Ogre::Vector3 getRootMotionDelta();
|
||||
bool addTime(float time);
|
||||
void setWeight(float weight)
|
||||
{
|
||||
m_builder.animation_nodes[0]->setWeight(weight);
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
m_builder.animation_nodes[0]->reset();
|
||||
}
|
||||
AnimationSystemBuilder *builder()
|
||||
{
|
||||
m_builder.animation_nodes.reserve(8);
|
||||
m_builder.parent = nullptr;
|
||||
return &m_builder;
|
||||
}
|
||||
template <class T> T *get(const Ogre::String &name)
|
||||
{
|
||||
return static_cast<T *>(m_builder.nodeMap[name]);
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
return m_builder.animation_nodes[0]->getLength();
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
return m_builder.animation_nodes[0]->getTimePosition();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ANIMATIONSYSTEM_H
|
||||
@@ -4,19 +4,22 @@ find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain Overlay CONFIG
|
||||
find_package(Bullet REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
find_package(OgreProcedural REQUIRED CONFIG)
|
||||
find_package(Tracy REQUIRED CONFIG)
|
||||
add_subdirectory(items)
|
||||
add_subdirectory(LuaModule)
|
||||
add_library(GameData STATIC GameData.cpp CharacterModule.cpp WaterModule.cpp SunModule.cpp TerrainModule.cpp
|
||||
GUIModule.cpp EditorGUIModule.cpp LuaData.cpp WorldMapModule.cpp BoatModule.cpp EventTriggerModule.cpp
|
||||
GUIModule.cpp EditorGUIModule.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 QuestModule.cpp
|
||||
PlayerActionModule.cpp CharacterAIModule.cpp goap.cpp)
|
||||
PlayerActionModule.cpp CharacterAIModule.cpp goap.cpp AnimationSystem.cpp)
|
||||
target_link_libraries(GameData PUBLIC
|
||||
lua
|
||||
items luamodule
|
||||
flecs::flecs_static
|
||||
nlohmann_json::nlohmann_json
|
||||
OgreMain
|
||||
OgreBites
|
||||
OgrePaging OgreTerrain OgreOverlay OgreProcedural::OgreProcedural items
|
||||
PRIVATE sceneloader world-build physics editor)
|
||||
target_include_directories(GameData PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${BULLET_INCLUDE_DIR} ../luaaa ../aitoolkit/include)
|
||||
target_compile_definitions(GameData PRIVATE FLECS_CPP_NO_AUTO_REGISTRATION)
|
||||
OgrePaging OgreTerrain OgreOverlay OgreProcedural::OgreProcedural
|
||||
PRIVATE sceneloader world-build physics editor Tracy::TracyClient
|
||||
)
|
||||
target_include_directories(GameData PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${BULLET_INCLUDE_DIR})
|
||||
target_compile_definitions(GameData PRIVATE FLECS_CPP_NO_AUTO_REGISTRATION PUBLIC TRACY_ENABLE)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "CharacterModule.h"
|
||||
#include "items.h"
|
||||
#include "CharacterAIModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
struct ActionExec {
|
||||
@@ -231,7 +232,6 @@ public:
|
||||
Ogre::Vector3 direction =
|
||||
(targetPosition - npc.position).normalisedCopy();
|
||||
targetPosition -= direction * radius;
|
||||
std::cout << action->get_name();
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -245,21 +245,20 @@ public:
|
||||
private:
|
||||
int update(float delta) override
|
||||
{
|
||||
OgreAssert(false, "update");
|
||||
return OK;
|
||||
}
|
||||
void finish(int rc) override
|
||||
{
|
||||
if (rc == OK)
|
||||
bb.apply(action->effects);
|
||||
OgreAssert(false, "finish");
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
std::cout << action->get_name();
|
||||
const ActionNodeActions::RunActionNode *runaction =
|
||||
static_cast<const ActionNodeActions::RunActionNode
|
||||
*>(action);
|
||||
if (runaction)
|
||||
std::cout << "Is Run" << std::endl;
|
||||
OgreAssert(false, "activate");
|
||||
}
|
||||
|
||||
@@ -329,14 +328,32 @@ public:
|
||||
jactionPrereq["is_seated"] = 0;
|
||||
jactionEffect["is_seated"] = 1;
|
||||
} else if (action == "use") {
|
||||
if (props["tags"].find("toilet") !=
|
||||
props["tags"].end()) {
|
||||
std::cout << "toilet" << std::endl;
|
||||
OgreAssert(false, "props: " + props.dump(4));
|
||||
OgreAssert(props["tags"].is_array(), "bad formed tags");
|
||||
const nlohmann::json &tags = props["tags"];
|
||||
if (tags.size() == 1 &&
|
||||
tags[0].get<Ogre::String>() == "") {
|
||||
} else {
|
||||
std::cout << "use: " << props.dump(4)
|
||||
<< std::endl;
|
||||
// OgreAssert(false, "props: " + props.dump(4));
|
||||
bool have_bits = false;
|
||||
if (std::find(tags.begin(), tags.end(),
|
||||
"dance-pole") != tags.end()) {
|
||||
jactionPrereq["is_pole_dancing"] = 0;
|
||||
jactionEffect["is_pole_dancing"] = 1;
|
||||
have_bits = true;
|
||||
}
|
||||
if (std::find(tags.begin(), tags.end(),
|
||||
"toilet") != tags.end()) {
|
||||
jactionPrereq["toilet"] = 1;
|
||||
jactionEffect["toilet"] = 0;
|
||||
have_bits = true;
|
||||
}
|
||||
if (!have_bits) {
|
||||
std::cout << "use: " << props.dump(4)
|
||||
<< std::endl;
|
||||
// OgreAssert(false, "props: " + props.dump(4));
|
||||
OgreAssert(tags.size() == 0,
|
||||
"Some tags: " +
|
||||
props.dump(4));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OgreAssert(false, "props: " + props.dump(4));
|
||||
@@ -363,27 +380,32 @@ public:
|
||||
};
|
||||
struct ActionExecCommon : ActionExec {
|
||||
private:
|
||||
float delay;
|
||||
int update(float delta) override
|
||||
{
|
||||
std::cout << "running: " << action->get_name() << std::endl;
|
||||
return OK;
|
||||
delay -= delta;
|
||||
if (delay > 0.0f)
|
||||
return BUSY;
|
||||
else
|
||||
return OK;
|
||||
}
|
||||
void finish(int rc) override
|
||||
{
|
||||
if (rc == OK)
|
||||
bb.apply(action->effects);
|
||||
std::cout << "finish: " << action->get_name() << std::endl;
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
std::cout << action->get_name();
|
||||
std::cout << "!";
|
||||
delay = 1.0f;
|
||||
}
|
||||
|
||||
public:
|
||||
ActionExecCommon(ActionExec::PlanExecData &data,
|
||||
goap::BaseAction<Blackboard> *action)
|
||||
: ActionExec(data, action)
|
||||
, delay(0.0f)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -439,20 +461,30 @@ CharacterAIModule::CharacterAIModule(flecs::world &ecs)
|
||||
{ "thirsty", 1 } } },
|
||||
{ { { "thirsty", 0 } } },
|
||||
10 },
|
||||
#if 0
|
||||
{ "DrinkWater",
|
||||
{ { { "have_water", 1 }, { "thirsty", 1 } } },
|
||||
{ { { "have_water", 1 },
|
||||
{ "thirsty", 1 },
|
||||
{ "is_seated", 0 } } },
|
||||
{ { { "thirsty", 0 } } },
|
||||
2000 },
|
||||
#endif
|
||||
{ "EatMedicine",
|
||||
{ { { "have_medicine", 1 }, { "healthy", 0 } } },
|
||||
{ "EatMedicineSeated",
|
||||
{ { { "have_medicine", 1 },
|
||||
{ "healthy", 0 },
|
||||
{ "is_seated", 1 } } },
|
||||
{ { { "healthy", 1 } } },
|
||||
100 },
|
||||
{ "EatMedicine",
|
||||
{ { { "have_medicine", 1 },
|
||||
{ "healthy", 0 },
|
||||
{ "is_seated", 0 } } },
|
||||
{ { { "healthy", 1 } } },
|
||||
10000 },
|
||||
#if 0
|
||||
{ "UseToilet",
|
||||
{ { { "toilet", 1 } } },
|
||||
{ { { "toilet", 0 } } },
|
||||
100 },
|
||||
#endif
|
||||
{ "GetFood",
|
||||
{ { { "have_food", 0 } } },
|
||||
{ { { "have_food", 1 } } },
|
||||
@@ -478,25 +510,15 @@ CharacterAIModule::CharacterAIModule(flecs::world &ecs)
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity town, TownAI &ai,
|
||||
const TownNPCs &npcs) {
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask(
|
||||
[this, town, npcs, &ai]() {
|
||||
Ogre::Root::getSingleton()
|
||||
.getWorkQueue()
|
||||
->addMainThreadTask([this, town,
|
||||
npcs,
|
||||
&ai]() {
|
||||
std::lock_guard<
|
||||
std::mutex>
|
||||
lock(ecs_mutex);
|
||||
createBlackboards(
|
||||
town, npcs, ai);
|
||||
});
|
||||
});
|
||||
ZoneScopedN("CreateBlackboards");
|
||||
std::lock_guard<std::mutex> lock(ecs_mutex);
|
||||
createBlackboards(town, npcs, ai);
|
||||
});
|
||||
ecs.system<ActionNodeList, TownAI, TownNPCs>("UpdateDynamicActions")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([](flecs::entity e, ActionNodeList &alist, TownAI &ai,
|
||||
TownNPCs &npcs) {
|
||||
ZoneScopedN("UpdateDynamicActions");
|
||||
std::lock_guard<std::mutex> lock(ecs_mutex);
|
||||
if (ai.nodeActions.size() > 0)
|
||||
return;
|
||||
@@ -527,12 +549,31 @@ CharacterAIModule::CharacterAIModule(flecs::world &ecs)
|
||||
.interval(0.1f)
|
||||
.each([this](flecs::entity town, ActionNodeList &alist,
|
||||
TownAI &ai, TownNPCs &npcs) {
|
||||
ZoneScopedN("UpdateDynamicNodes");
|
||||
std::lock_guard<std::mutex> lock(ecs_mutex);
|
||||
ECS::get_mut<ActionNodeList>().updateDynamicNodes();
|
||||
});
|
||||
struct MeasureTime {
|
||||
std::chrono::system_clock::time_point start;
|
||||
std::string what;
|
||||
MeasureTime(const std::string &s)
|
||||
: start(std::chrono::high_resolution_clock::now())
|
||||
, what(s)
|
||||
{
|
||||
}
|
||||
~MeasureTime()
|
||||
{
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<float, std::milli> elapsed =
|
||||
end - start;
|
||||
std::cout << what << " " << elapsed.count()
|
||||
<< std::endl;
|
||||
}
|
||||
};
|
||||
ecs.system<TownNPCs>("UpdateNPCPositions")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([](flecs::entity e, TownNPCs &npcs) {
|
||||
ZoneScopedN("UpdateNPCPositions");
|
||||
for (auto it = npcs.npcs.begin(); it != npcs.npcs.end();
|
||||
it++) {
|
||||
auto &npc = npcs.npcs.at(it->first);
|
||||
@@ -549,49 +590,62 @@ CharacterAIModule::CharacterAIModule(flecs::world &ecs)
|
||||
.interval(0.1f)
|
||||
.each([this](flecs::entity town, ActionNodeList &alist,
|
||||
TownAI &ai, const TownNPCs &npcs) {
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask(
|
||||
[this, town, &alist, npcs, &ai]() {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(
|
||||
ecs_mutex);
|
||||
ZoneScopedN("UpdateBlackboards");
|
||||
|
||||
updateBlackboards(town, alist,
|
||||
npcs, ai);
|
||||
}
|
||||
Ogre::Root::getSingleton()
|
||||
.getWorkQueue()
|
||||
->addMainThreadTask([this, town,
|
||||
&alist]() {
|
||||
town.modified<TownAI>();
|
||||
town.modified<TownNPCs>();
|
||||
ECS::modified<
|
||||
ActionNodeList>();
|
||||
});
|
||||
});
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask([this,
|
||||
town,
|
||||
&alist,
|
||||
npcs,
|
||||
&ai]() {
|
||||
{
|
||||
ZoneScopedN(
|
||||
"UpdateBlackboards::Thread");
|
||||
std::lock_guard<std::mutex> lock(
|
||||
ecs_mutex);
|
||||
|
||||
updateBlackboards(town, alist, npcs,
|
||||
ai);
|
||||
}
|
||||
Ogre::Root::getSingleton()
|
||||
.getWorkQueue()
|
||||
->addMainThreadTask([this, town,
|
||||
&alist]() {
|
||||
ZoneScopedN(
|
||||
"UpdateBlackboards::MainThread");
|
||||
town.modified<TownAI>();
|
||||
town.modified<TownNPCs>();
|
||||
ECS::modified<ActionNodeList>();
|
||||
});
|
||||
});
|
||||
});
|
||||
ecs.system<TownAI, TownNPCs>("PlanAI")
|
||||
.kind(flecs::OnUpdate)
|
||||
.interval(0.5f)
|
||||
.each([&](flecs::entity town, TownAI &ai,
|
||||
const TownNPCs &npcs) {
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask(
|
||||
[this, town, npcs, &ai]() {
|
||||
std::lock_guard<std::mutex> lock(
|
||||
ecs_mutex);
|
||||
buildPlans(town, npcs, ai);
|
||||
Ogre::Root::getSingleton()
|
||||
.getWorkQueue()
|
||||
->addMainThreadTask([this,
|
||||
town]() {
|
||||
town.modified<TownAI>();
|
||||
});
|
||||
});
|
||||
ZoneScopedN("PlanAI");
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask([this,
|
||||
town,
|
||||
npcs,
|
||||
&ai]() {
|
||||
ZoneScopedN("PlanAI::Thread");
|
||||
std::lock_guard<std::mutex> lock(ecs_mutex);
|
||||
buildPlans(town, npcs, ai);
|
||||
Ogre::Root::getSingleton()
|
||||
.getWorkQueue()
|
||||
->addMainThreadTask([this, town]() {
|
||||
ZoneScopedN(
|
||||
"PlanAI::MainThread");
|
||||
town.modified<TownAI>();
|
||||
});
|
||||
});
|
||||
});
|
||||
static std::unordered_map<int, struct PlanExec> plan_exec;
|
||||
ecs.system<const EngineData, TownNPCs, TownAI>("RunPLAN")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([&](flecs::entity town, const EngineData &eng,
|
||||
TownNPCs &npcs, TownAI &ai) {
|
||||
ZoneScopedN("RunPLAN");
|
||||
for (const auto &plans : ai.plans) {
|
||||
if (plan_exec.find(plans.first) !=
|
||||
plan_exec.end()) {
|
||||
@@ -712,6 +766,7 @@ static std::deque<PlanTask> plan_tasks;
|
||||
void CharacterAIModule::buildPlans(flecs::entity town, const TownNPCs &npcs,
|
||||
TownAI &ai)
|
||||
{
|
||||
ZoneScopedN("buildPlans");
|
||||
OgreAssert(town.is_valid(), "Bad town entity");
|
||||
std::lock_guard<std::mutex> lock(*ai.mutex);
|
||||
auto planner = ai.planner;
|
||||
@@ -758,6 +813,7 @@ void CharacterAIModule::buildPlans(flecs::entity town, const TownNPCs &npcs,
|
||||
void CharacterAIModule::createBlackboards(flecs::entity town,
|
||||
const TownNPCs &npcs, TownAI &ai)
|
||||
{
|
||||
ZoneScopedN("createBlackboards");
|
||||
OgreAssert(town.is_valid(), "Bad town entity");
|
||||
std::lock_guard<std::mutex> lock(*ai.mutex);
|
||||
for (auto it = npcs.npcs.begin(); it != npcs.npcs.end(); it++) {
|
||||
@@ -871,6 +927,7 @@ void CharacterAIModule::updateBlackboards(flecs::entity town,
|
||||
ActionNodeList &alist,
|
||||
const TownNPCs &npcs, TownAI &ai)
|
||||
{
|
||||
ZoneScopedN("updateBlackboards");
|
||||
std::lock_guard<std::mutex> lock(*ai.mutex);
|
||||
OgreAssert(town.is_valid(), "Bad town entity");
|
||||
alist.build();
|
||||
@@ -1124,7 +1181,8 @@ void Blackboard::query_ai()
|
||||
const TownNPCs &npcs = town.get<TownNPCs>();
|
||||
const float distance = 10000.0f;
|
||||
Ogre::Vector3 position(0, 0, 0);
|
||||
if (npcs.npcs.at(index).e.is_valid())
|
||||
if (npcs.npcs.at(index).e.is_valid() &&
|
||||
npcs.npcs.at(index).e.has<CharacterBase>())
|
||||
position = npcs.npcs.at(index)
|
||||
.e.get<CharacterBase>()
|
||||
.mBodyNode->_getDerivedPosition();
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
#include "TerrainModule.h"
|
||||
#include "WaterModule.h"
|
||||
#include "world-build.h"
|
||||
#include "AnimationSystem.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
{
|
||||
ZoneScoped;
|
||||
ecs.module<CharacterAnimationModule>();
|
||||
ecs.component<AnimationControl>();
|
||||
ecs.import <EventModule>();
|
||||
@@ -21,7 +24,8 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
ecs.system<const CharacterBase, AnimationControl>("HandleAnimations")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, const CharacterBase &ch,
|
||||
AnimationControl &anim) {
|
||||
AnimationControl &anim) {
|
||||
ZoneScopedN("HandleAnimations");
|
||||
if (!anim.configured) {
|
||||
int i, j;
|
||||
e.set<EventData>({});
|
||||
@@ -32,19 +36,22 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
const Ogre::AnimationStateMap &animMap =
|
||||
animStateSet->getAnimationStates();
|
||||
anim.mAnimationSystem =
|
||||
new AnimationSystem(false);
|
||||
new AnimationSystem::AnimationSystem(
|
||||
false);
|
||||
ch.mBodyEnt->getSkeleton()
|
||||
->getBone("Root")
|
||||
->removeAllChildren();
|
||||
for (auto it = animMap.begin();
|
||||
it != animMap.end(); it++) {
|
||||
Animation *animation = new Animation(
|
||||
ch.mBodyEnt->getSkeleton(),
|
||||
it->second,
|
||||
ch.mBodyEnt->getSkeleton()
|
||||
->getAnimation(
|
||||
it->first),
|
||||
e);
|
||||
AnimationSystem::Animation *animation =
|
||||
new AnimationSystem::Animation(
|
||||
ch.mBodyEnt
|
||||
->getSkeleton(),
|
||||
it->second,
|
||||
ch.mBodyEnt
|
||||
->getSkeleton()
|
||||
->getAnimation(
|
||||
it->first));
|
||||
#ifdef VDEBUG
|
||||
std::cout
|
||||
<< "animation: " << animNames[i]
|
||||
@@ -93,18 +100,18 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
->end()
|
||||
->state("swimming-edge-climb")
|
||||
->animation("swimming-edge-climb")
|
||||
->trigger(e, "end_of_climb", 0.99f, "animation:swimming-edge-climb:end")
|
||||
->trigger_entity(e, "end_of_climb", 0.99f, "animation:swimming-edge-climb:end")
|
||||
->end()
|
||||
->state("hanging-climb")
|
||||
->animation("hanging-climb")
|
||||
->trigger(e, "end_of_climb2", 0.99f, "animation:hanging-climb:end")
|
||||
->trigger_entity(e, "end_of_climb2", 0.99f, "animation:hanging-climb:end")
|
||||
->end()
|
||||
->state("idle")
|
||||
->animation("idle-act")
|
||||
->end()
|
||||
->state("pass-character")
|
||||
->animation("pass-character")
|
||||
->trigger(e, "pass-character", 0.99f, "animation:pass-character:end")
|
||||
->trigger_entity(e, "pass-character", 0.99f, "animation:pass-character:end")
|
||||
->end()
|
||||
->state("character-talk")
|
||||
->animation("character-talk")
|
||||
@@ -127,10 +134,13 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
/* clang-format on */
|
||||
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>("main")
|
||||
->get<AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
"main")
|
||||
->setAnimation("locomotion", true);
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
->get<AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
"locomotion-state")
|
||||
->setAnimation("idle", true);
|
||||
anim.configured = true;
|
||||
@@ -148,73 +158,25 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
CharacterBase &ch, AnimationControl &anim) {
|
||||
float delta = eng.delta;
|
||||
ZoneScopedN("HandleAnimations1");
|
||||
float delta = eng.delta;
|
||||
// ch.mBoneMotion = Ogre::Vector3::ZERO;
|
||||
if (!anim.mAnimationSystem)
|
||||
return;
|
||||
#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();
|
||||
#if 0
|
||||
{
|
||||
ZoneScopedN("Ogre::Entity::_updateAnimation");
|
||||
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 *>(
|
||||
anim.mListener)
|
||||
->getDeltaMotion();
|
||||
ch.mRootBone->setPosition(Ogre::Vector3::ZERO);
|
||||
Ogre::Vector3 d = offset - ch.mBonePrevMotion;
|
||||
ch.mBonePrevMotion = offset;
|
||||
|
||||
std::cout << "length: " << d.length() << std::endl;
|
||||
if (d.squaredLength() > 0.02f * 0.02f)
|
||||
d = offset;
|
||||
if (d.squaredLength() > 0.02f * 0.02f)
|
||||
d = Ogre::Vector3::ZERO;
|
||||
std::cout << "length2: " << d.length() << std::endl;
|
||||
OgreAssert(d.length() < 0.5f, "bad offset");
|
||||
ch.mBoneMotion = d;
|
||||
#endif
|
||||
#if 0
|
||||
if (result) {
|
||||
if (d.squaredLength() > 0.0f)
|
||||
ch.mBoneMotion =
|
||||
ch.mRootBone->getPosition() -
|
||||
ch.mBoneMotion;
|
||||
else
|
||||
ch.mBoneMotion =
|
||||
ch.mRootBone->getPosition();
|
||||
} else {
|
||||
ch.mBoneMotion = ch.mRootBone->getPosition() -
|
||||
ch.mBoneMotion;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef VDEBUG
|
||||
#ifdef VDEBUG
|
||||
@@ -224,10 +186,6 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
<< " result: " << result << std::endl;
|
||||
#endif
|
||||
#undef VDEBUG
|
||||
#if 0
|
||||
// ch.mRootBone->setPosition(Ogre::Vector3::ZERO);
|
||||
ch.mBonePrevMotion = offset;
|
||||
#endif
|
||||
});
|
||||
ecs.system<const EngineData, CharacterBase, CharacterVelocity>(
|
||||
"HandleRootMotionVelocity")
|
||||
@@ -236,11 +194,12 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
.with<WaterReady>()
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
CharacterBase &ch, CharacterVelocity &v) {
|
||||
if (eng.delta < 0.0000001f)
|
||||
ZoneScopedN("HandleRootMotionVelocity");
|
||||
if (eng.delta < 0.0000001f)
|
||||
return;
|
||||
if (!ch.mBodyNode)
|
||||
return;
|
||||
Ogre::Quaternion rot = ch.mBodyNode->getOrientation();
|
||||
Ogre::Quaternion rot = ch.mBodyNode->getOrientation();
|
||||
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
|
||||
Ogre::Vector3 boneMotion = ch.mBoneMotion;
|
||||
v.velocity = Ogre::Vector3::ZERO;
|
||||
@@ -273,39 +232,16 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
#if 0
|
||||
v.velocity.y = 0.0f;
|
||||
#endif
|
||||
OgreAssert(v.velocity.squaredLength() < 1000.0f,
|
||||
"Bad velocity setting");
|
||||
});
|
||||
#if 0
|
||||
ecs.system<const EngineData, const AnimationControl,
|
||||
const CharacterBase, CharacterVelocity>("HandleSwimming")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<TerrainReady>()
|
||||
.with<WaterReady>()
|
||||
.with<InWater>()
|
||||
.with<CharacterBuoyancy>()
|
||||
.without<CharacterDisablePhysics>()
|
||||
.without<CharacterInActuator>()
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
const AnimationControl &anim,
|
||||
const CharacterBase &ch, CharacterVelocity &gr) {
|
||||
if (anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
"locomotion-state")
|
||||
->getCurrentState() == "swimming") {
|
||||
float h = Ogre::Math::Clamp(
|
||||
0.0f - ch.mBodyNode->getPosition().y,
|
||||
0.0f, 2000.0f);
|
||||
if (h > 0.05 && h < 2.0f)
|
||||
gr.gvelocity.y += 0.1f * (h + 1.0f) *
|
||||
h * eng.delta;
|
||||
}
|
||||
});
|
||||
#endif
|
||||
ecs.system<const EngineData, CharacterBase, AnimationControl,
|
||||
CharacterVelocity>("HandleRootMotion")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
CharacterBase &ch, AnimationControl &anim,
|
||||
CharacterVelocity &v) {
|
||||
ZoneScopedN("HandleRootMotion");
|
||||
if (!ch.mBodyNode)
|
||||
return;
|
||||
if (eng.delta < 0.0000001f)
|
||||
@@ -324,23 +260,32 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
.without<Player>()
|
||||
.each([](flecs::entity e, const Input &input,
|
||||
const CharacterBase &ch, AnimationControl &anim) {
|
||||
if (!anim.configured)
|
||||
ZoneScopedNC("HandleNPCAnimations", 0xFF2020);
|
||||
if (!anim.configured)
|
||||
return;
|
||||
if (!anim.mAnimationSystem)
|
||||
return;
|
||||
AnimationNodeStateMachine *state_machine =
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
"locomotion-state");
|
||||
AnimationSystem::AnimationNodeStateMachine
|
||||
*state_machine = anim.mAnimationSystem->get<
|
||||
AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
"locomotion-state");
|
||||
Ogre::String current_state =
|
||||
state_machine->getCurrentState();
|
||||
Ogre::String next_state = "idle";
|
||||
if (current_state != "treading_water" &&
|
||||
ch.is_submerged)
|
||||
e.has<InWater>())
|
||||
next_state = "treading_water";
|
||||
if (current_state != "idle" && !ch.is_submerged)
|
||||
if (current_state != "idle" && !e.has<InWater>())
|
||||
next_state = "idle";
|
||||
state_machine->setAnimation(next_state);
|
||||
{
|
||||
ZoneScoped;
|
||||
ZoneTextF("animation: next_state: %s %d %d",
|
||||
next_state.c_str(),
|
||||
(int)ch.is_submerged,
|
||||
(int)e.has<InWater>());
|
||||
}
|
||||
});
|
||||
ecs.system<const CharacterBase, const CharacterInActuator,
|
||||
AnimationControl>("HandlePlayerAnimationsActuator")
|
||||
@@ -349,15 +294,18 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
.each([](flecs::entity e, const CharacterBase &ch,
|
||||
const CharacterInActuator &inact,
|
||||
AnimationControl &anim) {
|
||||
if (!anim.configured)
|
||||
ZoneScopedN("HandlePlayerAnimationsActuator");
|
||||
if (!anim.configured)
|
||||
return;
|
||||
AnimationNodeStateMachine *main_sm =
|
||||
AnimationSystem::AnimationNodeStateMachine *main_sm =
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
->get<AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
"main");
|
||||
AnimationNodeStateMachine *actuator_sm =
|
||||
AnimationSystem::AnimationNodeStateMachine *actuator_sm =
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
->get<AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
"actuator-state");
|
||||
Ogre::String current_state = main_sm->getCurrentState();
|
||||
if (current_state != "actuator")
|
||||
@@ -372,13 +320,15 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
.without<CharacterControlDisable>()
|
||||
.each([](flecs::entity e, const CharacterBase &ch,
|
||||
AnimationControl &anim) {
|
||||
if (!anim.configured)
|
||||
ZoneScopedN("HandlePlayerAnimationsNoActuator");
|
||||
if (!anim.configured)
|
||||
return;
|
||||
if (!anim.mAnimationSystem)
|
||||
return;
|
||||
AnimationNodeStateMachine *main_sm =
|
||||
AnimationSystem::AnimationNodeStateMachine *main_sm =
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
->get<AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
"main");
|
||||
Ogre::String current_state = main_sm->getCurrentState();
|
||||
if (current_state != "locomotion")
|
||||
@@ -393,12 +343,14 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
.without<CharacterControlDisable>()
|
||||
.each([](flecs::entity e, const Input &input,
|
||||
const CharacterBase &ch, AnimationControl &anim) {
|
||||
if (!anim.configured)
|
||||
ZoneScopedN("HandlePlayerAnimations");
|
||||
if (!anim.configured)
|
||||
return;
|
||||
AnimationNodeStateMachine *state_machine =
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
"locomotion-state");
|
||||
AnimationSystem::AnimationNodeStateMachine
|
||||
*state_machine = anim.mAnimationSystem->get<
|
||||
AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
"locomotion-state");
|
||||
Ogre::String current_state =
|
||||
state_machine->getCurrentState();
|
||||
bool controls_idle = input.motion.zeroLength();
|
||||
@@ -474,6 +426,7 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
.each([](flecs::entity e, const Input &input,
|
||||
const CharacterBase &ch, AnimationControl &anim,
|
||||
CharacterInActuator &act) {
|
||||
ZoneScopedN("HandlePlayerAnimations2");
|
||||
bool controls_idle = input.motion.zeroLength();
|
||||
if (!controls_idle) {
|
||||
std::cout << "motion.z: "
|
||||
@@ -547,7 +500,8 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<Character>()
|
||||
.each([](flecs::entity e, EventData &evt) {
|
||||
for (auto ev : evt.events) {
|
||||
ZoneScopedN("HandleEvents");
|
||||
for (auto ev : evt.events) {
|
||||
std::cout << "character event: " << ev.event
|
||||
<< std::endl;
|
||||
/* parse character events */
|
||||
@@ -585,6 +539,7 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
int operator()(const std::vector<GameWorld::Parameter *> &args)
|
||||
override
|
||||
{
|
||||
ZoneScoped;
|
||||
GameWorld::ValueParameter<flecs::entity> *param_e =
|
||||
static_cast<GameWorld::ValueParameter<
|
||||
flecs::entity> *>(args[0]);
|
||||
@@ -600,10 +555,11 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
true) {
|
||||
const AnimationControl &control =
|
||||
param_e->get().get<AnimationControl>();
|
||||
AnimationNodeStateMachine *sm =
|
||||
control.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
param_node->get());
|
||||
AnimationSystem::AnimationNodeStateMachine *sm =
|
||||
control.mAnimationSystem->get<
|
||||
AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
param_node->get());
|
||||
bool reset = false;
|
||||
if (args.size() == 4) {
|
||||
GameWorld::ValueParameter<bool>
|
||||
@@ -622,6 +578,7 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
}
|
||||
};
|
||||
ECS::get_mut<GameWorld>().add_command<AnimationSetCommand>(
|
||||
"set_animation_state");
|
||||
"set_animation_state");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,11 +9,13 @@
|
||||
#include "PlayerActionModule.h"
|
||||
#include "items.h"
|
||||
#include "CharacterManagerModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
namespace ECS
|
||||
{
|
||||
void createNPCActionNodes(flecs::entity town, int index)
|
||||
{
|
||||
ZoneScoped;
|
||||
TownNPCs &npcs = town.get_mut<TownNPCs>();
|
||||
TownNPCs::NPCData &npc = npcs.npcs.at(index);
|
||||
flecs::entity e = npc.e;
|
||||
@@ -102,82 +104,71 @@ CharacterManagerModule::CharacterManagerModule(flecs::world &ecs)
|
||||
.write<LivesIn>()
|
||||
.each([this](flecs::entity town, TerrainItem &item,
|
||||
TownNPCs &npcs) {
|
||||
ZoneScopedN("UpdateCharacters");
|
||||
if (!player.is_valid())
|
||||
return;
|
||||
if (!player.has<CharacterBase>())
|
||||
return;
|
||||
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([this,
|
||||
town]() {
|
||||
flecs::entity player =
|
||||
ECS::get<CharacterManagerModule>()
|
||||
.getPlayer();
|
||||
if (!player.is_valid())
|
||||
return;
|
||||
if (!player.has<CharacterBase>())
|
||||
return;
|
||||
TownNPCs &npcs = town.get_mut<TownNPCs>();
|
||||
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;
|
||||
}
|
||||
flecs::entity player =
|
||||
ECS::get<CharacterManagerModule>().getPlayer();
|
||||
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()) {
|
||||
data.e = createCharacterData(
|
||||
data.model,
|
||||
data.position,
|
||||
data.orientation);
|
||||
data.e.add<LivesIn>(town);
|
||||
break;
|
||||
}
|
||||
}
|
||||
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,
|
||||
index);
|
||||
}
|
||||
if (cameraPos.squaredDistance(npcPosition) >
|
||||
22500.0f) {
|
||||
if (data.e.is_valid()) {
|
||||
data.e.destruct();
|
||||
data.e = flecs::entity();
|
||||
break;
|
||||
}
|
||||
}
|
||||
town.modified<TownNPCs>();
|
||||
});
|
||||
}
|
||||
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, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
town.modified<TownNPCs>();
|
||||
});
|
||||
}
|
||||
flecs::entity
|
||||
CharacterManagerModule::createPlayer(const Ogre::Vector3 &position,
|
||||
const Ogre::Quaternion &rotation)
|
||||
{
|
||||
ZoneScoped;
|
||||
static int count = 0;
|
||||
OgreAssert(count == 0, "overspawn");
|
||||
OgreAssert(!player.is_valid(), "Player already created");
|
||||
@@ -197,6 +188,7 @@ CharacterManagerModule::createCharacterData(const Ogre::String model,
|
||||
const Ogre::Vector3 &position,
|
||||
const Ogre::Quaternion &rotation)
|
||||
{
|
||||
ZoneScoped;
|
||||
flecs::entity e = ECS::get().entity();
|
||||
ECS::get_mut<CharacterModule>().createCharacter(e, position, rotation,
|
||||
model);
|
||||
@@ -206,6 +198,7 @@ CharacterManagerModule::createCharacterData(const Ogre::String model,
|
||||
|
||||
void CharacterManagerModule::registerTownCharacters(flecs::entity town)
|
||||
{
|
||||
ZoneScoped;
|
||||
Ogre::MeshManager::getSingleton().load("normal-male.glb", "General");
|
||||
Ogre::MeshManager::getSingleton().load("normal-female.glb", "General");
|
||||
Ogre::String props = StaticGeometryModule::getItemProperties(town);
|
||||
|
||||
@@ -9,16 +9,19 @@
|
||||
#include "CharacterAnimationModule.h"
|
||||
#include "CharacterManagerModule.h"
|
||||
#include "CharacterModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
{
|
||||
ZoneScoped;
|
||||
struct TriggerPhysicsChange {};
|
||||
ecs.module<CharacterModule>();
|
||||
ecs.component<Character>();
|
||||
ecs.component<Player>();
|
||||
ecs.component<CharacterBase>()
|
||||
.on_remove([this](flecs::entity e, CharacterBase &ch) {
|
||||
ZoneScoped;
|
||||
// FIXME: clean up data
|
||||
if (characterEntities.find(e) !=
|
||||
characterEntities.end() ||
|
||||
@@ -30,6 +33,7 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
})
|
||||
.on_add([this](flecs::entity e, CharacterBase &ch) {
|
||||
if (characterNodes.find(e) == characterNodes.end()) {
|
||||
ZoneScoped;
|
||||
OgreAssert(characterModels.find(e) !=
|
||||
characterModels.end(),
|
||||
"no model set");
|
||||
@@ -60,6 +64,7 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
ecs.component<CharacterGravity>();
|
||||
ecs.component<CharacterLocation>().on_set(
|
||||
[this](flecs::entity e, CharacterLocation &loc) {
|
||||
ZoneScoped;
|
||||
characterOrientations[e] = loc.orientation;
|
||||
characterPositions[e] = loc.position;
|
||||
ECS::modified<CharacterModule>();
|
||||
@@ -78,11 +83,13 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
ecs.system<EngineData, CharacterBase>("UpdateTimer")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](EngineData &eng, CharacterBase &ch) {
|
||||
ch.mTimer += eng.delta;
|
||||
ZoneScopedN("UpdateTimer");
|
||||
ch.mTimer += eng.delta;
|
||||
});
|
||||
ecs.system<Input, Camera>("HandleInput")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](Input &input, Camera &camera) {
|
||||
ZoneScopedN("HandleInput");
|
||||
flecs::entity player =
|
||||
ECS::get<CharacterManagerModule>().getPlayer();
|
||||
if (!player.is_valid())
|
||||
@@ -142,39 +149,24 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
else
|
||||
input.fast = false;
|
||||
input.control_prev = input.control;
|
||||
float a = 0, b = 0, c = 0;
|
||||
if (input.mouse_moved) {
|
||||
updateCameraGoal(camera, -0.18f * input.mouse.x,
|
||||
-0.12f * input.mouse.y, 0);
|
||||
a += -0.18f * input.mouse.x;
|
||||
b += -0.12f * input.mouse.y;
|
||||
input.mouse_moved = false;
|
||||
input.mouse.x = 0;
|
||||
input.mouse.y = 0;
|
||||
}
|
||||
updateCameraGoal(camera, a, b, c);
|
||||
}
|
||||
if (input.wheel_moved) {
|
||||
updateCameraGoal(camera, 0, 0,
|
||||
-0.15f * input.wheel_y);
|
||||
c += -0.15f * input.wheel_y;
|
||||
input.wheel_moved = false;
|
||||
input.wheel_y = 0;
|
||||
}
|
||||
updateCameraGoal(camera, a, b, c);
|
||||
}
|
||||
|
||||
ECS::get().modified<ECS::Input>();
|
||||
});
|
||||
ecs.system<CharacterBase>()
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<TerrainReady>()
|
||||
.with<WaterReady>()
|
||||
.with<InWater>()
|
||||
.each([this](flecs::entity e, CharacterBase &ch) {
|
||||
float full_subm = 2.0f;
|
||||
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
|
||||
float current_subm = -Ogre::Math::Clamp(
|
||||
pos.y + Ogre::Math::Sin(ch.mTimer * 0.13f +
|
||||
130.0f) *
|
||||
0.07f,
|
||||
-full_subm, 0.0f);
|
||||
if (current_subm > 0.9f)
|
||||
ch.is_submerged = true;
|
||||
else if (current_subm < 0.8f)
|
||||
ch.is_submerged = false;
|
||||
});
|
||||
#define TURN_SPEED 500.0f // character turning in degrees per second
|
||||
ecs.system<const Input, const Camera, CharacterBase>("UpdateBody")
|
||||
.kind(flecs::OnUpdate)
|
||||
@@ -184,7 +176,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
.without<CharacterControlDisable>()
|
||||
.each([](flecs::entity e, const Input &input,
|
||||
const Camera &camera, CharacterBase &ch) {
|
||||
ch.mGoalDirection = Ogre::Vector3::ZERO;
|
||||
ZoneScopedN("UpdateBody");
|
||||
ch.mGoalDirection = Ogre::Vector3::ZERO;
|
||||
float delta = e.world().delta_time();
|
||||
if (!input.motion.zeroLength()) {
|
||||
// calculate actually goal direction in world based on player's key directions
|
||||
@@ -253,85 +246,6 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
anim.configured = false;
|
||||
});
|
||||
|
||||
#if 0
|
||||
ecs.system<const EngineData, const CharacterLocation,
|
||||
const CharacterConf, Body2Entity>("SetupCharacter")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<Character>()
|
||||
.without<CharacterBase>()
|
||||
.without<CharacterBody>()
|
||||
.each([](flecs::entity e, const EngineData &eng,
|
||||
const CharacterLocation &loc,
|
||||
const CharacterConf &conf, Body2Entity &b2e) {
|
||||
CharacterBase &ch = e.ensure<CharacterBase>();
|
||||
CharacterBody &body = e.ensure<CharacterBody>();
|
||||
AnimationControl &anim = e.ensure<AnimationControl>();
|
||||
ch.mBodyEnt = eng.mScnMgr->createEntity(conf.type);
|
||||
ch.mBodyNode = eng.mScnMgr->getRootSceneNode()
|
||||
->createChildSceneNode();
|
||||
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");
|
||||
// body.mController = nullptr;
|
||||
ch.mBoneMotion = Ogre::Vector3::ZERO;
|
||||
ch.mBonePrevMotion = Ogre::Vector3::ZERO;
|
||||
e.set<CharacterVelocity>(
|
||||
{ { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } });
|
||||
body.checkGround = false;
|
||||
body.checkGroundResult = false;
|
||||
#if 0
|
||||
body.mCollisionShape = nullptr;
|
||||
body.mGhostObject = nullptr;
|
||||
body.mController = nullptr;
|
||||
body.mGhostObject = new btPairCachingGhostObject();
|
||||
b2e.entities[body.mGhostObject] = e;
|
||||
body.mCollisionShape = new btCompoundShape(false);
|
||||
body.mGhostObject->setCollisionShape(
|
||||
body.mCollisionShape);
|
||||
{
|
||||
btVector3 inertia(0, 0, 0);
|
||||
// mCollisionShape = new btCompoundShape();
|
||||
btScalar height = 1.0f;
|
||||
btScalar radius = 0.3f;
|
||||
btCapsuleShape *shape = new btCapsuleShape(
|
||||
radius, 2 * height - 2 * radius);
|
||||
btTransform transform;
|
||||
transform.setIdentity();
|
||||
transform.setOrigin(btVector3(0, 1, 0));
|
||||
static_cast<btCompoundShape *>(
|
||||
body.mCollisionShape)
|
||||
->addChildShape(transform, shape);
|
||||
btScalar masses[1] = { 0 };
|
||||
btTransform principal;
|
||||
static_cast<btCompoundShape *>(
|
||||
body.mCollisionShape)
|
||||
->calculatePrincipalAxisTransform(
|
||||
masses, principal, inertia);
|
||||
}
|
||||
body.mGhostObject->setCollisionFlags(body.mGhostObject->getCollisionFlags() | btCollisionObject::CF_CHARACTER_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT
|
||||
/*btCollisionObject::CF_KINEMATIC_OBJECT |
|
||||
btCollisionObject::CF_NO_CONTACT_RESPONSE */);
|
||||
body.mGhostObject->setActivationState(
|
||||
DISABLE_DEACTIVATION);
|
||||
eng.mWorld->attachCollisionObject(
|
||||
body.mGhostObject, ch.mBodyEnt, 1, 0x7FFFFFFF);
|
||||
OgreAssert(body.mGhostObject, "Need GhostObject");
|
||||
OgreAssert(body.mCollisionShape, "No collision shape");
|
||||
#endif
|
||||
e.add<CharacterGravity>();
|
||||
e.add<CharacterBuoyancy>();
|
||||
anim.configured = false;
|
||||
// OgreAssert(body.mGhostObject->hasContactResponse(),
|
||||
// "need contact response");
|
||||
});
|
||||
#endif
|
||||
#define CAM_HEIGHT 1.6f // height of camera above character's center of mass
|
||||
ecs.system<const EngineData, Camera, const CharacterBase>(
|
||||
"UpdateCamera")
|
||||
@@ -340,7 +254,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
.with<GroundCheckReady>()
|
||||
.each([](const EngineData &eng, Camera &camera,
|
||||
const CharacterBase &ch) {
|
||||
float delta = eng.delta;
|
||||
ZoneScopedN("UpdateCamera");
|
||||
float delta = eng.delta;
|
||||
if (!camera.configured) {
|
||||
// create a pivot at roughly the character's shoulder
|
||||
camera.mCameraPivot =
|
||||
@@ -411,6 +326,7 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
.with<Player>()
|
||||
.without<GroundCheckReady>()
|
||||
.each([](const EngineData &eng, CharacterBase &ch) {
|
||||
ZoneScopedN("CheckGround");
|
||||
#if 0
|
||||
if (body.mGhostObject) {
|
||||
btVector3 from =
|
||||
@@ -491,6 +407,7 @@ void CharacterModule::updateCameraGoal(Camera &camera, Ogre::Real deltaYaw,
|
||||
Ogre::Real deltaPitch,
|
||||
Ogre::Real deltaZoom)
|
||||
{
|
||||
ZoneScoped;
|
||||
static float canonDist = 0;
|
||||
camera.mCameraPivot->yaw(Ogre::Degree(deltaYaw), Ogre::Node::TS_PARENT);
|
||||
if (!(camera.mPivotPitch + deltaPitch > 25 && deltaPitch > 0) &&
|
||||
@@ -549,6 +466,7 @@ void applyWeightBasedScale(Ogre::Entity *ent,
|
||||
const Ogre::String &targetBoneName,
|
||||
const Ogre::Vector3 &scale)
|
||||
{
|
||||
ZoneScoped;
|
||||
Ogre::MeshPtr mesh = ent->getMesh();
|
||||
Ogre::SkeletonInstance *skel = ent->getSkeleton();
|
||||
Ogre::Bone *targetBone = skel->getBone(targetBoneName);
|
||||
@@ -636,6 +554,7 @@ void CharacterModule::createCharacter(flecs::entity e,
|
||||
const Ogre::Quaternion &rotation,
|
||||
const Ogre::String model)
|
||||
{
|
||||
ZoneScoped;
|
||||
if (e.has<CharacterBase>() || e.has<AnimationControl>())
|
||||
return;
|
||||
if (characterNodes.find(e) != characterNodes.end())
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "LuaData.h"
|
||||
#include "EventModule.h"
|
||||
#include "EventTriggerModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
struct TriggerBody {
|
||||
void *data;
|
||||
@@ -77,6 +78,7 @@ ECS::EventTriggerModule::EventTriggerModule(flecs::world &ecs)
|
||||
.event(flecs::OnSet)
|
||||
.each([](flecs::entity e, const EngineData &eng,
|
||||
const EventTrigger &trigger) {
|
||||
ZoneScoped;
|
||||
e.set<EventTriggerData>({});
|
||||
e.set<EventData>({});
|
||||
});
|
||||
@@ -84,13 +86,15 @@ ECS::EventTriggerModule::EventTriggerModule(flecs::world &ecs)
|
||||
.event(flecs::OnSet)
|
||||
.each([](flecs::entity e, const EventTrigger &trigger,
|
||||
EventData &evt) {
|
||||
evt.add(e, "actuator_created", e, e);
|
||||
ZoneScoped;
|
||||
evt.add(e, "actuator_created", e, e);
|
||||
});
|
||||
ecs.system<const EventTrigger, EventData>("HandleEventSystem")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([](flecs::entity e, const EventTrigger &trigger,
|
||||
EventData &evt) {
|
||||
if (e.parent().is_valid() &&
|
||||
ZoneScoped;
|
||||
if (e.parent().is_valid() &&
|
||||
e.parent().has<EventData>()) {
|
||||
bool added = false;
|
||||
for (auto ev : evt.events) {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "QuestModule.h"
|
||||
#include "GUIModule.h"
|
||||
#include "GUIModuleCommon.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
struct GUIListener;
|
||||
@@ -46,6 +47,7 @@ struct GUIListener : public Ogre::RenderTargetListener {
|
||||
GUIListener()
|
||||
: Ogre::RenderTargetListener()
|
||||
{
|
||||
ZoneScoped;
|
||||
_midFont = createFont("midFont", "General",
|
||||
"Jupiteroid-Regular.ttf", 24.0f);
|
||||
_smallFont = createFont("smallFont", "General",
|
||||
@@ -66,7 +68,8 @@ struct GUIListener : public Ogre::RenderTargetListener {
|
||||
const Ogre::String &group,
|
||||
const Ogre::String &ttfname, float fontSize)
|
||||
{
|
||||
Ogre::FontPtr ret =
|
||||
ZoneScoped;
|
||||
Ogre::FontPtr ret =
|
||||
Ogre::FontManager::getSingleton().create(name, group);
|
||||
ret->setType(Ogre::FontType::FT_TRUETYPE);
|
||||
ret->setSource(ttfname);
|
||||
@@ -79,10 +82,12 @@ struct GUIListener : public Ogre::RenderTargetListener {
|
||||
void
|
||||
preViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override
|
||||
{
|
||||
preview(evt);
|
||||
ZoneScopedN("GUIModule::preViewportUpdate");
|
||||
preview(evt);
|
||||
}
|
||||
void buttons_panel()
|
||||
{
|
||||
ZoneScoped;
|
||||
bool enableDebugRender = ECS::get<EngineData>().enableDbgDraw;
|
||||
ImVec2 size = ImGui::GetMainViewport()->Size;
|
||||
float window_width = size.x * 0.2f;
|
||||
@@ -120,7 +125,8 @@ struct GUIListener : public Ogre::RenderTargetListener {
|
||||
}
|
||||
void create_entity_node(const Ogre::String &name, int key)
|
||||
{
|
||||
Ogre::Entity *ent =
|
||||
ZoneScoped;
|
||||
Ogre::Entity *ent =
|
||||
ECS::get().get<EngineData>().mScnMgr->createEntity(
|
||||
name);
|
||||
Ogre::SceneNode *pnode =
|
||||
@@ -147,7 +153,8 @@ struct GUIListener : public Ogre::RenderTargetListener {
|
||||
}
|
||||
void buildings_editor()
|
||||
{
|
||||
int i;
|
||||
ZoneScoped;
|
||||
int i;
|
||||
ImVec2 size = ImGui::GetMainViewport()->Size;
|
||||
float window_width = size.x * 0.2f;
|
||||
if (window_width > panel_width)
|
||||
@@ -174,7 +181,8 @@ struct GUIListener : public Ogre::RenderTargetListener {
|
||||
}
|
||||
void position_editor(Ogre::SceneNode *node)
|
||||
{
|
||||
Ogre::Vector3 position = node->getPosition();
|
||||
ZoneScoped;
|
||||
Ogre::Vector3 position = node->getPosition();
|
||||
float v[3] = { position.x, position.y, position.z };
|
||||
ImGui::InputFloat3("position", v);
|
||||
position.x = v[0];
|
||||
@@ -184,7 +192,8 @@ struct GUIListener : public Ogre::RenderTargetListener {
|
||||
}
|
||||
void orientation_editor(Ogre::SceneNode *node)
|
||||
{
|
||||
Ogre::Quaternion q = node->getOrientation();
|
||||
ZoneScoped;
|
||||
Ogre::Quaternion q = node->getOrientation();
|
||||
float yaw = Ogre::Radian(q.getYaw()).valueDegrees();
|
||||
float pitch = Ogre::Radian(q.getPitch()).valueDegrees();
|
||||
float roll = Ogre::Radian(q.getRoll()).valueDegrees();
|
||||
@@ -203,7 +212,8 @@ struct GUIListener : public Ogre::RenderTargetListener {
|
||||
}
|
||||
void attachments_editor(Ogre::SceneNode *node)
|
||||
{
|
||||
const Ogre::SceneNode::ObjectMap &pmap =
|
||||
ZoneScoped;
|
||||
const Ogre::SceneNode::ObjectMap &pmap =
|
||||
node->getAttachedObjects();
|
||||
int i;
|
||||
for (i = 0; i < pmap.size(); i++) {
|
||||
@@ -217,6 +227,7 @@ struct GUIListener : public Ogre::RenderTargetListener {
|
||||
}
|
||||
Ogre::Vector2 projectToScreen(const Ogre::Vector3 &worldPoint)
|
||||
{
|
||||
ZoneScoped;
|
||||
ImVec2 size = ImGui::GetMainViewport()->Size;
|
||||
float width = size.x;
|
||||
float height = size.y;
|
||||
@@ -241,7 +252,8 @@ struct GUIListener : public Ogre::RenderTargetListener {
|
||||
}
|
||||
void preview(const Ogre::RenderTargetViewportEvent &evt)
|
||||
{
|
||||
int i;
|
||||
ZoneScoped;
|
||||
int i;
|
||||
Ogre::ImGuiOverlay::NewFrame();
|
||||
|
||||
if (ECS::get().get<EngineData>().startupDelay > 0.0f &&
|
||||
@@ -742,6 +754,7 @@ GUIModule::GUIModule(flecs::world &ecs)
|
||||
|
||||
void GUIModule::configure()
|
||||
{
|
||||
ZoneScoped;
|
||||
ECS::get().set<GUIData>({ nullptr, {}, nullptr });
|
||||
const RenderWindow &window = ECS::get<RenderWindow>();
|
||||
GUIData &gui = ECS::get_mut<GUIData>();
|
||||
|
||||
@@ -28,12 +28,14 @@
|
||||
#include "QuestModule.h"
|
||||
#include "world-build.h"
|
||||
#include "physics.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
namespace ECS
|
||||
{
|
||||
static flecs::world ecs;
|
||||
void setup_minimal()
|
||||
{
|
||||
ZoneScoped;
|
||||
ecs.component<EngineData>().add(flecs::Singleton);
|
||||
ecs.component<GameData>().add(flecs::Singleton);
|
||||
ecs.component<Input>().add(flecs::Singleton);
|
||||
@@ -50,6 +52,7 @@ void setup_minimal()
|
||||
void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window)
|
||||
{
|
||||
ZoneScoped;
|
||||
std::cout << "Setup GameData\n";
|
||||
setup_minimal();
|
||||
|
||||
@@ -92,19 +95,19 @@ void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
std::cout << "ground check ready\n";
|
||||
#endif
|
||||
});
|
||||
ecs.system<EngineData>("CheckStatus")
|
||||
#ifdef VDEBUG
|
||||
ecs.system<EngineData>("CheckStatus")
|
||||
.kind(flecs::OnUpdate)
|
||||
.run([](flecs::iter &it) {
|
||||
#ifdef VDEBUG
|
||||
if (ECS::get().has<WaterReady>())
|
||||
std::cout << "water ready\n";
|
||||
if (ECS::get().has<TerrainReady>())
|
||||
std::cout << "terrain ready\n";
|
||||
if (ECS::get().has<GroundCheckReady>())
|
||||
std::cout << "ground check ready\n";
|
||||
#endif
|
||||
});
|
||||
ecs.set<EngineData>({ scnMgr, 0.0f, 5.0f, (int)window->getWidth(),
|
||||
#endif
|
||||
ecs.set<EngineData>({ scnMgr, 0.0f, 5.0f, (int)window->getWidth(),
|
||||
(int)window->getHeight(), false });
|
||||
ecs.set<Camera>({ cameraNode, camera, false });
|
||||
ecs.add<GameData>();
|
||||
@@ -112,6 +115,7 @@ void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
ecs.observer<GameState>("Game_Start_Scen_Startup")
|
||||
.event(flecs::OnAdd)
|
||||
.each([](GameState &game) {
|
||||
ZoneScopedN("Game_Start_Scen_Startup");
|
||||
ECS::get().add<WaterSurface>();
|
||||
ECS::get().set<Sun>(
|
||||
{ nullptr, nullptr, nullptr, nullptr });
|
||||
@@ -136,6 +140,7 @@ void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
.kind(flecs::OnUpdate)
|
||||
.interval(0.5f)
|
||||
.each([&](Terrain &mterrain, GameState &game) {
|
||||
ZoneScopedN("SpawnPlayer");
|
||||
flecs::entity player =
|
||||
ECS::get<CharacterManagerModule>().getPlayer();
|
||||
if (!player.is_valid()) {
|
||||
@@ -182,6 +187,7 @@ void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
.kind(flecs::OnUpdate)
|
||||
.interval(0.5f)
|
||||
.each([&](GameState &game) {
|
||||
ZoneScopedN("NewHame");
|
||||
flecs::entity player =
|
||||
ECS::get<CharacterManagerModule>()
|
||||
.getPlayer();
|
||||
@@ -210,6 +216,7 @@ void setupInventoryScene(Ogre::SceneManager *scnMgr,
|
||||
void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window)
|
||||
{
|
||||
ZoneScoped;
|
||||
setup_minimal();
|
||||
ecs.component<RenderWindow>().add(flecs::Singleton);
|
||||
ecs.component<EditorSceneSwitch>().add(flecs::Singleton);
|
||||
@@ -245,19 +252,19 @@ void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
std::cout << "ground check ready\n";
|
||||
#endif
|
||||
});
|
||||
ecs.system<EngineData>("CheckStatus")
|
||||
#ifdef VDEBUG
|
||||
ecs.system<EngineData>("CheckStatus")
|
||||
.kind(flecs::OnUpdate)
|
||||
.run([](flecs::iter &it) {
|
||||
#ifdef VDEBUG
|
||||
if (ECS::get().has<WaterReady>())
|
||||
std::cout << "water ready\n";
|
||||
if (ECS::get().has<TerrainReady>())
|
||||
std::cout << "terrain ready\n";
|
||||
if (ECS::get().has<GroundCheckReady>())
|
||||
std::cout << "ground check ready\n";
|
||||
#endif
|
||||
});
|
||||
ecs.set<EngineData>({ scnMgr, 0.0f, 5.0f, (int)window->getWidth(),
|
||||
#endif
|
||||
ecs.set<EngineData>({ scnMgr, 0.0f, 5.0f, (int)window->getWidth(),
|
||||
(int)window->getHeight(), false });
|
||||
ecs.set<Camera>({ cameraNode, camera, false });
|
||||
#if 0
|
||||
@@ -286,7 +293,10 @@ void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
|
||||
void update(float delta)
|
||||
{
|
||||
ecs.progress(delta);
|
||||
{
|
||||
ZoneScopedN("ECS");
|
||||
ecs.progress(delta);
|
||||
}
|
||||
}
|
||||
flecs::world get()
|
||||
{
|
||||
|
||||
13
src/gamedata/LuaModule/CMakeLists.txt
Normal file
13
src/gamedata/LuaModule/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
project(LuaModule)
|
||||
find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain Overlay CONFIG)
|
||||
find_package(flecs REQUIRED CONFIG)
|
||||
find_package(Tracy REQUIRED CONFIG)
|
||||
|
||||
add_library(luamodule STATIC LuaData.cpp)
|
||||
target_include_directories(luamodule PUBLIC .)
|
||||
target_link_libraries(luamodule PUBLIC
|
||||
lua
|
||||
OgreMain
|
||||
flecs::flecs_static
|
||||
PRIVATE GameData Tracy::TracyClient
|
||||
)
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "lua.hpp"
|
||||
#include <OgreFileSystemLayer.h>
|
||||
#include "GameData.h"
|
||||
#include "Components.h"
|
||||
@@ -10,11 +11,10 @@
|
||||
#include "BoatModule.h"
|
||||
#include "EventTriggerModule.h"
|
||||
#include "SlotsModule.h"
|
||||
#include "world-build.h"
|
||||
#include "PlayerActionModule.h"
|
||||
#include "QuestModule.h"
|
||||
#include "LuaData.h"
|
||||
#include "lua.hpp"
|
||||
#include <tracy/Tracy.hpp>
|
||||
extern "C" {
|
||||
int luaopen_lpeg(lua_State *L);
|
||||
}
|
||||
@@ -25,51 +25,6 @@ struct FooPosition {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
#if 0
|
||||
namespace luaaa
|
||||
{
|
||||
template <> struct LuaStack<FooPosition> {
|
||||
inline static FooPosition get(lua_State *L, int idx)
|
||||
{
|
||||
FooPosition result;
|
||||
if (lua_istable(L, idx)) {
|
||||
lua_pushnil(L);
|
||||
while (0 != lua_next(L, idx)) {
|
||||
const int top = lua_gettop(L);
|
||||
const char *name =
|
||||
LuaStack<const char *>::get(L, top - 1);
|
||||
if (strncmp(name, "x", 1) == 0)
|
||||
result.value.x =
|
||||
LuaStack<float>::get(L, top);
|
||||
else if (strncmp(name, "y", 1) == 0)
|
||||
result.value.y =
|
||||
LuaStack<float>::get(L, top);
|
||||
else if (strncmp(name, "z", 1) == 0)
|
||||
result.value.z =
|
||||
LuaStack<float>::get(L, top);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
inline static void put(lua_State *L, const FooPosition &v)
|
||||
{
|
||||
lua_newtable(L);
|
||||
LuaStack<const char *>::put(L, "x");
|
||||
LuaStack<float>::put(L, v.value.x);
|
||||
lua_rawset(L, -3);
|
||||
LuaStack<const char *>::put(L, "y");
|
||||
LuaStack<float>::put(L, v.value.y);
|
||||
lua_rawset(L, -3);
|
||||
LuaStack<const char *>::put(L, "z");
|
||||
LuaStack<float>::put(L, v.value.z);
|
||||
lua_rawset(L, -3);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
namespace ECS
|
||||
{
|
||||
struct LuaEcsEntity {
|
||||
@@ -635,6 +590,7 @@ LuaData::LuaData()
|
||||
flecs::entity object_e = idmap.get_entity(object);
|
||||
Ogre::String nodeName = lua_tostring(L, 3);
|
||||
Ogre::String stateName = lua_tostring(L, 4);
|
||||
#if 0
|
||||
bool reset = false;
|
||||
if (lua_gettop(L) == 5)
|
||||
reset = lua_toboolean(L, 5);
|
||||
@@ -654,6 +610,8 @@ LuaData::LuaData()
|
||||
{ obj, obj_node,
|
||||
obj_state });
|
||||
ECS::modified<GameWorld>();
|
||||
#endif
|
||||
OgreAssert(false, "Not implemented");
|
||||
|
||||
return 0;
|
||||
} else if (command == "params-set") {
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "EventModule.h"
|
||||
#include "TerrainModule.h"
|
||||
#include "PhysicsModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
struct PhysicsShape {
|
||||
@@ -34,6 +35,7 @@ struct TriggerBody {
|
||||
};
|
||||
PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
{
|
||||
ZoneScoped;
|
||||
ecs.module<PhysicsModule>();
|
||||
ecs.import <EventModule>();
|
||||
ecs.import <EventTriggerModule>();
|
||||
@@ -54,8 +56,18 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
ecs.component<PhysicsMeshPtr>();
|
||||
ecs.component<PhysicsHeightfieldData>();
|
||||
|
||||
ecs.component<CharacterBody>();
|
||||
ecs.component<TriggerBody>();
|
||||
ecs.component<CharacterBody>().on_remove([](flecs::entity e,
|
||||
CharacterBody &body) {
|
||||
JPH::Character *ch =
|
||||
static_cast<JPH::Character *>(body.ch.get());
|
||||
if (ch) {
|
||||
if (e.has<JPH::BodyID>())
|
||||
e.remove<JPH::BodyID>();
|
||||
JoltPhysicsWrapper::getSingleton().destroyCharacter(ch);
|
||||
body.ch = nullptr;
|
||||
}
|
||||
});
|
||||
ecs.component<TriggerBody>();
|
||||
ecs.component<CharacterVelocity>();
|
||||
ecs.component<WaterBody>().add(flecs::Singleton);
|
||||
ecs.component<CachedMass>();
|
||||
@@ -64,6 +76,7 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
ecs.system<EngineData, Physics>("physics_update")
|
||||
.kind(PhysicsUpdate)
|
||||
.each([&](EngineData &e, Physics &ph) {
|
||||
ZoneScopedN("physics_update");
|
||||
ph.physics->update(e.delta);
|
||||
});
|
||||
ecs.observer<const EngineData, PhysicsMeshName>(
|
||||
@@ -74,6 +87,7 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.write<PhysicsShape>()
|
||||
.each([&](flecs::entity e, const EngineData &eng,
|
||||
PhysicsMeshName &name) {
|
||||
ZoneScopedN("create_shape_mesh_name");
|
||||
Ogre::DefaultHardwareBufferManagerBase dmgr;
|
||||
Ogre::MeshPtr mesh =
|
||||
Ogre::MeshManager::getSingleton().getByName(
|
||||
@@ -94,7 +108,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.write<PhysicsShape>()
|
||||
.each([&](flecs::entity e, const EngineData &eng,
|
||||
PhysicsMeshPtr &meshPtr) {
|
||||
Ogre::DefaultHardwareBufferManager dmgr;
|
||||
ZoneScopedN("create_shape_mesh_ptr");
|
||||
Ogre::DefaultHardwareBufferManager dmgr;
|
||||
Ogre::MeshPtr mesh = meshPtr.mesh;
|
||||
if (!mesh->isLoaded()) {
|
||||
mesh->setHardwareBufferManager(&dmgr);
|
||||
@@ -115,7 +130,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.write<PhysicsShape>()
|
||||
.each([&](flecs::entity e, const EngineData &eng,
|
||||
PhysicsHeightfieldData &hfd) {
|
||||
JPH::ShapeRefC shape =
|
||||
ZoneScopedN("create_shape_heightfield");
|
||||
JPH::ShapeRefC shape =
|
||||
JoltPhysicsWrapper::getSingleton()
|
||||
.createHeightfieldShape(
|
||||
hfd.samples, hfd.offset,
|
||||
@@ -136,7 +152,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.each([&](flecs::entity e, const EngineData &eng,
|
||||
const PhysicsShape &shape, const PhysicsNode &node,
|
||||
const PhysicsBody &body) {
|
||||
JPH::BodyID id =
|
||||
ZoneScopedN("create_body_from_shape");
|
||||
JPH::BodyID id =
|
||||
JoltPhysicsWrapper::getSingleton().createBody(
|
||||
shape.shape.GetPtr(), 0.0f, node.node,
|
||||
(JPH::EMotionType)body.motion,
|
||||
@@ -149,9 +166,13 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
ecs.observer<const JPH::BodyID>("remove_body")
|
||||
.event(flecs::OnRemove)
|
||||
.each([&](flecs::entity e, const JPH::BodyID &id) {
|
||||
JoltPhysicsWrapper::getSingleton().removeBody(id);
|
||||
ZoneScopedN("remove_body");
|
||||
JoltPhysicsWrapper::getSingleton().removeBody(id);
|
||||
if (e.has<CharacterBase>() || e.has<Character>())
|
||||
return;
|
||||
if (JoltPhysicsWrapper::getSingleton().bodyIsCharacter(
|
||||
id))
|
||||
return;
|
||||
JoltPhysicsWrapper::getSingleton().destroyBody(id);
|
||||
std::cout << "body destroyed" << std::endl;
|
||||
});
|
||||
@@ -164,7 +185,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.write<JPH::BodyID>()
|
||||
.each([](flecs::entity e, const EngineData &eng,
|
||||
const CharacterBase &base) {
|
||||
CharacterBody &b = e.ensure<CharacterBody>();
|
||||
ZoneScopedN("SetupCharacterPh");
|
||||
CharacterBody &b = e.ensure<CharacterBody>();
|
||||
b.ch.reset(JoltPhysicsWrapper::getSingleton()
|
||||
.createCharacter(base.mBodyNode,
|
||||
1.75f, 0.23f));
|
||||
@@ -183,7 +205,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.without<JPH::BodyID>()
|
||||
.each([](flecs::entity e, const EngineData &eng,
|
||||
const EventTrigger &trigger) {
|
||||
JPH::ShapeRefC shape =
|
||||
ZoneScopedN("CreateTriggerPhysics");
|
||||
JPH::ShapeRefC shape =
|
||||
JoltPhysicsWrapper::getSingleton()
|
||||
.createCylinderShape(trigger.halfheight,
|
||||
trigger.radius);
|
||||
@@ -267,20 +290,23 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
ECS::modified<LuaEvent>();
|
||||
});
|
||||
});
|
||||
// FIXME: convert to normal configure to prevent multiple instances
|
||||
ecs.system<const EngineData>("init_water")
|
||||
.kind(PhysicsPreUpdate)
|
||||
.with<TerrainReady>()
|
||||
.with<WaterAlmostReady>()
|
||||
.without<WaterBody>()
|
||||
.each([this](const EngineData &eng) {
|
||||
ECS::get().set<WaterBody>({});
|
||||
ZoneScopedN("init_water");
|
||||
ECS::get().set<WaterBody>({});
|
||||
});
|
||||
ecs.system<const EngineData, WaterBody>("update_water")
|
||||
.kind(PhysicsPostUpdate)
|
||||
.with<TerrainReady>()
|
||||
.with<WaterAlmostReady>()
|
||||
.each([this](const EngineData &eng, WaterBody &body) {
|
||||
const WaterSurface &water = ECS::get<WaterSurface>();
|
||||
ZoneScopedN("update_water");
|
||||
const WaterSurface &water = ECS::get<WaterSurface>();
|
||||
body.inWater.clear();
|
||||
JoltPhysicsWrapper::getSingleton().broadphaseQuery(
|
||||
eng.delta,
|
||||
@@ -295,8 +321,11 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.with<InWater>()
|
||||
.each([this](flecs::entity e, const JPH::BodyID &id,
|
||||
const WaterBody &body) {
|
||||
if (!body.isInWater(id))
|
||||
ZoneScopedN("update_water_status1");
|
||||
if (!body.isInWater(id)) {
|
||||
e.remove<InWater>();
|
||||
ZoneTextF("in water");
|
||||
}
|
||||
});
|
||||
ecs.system<const JPH::BodyID, const WaterBody>("update_water_status2")
|
||||
.kind(PhysicsPostUpdate)
|
||||
@@ -305,8 +334,11 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.without<InWater>()
|
||||
.each([this](flecs::entity e, const JPH::BodyID &id,
|
||||
const WaterBody &body) {
|
||||
if (body.isInWater(id))
|
||||
ZoneScopedN("update_water_status2");
|
||||
if (body.isInWater(id)) {
|
||||
e.add<InWater>();
|
||||
ZoneTextF("not in water");
|
||||
}
|
||||
});
|
||||
ecs.system<const CharacterBody, const WaterBody>(
|
||||
"update_water_character1")
|
||||
@@ -316,10 +348,13 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.with<InWater>()
|
||||
.each([this](flecs::entity e, const CharacterBody &ch,
|
||||
const WaterBody &body) {
|
||||
JPH::Character *chptr =
|
||||
ZoneScopedN("update_water_character1");
|
||||
JPH::Character *chptr =
|
||||
static_cast<JPH::Character *>(ch.ch.get());
|
||||
if (!body.isInWater(chptr->GetBodyID()))
|
||||
if (!body.isInWater(chptr->GetBodyID())) {
|
||||
e.remove<InWater>();
|
||||
ZoneTextF("not in water");
|
||||
}
|
||||
});
|
||||
ecs.system<const CharacterBody, const WaterBody>(
|
||||
"update_water_character2")
|
||||
@@ -329,10 +364,13 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.without<InWater>()
|
||||
.each([this](flecs::entity e, const CharacterBody &ch,
|
||||
const WaterBody &body) {
|
||||
JPH::Character *chptr =
|
||||
ZoneScopedN("update_water_character2");
|
||||
JPH::Character *chptr =
|
||||
static_cast<JPH::Character *>(ch.ch.get());
|
||||
if (body.isInWater(chptr->GetBodyID()))
|
||||
if (body.isInWater(chptr->GetBodyID())) {
|
||||
e.add<InWater>();
|
||||
ZoneTextF("in water");
|
||||
}
|
||||
});
|
||||
ecs.system<const EngineData, const BoatBase, const WaterBody,
|
||||
const JPH::BodyID>("update_water_boat_enable")
|
||||
@@ -342,7 +380,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
const BoatBase &boat, const WaterBody &body,
|
||||
const JPH::BodyID &id) {
|
||||
if (!JoltPhysicsWrapper::getSingleton().isAdded(id))
|
||||
ZoneScopedN("update_water_boat_enable");
|
||||
if (!JoltPhysicsWrapper::getSingleton().isAdded(id))
|
||||
JoltPhysicsWrapper::getSingleton().addBody(
|
||||
id, JPH::EActivation::Activate);
|
||||
});
|
||||
@@ -355,7 +394,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
const BoatBase &boat, const WaterBody &body,
|
||||
const JPH::BodyID &id) {
|
||||
if (!JoltPhysicsWrapper::getSingleton().isActive(id))
|
||||
ZoneScopedN("update_water_boat_activation");
|
||||
if (!JoltPhysicsWrapper::getSingleton().isActive(id))
|
||||
JoltPhysicsWrapper::getSingleton().activate(id);
|
||||
});
|
||||
ecs.system<const EngineData, const BoatBase, const WaterBody,
|
||||
@@ -368,7 +408,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
const BoatBase &boat, const WaterBody &body,
|
||||
const JPH::BodyID &id, const CachedMass &mass) {
|
||||
const WaterSurface &water = ECS::get<WaterSurface>();
|
||||
ZoneScopedN("update_water_boat_buoyancy");
|
||||
const WaterSurface &water = ECS::get<WaterSurface>();
|
||||
float b = 1.0f, drag = 0.5f, adrag = 0.5f;
|
||||
float level = 0.25f;
|
||||
float my = JoltPhysicsWrapper::getSingleton()
|
||||
@@ -425,7 +466,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.with<CharacterBuoyancy>()
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
const CharacterBody &ch, const WaterBody &body) {
|
||||
JPH::Character *chptr =
|
||||
ZoneScopedN("update_water_character_buoyancy");
|
||||
JPH::Character *chptr =
|
||||
static_cast<JPH::Character *>(ch.ch.get());
|
||||
JPH::BodyID id = chptr->GetBodyID();
|
||||
if (JoltPhysicsWrapper::getSingleton().isActive(id)) {
|
||||
@@ -467,13 +509,15 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
eng.delta);
|
||||
}
|
||||
});
|
||||
ecs.system<const EngineData, const CharacterBody>("UpdatePhysics")
|
||||
ecs.system<const EngineData, const CharacterBody>(
|
||||
"UpdateCharacterPhysicsState")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<CharacterUpdatePhysicsState>()
|
||||
.write<CharacterUpdatePhysicsState>()
|
||||
.each([](flecs::entity e, const EngineData &eng,
|
||||
const CharacterBody &body) {
|
||||
if (e.has<CharacterDisablePhysics>())
|
||||
ZoneScopedN("UpdateCharacterPhysicsState");
|
||||
if (e.has<CharacterDisablePhysics>())
|
||||
PhysicsModule::controlPhysics(e, false);
|
||||
else
|
||||
PhysicsModule::controlPhysics(e, true);
|
||||
@@ -489,7 +533,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
const CharacterBase &chbase,
|
||||
const CharacterBody &body, CharacterVelocity &gr) {
|
||||
if (e.has<InWater>() &&
|
||||
ZoneScopedN("HandleVelocity");
|
||||
if (e.has<InWater>() &&
|
||||
chbase.mBodyNode->_getDerivedPosition().y > -0.5f)
|
||||
e.remove<InWater>();
|
||||
Ogre::Vector3 v = gr.velocity;
|
||||
@@ -519,7 +564,27 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
JoltPhysics::convert<JPH::Vec3>(v));
|
||||
gr.velocity = Ogre::Vector3::ZERO;
|
||||
});
|
||||
ecs.system<const EngineData, CharacterBase, const CharacterBody,
|
||||
ecs.system<CharacterBase>("HandleSubmerge")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<TerrainReady>()
|
||||
.with<WaterReady>()
|
||||
.with<InWater>()
|
||||
.each([this](flecs::entity e, CharacterBase &ch) {
|
||||
ZoneScopedNC("HandleSubmerge", 0xFF3030);
|
||||
float full_subm = 2.0f;
|
||||
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
|
||||
float current_subm = -Ogre::Math::Clamp(
|
||||
pos.y + Ogre::Math::Sin(ch.mTimer * 0.13f +
|
||||
130.0f) *
|
||||
0.07f,
|
||||
-full_subm, 0.0f);
|
||||
if (current_subm > 0.9f)
|
||||
ch.is_submerged = true;
|
||||
else if (current_subm < 0.8f)
|
||||
ch.is_submerged = false;
|
||||
ZoneTextF("is submerged: %d", (int)ch.is_submerged);
|
||||
});
|
||||
ecs.system<const EngineData, CharacterBase, const CharacterBody,
|
||||
CharacterVelocity>("HandleVelocityNoPhysics")
|
||||
.kind(PhysicsPostUpdate)
|
||||
.with<TerrainReady>()
|
||||
@@ -529,7 +594,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
CharacterBase &ch, const CharacterBody &body,
|
||||
CharacterVelocity &gr) {
|
||||
Ogre::Vector3 v = gr.velocity;
|
||||
ZoneScopedNC("HandleVelocityNoPhysics", 0xFF4040);
|
||||
Ogre::Vector3 v = gr.velocity;
|
||||
// v.y = 0.0f;
|
||||
ch.mBodyNode->_setDerivedPosition(
|
||||
ch.mBodyNode->_getDerivedPosition() +
|
||||
@@ -548,9 +614,12 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
ch.mBodyNode->_getDerivedPosition().y > -0.5f) {
|
||||
e.remove<InWater>();
|
||||
ch.is_submerged = false;
|
||||
}
|
||||
if (!e.has<InWater>() && ch.is_submerged)
|
||||
ZoneTextF("remove in water");
|
||||
}
|
||||
if (!e.has<InWater>() && ch.is_submerged) {
|
||||
ch.is_submerged = false;
|
||||
ZoneTextF("not submerged");
|
||||
}
|
||||
});
|
||||
}
|
||||
flecs::entity PhysicsModule::createTerrainChunkBody(Ogre::SceneNode *node,
|
||||
@@ -559,6 +628,7 @@ flecs::entity PhysicsModule::createTerrainChunkBody(Ogre::SceneNode *node,
|
||||
const Ogre::Vector3 &scale,
|
||||
int sampleCount)
|
||||
{
|
||||
ZoneScoped;
|
||||
flecs::entity e = ECS::get().entity();
|
||||
e.set<PhysicsHeightfieldData>({ samples, offset, scale, sampleCount });
|
||||
e.set<PhysicsBody>({ (uint32_t)JPH::EMotionType::Static,
|
||||
@@ -569,6 +639,7 @@ flecs::entity PhysicsModule::createTerrainChunkBody(Ogre::SceneNode *node,
|
||||
}
|
||||
void PhysicsModule::controlPhysics(flecs::entity e, bool enable)
|
||||
{
|
||||
ZoneScoped;
|
||||
if (enable) {
|
||||
if (e.has<CharacterBase>()) {
|
||||
e.remove<CharacterDisablePhysics>();
|
||||
@@ -616,6 +687,7 @@ bool PhysicsModule::raycastQuery(const Ogre::Vector3 &startPos,
|
||||
const Ogre::Vector3 &endPos,
|
||||
Ogre::Vector3 &position, JPH::BodyID &id)
|
||||
{
|
||||
ZoneScoped;
|
||||
return JoltPhysicsWrapper::getSingleton().raycastQuery(startPos, endPos,
|
||||
position, id);
|
||||
}
|
||||
@@ -627,6 +699,7 @@ void PhysicsModule::setDebugDraw(bool enable)
|
||||
|
||||
bool WaterBody::isInWater(const JPH::BodyID &id) const
|
||||
{
|
||||
ZoneScoped;
|
||||
#if 0
|
||||
flecs::entity e =
|
||||
ECS::get().query_builder<const JPH::BodyID>().build().find(
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "LuaData.h"
|
||||
#include "PhysicsModule.h"
|
||||
#include "PlayerActionModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
namespace ECS
|
||||
{
|
||||
@@ -70,16 +71,19 @@ struct TestNarrativeHandler : GUI::NarrationHandler {
|
||||
}
|
||||
void finish() override
|
||||
{
|
||||
ZoneScoped;
|
||||
_clear_narration();
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
ZoneScoped;
|
||||
_narration("Greetings...", {});
|
||||
std::cout << getPropsJSON().dump(4) << std::endl;
|
||||
count = 0;
|
||||
}
|
||||
void event(const Ogre::String &evt) override
|
||||
{
|
||||
ZoneScoped;
|
||||
if (evt == "narration_progress" ||
|
||||
evt == "narration_answered") {
|
||||
count++;
|
||||
@@ -111,6 +115,7 @@ struct LuaNarrationHandler : GUI::NarrationHandler {
|
||||
: ref(ref)
|
||||
, L(L)
|
||||
{
|
||||
ZoneScoped;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
lua_pushlightuserdata(L, this);
|
||||
lua_pushcclosure(
|
||||
@@ -214,6 +219,7 @@ struct LuaNarrationHandler : GUI::NarrationHandler {
|
||||
}
|
||||
void finish() override
|
||||
{
|
||||
ZoneScoped;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
int type = lua_getfield(L, -1, "finish");
|
||||
OgreAssert(type == LUA_TFUNCTION, "bad finish()");
|
||||
@@ -227,6 +233,7 @@ struct LuaNarrationHandler : GUI::NarrationHandler {
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
ZoneScoped;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
int type = lua_getfield(L, -1, "activate");
|
||||
OgreAssert(type == LUA_TFUNCTION, "bad activate()");
|
||||
@@ -239,6 +246,7 @@ struct LuaNarrationHandler : GUI::NarrationHandler {
|
||||
}
|
||||
void event(const Ogre::String &evt) override
|
||||
{
|
||||
ZoneScoped;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
int type = lua_getfield(L, -1, "event");
|
||||
OgreAssert(type == LUA_TFUNCTION, "bad event()");
|
||||
@@ -256,6 +264,7 @@ struct SimpleWordHandler : PlayerActionModule::ActionWordHandler {
|
||||
void operator()(int actor, flecs::entity town, int index,
|
||||
const Ogre::String &word, int actionNode) override
|
||||
{
|
||||
ZoneScoped;
|
||||
if (index >= 0) {
|
||||
TestNarrativeHandler *handle =
|
||||
OGRE_NEW TestNarrativeHandler();
|
||||
@@ -280,10 +289,12 @@ struct SimpleWordHandler : PlayerActionModule::ActionWordHandler {
|
||||
|
||||
PlayerActionModule::PlayerActionModule(flecs::world &ecs)
|
||||
{
|
||||
ZoneScoped;
|
||||
ecs.module<PlayerActionModule>();
|
||||
ecs.import <CharacterManagerModule>();
|
||||
ecs.component<ActionNodeList>()
|
||||
.on_add([](flecs::entity e, ActionNodeList &alist) {
|
||||
ZoneScoped;
|
||||
alist.nodeMutex = std::make_shared<std::mutex>();
|
||||
alist.setDirty();
|
||||
alist.nodes.reserve(1000);
|
||||
@@ -295,6 +306,7 @@ PlayerActionModule::PlayerActionModule(flecs::world &ecs)
|
||||
ecs.system<ActionNodeList>("updateNodeList")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([](ActionNodeList &list) {
|
||||
ZoneScopedN("updateNodeList");
|
||||
if (list.isBusy())
|
||||
return;
|
||||
if (list.nodes.size() > 0) {
|
||||
@@ -319,6 +331,7 @@ PlayerActionModule::PlayerActionModule(flecs::world &ecs)
|
||||
ecs.system<ActionNodeList, const Input>("ActivateActionNode")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](ActionNodeList &list, const Input &input) {
|
||||
ZoneScopedN("ActivateActionNode");
|
||||
std::lock_guard<std::mutex> lock(*list.nodeMutex);
|
||||
if (input.control & 32)
|
||||
std::cout << "act pressed" << std::endl;
|
||||
@@ -365,6 +378,7 @@ PlayerActionModule::PlayerActionModule(flecs::world &ecs)
|
||||
ecs.system<const EngineData>("UpdateActivatedWords")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](const EngineData &eng) {
|
||||
ZoneScopedN("UpdateActivatedWords");
|
||||
for (auto it = activatedWords.begin();
|
||||
it != activatedWords.end();) {
|
||||
int ret = it->second->_update(eng.delta);
|
||||
@@ -380,12 +394,14 @@ PlayerActionModule::PlayerActionModule(flecs::world &ecs)
|
||||
void PlayerActionModule::addWordHandler(const Ogre::String &word,
|
||||
ActionWordHandler *handler)
|
||||
{
|
||||
ZoneScoped;
|
||||
actionWords.insert({ word, handler });
|
||||
}
|
||||
|
||||
void PlayerActionModule::removeWordHandler(const Ogre::String &word,
|
||||
ActionWordHandler *handler)
|
||||
{
|
||||
ZoneScoped;
|
||||
for (auto it = actionWords.begin(); it != actionWords.end();) {
|
||||
if (it->first == word && it->second == handler)
|
||||
it = actionWords.erase(it);
|
||||
@@ -418,6 +434,7 @@ struct TestActivatedWordHandler : PlayerActionModule::ActivatedWordHandler {
|
||||
, state(0)
|
||||
, delay(0)
|
||||
{
|
||||
ZoneScoped;
|
||||
activeActors.insert(actor);
|
||||
// dynamic nodes can disappear on us so to avoid that use a copy
|
||||
anode = ECS::get<ActionNodeList>().dynamicNodes[actionNode];
|
||||
@@ -450,6 +467,7 @@ out:;
|
||||
}
|
||||
void teleport(const Ogre::String &place)
|
||||
{
|
||||
ZoneScoped;
|
||||
if (placeLocalOffset.find(place) == placeLocalOffset.end())
|
||||
return;
|
||||
std::cout << "local offset: " << placeLocalOffset[place]
|
||||
@@ -476,6 +494,7 @@ out:;
|
||||
}
|
||||
int update(float delta)
|
||||
{
|
||||
ZoneScoped;
|
||||
switch (state) {
|
||||
case 0:
|
||||
if (ECS::get<Input>().act)
|
||||
@@ -579,6 +598,7 @@ out:;
|
||||
}
|
||||
void enter()
|
||||
{
|
||||
ZoneScoped;
|
||||
delay = 0.0f;
|
||||
state = 0;
|
||||
ECS::get_mut<GUI>().enableActions = false;
|
||||
@@ -587,6 +607,7 @@ out:;
|
||||
}
|
||||
void exit(int result)
|
||||
{
|
||||
ZoneScoped;
|
||||
ch.remove<CharacterInActuator>();
|
||||
ch.remove<CharacterControlDisable>();
|
||||
PhysicsModule::controlPhysics(ch, true);
|
||||
@@ -599,6 +620,7 @@ out:;
|
||||
}
|
||||
virtual ~TestActivatedWordHandler()
|
||||
{
|
||||
ZoneScoped;
|
||||
activeActors.erase(actor);
|
||||
}
|
||||
};
|
||||
@@ -609,6 +631,7 @@ struct LuaWordHandler : PlayerActionModule::ActionWordHandler {
|
||||
void operator()(int actor, flecs::entity town, int index,
|
||||
const Ogre::String &word, int actionNode) override
|
||||
{
|
||||
ZoneScoped;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
if (lua_type(L, -1) == LUA_TFUNCTION) {
|
||||
luaL_checktype(L, -1, LUA_TFUNCTION);
|
||||
@@ -662,6 +685,7 @@ struct LuaWordHandler : PlayerActionModule::ActionWordHandler {
|
||||
void PlayerActionModule::addLuaWordHandler(const Ogre::String &word,
|
||||
lua_State *L, int ref)
|
||||
{
|
||||
ZoneScoped;
|
||||
struct LuaWordHandler *handler = OGRE_NEW LuaWordHandler;
|
||||
handler->L = L;
|
||||
handler->ref = ref;
|
||||
@@ -671,6 +695,7 @@ void PlayerActionModule::addLuaWordHandler(const Ogre::String &word,
|
||||
void PlayerActionModule::removeLuaWordHandler(const Ogre::String &word,
|
||||
lua_State *L, int ref)
|
||||
{
|
||||
ZoneScoped;
|
||||
for (auto it = actionWords.begin(); it != actionWords.end();) {
|
||||
LuaWordHandler *handler =
|
||||
static_cast<LuaWordHandler *>(it->second);
|
||||
@@ -683,6 +708,7 @@ void PlayerActionModule::removeLuaWordHandler(const Ogre::String &word,
|
||||
|
||||
int PlayerActionModule::setupLuaActionHandler(lua_State *L)
|
||||
{
|
||||
ZoneScoped;
|
||||
luaL_checktype(L, 1, LUA_TSTRING);
|
||||
if (lua_type(L, 2) == LUA_TFUNCTION) {
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||
@@ -703,6 +729,7 @@ int PlayerActionModule::setupLuaActionHandler(lua_State *L)
|
||||
void PlayerActionModule::addActivatedWordHandler(const Ogre::String &word,
|
||||
ActivatedWordHandler *handler)
|
||||
{
|
||||
ZoneScoped;
|
||||
for (auto it = activatedWords.begin(); it != activatedWords.end();
|
||||
it++) {
|
||||
}
|
||||
@@ -712,6 +739,7 @@ void PlayerActionModule::addActivatedWordHandler(const Ogre::String &word,
|
||||
void PlayerActionModule::removeActivatedWordHandler(
|
||||
const Ogre::String &word, ActivatedWordHandler *handler)
|
||||
{
|
||||
ZoneScoped;
|
||||
for (auto it = activatedWords.begin(); it != activatedWords.end();) {
|
||||
if (it->first == word && it->second == handler)
|
||||
it = activatedWords.erase(it);
|
||||
@@ -722,29 +750,42 @@ void PlayerActionModule::removeActivatedWordHandler(
|
||||
|
||||
void ActionNodeList::updateDynamicNodes()
|
||||
{
|
||||
ZoneScoped;
|
||||
std::lock_guard<std::mutex> lock(*nodeMutex);
|
||||
if (dynamicNodes.size() > nodes.size())
|
||||
dynamicNodes.resize(nodes.size());
|
||||
else {
|
||||
dynamicNodes.clear();
|
||||
dynamicNodes.insert(dynamicNodes.end(), nodes.begin(),
|
||||
nodes.end());
|
||||
{
|
||||
ZoneScopedN("static");
|
||||
ZoneTextF("before: dynamicNodes: %d nodes: %d",
|
||||
(int)dynamicNodes.size(), (int)nodes.size());
|
||||
// Do not constantly re-create static nodes
|
||||
if (dynamicNodes.size() > nodes.size())
|
||||
dynamicNodes.resize(nodes.size());
|
||||
else if (dynamicNodes.size() < nodes.size()) {
|
||||
dynamicNodes.clear();
|
||||
dynamicNodes.insert(dynamicNodes.end(), nodes.begin(),
|
||||
nodes.end());
|
||||
ZoneTextF("updated: dynamicNodes: %d nodes: %d",
|
||||
(int)dynamicNodes.size(), (int)nodes.size());
|
||||
}
|
||||
}
|
||||
{
|
||||
ZoneScopedN("dynamic");
|
||||
ECS::get().query_builder<const TownNPCs>().each(
|
||||
[this](flecs::entity town, const TownNPCs &npcs) {
|
||||
for (auto it = npcs.npcs.begin();
|
||||
it != npcs.npcs.end(); it++) {
|
||||
dynamicNodes.insert(
|
||||
dynamicNodes.end(),
|
||||
it->second.actionNodes.begin(),
|
||||
it->second.actionNodes.end());
|
||||
}
|
||||
});
|
||||
}
|
||||
ECS::get().query_builder<const TownNPCs>().each(
|
||||
[this](flecs::entity town, const TownNPCs &npcs) {
|
||||
for (auto it = npcs.npcs.begin(); it != npcs.npcs.end();
|
||||
it++) {
|
||||
dynamicNodes.insert(
|
||||
dynamicNodes.end(),
|
||||
it->second.actionNodes.begin(),
|
||||
it->second.actionNodes.end());
|
||||
}
|
||||
});
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void ActionNodeList::build()
|
||||
{
|
||||
ZoneScoped;
|
||||
std::lock_guard<std::mutex> lock(*nodeMutex);
|
||||
indexObj = std::make_shared<ActionNodeList::indexObject>(dynamicNodes);
|
||||
indexObj->index.buildIndex();
|
||||
@@ -755,6 +796,7 @@ bool ActionNodeList::_query(const Ogre::Vector3 &position,
|
||||
std::vector<size_t> &points,
|
||||
std::vector<float> &distances)
|
||||
{
|
||||
ZoneScoped;
|
||||
std::vector<size_t> tmppoints;
|
||||
std::vector<float> tmpdistances;
|
||||
points.clear();
|
||||
@@ -784,6 +826,7 @@ bool ActionNodeList::query_ai(const Ogre::Vector3 &position, float distance,
|
||||
std::vector<size_t> &points,
|
||||
std::vector<float> &distances)
|
||||
{
|
||||
ZoneScoped;
|
||||
std::lock_guard<std::mutex> lock(*nodeMutex);
|
||||
std::vector<size_t> tmppoints;
|
||||
std::vector<float> tmpdistances;
|
||||
@@ -812,6 +855,7 @@ bool ActionNodeList::query_ai(const Ogre::Vector3 &position, float distance,
|
||||
|
||||
int ActionNodeList::addNode(ActionNode &node)
|
||||
{
|
||||
ZoneScoped;
|
||||
std::lock_guard<std::mutex> lock(*nodeMutex);
|
||||
int index = nodes.size();
|
||||
nodes.push_back(node);
|
||||
@@ -821,6 +865,7 @@ int ActionNodeList::addNode(ActionNode &node)
|
||||
|
||||
void ActionNodeList::removeNode(int index)
|
||||
{
|
||||
ZoneScoped;
|
||||
std::lock_guard<std::mutex> lock(*nodeMutex);
|
||||
nodes.erase(nodes.begin() + index);
|
||||
dirty = true;
|
||||
@@ -828,12 +873,14 @@ void ActionNodeList::removeNode(int index)
|
||||
|
||||
const ActionNodeList::UIData &ActionNodeList::getUIData()
|
||||
{
|
||||
ZoneScoped;
|
||||
std::lock_guard<std::mutex> lock(*uidata.mutex);
|
||||
return uidata;
|
||||
}
|
||||
|
||||
void ActionNodeList::setUISelected(int selected)
|
||||
{
|
||||
ZoneScoped;
|
||||
std::lock_guard<std::mutex> lock(*uidata.mutex);
|
||||
|
||||
uidata.selected = selected;
|
||||
@@ -842,6 +889,7 @@ void ActionNodeList::setUISelected(int selected)
|
||||
void ActionNodeList::setUIPoints(const std::vector<size_t> &points,
|
||||
const std::vector<float> &distances)
|
||||
{
|
||||
ZoneScoped;
|
||||
std::lock_guard<std::mutex> lock(*uidata.mutex);
|
||||
uidata.points = points;
|
||||
uidata.distances = distances;
|
||||
@@ -849,6 +897,7 @@ void ActionNodeList::setUIPoints(const std::vector<size_t> &points,
|
||||
|
||||
void ActionNodeList::UIquery(const Ogre::Vector3 &position)
|
||||
{
|
||||
ZoneScoped;
|
||||
bool needBuild = false;
|
||||
|
||||
{
|
||||
|
||||
@@ -3,16 +3,21 @@
|
||||
#include "GameData.h"
|
||||
#include "GUIModuleCommon.h"
|
||||
#include "QuestModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
namespace ECS
|
||||
{
|
||||
|
||||
QuestModule::QuestModule(flecs::world &ecs)
|
||||
{
|
||||
ZoneScoped;
|
||||
ecs.module<QuestModule>();
|
||||
ecs.observer<GameState>("EnableQuests")
|
||||
.event(flecs::OnAdd)
|
||||
.each([this](GameState &game) {
|
||||
ZoneScoped;
|
||||
if (quest_update.is_valid())
|
||||
return;
|
||||
quest_update =
|
||||
ECS::get()
|
||||
.system<const EngineData>(
|
||||
@@ -28,6 +33,7 @@ QuestModule::QuestModule(flecs::world &ecs)
|
||||
ecs.observer<GameState>("DisableQuests")
|
||||
.event(flecs::OnRemove)
|
||||
.each([this](GameState &game) {
|
||||
ZoneScoped;
|
||||
if (quest_update.is_valid())
|
||||
quest_update.destruct();
|
||||
});
|
||||
@@ -35,11 +41,13 @@ QuestModule::QuestModule(flecs::world &ecs)
|
||||
|
||||
void QuestModule::addQuest(Quest *quest)
|
||||
{
|
||||
ZoneScoped;
|
||||
quests.insert(quest);
|
||||
}
|
||||
|
||||
void QuestModule::removeQuest(Quest *quest)
|
||||
{
|
||||
ZoneScoped;
|
||||
quests.erase(quests.find(quest));
|
||||
}
|
||||
struct LuaNarrationHandler : GUI::NarrationHandler {
|
||||
@@ -49,6 +57,7 @@ struct LuaNarrationHandler : GUI::NarrationHandler {
|
||||
: ref(ref)
|
||||
, L(L)
|
||||
{
|
||||
ZoneScoped;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
lua_pushlightuserdata(L, this);
|
||||
lua_pushcclosure(
|
||||
@@ -125,6 +134,7 @@ struct LuaNarrationHandler : GUI::NarrationHandler {
|
||||
}
|
||||
void finish() override
|
||||
{
|
||||
ZoneScoped;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
int type = lua_getfield(L, -1, "finish");
|
||||
OgreAssert(type == LUA_TFUNCTION, "bad finish()");
|
||||
@@ -138,6 +148,7 @@ struct LuaNarrationHandler : GUI::NarrationHandler {
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
ZoneScoped;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
int type = lua_getfield(L, -1, "activate");
|
||||
OgreAssert(type == LUA_TFUNCTION, "bad activate()");
|
||||
@@ -150,6 +161,7 @@ struct LuaNarrationHandler : GUI::NarrationHandler {
|
||||
}
|
||||
void event(const Ogre::String &evt) override
|
||||
{
|
||||
ZoneScoped;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
int type = lua_getfield(L, -1, "event");
|
||||
OgreAssert(type == LUA_TFUNCTION, "bad event()");
|
||||
@@ -171,6 +183,7 @@ struct LuaQuest : QuestModule::Quest {
|
||||
, L(L)
|
||||
, ref(ref)
|
||||
{
|
||||
ZoneScoped;
|
||||
OgreAssert(L, "bad Lua state");
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
lua_pushlightuserdata(L, this);
|
||||
@@ -206,6 +219,7 @@ struct LuaQuest : QuestModule::Quest {
|
||||
}
|
||||
void finish(int rc) override
|
||||
{
|
||||
ZoneScoped;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
int type = lua_getfield(L, -1, "finish");
|
||||
OgreAssert(type == LUA_TFUNCTION, "bad finish()");
|
||||
@@ -219,6 +233,7 @@ struct LuaQuest : QuestModule::Quest {
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
ZoneScoped;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
int type = lua_getfield(L, -1, "activate");
|
||||
OgreAssert(type == LUA_TFUNCTION, "bad activate()");
|
||||
@@ -231,6 +246,7 @@ struct LuaQuest : QuestModule::Quest {
|
||||
}
|
||||
void event(const Ogre::String &evt) override
|
||||
{
|
||||
ZoneScoped;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
int type = lua_getfield(L, -1, "event");
|
||||
OgreAssert(type == LUA_TFUNCTION, "bad event()");
|
||||
@@ -244,6 +260,7 @@ struct LuaQuest : QuestModule::Quest {
|
||||
}
|
||||
int update(float delta) override
|
||||
{
|
||||
ZoneScoped;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
int type = lua_getfield(L, -1, "finish");
|
||||
OgreAssert(type == LUA_TFUNCTION, "bad finish()");
|
||||
@@ -263,6 +280,7 @@ struct LuaQuest : QuestModule::Quest {
|
||||
|
||||
void QuestModule::addLuaQuest(lua_State *L)
|
||||
{
|
||||
ZoneScoped;
|
||||
luaL_checktype(L, 1, LUA_TSTRING);
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
Ogre::String name = lua_tostring(L, 1);
|
||||
@@ -274,12 +292,14 @@ void QuestModule::addLuaQuest(lua_State *L)
|
||||
|
||||
void QuestModule::Quest::_activate()
|
||||
{
|
||||
ZoneScoped;
|
||||
activate();
|
||||
active = true;
|
||||
}
|
||||
|
||||
void QuestModule::Quest::_finish(int rc)
|
||||
{
|
||||
ZoneScoped;
|
||||
finish(rc);
|
||||
active = false;
|
||||
if (rc == OK)
|
||||
@@ -301,6 +321,7 @@ QuestModule::Quest::~Quest()
|
||||
|
||||
int QuestModule::Quest::_update(float delta)
|
||||
{
|
||||
ZoneScoped;
|
||||
if (!active && !_can_activate())
|
||||
return ERROR;
|
||||
if (!active)
|
||||
@@ -320,6 +341,7 @@ int QuestModule::Quest::_update(float delta)
|
||||
|
||||
void QuestModule::Quest::_event(const std::string &evt)
|
||||
{
|
||||
ZoneScoped;
|
||||
event(evt);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
#include "WaterModule.h"
|
||||
#include "BoatModule.h"
|
||||
#include "SlotsModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
SlotsModule::SlotsModule(flecs::world &ecs)
|
||||
{
|
||||
ecs.module<SlotsModule>();
|
||||
ZoneScoped;
|
||||
ecs.module<SlotsModule>();
|
||||
ecs.import <CharacterModule>();
|
||||
ecs.component<ParentSlot>();
|
||||
ecs.component<ParentSlotData>();
|
||||
@@ -20,7 +22,10 @@ SlotsModule::SlotsModule(flecs::world &ecs)
|
||||
ecs.observer<const EngineData, const BoatBase>("CreateBoatSlots")
|
||||
.event(flecs::OnSet)
|
||||
.each([&](flecs::entity e, const EngineData &eng,
|
||||
const BoatBase &boat) { createBoatSlots(e); });
|
||||
const BoatBase &boat) {
|
||||
ZoneScoped;
|
||||
createBoatSlots(e);
|
||||
});
|
||||
#if 1
|
||||
ecs.system<const EngineData, const CharacterBase, ParentSlot>(
|
||||
"UpdateSlotData")
|
||||
@@ -29,6 +34,7 @@ SlotsModule::SlotsModule(flecs::world &ecs)
|
||||
.without<ParentSlotData>()
|
||||
.each([&](flecs::entity e, const EngineData &eng,
|
||||
const CharacterBase &ch, ParentSlot &slot) {
|
||||
ZoneScoped;
|
||||
if (slot.slot_name == "") {
|
||||
slot.removeSlot(e);
|
||||
return;
|
||||
@@ -77,7 +83,8 @@ SlotsModule::SlotsModule(flecs::world &ecs)
|
||||
}
|
||||
void SlotsModule::createBoatSlots(flecs::entity e)
|
||||
{
|
||||
const EngineData &eng = e.world().get<EngineData>();
|
||||
ZoneScoped;
|
||||
const EngineData &eng = e.world().get<EngineData>();
|
||||
const BoatBase &boat = e.get<BoatBase>();
|
||||
int i;
|
||||
std::vector<Ogre::Node *> slots = boat.mNode->getChildren();
|
||||
@@ -115,7 +122,8 @@ void SlotsModule::createBoatSlots(flecs::entity e)
|
||||
}
|
||||
void ParentSlot::createSlot(flecs::entity e)
|
||||
{
|
||||
if (e.has<CharacterBase>()) {
|
||||
ZoneScoped;
|
||||
if (e.has<CharacterBase>()) {
|
||||
createCharacterSlot(e);
|
||||
}
|
||||
}
|
||||
@@ -124,14 +132,16 @@ void ParentSlot::createCharacterSlot(flecs::entity e)
|
||||
}
|
||||
void ParentSlot::removeSlot(flecs::entity e)
|
||||
{
|
||||
if (e.has<ParentSlot>())
|
||||
ZoneScoped;
|
||||
if (e.has<ParentSlot>())
|
||||
e.remove<ParentSlot>();
|
||||
if (e.has<ParentSlot>())
|
||||
e.remove<ParentSlotData>();
|
||||
}
|
||||
bool ParentSlot::check() const
|
||||
{
|
||||
if (!parent_e.has<ObjectSlots>())
|
||||
ZoneScoped;
|
||||
if (!parent_e.has<ObjectSlots>())
|
||||
return false;
|
||||
const ObjectSlots &slots = parent_e.get<ObjectSlots>();
|
||||
if (!slots.exists(slot_name))
|
||||
@@ -140,13 +150,15 @@ bool ParentSlot::check() const
|
||||
}
|
||||
bool ParentSlot::parentIsValid()
|
||||
{
|
||||
if (!parent_e.has<ObjectSlots>())
|
||||
ZoneScoped;
|
||||
if (!parent_e.has<ObjectSlots>())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
Ogre::SceneNode *ParentSlot::getSlotBase() const
|
||||
{
|
||||
if (!check())
|
||||
ZoneScoped;
|
||||
if (!check())
|
||||
return nullptr;
|
||||
const ObjectSlots &slots = parent_e.get<ObjectSlots>();
|
||||
Ogre::SceneNode *slot_base = slots.slots.at(slot_name).second;
|
||||
@@ -154,7 +166,8 @@ Ogre::SceneNode *ParentSlot::getSlotBase() const
|
||||
}
|
||||
void ParentSlot::addChild(Ogre::SceneNode *childNode)
|
||||
{
|
||||
Ogre::SceneNode *parentNode = getSlotBase();
|
||||
ZoneScoped;
|
||||
Ogre::SceneNode *parentNode = getSlotBase();
|
||||
if (childNode->getParentSceneNode())
|
||||
childNode->getParentSceneNode()->removeChild(childNode);
|
||||
parentNode->addChild(childNode);
|
||||
@@ -163,7 +176,8 @@ void ParentSlot::addChild(Ogre::SceneNode *childNode)
|
||||
}
|
||||
void ParentSlot::createSlotData(flecs::entity e)
|
||||
{
|
||||
const ObjectSlots &slots = parent_e.get<ObjectSlots>();
|
||||
ZoneScoped;
|
||||
const ObjectSlots &slots = parent_e.get<ObjectSlots>();
|
||||
ParentSlotData &psdata = e.ensure<ParentSlotData>();
|
||||
Ogre::SceneNode *slot_base = getSlotBase();
|
||||
// Ogre::Vector3 position = slot_base->_getDerivedPosition();
|
||||
@@ -178,6 +192,7 @@ void ParentSlot::createSlotData(flecs::entity e)
|
||||
}
|
||||
bool ObjectSlots::exists(const Ogre::String &name) const
|
||||
{
|
||||
return slots.find(name) != slots.end();
|
||||
ZoneScoped;
|
||||
return slots.find(name) != slots.end();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#include "SmartObject.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
SmartObjectModule::SmartObjectModule(flecs::world &ecs)
|
||||
{
|
||||
ZoneScoped;
|
||||
ecs.module<SmartObjectModule>();
|
||||
ecs.component<SmartObjectManager>().add(flecs::Singleton);
|
||||
ecs.component<SmartObject>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "PhysicsModule.h"
|
||||
#include "items.h"
|
||||
#include "StaticGeometryModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
namespace ECS
|
||||
{
|
||||
@@ -25,12 +26,14 @@ static bool templatesLoaded = false;
|
||||
static std::list<std::pair<long, long> > addQueue;
|
||||
StaticGeometryModule::StaticGeometryModule(flecs::world &ecs)
|
||||
{
|
||||
ZoneScoped;
|
||||
ecs.module<StaticGeometryModule>();
|
||||
ecs.component<TerrainSlotParent>();
|
||||
ecs.component<TerrainItem>();
|
||||
ecs.component<FurnitureItem>();
|
||||
ecs.component<FurnitureInstance>()
|
||||
.on_remove([](flecs::entity e, FurnitureInstance &instance) {
|
||||
ZoneScoped;
|
||||
if (instance.furniture) {
|
||||
instance.furniture
|
||||
->destroyAllChildrenAndObjects();
|
||||
@@ -40,6 +43,7 @@ StaticGeometryModule::StaticGeometryModule(flecs::world &ecs)
|
||||
}
|
||||
})
|
||||
.on_set([](flecs::entity e, FurnitureInstance &instance) {
|
||||
ZoneScoped;
|
||||
if (instance.furniture !=
|
||||
e.get<FurnitureInstance>().furniture) {
|
||||
FurnitureInstance &f =
|
||||
@@ -53,11 +57,13 @@ StaticGeometryModule::StaticGeometryModule(flecs::world &ecs)
|
||||
}
|
||||
})
|
||||
.on_add([](flecs::entity e, FurnitureInstance &instance) {
|
||||
ZoneScoped;
|
||||
instance.furniture = nullptr;
|
||||
});
|
||||
ecs.component<TerrainItemNode>().on_remove([](flecs::entity e,
|
||||
TerrainItemNode &item) {
|
||||
if (item.itemNode) {
|
||||
ZoneScoped;
|
||||
if (item.itemNode) {
|
||||
item.itemNode->destroyAllChildrenAndObjects();
|
||||
item.itemNode->getCreator()->destroySceneNode(
|
||||
item.itemNode);
|
||||
@@ -75,7 +81,8 @@ StaticGeometryModule::StaticGeometryModule(flecs::world &ecs)
|
||||
ecs.observer<const Terrain>("LoadTerrainItems")
|
||||
.event(flecs::OnSet)
|
||||
.each([&](const Terrain &terrain) {
|
||||
if (terrain.mTerrainGroup && !itemsLoaded) {
|
||||
ZoneScopedN("LoadTerrainItems");
|
||||
if (terrain.mTerrainGroup && !itemsLoaded) {
|
||||
loadItems();
|
||||
itemsLoaded = true;
|
||||
}
|
||||
@@ -83,7 +90,8 @@ StaticGeometryModule::StaticGeometryModule(flecs::world &ecs)
|
||||
if (!Ogre::MeshLodGenerator::getSingletonPtr())
|
||||
new Ogre::MeshLodGenerator();
|
||||
ecs.system("AddGeometryQueue").kind(flecs::OnUpdate).run([&](flecs::iter &it) {
|
||||
std::list<flecs::entity> items;
|
||||
ZoneScopedN("AddGeometryQueue");
|
||||
std::list<flecs::entity> items;
|
||||
if (!ECS::get().has<Terrain>())
|
||||
return;
|
||||
if (!ECS::get<Terrain>().mTerrainGroup)
|
||||
@@ -142,11 +150,13 @@ StaticGeometryModule::StaticGeometryModule(flecs::world &ecs)
|
||||
}
|
||||
void StaticGeometryModule::addGeometryForSlot(long x, long y)
|
||||
{
|
||||
addQueue.push_back({ x, y });
|
||||
ZoneScoped;
|
||||
addQueue.push_back({ x, y });
|
||||
}
|
||||
void StaticGeometryModule::removeGeometryForSlot(long x, long y)
|
||||
{
|
||||
std::pair<long, long> slot = { x, y };
|
||||
ZoneScoped;
|
||||
std::pair<long, long> slot = { x, y };
|
||||
flecs::entity parent =
|
||||
ECS::get().query_builder<const TerrainSlotParent>().build().find(
|
||||
[&slot](const TerrainSlotParent &parent) {
|
||||
@@ -169,7 +179,8 @@ StaticGeometryModule::createItem(const Ogre::Vector3 &position,
|
||||
const Ogre::Quaternion &orientation,
|
||||
const Ogre::String &type)
|
||||
{
|
||||
long x, y;
|
||||
ZoneScoped;
|
||||
long x, y;
|
||||
ECS::get<Terrain>().mTerrainGroup->convertWorldPositionToTerrainSlot(
|
||||
position, &x, &y);
|
||||
std::pair<long, long> pos{ x, y };
|
||||
@@ -191,19 +202,22 @@ StaticGeometryModule::createItem(const Ogre::Vector3 &position,
|
||||
void StaticGeometryModule::setItemProperties(flecs::entity id,
|
||||
Ogre::String properties)
|
||||
{
|
||||
OgreAssert(id.is_valid(), "bad id");
|
||||
ZoneScoped;
|
||||
OgreAssert(id.is_valid(), "bad id");
|
||||
id.get_mut<TerrainItem>().properties = properties;
|
||||
id.modified<TerrainItem>();
|
||||
}
|
||||
const Ogre::String &StaticGeometryModule::getItemProperties(flecs::entity id)
|
||||
{
|
||||
OgreAssert(id.is_valid(), "bad id");
|
||||
ZoneScoped;
|
||||
OgreAssert(id.is_valid(), "bad id");
|
||||
return id.get<TerrainItem>().properties;
|
||||
}
|
||||
|
||||
nlohmann::json templates;
|
||||
void StaticGeometryModule::loadTemplates()
|
||||
{
|
||||
ZoneScoped;
|
||||
if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(
|
||||
"templates.list"))
|
||||
return;
|
||||
@@ -220,6 +234,7 @@ void StaticGeometryModule::loadTemplates()
|
||||
|
||||
void StaticGeometryModule::saveTemplates()
|
||||
{
|
||||
ZoneScoped;
|
||||
Ogre::String path = "resources/buildings/templates.list";
|
||||
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(
|
||||
"templates.list")) {
|
||||
@@ -242,7 +257,8 @@ void StaticGeometryModule::saveTemplates()
|
||||
|
||||
void StaticGeometryModule::saveItems()
|
||||
{
|
||||
Ogre::String path = "resources/buildings/items.list";
|
||||
ZoneScoped;
|
||||
Ogre::String path = "resources/buildings/items.list";
|
||||
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(
|
||||
"items.list")) {
|
||||
Ogre::String group =
|
||||
@@ -288,7 +304,8 @@ void StaticGeometryModule::saveItems()
|
||||
}
|
||||
void StaticGeometryModule::loadItems()
|
||||
{
|
||||
if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(
|
||||
ZoneScoped;
|
||||
if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(
|
||||
"items.list"))
|
||||
return;
|
||||
Ogre::String group = Ogre::ResourceGroupManager::getSingleton()
|
||||
@@ -362,6 +379,7 @@ void StaticGeometryModule::saveFurniture()
|
||||
|
||||
void StaticGeometryModule::loadFurniture()
|
||||
{
|
||||
ZoneScoped;
|
||||
ECS::get().delete_with<FurnitureItem>();
|
||||
static std::vector<Ogre::String> glb_names;
|
||||
const std::vector<Ogre::String> &groups =
|
||||
@@ -405,6 +423,7 @@ void StaticGeometryModule::loadFurniture()
|
||||
void StaticGeometryModule::getItemPositionPerSlot(
|
||||
long x, long y, std::list<Ogre::Vector3> *positions)
|
||||
{
|
||||
ZoneScoped;
|
||||
std::pair<long, long> pos{ x, y };
|
||||
if (!positions)
|
||||
return;
|
||||
@@ -425,6 +444,7 @@ void StaticGeometryModule::getItemPositionPerSlot(
|
||||
}
|
||||
void StaticGeometryModule::getItemPositions(std::list<Ogre::Vector3> *positions)
|
||||
{
|
||||
ZoneScoped;
|
||||
ECS::get().query_builder<const TerrainItem>().build().each(
|
||||
[&](flecs::entity e, const TerrainItem &item) {
|
||||
positions->push_back(item.position);
|
||||
@@ -433,12 +453,14 @@ void StaticGeometryModule::getItemPositions(std::list<Ogre::Vector3> *positions)
|
||||
void StaticGeometryModule::getItemPositionAndRotation(
|
||||
flecs::entity e, Ogre::Vector3 &position, Ogre::Quaternion &orientation)
|
||||
{
|
||||
ZoneScoped;
|
||||
position = e.get<TerrainItem>().position;
|
||||
orientation = e.get<TerrainItem>().orientation;
|
||||
}
|
||||
void StaticGeometryModule::getItemsProperties(
|
||||
std::list<std::pair<flecs::entity, Ogre::String> > *items)
|
||||
{
|
||||
ZoneScoped;
|
||||
ECS::get().query_builder<const TerrainItem>().build().each(
|
||||
[&](flecs::entity e, const TerrainItem &item) {
|
||||
items->push_back({ e, item.properties });
|
||||
@@ -446,11 +468,13 @@ void StaticGeometryModule::getItemsProperties(
|
||||
}
|
||||
void StaticGeometryModule::createItemGeometry(flecs::entity e)
|
||||
{
|
||||
ZoneScoped;
|
||||
Geometry::createItemGeometry(e);
|
||||
}
|
||||
|
||||
void StaticGeometryModule::destroyItemGeometry(flecs::entity e)
|
||||
{
|
||||
ZoneScoped;
|
||||
Geometry::destroyItemGeometry(e);
|
||||
}
|
||||
|
||||
@@ -461,16 +485,15 @@ nlohmann::json &StaticGeometryModule::getTemplates()
|
||||
|
||||
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>();
|
||||
});
|
||||
ZoneScoped;
|
||||
// We add this as task to reduce UI load
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([e]() {
|
||||
ZoneScopedN("updateItemGeometry");
|
||||
if (e.has<GeometryUpdateItem>())
|
||||
return;
|
||||
e.add<GeometryUpdateItem>();
|
||||
Geometry::updateItemGeometry(e);
|
||||
e.remove<GeometryUpdateItem>();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -479,6 +502,7 @@ void StaticGeometryModule::addTriangleBufferWork(
|
||||
const Ogre::Vector3 &position, const Ogre::Quaternion &rotation,
|
||||
const Procedural::TriangleBuffer &tb)
|
||||
{
|
||||
ZoneScoped;
|
||||
struct WorkData {
|
||||
Ogre::String meshName;
|
||||
Ogre::StaticGeometry *geo;
|
||||
@@ -487,22 +511,14 @@ void StaticGeometryModule::addTriangleBufferWork(
|
||||
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);
|
||||
});
|
||||
// We add this as task to reduce UI load
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([data]() {
|
||||
ZoneScopedN("addTriangleBufferWork");
|
||||
Ogre::MeshPtr mesh = data.tb.transformToMesh(data.meshName);
|
||||
Ogre::Entity *ent =
|
||||
ECS::get<EngineData>().mScnMgr->createEntity(mesh);
|
||||
data.geo->addEntity(ent, data.position, data.rotation);
|
||||
ECS::get<EngineData>().mScnMgr->destroyEntity(ent);
|
||||
});
|
||||
}
|
||||
struct TiledMeshes {
|
||||
|
||||
@@ -2,16 +2,19 @@
|
||||
#include <Ogre.h>
|
||||
#include "Components.h"
|
||||
#include "SunModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
namespace ECS
|
||||
{
|
||||
SunModule::SunModule(flecs::world &ecs)
|
||||
{
|
||||
ecs.component<Sun>().add(flecs::Singleton);
|
||||
ZoneScoped;
|
||||
ecs.component<Sun>().add(flecs::Singleton);
|
||||
ecs.system<const EngineData, Sun>("UpdateSetupSun")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([](const EngineData &eng, Sun &sun) {
|
||||
if (!sun.mSun) {
|
||||
ZoneScopedN("UpdateSetupSun");
|
||||
if (!sun.mSun) {
|
||||
Ogre::Light *light =
|
||||
eng.mScnMgr->createLight("Sun");
|
||||
sun.mSunNode = eng.mScnMgr->getRootSceneNode()
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "PhysicsModule.h"
|
||||
#include "StaticGeometryModule.h"
|
||||
#include "TerrainModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
#define TERRAIN_SIZE 65
|
||||
#define TERRAIN_WORLD_SIZE 500.0f
|
||||
@@ -48,6 +49,7 @@ struct HeightData {
|
||||
static HeightData *singleton;
|
||||
HeightData()
|
||||
{
|
||||
ZoneScoped;
|
||||
img.load(
|
||||
"world_map.png",
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||
@@ -60,13 +62,15 @@ struct HeightData {
|
||||
}
|
||||
static HeightData *get_singleton()
|
||||
{
|
||||
if (!singleton)
|
||||
ZoneScoped;
|
||||
if (!singleton)
|
||||
singleton = new HeightData();
|
||||
return singleton;
|
||||
}
|
||||
float get_brush_height(int id, int x, int y)
|
||||
{
|
||||
int m = 0;
|
||||
ZoneScoped;
|
||||
int m = 0;
|
||||
switch (id) {
|
||||
case 0:
|
||||
m = 0;
|
||||
@@ -110,7 +114,8 @@ struct HeightData {
|
||||
}
|
||||
void save_heightmap()
|
||||
{
|
||||
Ogre::String group =
|
||||
ZoneScoped;
|
||||
Ogre::String group =
|
||||
Ogre::ResourceGroupManager::getSingleton()
|
||||
.findGroupContainingResource("world_map.png");
|
||||
Ogre::FileInfoListPtr fileInfoList(
|
||||
@@ -125,7 +130,7 @@ struct HeightData {
|
||||
}
|
||||
float get_base_height(long world_x, long world_y)
|
||||
{
|
||||
float height = 0.0f;
|
||||
float height = 0.0f;
|
||||
int world_img_x =
|
||||
world_x + (int)img.getWidth() * BRUSH_SIZE / 2;
|
||||
int world_img_y =
|
||||
@@ -155,7 +160,7 @@ out:
|
||||
}
|
||||
float get_noise_height(long world_x, long world_y)
|
||||
{
|
||||
int h;
|
||||
int h;
|
||||
Ogre::Vector2 noisePoint;
|
||||
|
||||
struct noise_types {
|
||||
@@ -192,7 +197,7 @@ out:
|
||||
float get_height(Ogre::TerrainGroup *terrainGroup, long world_x,
|
||||
long world_y)
|
||||
{
|
||||
long grid_center_x = img.getWidth() * BRUSH_SIZE / 2;
|
||||
long grid_center_x = img.getWidth() * BRUSH_SIZE / 2;
|
||||
long grid_center_y = img.getHeight() * BRUSH_SIZE / 2;
|
||||
long world_grid_x = world_x + grid_center_x;
|
||||
long world_grid_y = world_y + grid_center_y;
|
||||
@@ -265,6 +270,7 @@ public:
|
||||
void createTerrainChunk(Ogre::TerrainGroup *terrainGroup, long x,
|
||||
long y)
|
||||
{
|
||||
ZoneScoped;
|
||||
Ogre::Terrain *terrain = terrainGroup->getTerrain(x, y);
|
||||
float minH = terrain->getMinHeight();
|
||||
float maxH = terrain->getMaxHeight();
|
||||
@@ -290,7 +296,8 @@ public:
|
||||
}
|
||||
void define(Ogre::TerrainGroup *terrainGroup, long x, long y) override
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mtx);
|
||||
ZoneScoped;
|
||||
std::lock_guard<std::mutex> guard(mtx);
|
||||
uint16_t terrainSize = terrainGroup->getTerrainSize();
|
||||
float *heightMap = OGRE_ALLOC_T(float, terrainSize *terrainSize,
|
||||
MEMCATEGORY_GEOMETRY);
|
||||
@@ -332,13 +339,15 @@ public:
|
||||
}
|
||||
bool frameStarted(const Ogre::FrameEvent &evt) override
|
||||
{
|
||||
(void)evt;
|
||||
ZoneScoped;
|
||||
(void)evt;
|
||||
update();
|
||||
return true;
|
||||
}
|
||||
void update()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mtx);
|
||||
ZoneScoped;
|
||||
std::lock_guard<std::mutex> guard(mtx);
|
||||
static bool created = false;
|
||||
while (!collider_queue.empty()) {
|
||||
Ogre::TerrainGroup *group =
|
||||
@@ -478,7 +487,8 @@ public:
|
||||
bool unloadProceduralPage(Ogre::Page *page,
|
||||
Ogre::PagedWorldSection *section)
|
||||
{
|
||||
long x, y;
|
||||
ZoneScoped;
|
||||
long x, y;
|
||||
ECS::get<Terrain>().mTerrainGroup->unpackIndex(page->CHUNK_ID,
|
||||
&x, &y);
|
||||
StaticGeometryModule::removeGeometryForSlot(x, y);
|
||||
@@ -492,7 +502,8 @@ public:
|
||||
};
|
||||
TerrainModule::TerrainModule(flecs::world &ecs)
|
||||
{
|
||||
struct CanSetPlayerPosition {};
|
||||
ZoneScoped;
|
||||
struct CanSetPlayerPosition {};
|
||||
ecs.module<TerrainModule>();
|
||||
ecs.component<CanSetPlayerPosition>().add(flecs::Singleton);
|
||||
ecs.component<Terrain>().add(flecs::Singleton);
|
||||
@@ -509,7 +520,8 @@ TerrainModule::TerrainModule(flecs::world &ecs)
|
||||
.each([](const EngineData &eng, const Camera &camera,
|
||||
const Sun &sun, Terrain &terrain,
|
||||
TerrainPrivate &priv) {
|
||||
if (!terrain.mTerrainGroup && sun.mSun && eng.mScnMgr) {
|
||||
ZoneScoped;
|
||||
if (!terrain.mTerrainGroup && sun.mSun && eng.mScnMgr) {
|
||||
std::cout << "Terrain setup\n";
|
||||
if (!priv.mDummyPageProvider)
|
||||
priv.mDummyPageProvider =
|
||||
@@ -635,7 +647,8 @@ TerrainModule::TerrainModule(flecs::world &ecs)
|
||||
.kind(flecs::OnUpdate)
|
||||
.without<TerrainReady>()
|
||||
.each([](const ECS::Camera &cam, const Terrain &terrain) {
|
||||
std::cout << "mTerrainReady: " << terrain.mTerrainReady
|
||||
ZoneScoped;
|
||||
std::cout << "mTerrainReady: " << terrain.mTerrainReady
|
||||
<< "\n";
|
||||
if (cam.mCameraNode && terrain.mTerrainReady) {
|
||||
long x, y;
|
||||
@@ -653,7 +666,8 @@ TerrainModule::TerrainModule(flecs::world &ecs)
|
||||
ecs.system<const Terrain, PlacementObjects>("UpdatePlacementObjects")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([](const Terrain &terrain, PlacementObjects &placement) {
|
||||
if (placement.altar_items.size() == 0) {
|
||||
ZoneScoped;
|
||||
if (placement.altar_items.size() == 0) {
|
||||
struct PlacementObjects::item item;
|
||||
int i, j;
|
||||
int worldSize = terrain.mTerrainGroup
|
||||
@@ -766,7 +780,8 @@ TerrainModule::TerrainModule(flecs::world &ecs)
|
||||
.kind(flecs::OnUpdate)
|
||||
.interval(2.0f)
|
||||
.each([](const Terrain &terrain) {
|
||||
if (!terrain.mTerrainGroup
|
||||
ZoneScoped;
|
||||
if (!terrain.mTerrainGroup
|
||||
->isDerivedDataUpdateInProgress())
|
||||
terrain.mTerrainGroup->update(false);
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "GameData.h"
|
||||
#include "Components.h"
|
||||
#include "WaterModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
#if 0
|
||||
@@ -112,12 +113,6 @@ WaterModule::WaterModule(flecs::world &ecs)
|
||||
Ogre::Plane(Ogre::Vector3(0.0, -1.0, 0.0), h);
|
||||
water.mRefractionClipPlaneBelow =
|
||||
Ogre::Plane(Ogre::Vector3(0.0, 1.0, 0.0), -h);
|
||||
#if 0
|
||||
if (Ogre::TextureManager::getSingleton()
|
||||
.resourceExists(renderTargetName))
|
||||
Ogre::TextureManager::getSingleton()
|
||||
.remove(renderTargetName);
|
||||
#endif
|
||||
Ogre::TexturePtr reflectionTexture =
|
||||
Ogre::TextureManager::getSingleton().createManual(
|
||||
renderTargetName,
|
||||
@@ -201,64 +196,6 @@ WaterModule::WaterModule(flecs::world &ecs)
|
||||
Ogre::MANUAL_CULL_NONE);
|
||||
pass->setVertexProgram("Water/water_vp");
|
||||
pass->setFragmentProgram("Water/water_fp");
|
||||
#if 0
|
||||
Ogre::GpuProgramPtr water_vp =
|
||||
Ogre::GpuProgramManager::getSingleton()
|
||||
.getByName(
|
||||
"Water/water_vp",
|
||||
Ogre::RGN_AUTODETECT);
|
||||
OgreAssert(water_vp != nullptr,
|
||||
"VP failed");
|
||||
pass->setGpuProgram(
|
||||
Ogre::GPT_VERTEX_PROGRAM,
|
||||
water_vp);
|
||||
OgreAssert(water_vp->isSupported(),
|
||||
"VP not supported");
|
||||
Ogre::GpuProgramPtr water_fp =
|
||||
Ogre::GpuProgramManager::getSingleton()
|
||||
.getByName(
|
||||
"Water/water_fp",
|
||||
Ogre::RGN_AUTODETECT);
|
||||
OgreAssert(water_vp != nullptr,
|
||||
"FP failed");
|
||||
pass->setGpuProgram(
|
||||
Ogre::GPT_FRAGMENT_PROGRAM,
|
||||
water_fp);
|
||||
OgreAssert(water_fp->isSupported(),
|
||||
"FP not supported");
|
||||
Ogre::GpuProgramParametersSharedPtr paramsVP =
|
||||
water_vp->getDefaultParameters();
|
||||
paramsVP->setNamedAutoConstant(
|
||||
"world",
|
||||
Ogre::GpuProgramParameters::
|
||||
ACT_WORLD_MATRIX);
|
||||
paramsVP->setNamedAutoConstant(
|
||||
"worldViewProj",
|
||||
Ogre::GpuProgramParameters::
|
||||
ACT_WORLDVIEWPROJ_MATRIX);
|
||||
paramsVP->setNamedAutoConstant(
|
||||
"textureProjMatrix",
|
||||
Ogre::GpuProgramParameters::
|
||||
ACT_TEXTURE_WORLDVIEWPROJ_MATRIX);
|
||||
paramsVP->setNamedAutoConstant(
|
||||
"eyePosition",
|
||||
Ogre::GpuProgramParameters::
|
||||
ACT_CAMERA_POSITION_OBJECT_SPACE);
|
||||
paramsVP->setNamedAutoConstant(
|
||||
"normalMatrix",
|
||||
Ogre::GpuProgramParameters::
|
||||
ACT_NORMAL_MATRIX);
|
||||
paramsVP->setNamedAutoConstant(
|
||||
"worldView",
|
||||
Ogre::GpuProgramParameters::
|
||||
ACT_WORLDVIEW_MATRIX);
|
||||
paramsVP->setNamedAutoConstant(
|
||||
"viewProj",
|
||||
Ogre::GpuProgramParameters::
|
||||
ACT_VIEWPROJ_MATRIX);
|
||||
Ogre::GpuProgramParametersSharedPtr paramsFP =
|
||||
water_fp->getDefaultParameters();
|
||||
#endif
|
||||
Ogre::TextureUnitState *texture_unit =
|
||||
pass->createTextureUnitState();
|
||||
texture_unit->setTextureName(
|
||||
@@ -284,38 +221,7 @@ WaterModule::WaterModule(flecs::world &ecs)
|
||||
Ogre::FT_MAG, Ogre::FO_LINEAR);
|
||||
texture_unit2->setTextureFiltering(
|
||||
Ogre::FT_MIP, Ogre::FO_LINEAR);
|
||||
#if 0
|
||||
bool success =
|
||||
Ogre::RTShader::ShaderGenerator::getSingletonPtr()
|
||||
->createShaderBasedTechnique(
|
||||
*mat,
|
||||
Ogre::MSN_DEFAULT,
|
||||
Ogre::MSN_SHADERGEN);
|
||||
OgreAssert(
|
||||
success,
|
||||
"createShaderBasedTechnique");
|
||||
Ogre::RTShader::RenderState *renderState =
|
||||
Ogre::RTShader::ShaderGenerator::
|
||||
getSingletonPtr()
|
||||
->getRenderState(
|
||||
Ogre::MSN_SHADERGEN,
|
||||
*mat,
|
||||
0);
|
||||
|
||||
Ogre::RTShader::SubRenderState *perPixelLightModel =
|
||||
Ogre::RTShader::ShaderGenerator::getSingletonPtr()
|
||||
->createSubRenderState(
|
||||
Ogre::RTShader::
|
||||
SRS_PER_PIXEL_LIGHTING);
|
||||
renderState->addTemplateSubRenderState(
|
||||
perPixelLightModel);
|
||||
#endif
|
||||
}
|
||||
#if 0
|
||||
mat = Ogre::MaterialManager::getSingleton()
|
||||
.getByName("Water/Above");
|
||||
mat->load();
|
||||
#endif
|
||||
mat->load();
|
||||
mat->setReceiveShadows(false);
|
||||
/*
|
||||
@@ -494,202 +400,37 @@ WaterModule::WaterModule(flecs::world &ecs)
|
||||
"Water/Above");
|
||||
})
|
||||
.add(flecs::Singleton);
|
||||
#if 0
|
||||
ecs.component<WaterBody>().add(flecs::Singleton);
|
||||
ecs.component<WaterBody>()
|
||||
.on_add([this](WaterBody &body) {
|
||||
#if 0
|
||||
body.mShapeAabbMax = btVector3(0, 0, 0);
|
||||
body.mShapeAabbMin = btVector3(0, 0, 0);
|
||||
body.mSurface.clear();
|
||||
body.mWaterBody = OGRE_NEW btPairCachingGhostObject();
|
||||
createWaterShape(&body);
|
||||
body.mWaterBody->setCollisionShape(body.mWaterShape);
|
||||
btTransform bodyTransform;
|
||||
bodyTransform.setIdentity();
|
||||
body.mWaterBody->setWorldTransform(bodyTransform);
|
||||
body.mWaterBody->setCollisionFlags(
|
||||
body.mWaterBody->getCollisionFlags() |
|
||||
btCollisionObject::CF_KINEMATIC_OBJECT |
|
||||
btCollisionObject::CF_NO_CONTACT_RESPONSE);
|
||||
body.mWaterBody->setActivationState(
|
||||
DISABLE_DEACTIVATION);
|
||||
const EngineData &eng = ECS::get<EngineData>();
|
||||
const WaterSurface &water = ECS::get<WaterSurface>();
|
||||
|
||||
eng.mWorld->attachCollisionObject(body.mWaterBody,
|
||||
water.mWaterEnt, 16,
|
||||
0x7fffffff & ~2);
|
||||
WaterPhysicsAction *action =
|
||||
OGRE_NEW WaterPhysicsAction(body.mWaterBody);
|
||||
body.action = action;
|
||||
ECS::get()
|
||||
.get<EngineData>()
|
||||
.mWorld->getBtWorld()
|
||||
->addAction(body.action);
|
||||
#endif
|
||||
ECS::get().add<WaterReady>();
|
||||
})
|
||||
.add(flecs::Singleton);
|
||||
#endif
|
||||
ecs.system<const EngineData, const Camera, WaterSurface>("UpdateWater")
|
||||
ecs.system<const EngineData, const Camera, WaterSurface>(
|
||||
"UpdateWaterPosition")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<WaterReady>()
|
||||
.interval(0.3f)
|
||||
.each([](const EngineData &eng, const Camera &camera,
|
||||
WaterSurface &water) {
|
||||
float delta = eng.delta;
|
||||
Ogre::Vector3 mCameraPos =
|
||||
camera.mCameraNode->_getDerivedPosition();
|
||||
Ogre::Vector3 waterPos =
|
||||
water.mWaterNode->_getDerivedPosition();
|
||||
mCameraPos.y = 0;
|
||||
waterPos.y = 0;
|
||||
Ogre::Vector3 d = mCameraPos - waterPos;
|
||||
// Ogre::Vector3 waterPosition = mCameraPos;
|
||||
// mWaterNode->setPosition(waterPosition);
|
||||
if (d.squaredLength() < 100.0f * 100.0f)
|
||||
water.mWaterNode->translate(d * 3.0f * delta);
|
||||
else
|
||||
water.mWaterNode->translate(d);
|
||||
// water.mWaterEnt->setVisible(false);
|
||||
water.mViewports[0]->update();
|
||||
water.mViewports[1]->update();
|
||||
// water.mRenderTargetListener.mInDepth = true;
|
||||
// water.mViewports[2]->update();
|
||||
// water.mViewports[3]->update();
|
||||
// water.mRenderTargetListener.mInDepth = false;
|
||||
// water.mWaterEnt->setVisible(true);
|
||||
ZoneScopedN("UpdateWaterPosition");
|
||||
float delta = eng.delta;
|
||||
Ogre::Vector3 mCameraPos =
|
||||
camera.mCameraNode->_getDerivedPosition();
|
||||
Ogre::Vector3 waterPos =
|
||||
water.mWaterNode->_getDerivedPosition();
|
||||
mCameraPos.y = 0;
|
||||
waterPos.y = 0;
|
||||
Ogre::Vector3 d = mCameraPos - waterPos;
|
||||
if (d.squaredLength() < 100.0f * 100.0f)
|
||||
water.mWaterNode->translate(d * 3.0f * delta);
|
||||
else
|
||||
water.mWaterNode->translate(d);
|
||||
});
|
||||
ecs.system<WaterSurface>("UpdateWater")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<WaterReady>()
|
||||
.each([](WaterSurface &water) {
|
||||
static int updateViewport = 0;
|
||||
ZoneScopedN("UpdateWaterRender");
|
||||
water.mViewports[updateViewport++]->update();
|
||||
if (updateViewport > 1)
|
||||
updateViewport = 0;
|
||||
});
|
||||
#if 0
|
||||
ecs.system<const EngineData, const WaterSurface, WaterBody>(
|
||||
"UpdateWaterBody")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<WaterReady>()
|
||||
.each([this](const EngineData &eng, const WaterSurface &water,
|
||||
WaterBody &body) {
|
||||
int i;
|
||||
#if 0
|
||||
OgreAssert(body.mWaterBody, "Water not ready");
|
||||
std::set<btCollisionObject *> currentOverlaps;
|
||||
Ogre::Vector3 waterPos =
|
||||
water.mWaterNode->_getDerivedPosition();
|
||||
Ogre::Vector3 waterBodyPos = Ogre::Bullet::convert(
|
||||
body.mWaterBody->getWorldTransform()
|
||||
.getOrigin());
|
||||
waterPos.y = 0;
|
||||
waterBodyPos.y = 0;
|
||||
Ogre::Vector3 d = waterPos - waterBodyPos;
|
||||
d.y = 0;
|
||||
if (d.squaredLength() > 10.0f * 10.0f)
|
||||
body.mWaterBody->getWorldTransform().setOrigin(
|
||||
Ogre::Bullet::convert(waterBodyPos +
|
||||
d));
|
||||
#endif
|
||||
#if 0
|
||||
btCompoundShape *mshape =
|
||||
static_cast<btCompoundShape *>(
|
||||
body.mWaterBody->getCollisionShape());
|
||||
btDispatcher *dispatch =
|
||||
eng.mWorld->getBtWorld()->getDispatcher();
|
||||
btHashedOverlappingPairCache *cache =
|
||||
body.mWaterBody->getOverlappingPairCache();
|
||||
btBroadphasePairArray &collisionPairs =
|
||||
cache->getOverlappingPairArray();
|
||||
const int numObjects = collisionPairs.size();
|
||||
std::cout << "numObjects: " << numObjects << "\n";
|
||||
std::cout
|
||||
<< "numObjects: "
|
||||
<< body.mWaterBody->getOverlappingPairs().size()
|
||||
<< "\n";
|
||||
for (int i = 0; i < numObjects; i++) {
|
||||
const btBroadphasePair &collisionPair =
|
||||
collisionPairs[i];
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
body.mShapeAabbMin =
|
||||
body.mWaterBody->getWorldTransform()
|
||||
.getOrigin() +
|
||||
btVector3(-100, -100, -100);
|
||||
body.mShapeAabbMax =
|
||||
body.mWaterBody->getWorldTransform()
|
||||
.getOrigin() +
|
||||
btVector3(100, 100, 100);
|
||||
#if 0
|
||||
body.mWaterShape->getAabb(
|
||||
body.mWaterBody->getWorldTransform(),
|
||||
body.mShapeAabbMin, body.mShapeAabbMax);
|
||||
#endif
|
||||
std::cout << "manifolds: "
|
||||
<< static_cast<WaterPhysicsAction *>(
|
||||
body.action)
|
||||
->mManifoldArray.size()
|
||||
<< "\n";
|
||||
for (int j = 0;
|
||||
j < static_cast<WaterPhysicsAction *>(body.action)
|
||||
->mManifoldArray.size();
|
||||
j++) {
|
||||
btPersistentManifold *manifold =
|
||||
static_cast<WaterPhysicsAction *>(
|
||||
body.action)
|
||||
->mManifoldArray[j];
|
||||
std::cout << "contacts: "
|
||||
<< manifold->getNumContacts() << "\n";
|
||||
if (manifold->getNumContacts() == 0)
|
||||
continue;
|
||||
const btCollisionObject *obj =
|
||||
(manifold->getBody0() ==
|
||||
body.mWaterBody) ?
|
||||
manifold->getBody1() :
|
||||
manifold->getBody0();
|
||||
btCollisionObject *nobj =
|
||||
const_cast<btCollisionObject *>(obj);
|
||||
#if 0
|
||||
if (obj->getCollisionFlags() &
|
||||
btCollisionObject::CF_STATIC_OBJECT)
|
||||
continue;
|
||||
#endif
|
||||
bool ok = false;
|
||||
Ogre::Vector3 contactPosA, contactPosB;
|
||||
float minDist = 0.0f;
|
||||
for (int p = 0; p < manifold->getNumContacts();
|
||||
p++) {
|
||||
const btManifoldPoint &pt =
|
||||
manifold->getContactPoint(p);
|
||||
float dist = pt.getDistance();
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
currentOverlaps.insert(nobj);
|
||||
if (body.mInWater.find(nobj) ==
|
||||
body.mInWater.end()) {
|
||||
/* new body */
|
||||
body.mInWater.insert(nobj);
|
||||
/* calculate proj surface */
|
||||
body.mSurface[nobj] = 100.0f;
|
||||
body.count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (std::set<btCollisionObject *>::iterator it =
|
||||
body.mInWater.begin();
|
||||
it != body.mInWater.end();) {
|
||||
btCollisionObject *obj = *it;
|
||||
if (currentOverlaps.find(obj) ==
|
||||
currentOverlaps.end()) {
|
||||
/* remove body */
|
||||
it = body.mInWater.erase(it);
|
||||
body.mSurface.erase(obj);
|
||||
body.count--;
|
||||
} else
|
||||
it++;
|
||||
}
|
||||
#endif
|
||||
});
|
||||
#endif
|
||||
}
|
||||
struct shapeParams {
|
||||
float offsetX, offsetY, offsetZ;
|
||||
@@ -698,38 +439,6 @@ struct shapeParams {
|
||||
static struct shapeParams childShapes[] = {
|
||||
{ 0.0f, 0.0f, 0.0f, 100.0f, 100.0f, 100.0f },
|
||||
};
|
||||
#if 0
|
||||
void WaterModule::createWaterShape(WaterBody *water)
|
||||
{
|
||||
int i = 0;
|
||||
btCompoundShape *shape = OGRE_NEW btCompoundShape();
|
||||
shape->setMargin(0.2f);
|
||||
{
|
||||
btVector3 inertia(0, 0, 0);
|
||||
std::vector<btScalar> masses;
|
||||
btTransform principal;
|
||||
principal.setIdentity();
|
||||
for (i = 0; i < sizeof(childShapes) / sizeof(childShapes[0]);
|
||||
i++) {
|
||||
btTransform xform;
|
||||
xform.setIdentity();
|
||||
xform.setOrigin(btVector3(childShapes[i].offsetX,
|
||||
childShapes[i].offsetY,
|
||||
childShapes[i].offsetZ));
|
||||
btBoxShape *box = OGRE_NEW btBoxShape(btVector3(
|
||||
childShapes[i].boxX, childShapes[i].boxY,
|
||||
childShapes[i].boxZ));
|
||||
water->mChildShapes.push_back(box);
|
||||
shape->addChildShape(xform, box);
|
||||
masses.push_back(0);
|
||||
}
|
||||
shape->calculatePrincipalAxisTransform(masses.data(), principal,
|
||||
inertia);
|
||||
}
|
||||
shape->recalculateLocalAabb();
|
||||
water->mWaterShape = shape;
|
||||
}
|
||||
#endif
|
||||
void WaterSurface::RenderTextureListener::preRenderTargetUpdate(
|
||||
const Ogre::RenderTargetEvent &evt)
|
||||
{
|
||||
@@ -758,254 +467,4 @@ bool WaterSurface::RenderTextureListener::renderableQueued(
|
||||
*ppTech = mSurface->mDepthTech;
|
||||
return true;
|
||||
}
|
||||
#if 0
|
||||
struct DeepPenetrationContactResultCallback : public btManifoldResult {
|
||||
DeepPenetrationContactResultCallback(
|
||||
const btCollisionObjectWrapper *body0Wrap,
|
||||
const btCollisionObjectWrapper *body1Wrap)
|
||||
: btManifoldResult(body0Wrap, body1Wrap)
|
||||
, mPenetrationDistance(0)
|
||||
, mOtherIndex(0)
|
||||
{
|
||||
}
|
||||
float mPenetrationDistance;
|
||||
int mOtherIndex;
|
||||
btVector3 mNormal, mPoint;
|
||||
void reset()
|
||||
{
|
||||
mPenetrationDistance = 0.0f;
|
||||
}
|
||||
bool hasHit()
|
||||
{
|
||||
return mPenetrationDistance < 0.0f;
|
||||
}
|
||||
virtual void addContactPoint(const btVector3 &normalOnBInWorld,
|
||||
const btVector3 &pointInWorldOnB,
|
||||
btScalar depth)
|
||||
{
|
||||
#ifdef VDEBUG
|
||||
std::cout
|
||||
<< "contact: " << Ogre::Bullet::convert(pointInWorldOnB)
|
||||
<< " " << Ogre::Bullet::convert(normalOnBInWorld)
|
||||
<< "\n";
|
||||
#endif
|
||||
if (mPenetrationDistance > depth) { // Has penetration?
|
||||
|
||||
const bool isSwapped =
|
||||
m_manifoldPtr->getBody0() !=
|
||||
m_body0Wrap->getCollisionObject();
|
||||
mPenetrationDistance = depth;
|
||||
mOtherIndex = isSwapped ? m_index0 : m_index1;
|
||||
mPoint = isSwapped ? (pointInWorldOnB +
|
||||
(normalOnBInWorld * depth)) :
|
||||
pointInWorldOnB;
|
||||
|
||||
mNormal = isSwapped ? normalOnBInWorld * -1 :
|
||||
normalOnBInWorld;
|
||||
}
|
||||
}
|
||||
};
|
||||
void WaterPhysicsAction::updateAction(btCollisionWorld *collisionWorld,
|
||||
btScalar deltaTimeStep)
|
||||
{
|
||||
collisionWorld->updateSingleAabb(mWaterBody);
|
||||
mWaterBody->getCollisionShape()->getAabb(
|
||||
mWaterBody->getWorldTransform(), mShapeAabbMin, mShapeAabbMax);
|
||||
btDispatcher *dispatch = collisionWorld->getDispatcher();
|
||||
btHashedOverlappingPairCache *cache =
|
||||
mWaterBody->getOverlappingPairCache();
|
||||
btBroadphasePairArray &collisionPairs =
|
||||
cache->getOverlappingPairArray();
|
||||
btVector3 a, b;
|
||||
collisionWorld->getBroadphase()->getAabb(
|
||||
mWaterBody->getBroadphaseHandle(), a, b);
|
||||
collisionWorld->getBroadphase()->setAabb(
|
||||
mWaterBody->getBroadphaseHandle(), mShapeAabbMin, mShapeAabbMax,
|
||||
dispatch);
|
||||
btDispatcherInfo &dispatchInfo = collisionWorld->getDispatchInfo();
|
||||
dispatch->dispatchAllCollisionPairs(cache, dispatchInfo, dispatch);
|
||||
std::set<btCollisionObject *> currentOverlaps;
|
||||
std::set<btCollisionObject *>::iterator it;
|
||||
const int numObjects = collisionPairs.size();
|
||||
#ifdef VDEBUG
|
||||
std::cout << "collision pairs: " << numObjects << "\n";
|
||||
std::cout << "MIN: " << Ogre::Bullet::convert(mShapeAabbMin) << "\n";
|
||||
std::cout << "MAX: " << Ogre::Bullet::convert(mShapeAabbMax) << "\n";
|
||||
std::cout << "MIN: " << Ogre::Bullet::convert(a) << "\n";
|
||||
std::cout << "MAX: " << Ogre::Bullet::convert(b) << "\n";
|
||||
#endif
|
||||
std::set<const btCollisionObject *> mCurrentInWater;
|
||||
/* perform narrow phase */
|
||||
for (int i = 0; i < numObjects; i++) {
|
||||
int j;
|
||||
const btBroadphasePair *collisionPairPtr =
|
||||
collisionWorld->getBroadphase()
|
||||
->getOverlappingPairCache()
|
||||
->findPair(collisionPairs[i].m_pProxy0,
|
||||
collisionPairs[i].m_pProxy1);
|
||||
if (!collisionPairPtr)
|
||||
continue;
|
||||
#ifndef USE_MANIFOLD
|
||||
const btBroadphasePair &collisionPair = *collisionPairPtr;
|
||||
const btCollisionObject *objA =
|
||||
static_cast<btCollisionObject *>(
|
||||
collisionPair.m_pProxy0->m_clientObject);
|
||||
const btCollisionObject *objB =
|
||||
static_cast<btCollisionObject *>(
|
||||
collisionPair.m_pProxy1->m_clientObject);
|
||||
#ifdef VDEBUG
|
||||
std::cout << "bodies: " << objA << " " << objB << "\n";
|
||||
std::cout << "bodies: " << objA->getCollisionShape()->getName()
|
||||
<< " " << objB->getCollisionShape()->getName()
|
||||
<< "\n";
|
||||
std::cout << "pair: " << i << " " << collisionPair.m_algorithm
|
||||
<< "\n";
|
||||
#endif
|
||||
const btCollisionObject *me, *other;
|
||||
if (objA == static_cast<btCollisionObject *>(mWaterBody)) {
|
||||
me = objA;
|
||||
other = objB;
|
||||
} else {
|
||||
me = objB;
|
||||
other = objA;
|
||||
}
|
||||
const btCollisionShape *my_shape = me->getCollisionShape();
|
||||
const btCollisionShape *other_shape =
|
||||
other->getCollisionShape();
|
||||
btCollisionObjectWrapper obA(NULL, my_shape, mWaterBody,
|
||||
mWaterBody->getWorldTransform(),
|
||||
-1, j);
|
||||
btCollisionObjectWrapper obB(NULL, other_shape, other,
|
||||
other->getWorldTransform(), -1, 0);
|
||||
btCollisionAlgorithm *algorithm = dispatch->findAlgorithm(
|
||||
&obA, &obB, NULL, BT_CONTACT_POINT_ALGORITHMS);
|
||||
#else
|
||||
btCollisionAlgorithm *algorithm = collisionPairPtr->m_algorithm;
|
||||
OgreAssert(algorithm, "No algorithm found");
|
||||
#endif
|
||||
#ifdef VDEBUG
|
||||
std::cout << "algorithm: " << algorithm << "\n";
|
||||
#endif
|
||||
#ifndef USE_MANIFOLD
|
||||
DeepPenetrationContactResultCallback contactPointResult(&obA,
|
||||
&obB);
|
||||
#ifdef VDEBUG
|
||||
std::cout << "process collision\n";
|
||||
#endif
|
||||
algorithm->processCollision(&obA, &obB,
|
||||
collisionWorld->getDispatchInfo(),
|
||||
&contactPointResult);
|
||||
algorithm->~btCollisionAlgorithm();
|
||||
dispatch->freeCollisionAlgorithm(algorithm);
|
||||
if (contactPointResult.hasHit()) {
|
||||
mCurrentInWater.insert(other);
|
||||
mInWater.insert(other);
|
||||
}
|
||||
#ifdef VDEBUG
|
||||
std::cout << "process collision done\n";
|
||||
#endif
|
||||
#else
|
||||
if (collisionPairPtr->m_algorithm)
|
||||
collisionPairPtr->m_algorithm->getAllContactManifolds(
|
||||
mManifoldArray);
|
||||
std::cout << "action: manifold: " << mManifoldArray.size()
|
||||
<< "\n";
|
||||
#endif
|
||||
#if 0
|
||||
std::cout << " "
|
||||
<< Ogre::Bullet::convert(
|
||||
collisionPair.m_pProxy0->m_aabbMin)
|
||||
<< " -> "
|
||||
<< Ogre::Bullet::convert(
|
||||
collisionPair.m_pProxy0->m_aabbMax)
|
||||
<< " VS "
|
||||
<< Ogre::Bullet::convert(
|
||||
collisionPair.m_pProxy1->m_aabbMin)
|
||||
<< " -> "
|
||||
<< Ogre::Bullet::convert(
|
||||
collisionPair.m_pProxy1->m_aabbMax)
|
||||
<< "\n";
|
||||
std::cout << "group: 0 " << std::dec
|
||||
<< collisionPair.m_pProxy0->m_collisionFilterGroup
|
||||
<< "mask: " << std::hex
|
||||
<< collisionPair.m_pProxy0->m_collisionFilterMask
|
||||
<< "\n";
|
||||
std::cout << "group: 1 " << std::dec
|
||||
<< collisionPair.m_pProxy1->m_collisionFilterGroup
|
||||
<< "mask: " << std::hex
|
||||
<< collisionPair.m_pProxy1->m_collisionFilterMask
|
||||
<< std::dec << "\n";
|
||||
if (collisionPair.m_algorithm)
|
||||
collisionPair.m_algorithm->getAllContactManifolds(
|
||||
mManifoldArray);
|
||||
std::cout << "action: manifold: " << mManifoldArray.size()
|
||||
<< "\n";
|
||||
#endif
|
||||
#ifdef USE_MANIFOLD
|
||||
for (int j = 0; j < mManifoldArray.size(); j++) {
|
||||
btPersistentManifold *manifold = mManifoldArray[j];
|
||||
std::cout << "contacts: " << manifold->getNumContacts()
|
||||
<< "\n";
|
||||
if (manifold->getNumContacts() == 0)
|
||||
continue;
|
||||
const btCollisionObject *obj =
|
||||
(manifold->getBody0() == mWaterBody) ?
|
||||
manifold->getBody1() :
|
||||
manifold->getBody0();
|
||||
btCollisionObject *nobj =
|
||||
const_cast<btCollisionObject *>(obj);
|
||||
#if 1
|
||||
if (obj->getCollisionFlags() &
|
||||
btCollisionObject::CF_STATIC_OBJECT)
|
||||
continue;
|
||||
#endif
|
||||
bool ok = false;
|
||||
Ogre::Vector3 contactPosA, contactPosB;
|
||||
float minDist = 0.0f;
|
||||
for (int p = 0; p < manifold->getNumContacts(); p++) {
|
||||
const btManifoldPoint &pt =
|
||||
manifold->getContactPoint(p);
|
||||
float dist = pt.getDistance();
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
currentOverlaps.insert(nobj);
|
||||
if (mInWater.find(nobj) == mInWater.end()) {
|
||||
/* new body */
|
||||
mInWater.insert(nobj);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
for (std::set<const btCollisionObject *>::iterator it =
|
||||
mInWater.begin();
|
||||
it != mInWater.end();) {
|
||||
const btCollisionObject *obj = *it;
|
||||
if (mCurrentInWater.find(obj) == mCurrentInWater.end()) {
|
||||
/* remove body */
|
||||
it = mInWater.erase(it);
|
||||
} else
|
||||
it++;
|
||||
}
|
||||
#ifdef VDEBUG
|
||||
std::cout << "water count: " << mInWater.size() << "\n";
|
||||
#endif
|
||||
}
|
||||
void WaterPhysicsAction::debugDraw(btIDebugDraw *debugDrawer)
|
||||
{
|
||||
}
|
||||
void WaterPhysicsAction::setupBody()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
bool WaterBody::isInWater(const btCollisionObject *body) const
|
||||
{
|
||||
return static_cast<WaterPhysicsAction *>(action)->isInWater(body);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -3,6 +3,7 @@ find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain Overlay CONFIG
|
||||
find_package(Bullet REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
find_package(OgreProcedural REQUIRED CONFIG)
|
||||
find_package(flecs REQUIRED CONFIG)
|
||||
add_library(items STATIC items.cpp harbour.cpp temple.cpp town.cpp)
|
||||
target_include_directories(items PUBLIC . ${CMAKE_SOURCE_DIR}/src/FastNoiseLite)
|
||||
target_link_libraries(items PRIVATE
|
||||
@@ -13,4 +14,5 @@ target_link_libraries(items PRIVATE
|
||||
OgreBites
|
||||
editor
|
||||
physics
|
||||
Tracy::TracyClient
|
||||
)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "StaticGeometryModule.h"
|
||||
#include "items.h"
|
||||
#include "harbour.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
namespace Items
|
||||
@@ -19,6 +20,7 @@ namespace Items
|
||||
/* This is editor function */
|
||||
static bool findPierOffset(float &offset)
|
||||
{
|
||||
ZoneScoped;
|
||||
Ogre::Vector3 basePos =
|
||||
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
|
||||
Ogre::Quaternion baseRot =
|
||||
@@ -41,7 +43,8 @@ static bool findPierOffset(float &offset)
|
||||
static bool findPierOffsetAndLengthAndDepth(float &offset, float &length,
|
||||
float &depth)
|
||||
{
|
||||
if (!findPierOffset(offset))
|
||||
ZoneScoped;
|
||||
if (!findPierOffset(offset))
|
||||
return false;
|
||||
Ogre::Vector3 basePos =
|
||||
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
|
||||
@@ -66,7 +69,8 @@ static bool findPierOffsetAndLengthAndDepth(float &offset, float &length,
|
||||
}
|
||||
static void findPierHeight(float maxLength, float &height)
|
||||
{
|
||||
Ogre::Vector3 basePos =
|
||||
ZoneScoped;
|
||||
Ogre::Vector3 basePos =
|
||||
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
|
||||
Ogre::Quaternion baseRot =
|
||||
ECS::get<EditorGizmo>().sceneNode->_getDerivedOrientation();
|
||||
@@ -86,7 +90,8 @@ static void findPierHeight(float maxLength, float &height)
|
||||
}
|
||||
static void findPierPath(float pathLength, std::vector<Ogre::Vector3> &path)
|
||||
{
|
||||
float minHeight = 0.2f;
|
||||
ZoneScoped;
|
||||
float minHeight = 0.2f;
|
||||
int i;
|
||||
Ogre::Vector3 basePos =
|
||||
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
|
||||
@@ -146,7 +151,8 @@ static void findPierPath(float pathLength, std::vector<Ogre::Vector3> &path)
|
||||
}
|
||||
bool editHarbourDistrict(nlohmann::json &jitem)
|
||||
{
|
||||
float plazzaRadius = 5.0f;
|
||||
ZoneScoped;
|
||||
float plazzaRadius = 5.0f;
|
||||
float plazzaHeight = 0.2f;
|
||||
float plazzaElevation = 0.0f;
|
||||
float centerOffset = 0.0f;
|
||||
@@ -280,7 +286,8 @@ bool editHarbourDistrict(nlohmann::json &jitem)
|
||||
}
|
||||
void createHarbourPopup(const std::pair<flecs::entity, Ogre::String> item)
|
||||
{
|
||||
bool lighthouse = false;
|
||||
ZoneScoped;
|
||||
bool lighthouse = false;
|
||||
float lighthouseDistance = 0.0f;
|
||||
float lighthouseAngle = 0.0f;
|
||||
float centerOffset = 0.0f;
|
||||
@@ -328,7 +335,8 @@ void createHarbourPopup(const std::pair<flecs::entity, Ogre::String> item)
|
||||
}
|
||||
void createHarbourItem()
|
||||
{
|
||||
Ogre::Vector3 itemPosition =
|
||||
ZoneScoped;
|
||||
Ogre::Vector3 itemPosition =
|
||||
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
|
||||
Ogre::Quaternion itemOrientation =
|
||||
ECS::get<EditorGizmo>().sceneNode->_getDerivedOrientation();
|
||||
@@ -364,7 +372,8 @@ void createHarbourItem()
|
||||
}
|
||||
void createHarbourMenu()
|
||||
{
|
||||
if (ImGui::MenuItem("Create"))
|
||||
ZoneScoped;
|
||||
if (ImGui::MenuItem("Create"))
|
||||
createHarbourItem();
|
||||
}
|
||||
}
|
||||
@@ -373,7 +382,8 @@ namespace Geometry
|
||||
void createBridge(flecs::entity e, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
int i;
|
||||
ZoneScoped;
|
||||
int i;
|
||||
Procedural::TriangleBuffer tb;
|
||||
Ogre::MaterialPtr harbourMaterial;
|
||||
harbourMaterial = Ogre::MaterialManager::getSingleton().getByName(
|
||||
@@ -545,7 +555,8 @@ void createBridge(flecs::entity e, Ogre::SceneNode *sceneNode,
|
||||
void createPier(flecs::entity e, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
Ogre::MaterialPtr harbourMaterial;
|
||||
ZoneScoped;
|
||||
Ogre::MaterialPtr harbourMaterial;
|
||||
harbourMaterial = Ogre::MaterialManager::getSingleton().getByName(
|
||||
"proceduralMaterialHarbour" +
|
||||
Ogre::StringConverter::toString(e.id()));
|
||||
@@ -705,7 +716,8 @@ void createPier(flecs::entity e, Ogre::SceneNode *sceneNode,
|
||||
void createPlazza(flecs::entity e, const nlohmann::json &district,
|
||||
Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo)
|
||||
{
|
||||
Ogre::MaterialPtr harbourMaterial;
|
||||
ZoneScoped;
|
||||
Ogre::MaterialPtr harbourMaterial;
|
||||
harbourMaterial = Ogre::MaterialManager::getSingleton().getByName(
|
||||
"proceduralMaterialHarbour" +
|
||||
Ogre::StringConverter::toString(e.id()));
|
||||
@@ -784,7 +796,8 @@ void createPlazza(flecs::entity e, const nlohmann::json &district,
|
||||
void createBuildings(flecs::entity e, const nlohmann::json &district,
|
||||
Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo)
|
||||
{
|
||||
Ogre::MaterialPtr harbourMaterial;
|
||||
ZoneScoped;
|
||||
Ogre::MaterialPtr harbourMaterial;
|
||||
harbourMaterial = Ogre::MaterialManager::getSingleton().getByName(
|
||||
"proceduralMaterialHarbour" +
|
||||
Ogre::StringConverter::toString(e.id()));
|
||||
@@ -865,7 +878,8 @@ void createBuildings(flecs::entity e, const nlohmann::json &district,
|
||||
void createHarbour(flecs::entity e, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
std::cout << "createHarbour " << e.id() << std::endl;
|
||||
ZoneScoped;
|
||||
std::cout << "createHarbour " << e.id() << std::endl;
|
||||
Ogre::MaterialPtr harbourMaterial;
|
||||
harbourMaterial = Ogre::MaterialManager::getSingleton().getByName(
|
||||
"proceduralMaterialHarbour" +
|
||||
@@ -980,4 +994,4 @@ void createHarbour(flecs::entity e, Ogre::SceneNode *sceneNode,
|
||||
geo->build();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,14 @@
|
||||
#include "temple.h"
|
||||
#include "town.h"
|
||||
#include "items.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
namespace Items
|
||||
{
|
||||
void runScriptsForAllTowns()
|
||||
{
|
||||
ZoneScoped;
|
||||
std::pair<flecs::entity, Ogre::String> selected_item;
|
||||
std::list<std::pair<flecs::entity, Ogre::String> > items;
|
||||
StaticGeometryModule::getItemsProperties(&items);
|
||||
@@ -40,7 +42,8 @@ void runScriptsForAllTowns()
|
||||
}
|
||||
void showItemPopup(const std::pair<flecs::entity, Ogre::String> &item)
|
||||
{
|
||||
Ogre::String popupLabel =
|
||||
ZoneScoped;
|
||||
Ogre::String popupLabel =
|
||||
"EditPopup" + Ogre::StringConverter::toString(item.first.id());
|
||||
if (ImGui::BeginPopup(popupLabel.c_str())) {
|
||||
Ogre::String prop =
|
||||
@@ -160,7 +163,8 @@ void showItemPopup(const std::pair<flecs::entity, Ogre::String> &item)
|
||||
}
|
||||
void showItemButtons(const std::pair<flecs::entity, Ogre::String> &item)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ZoneScoped;
|
||||
ImGui::SameLine();
|
||||
Ogre::String upd_label =
|
||||
"Update Height##" +
|
||||
Ogre::StringConverter::toString(item.first.id());
|
||||
@@ -190,7 +194,8 @@ void showItemButtons(const std::pair<flecs::entity, Ogre::String> &item)
|
||||
}
|
||||
void createItemsMenu()
|
||||
{
|
||||
if (ImGui::BeginMenu("Harbour")) {
|
||||
ZoneScoped;
|
||||
if (ImGui::BeginMenu("Harbour")) {
|
||||
Items::createHarbourMenu();
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
@@ -209,6 +214,7 @@ namespace Geometry
|
||||
{
|
||||
void setupLods(Ogre::LodConfig &config)
|
||||
{
|
||||
ZoneScoped;
|
||||
int count = 0;
|
||||
// config.advanced.useCompression = false;
|
||||
config.advanced.useVertexNormals = true;
|
||||
@@ -246,7 +252,8 @@ void setupLods(Ogre::LodConfig &config)
|
||||
|
||||
Ogre::StaticGeometry *createStaticGeometry(flecs::entity e)
|
||||
{
|
||||
Ogre::String props = e.get<TerrainItem>().properties;
|
||||
ZoneScoped;
|
||||
Ogre::String props = e.get<TerrainItem>().properties;
|
||||
nlohmann::json jp = nlohmann::json::parse(props);
|
||||
if (jp.find("type") != jp.end()) {
|
||||
Ogre::String itemType = jp["type"].get<Ogre::String>();
|
||||
@@ -264,7 +271,8 @@ Ogre::StaticGeometry *createStaticGeometry(flecs::entity e)
|
||||
}
|
||||
void createItemGeometry(flecs::entity e)
|
||||
{
|
||||
OgreAssert(!e.has<TerrainItemNode>(), "Geometry already created");
|
||||
ZoneScoped;
|
||||
OgreAssert(!e.has<TerrainItemNode>(), "Geometry already created");
|
||||
std::cout << "creating geometry for item: " << e.id() << std::endl;
|
||||
Ogre::String props = e.get<TerrainItem>().properties;
|
||||
nlohmann::json jp = nlohmann::json::parse(props);
|
||||
@@ -322,7 +330,8 @@ void createItemGeometry(flecs::entity e)
|
||||
|
||||
void destroyItemGeometry(flecs::entity e)
|
||||
{
|
||||
OgreAssert(e.has<TerrainItemNode>(), "No geometry created");
|
||||
ZoneScoped;
|
||||
OgreAssert(e.has<TerrainItemNode>(), "No geometry created");
|
||||
#if 0
|
||||
ECS::get<EngineData>().mScnMgr->destroyStaticGeometry()
|
||||
e.get<TerrainItemNode>().geo->destroy();
|
||||
@@ -333,6 +342,7 @@ void destroyItemGeometry(flecs::entity e)
|
||||
}
|
||||
void updateItemGeometry(flecs::entity e)
|
||||
{
|
||||
ZoneScoped;
|
||||
OgreAssert(e.has<TerrainItem>(), "not terrain item");
|
||||
if (e.has<TerrainItemNode>())
|
||||
destroyItemGeometry(e);
|
||||
@@ -344,7 +354,8 @@ flecs::entity createMeshGeometry(const Ogre::String &meshName,
|
||||
Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().load(
|
||||
ZoneScoped;
|
||||
Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().load(
|
||||
meshName,
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||
OgreAssert(mesh, "mesh " + meshName + " not found");
|
||||
|
||||
@@ -14,12 +14,14 @@
|
||||
#include "PhysicsModule.h"
|
||||
#include "items.h"
|
||||
#include "temple.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
namespace Items
|
||||
{
|
||||
void createTempleItem()
|
||||
{
|
||||
ZoneScoped;
|
||||
Ogre::Vector3 itemPosition =
|
||||
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
|
||||
Ogre::Quaternion itemOrientation =
|
||||
@@ -38,12 +40,14 @@ void createTempleItem()
|
||||
}
|
||||
void createTempleMenu()
|
||||
{
|
||||
if (ImGui::MenuItem("Create"))
|
||||
ZoneScoped;
|
||||
if (ImGui::MenuItem("Create"))
|
||||
createTempleItem();
|
||||
}
|
||||
void createTemplePopup(const std::pair<flecs::entity, Ogre::String> item)
|
||||
{
|
||||
float size = 40.0f;
|
||||
ZoneScoped;
|
||||
float size = 40.0f;
|
||||
float pillarRadius = 0.5f;
|
||||
float pillarHeight = 16.0f;
|
||||
int pillarCount = 20;
|
||||
@@ -88,7 +92,8 @@ namespace Geometry
|
||||
void createTemple(flecs::entity e, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
Ogre::String props = e.get<TerrainItem>().properties;
|
||||
ZoneScoped;
|
||||
Ogre::String props = e.get<TerrainItem>().properties;
|
||||
nlohmann::json jp = nlohmann::json::parse(props);
|
||||
float size = 20.0f;
|
||||
int pillarCount = 4;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "CharacterAIModule.h"
|
||||
#include "items.h"
|
||||
#include "town.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
/*
|
||||
* TODO: Create doors and handle them via script.
|
||||
@@ -32,6 +33,7 @@
|
||||
|
||||
void serializeMesh(Ogre::MeshPtr mesh, const Ogre::String &meshName)
|
||||
{
|
||||
ZoneScoped;
|
||||
Ogre::MeshSerializer meshSerializer;
|
||||
|
||||
meshSerializer.exportMesh(mesh, meshName,
|
||||
@@ -43,12 +45,14 @@ namespace Items
|
||||
{
|
||||
int64_t makeCellKey(int kx, int ky, int kz)
|
||||
{
|
||||
ZoneScoped;
|
||||
int64_t key =
|
||||
(int64_t)kx + 1024 * (int64_t)ky + 1024 * 1024 * (int64_t)kz;
|
||||
return key;
|
||||
}
|
||||
int64_t makeCellKey(const nlohmann::json &cell)
|
||||
{
|
||||
ZoneScoped;
|
||||
int64_t kx = cell["x"].get<int>();
|
||||
int64_t ky = cell["y"].get<int>();
|
||||
int64_t kz = cell["z"].get<int>();
|
||||
@@ -59,6 +63,7 @@ void displayGrid(flecs::entity e, nlohmann::json &lot, int index,
|
||||
Ogre::SceneNode *sceneNode, const Ogre::Vector3 &localPosition,
|
||||
const Ogre::Quaternion &localRotation)
|
||||
{
|
||||
ZoneScoped;
|
||||
if (lot.find("edited") == lot.end()) {
|
||||
lot["edited"] = true;
|
||||
int width = lot["width"].get<int>();
|
||||
@@ -99,7 +104,8 @@ void displayGrid(flecs::entity e, nlohmann::json &lot, int index,
|
||||
}
|
||||
void createTownItem()
|
||||
{
|
||||
Ogre::Vector3 itemPosition =
|
||||
ZoneScoped;
|
||||
Ogre::Vector3 itemPosition =
|
||||
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
|
||||
Ogre::Quaternion itemOrientation =
|
||||
ECS::get<EditorGizmo>().sceneNode->_getDerivedOrientation();
|
||||
@@ -113,11 +119,13 @@ void createTownItem()
|
||||
}
|
||||
void createTownMenu()
|
||||
{
|
||||
if (ImGui::MenuItem("Create"))
|
||||
ZoneScoped;
|
||||
if (ImGui::MenuItem("Create"))
|
||||
createTownItem();
|
||||
}
|
||||
bool editCell(const Ogre::String &cellLabel, nlohmann::json &cell)
|
||||
{
|
||||
ZoneScoped;
|
||||
bool changed = false;
|
||||
auto checkboxBit = [cellLabel, &changed](Ogre::String label,
|
||||
nlohmann::json &cell,
|
||||
@@ -190,6 +198,7 @@ struct CellsScript {
|
||||
, cells(lot["cells"])
|
||||
, fucells(lot["furniture_cells"])
|
||||
{
|
||||
ZoneScoped;
|
||||
noise.SetNoiseType(FastNoiseLite::NoiseType_OpenSimplex2);
|
||||
noise.SetSeed(310);
|
||||
noise.SetFrequency(0.01f);
|
||||
@@ -484,6 +493,7 @@ struct CellsScript {
|
||||
}
|
||||
static std::string trim(const std::string &str)
|
||||
{
|
||||
ZoneScoped;
|
||||
// Find the first character that is not a whitespace character
|
||||
const std::string ws =
|
||||
" \t\n\r\f\v"; // Common whitespace characters
|
||||
@@ -503,6 +513,7 @@ struct CellsScript {
|
||||
static std::vector<std::string> split_and_trim(const std::string &s,
|
||||
char delimiter)
|
||||
{
|
||||
ZoneScoped;
|
||||
std::vector<std::string> tokens;
|
||||
std::string token;
|
||||
std::stringstream ss(s); // Use stringstream to parse the string
|
||||
@@ -520,16 +531,19 @@ struct CellsScript {
|
||||
}
|
||||
void buildCellIndex()
|
||||
{
|
||||
ZoneScoped;
|
||||
for (auto &cell : cells)
|
||||
cell["id"] = makeCellKey(cell);
|
||||
}
|
||||
void buildFCellIndex()
|
||||
{
|
||||
ZoneScoped;
|
||||
for (auto &fucell : fucells)
|
||||
fucell["id"] = makeCellKey(fucell);
|
||||
}
|
||||
int findCell(int X, int Y, int Z)
|
||||
{
|
||||
ZoneScoped;
|
||||
int64_t key = makeCellKey(X, Y, Z);
|
||||
int result = -1;
|
||||
int i;
|
||||
@@ -544,6 +558,7 @@ struct CellsScript {
|
||||
}
|
||||
int findFCell(int X, int Y, int Z)
|
||||
{
|
||||
ZoneScoped;
|
||||
int64_t key = makeCellKey(X, Y, Z);
|
||||
int result = -1;
|
||||
int i;
|
||||
@@ -558,6 +573,7 @@ struct CellsScript {
|
||||
}
|
||||
void bitCmd(const Ogre::String &cmd, const Ogre::String &bit)
|
||||
{
|
||||
ZoneScoped;
|
||||
uint64_t flags = 0;
|
||||
std::vector<Ogre::String> bitconv = {
|
||||
"floor", "ceiling", "wallx-", "wallx+",
|
||||
@@ -589,6 +605,7 @@ struct CellsScript {
|
||||
}
|
||||
bool isBit(const Ogre::String &bit)
|
||||
{
|
||||
ZoneScoped;
|
||||
uint64_t flags = 0;
|
||||
std::vector<Ogre::String> bitconv = {
|
||||
"floor", "ceiling", "wallx-", "wallx+",
|
||||
@@ -616,6 +633,7 @@ struct CellsScript {
|
||||
}
|
||||
static bool isBit(const nlohmann::json &cell, const Ogre::String &bit)
|
||||
{
|
||||
ZoneScoped;
|
||||
uint64_t flags = 0;
|
||||
std::vector<Ogre::String> bitconv = {
|
||||
"floor", "ceiling", "wallx-", "wallx+",
|
||||
@@ -641,6 +659,7 @@ struct CellsScript {
|
||||
}
|
||||
void cell(uint64_t flags)
|
||||
{
|
||||
ZoneScoped;
|
||||
if (findCell(currentX, currentY, currentZ) == -1) {
|
||||
nlohmann::json cell;
|
||||
buildCellIndex();
|
||||
@@ -658,12 +677,14 @@ struct CellsScript {
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
ZoneScoped;
|
||||
int index = findCell(currentX, currentY, currentZ);
|
||||
if (index >= 0)
|
||||
cells.erase(index);
|
||||
}
|
||||
void clear_area(int minX, int minZ, int sizeX, int sizeZ)
|
||||
{
|
||||
ZoneScoped;
|
||||
int i, j;
|
||||
for (i = 0; i < sizeZ; i++)
|
||||
for (j = 0; j < sizeX; j++) {
|
||||
@@ -674,12 +695,14 @@ struct CellsScript {
|
||||
}
|
||||
void clear_furniture()
|
||||
{
|
||||
ZoneScoped;
|
||||
int index = findFCell(currentX, currentY, currentZ);
|
||||
if (index >= 0)
|
||||
fucells.erase(index);
|
||||
}
|
||||
void clear_furniture_area(int minX, int minZ, int sizeX, int sizeZ)
|
||||
{
|
||||
ZoneScoped;
|
||||
int i, j;
|
||||
for (i = 0; i < sizeZ; i++)
|
||||
for (j = 0; j < sizeX; j++) {
|
||||
@@ -690,6 +713,7 @@ struct CellsScript {
|
||||
}
|
||||
int room(int minX, int minZ, int sizeX, int sizeZ)
|
||||
{
|
||||
ZoneScoped;
|
||||
int i, j, ret;
|
||||
clear_area(minX, minZ, sizeX, sizeZ);
|
||||
for (i = 0; i < sizeZ; i++)
|
||||
@@ -725,6 +749,7 @@ struct CellsScript {
|
||||
int roof(int minX, int minZ, int sizeX, int sizeZ, float height,
|
||||
int type)
|
||||
{
|
||||
ZoneScoped;
|
||||
nlohmann::json roofs = nlohmann::json::array();
|
||||
if (lot.find("roofs") != lot.end())
|
||||
roofs = lot["roofs"];
|
||||
@@ -747,11 +772,13 @@ struct CellsScript {
|
||||
}
|
||||
void clear_roofs()
|
||||
{
|
||||
ZoneScoped;
|
||||
lot["roofs"] = nlohmann::json::array();
|
||||
}
|
||||
void fcell(const std::vector<Ogre::String> &tags,
|
||||
nlohmann::json furniture, int rotation)
|
||||
{
|
||||
ZoneScoped;
|
||||
nlohmann::json jtags = nlohmann::json::array();
|
||||
for (const auto &tag : tags)
|
||||
jtags.push_back(tag);
|
||||
@@ -778,6 +805,7 @@ struct CellsScript {
|
||||
nlohmann::json select_furniture(const std::vector<Ogre::String> &tags,
|
||||
const std::vector<Ogre::String> ¬ags)
|
||||
{
|
||||
ZoneScoped;
|
||||
nlohmann::json adata = nlohmann::json::array();
|
||||
ECS::get().query_builder<const FurnitureItem>().build().each(
|
||||
[&](flecs::entity e, const FurnitureItem &item) {
|
||||
@@ -826,6 +854,7 @@ struct CellsScript {
|
||||
}
|
||||
bool place_furniture(int room, Ogre::String tags)
|
||||
{
|
||||
ZoneScoped;
|
||||
bool ret = true;
|
||||
std::vector<Ogre::String> atags = split_and_trim(tags, ',');
|
||||
int i, j;
|
||||
@@ -1025,6 +1054,7 @@ struct CellsScript {
|
||||
|
||||
std::vector<std::pair<int, int> > roomEdge(int room)
|
||||
{
|
||||
ZoneScoped;
|
||||
std::vector<std::pair<int, int> > seg;
|
||||
std::set<std::pair<int, int> > seen;
|
||||
int i;
|
||||
@@ -1075,12 +1105,14 @@ out:
|
||||
}
|
||||
bool adjacent(std::pair<int, int> c1, std::pair<int, int> c2)
|
||||
{
|
||||
ZoneScoped;
|
||||
int dx = std::abs(c1.first - c2.first);
|
||||
int dz = std::abs(c1.second - c2.second);
|
||||
return (dx == 0 && dz == 1) || (dx == 1 && dz == 0);
|
||||
}
|
||||
void dumpSeg(const std::vector<std::pair<int, int> > &seg)
|
||||
{
|
||||
ZoneScoped;
|
||||
int count = 0;
|
||||
for (auto &cell : seg) {
|
||||
std::cout << count << " " << cell.first << " "
|
||||
@@ -1092,6 +1124,7 @@ out:
|
||||
std::vector<std::pair<int, int> > &ret1,
|
||||
std::vector<std::pair<int, int> > &ret2)
|
||||
{
|
||||
ZoneScoped;
|
||||
std::vector<std::pair<int, int> > room_seg = roomEdge(room);
|
||||
std::vector<std::pair<int, int> > other_seg = roomEdge(other);
|
||||
std::vector<std::pair<int, int> > ret;
|
||||
@@ -1109,6 +1142,7 @@ out:
|
||||
}
|
||||
void createExit0(int room)
|
||||
{
|
||||
ZoneScoped;
|
||||
int posX = rooms[room].minX;
|
||||
int posZ = rooms[room].minZ;
|
||||
int i;
|
||||
@@ -1137,6 +1171,7 @@ out:
|
||||
}
|
||||
void createExit1(int room)
|
||||
{
|
||||
ZoneScoped;
|
||||
int posX = rooms[room].minX;
|
||||
int posZ = rooms[room].minZ + rooms[room].sizeZ - 1;
|
||||
int i;
|
||||
@@ -1165,6 +1200,7 @@ out:
|
||||
}
|
||||
void createExit2(int room)
|
||||
{
|
||||
ZoneScoped;
|
||||
int posX = rooms[room].minX + rooms[room].sizeX - 1;
|
||||
int posZ = rooms[room].minZ;
|
||||
int i;
|
||||
@@ -1193,6 +1229,7 @@ out:
|
||||
}
|
||||
void createExit3(int room)
|
||||
{
|
||||
ZoneScoped;
|
||||
int posX = rooms[room].minX;
|
||||
int posZ = rooms[room].minZ;
|
||||
int i;
|
||||
@@ -1221,6 +1258,7 @@ out:
|
||||
}
|
||||
void createWindows(int room)
|
||||
{
|
||||
ZoneScoped;
|
||||
int posX = rooms[room].minX;
|
||||
int posZ = rooms[room].minZ;
|
||||
int i;
|
||||
@@ -1273,6 +1311,7 @@ out:
|
||||
}
|
||||
void createExterior()
|
||||
{
|
||||
ZoneScoped;
|
||||
int room;
|
||||
for (room = 0; room < rooms.size(); room++) {
|
||||
int posX = rooms[room].minX;
|
||||
@@ -1340,6 +1379,7 @@ out:
|
||||
}
|
||||
void connectRooms(int r1, int r2)
|
||||
{
|
||||
ZoneScoped;
|
||||
std::vector<std::pair<int, int> > seg1, seg2;
|
||||
int index = 0;
|
||||
adjacentCells(r1, r2, seg1, seg2);
|
||||
@@ -1459,10 +1499,12 @@ out:
|
||||
}
|
||||
virtual ~CellsScript()
|
||||
{
|
||||
ZoneScoped;
|
||||
lua_close(L);
|
||||
}
|
||||
void run()
|
||||
{
|
||||
ZoneScoped;
|
||||
int result = luaL_dostring(L, cellScript.c_str());
|
||||
if (result != LUA_OK) {
|
||||
std::cerr << "Lua script execution failed: "
|
||||
@@ -1474,6 +1516,7 @@ out:
|
||||
};
|
||||
bool editRoofs(const Ogre::String &lotLabel, nlohmann::json &lot)
|
||||
{
|
||||
ZoneScoped;
|
||||
bool changed = false;
|
||||
static int roofPosition[3] = { 0, 0 };
|
||||
static int roofSize[2] = { 1, 1 };
|
||||
@@ -1624,6 +1667,7 @@ bool editRoofs(const Ogre::String &lotLabel, nlohmann::json &lot)
|
||||
}
|
||||
bool editLot(const Ogre::String &lotLabel, nlohmann::json &lot)
|
||||
{
|
||||
ZoneScoped;
|
||||
bool changed = false;
|
||||
float angle = lot["angle"].get<float>();
|
||||
if (ImGui::SliderFloat(("Lot Angle##" + lotLabel).c_str(), &angle,
|
||||
@@ -1793,6 +1837,7 @@ bool editLot(const Ogre::String &lotLabel, nlohmann::json &lot)
|
||||
}
|
||||
void commandEraseLot(nlohmann::json &district, int lotIndex)
|
||||
{
|
||||
ZoneScoped;
|
||||
nlohmann::json lots = nlohmann::json::array();
|
||||
for (const auto &lot : district["lots"])
|
||||
lots.push_back(lot);
|
||||
@@ -1801,6 +1846,7 @@ void commandEraseLot(nlohmann::json &district, int lotIndex)
|
||||
}
|
||||
void cleanupLot(nlohmann::json &lot)
|
||||
{
|
||||
ZoneScoped;
|
||||
lot.erase("cells");
|
||||
lot.erase("furniture_cells");
|
||||
lot.erase("roofs");
|
||||
@@ -1808,6 +1854,7 @@ void cleanupLot(nlohmann::json &lot)
|
||||
void addLotTemplate(nlohmann::json &district, nlohmann::json &lotTemplates,
|
||||
int lotIndex)
|
||||
{
|
||||
ZoneScoped;
|
||||
if (district.find("lots") != district.end()) {
|
||||
nlohmann::json &lots = district["lots"];
|
||||
nlohmann::json lotTemplate = lots[lotIndex];
|
||||
@@ -1819,6 +1866,7 @@ void addLotFromTemplate(nlohmann::json &district,
|
||||
const nlohmann::json &lotTemplates,
|
||||
int lotTemplateIndex)
|
||||
{
|
||||
ZoneScoped;
|
||||
nlohmann::json lots = nlohmann::json::array();
|
||||
OgreAssert(lotTemplateIndex < lotTemplates.size() &&
|
||||
lotTemplates.size() > 0,
|
||||
@@ -1854,6 +1902,7 @@ void addLotFromTemplate(nlohmann::json &district,
|
||||
void addLot(nlohmann::json &district, float angle, int width, int depth,
|
||||
float elevation, const Ogre::String &script)
|
||||
{
|
||||
ZoneScoped;
|
||||
nlohmann::json lots = nlohmann::json::array();
|
||||
for (const auto &lot : district["lots"])
|
||||
lots.push_back(lot);
|
||||
@@ -1872,6 +1921,7 @@ void addLot(nlohmann::json &district, float angle, int width, int depth,
|
||||
bool editDistrict(const Ogre::String &districtLabel, nlohmann::json &district,
|
||||
nlohmann::json &lotTemplates)
|
||||
{
|
||||
ZoneScoped;
|
||||
bool changed = false;
|
||||
nlohmann::json lots = nlohmann::json::array();
|
||||
for (const auto &lot : district["lots"])
|
||||
@@ -1972,6 +2022,7 @@ bool editDistrict(const Ogre::String &districtLabel, nlohmann::json &district,
|
||||
}
|
||||
bool editColorRects(nlohmann::json &rects)
|
||||
{
|
||||
ZoneScoped;
|
||||
bool changed = false;
|
||||
ImGui::Text("Color Rects");
|
||||
for (auto it = rects.begin(); it != rects.end(); it++) {
|
||||
@@ -2071,6 +2122,7 @@ bool editColorRects(nlohmann::json &rects)
|
||||
}
|
||||
void runAllScriptsForTown(flecs::entity e)
|
||||
{
|
||||
ZoneScoped;
|
||||
Ogre::String prop = StaticGeometryModule::getItemProperties(e);
|
||||
nlohmann::json j = nlohmann::json::parse(prop);
|
||||
auto &districts = j["districts"];
|
||||
@@ -2092,6 +2144,7 @@ void runAllScriptsForTown(flecs::entity e)
|
||||
}
|
||||
bool editNPCs(nlohmann::json &npcs)
|
||||
{
|
||||
ZoneScoped;
|
||||
bool changed = false;
|
||||
ImGui::Text("NPC");
|
||||
int id = 0;
|
||||
@@ -2220,6 +2273,7 @@ bool editNPCs(nlohmann::json &npcs)
|
||||
}
|
||||
void createTownPopup(const std::pair<flecs::entity, Ogre::String> item)
|
||||
{
|
||||
ZoneScoped;
|
||||
Ogre::String prop = StaticGeometryModule::getItemProperties(item.first);
|
||||
Ogre::Vector3 townPosition;
|
||||
Ogre::Quaternion townRotation;
|
||||
@@ -2340,6 +2394,7 @@ struct ProcessCells {
|
||||
std::vector<struct BitSet> bits_int_corners2;
|
||||
ProcessCells()
|
||||
{
|
||||
ZoneScoped;
|
||||
bits_ext_corners = {
|
||||
{ 4 | 16, // external wall
|
||||
4.0f,
|
||||
@@ -2954,6 +3009,7 @@ struct ProcessCells {
|
||||
void clampUV(flecs::entity e, Procedural::TriangleBuffer &tb,
|
||||
const Ogre::String &rectKey)
|
||||
{
|
||||
ZoneScoped;
|
||||
Ogre::String props = e.get<TerrainItem>().properties;
|
||||
nlohmann::json jp = nlohmann::json::parse(props);
|
||||
nlohmann::json colorRects = nlohmann::json::object();
|
||||
@@ -2978,6 +3034,7 @@ void clampUV(flecs::entity e, Procedural::TriangleBuffer &tb,
|
||||
}
|
||||
Ogre::MaterialPtr createTownMaterial(flecs::entity e, bool force)
|
||||
{
|
||||
ZoneScoped;
|
||||
Ogre::MaterialPtr townMaterial;
|
||||
Ogre::String props = e.get<TerrainItem>().properties;
|
||||
nlohmann::json jp = nlohmann::json::parse(props);
|
||||
@@ -3100,6 +3157,7 @@ Ogre::MaterialPtr createTownMaterial(flecs::entity e, bool force)
|
||||
}
|
||||
void createTownWindows(flecs::entity e)
|
||||
{
|
||||
ZoneScoped;
|
||||
Ogre::MeshPtr frame1mesh =
|
||||
Ogre::MeshManager::getSingleton().getByName("window-frame1");
|
||||
if (!frame1mesh) {
|
||||
@@ -3195,6 +3253,7 @@ void createTownWindows(flecs::entity e)
|
||||
}
|
||||
void createTownDoors(flecs::entity e)
|
||||
{
|
||||
ZoneScoped;
|
||||
Ogre::MeshPtr extframe1mesh =
|
||||
Ogre::MeshManager::getSingleton().getByName(
|
||||
"external-door-frame1");
|
||||
@@ -3334,6 +3393,7 @@ struct TownTask {
|
||||
const Ogre::Vector3 &position,
|
||||
const Ogre::Quaternion &orientation)
|
||||
{
|
||||
ZoneScoped;
|
||||
Ogre::Entity *ent =
|
||||
ECS::get<EngineData>().mScnMgr->createEntity(mesh);
|
||||
ent->setMaterial(material);
|
||||
@@ -3344,6 +3404,7 @@ struct TownTask {
|
||||
const Ogre::Vector3 &position,
|
||||
const Ogre::Quaternion &orientation)
|
||||
{
|
||||
ZoneScoped;
|
||||
JPH::ShapeRefC shape =
|
||||
JoltPhysicsWrapper::getSingleton().createMeshShape(
|
||||
mesh);
|
||||
@@ -3363,6 +3424,7 @@ struct TownPlazza : TownTask {
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScopedN("createTownPlazza");
|
||||
struct QueueData {
|
||||
Procedural::TriangleBuffer tb;
|
||||
Ogre::Vector3 position;
|
||||
@@ -3409,6 +3471,7 @@ struct TownPlazza : TownTask {
|
||||
queueData,
|
||||
localPosition,
|
||||
localRotation]() {
|
||||
ZoneScoped;
|
||||
const nlohmann::json &jp = queueData->jp;
|
||||
float radius = 5.0f;
|
||||
float height = 0.2f;
|
||||
@@ -3460,6 +3523,8 @@ struct TownPlazza : TownTask {
|
||||
.getWorkQueue()
|
||||
->addMainThreadTask([queueData, localPosition,
|
||||
localRotation]() {
|
||||
ZoneScopedN(
|
||||
"createTownPlazza::MainThread");
|
||||
Ogre::Vector3 worldPlazzaCenter =
|
||||
queueData->position +
|
||||
localPosition;
|
||||
@@ -3487,10 +3552,12 @@ struct TownPlazza : TownTask {
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScoped;
|
||||
createTownPlazza(e, jdistrict, index, sceneNode, geo);
|
||||
}
|
||||
void wait()
|
||||
{
|
||||
ZoneScoped;
|
||||
if (townPlazzaComplete.valid() &&
|
||||
townPlazzaComplete.wait_for(std::chrono::seconds(0)) !=
|
||||
std::future_status::ready)
|
||||
@@ -3504,6 +3571,7 @@ struct TownLots : TownTask {
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScopedN("createTownLots");
|
||||
struct QueueData {
|
||||
Procedural::TriangleBuffer tb;
|
||||
Ogre::Vector3 position;
|
||||
@@ -3606,6 +3674,7 @@ struct TownLots : TownTask {
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask([radius,
|
||||
baseHeight,
|
||||
promise]() {
|
||||
ZoneScoped;
|
||||
std::cout << "lots count: " << lots.size() << std::endl;
|
||||
OgreAssert(lots.size() > 0, "bad lots count");
|
||||
for (auto &lot : lots) {
|
||||
@@ -3647,6 +3716,8 @@ struct TownLots : TownTask {
|
||||
Ogre::Root::getSingleton()
|
||||
.getWorkQueue()
|
||||
->addMainThreadTask([promise, radius]() {
|
||||
ZoneScopedN(
|
||||
"createTownLots::MainThread");
|
||||
float distance = radius;
|
||||
for (auto &lot : lots) {
|
||||
std::cout
|
||||
@@ -3699,10 +3770,12 @@ struct TownLots : TownTask {
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScoped;
|
||||
createTownLots(e, jdistrict, index, sceneNode, geo);
|
||||
}
|
||||
void wait()
|
||||
{
|
||||
ZoneScoped;
|
||||
if (townLotsComplete.valid() &&
|
||||
townLotsComplete.wait_for(std::chrono::seconds(0)) !=
|
||||
std::future_status::ready)
|
||||
@@ -3715,6 +3788,7 @@ struct TownCells : TownTask {
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScoped;
|
||||
struct QueueData {
|
||||
Procedural::TriangleBuffer tb;
|
||||
Ogre::Vector3 position;
|
||||
@@ -3831,6 +3905,7 @@ struct TownCells : TownTask {
|
||||
baseHeight,
|
||||
promise]() {
|
||||
{
|
||||
ZoneScoped;
|
||||
int count = 0;
|
||||
for (auto &lot : lots) {
|
||||
for (auto &jcell : lot.jlot["cells"]) {
|
||||
@@ -3877,6 +3952,7 @@ struct TownCells : TownTask {
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([radius,
|
||||
baseHeight,
|
||||
promise]() {
|
||||
ZoneScopedN("createCells::MainThread");
|
||||
int count = 0;
|
||||
for (auto &lot : lots) {
|
||||
float distance = radius;
|
||||
@@ -4012,10 +4088,12 @@ struct TownCells : TownTask {
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScoped;
|
||||
createCells(e, jdistrict, index, sceneNode, geo);
|
||||
}
|
||||
void wait()
|
||||
{
|
||||
ZoneScoped;
|
||||
if (townCellsComplete.valid() &&
|
||||
townCellsComplete.wait_for(std::chrono::seconds(0)) !=
|
||||
std::future_status::ready)
|
||||
@@ -4029,6 +4107,7 @@ struct TownRoofs : TownTask {
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScoped;
|
||||
struct QueueData {
|
||||
Procedural::TriangleBuffer tb;
|
||||
Ogre::Vector3 position;
|
||||
@@ -4146,6 +4225,7 @@ struct TownRoofs : TownTask {
|
||||
}
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask([radius,
|
||||
promise]() {
|
||||
ZoneScoped;
|
||||
for (auto &lot : lots) {
|
||||
for (auto &jroof : lot.jlot["roofs"]) {
|
||||
int roofType = jroof["type"].get<int>();
|
||||
@@ -4803,6 +4883,7 @@ struct TownRoofs : TownTask {
|
||||
}
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([radius,
|
||||
promise]() {
|
||||
ZoneScopedN("createTownRoofs::MainThread");
|
||||
{
|
||||
int count = 0;
|
||||
for (auto lot : lots) {
|
||||
@@ -4878,10 +4959,12 @@ struct TownRoofs : TownTask {
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScoped;
|
||||
createTownRoofs(e, jdistrict, index, sceneNode, geo);
|
||||
}
|
||||
void wait()
|
||||
{
|
||||
ZoneScoped;
|
||||
if (townRoofsComplete.valid() &&
|
||||
townRoofsComplete.wait_for(std::chrono::seconds(0)) !=
|
||||
std::future_status::ready)
|
||||
@@ -4896,6 +4979,7 @@ struct TownDecorateWindows : TownTask {
|
||||
Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScoped;
|
||||
// FIXME: make furniture placement a background task.
|
||||
Ogre::MaterialPtr townMaterial = createTownMaterial(e);
|
||||
const nlohmann::json &jp = jdistrict;
|
||||
@@ -5109,10 +5193,12 @@ struct TownDecorateWindows : TownTask {
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScoped;
|
||||
createDecorateWindows(e, jdistrict, index, sceneNode, geo);
|
||||
}
|
||||
void wait()
|
||||
{
|
||||
ZoneScoped;
|
||||
if (townDecorateWindowsComplete.valid() &&
|
||||
townDecorateWindowsComplete.wait_for(std::chrono::seconds(
|
||||
0)) != std::future_status::ready)
|
||||
@@ -5126,6 +5212,7 @@ struct TownDecorateDoors : TownTask {
|
||||
Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScoped;
|
||||
// FIXME: make furniture placement a background task.
|
||||
Ogre::MaterialPtr townMaterial = createTownMaterial(e);
|
||||
const nlohmann::json &jp = jdistrict;
|
||||
@@ -5423,10 +5510,12 @@ struct TownDecorateDoors : TownTask {
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScoped;
|
||||
createDecorateDoors(e, jdistrict, index, sceneNode, geo);
|
||||
}
|
||||
void wait()
|
||||
{
|
||||
ZoneScoped;
|
||||
if (townDecorateDoorsComplete.valid() &&
|
||||
townDecorateDoorsComplete.wait_for(std::chrono::seconds(
|
||||
0)) != std::future_status::ready)
|
||||
@@ -5440,6 +5529,7 @@ struct TownDecorateFurniture : TownTask {
|
||||
Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScoped;
|
||||
// FIXME: make furniture placement a background task.
|
||||
Ogre::MaterialPtr townMaterial = createTownMaterial(e);
|
||||
const nlohmann::json &jp = jdistrict;
|
||||
@@ -5862,6 +5952,7 @@ void registerTownNPCs(flecs::entity e)
|
||||
void createTown(flecs::entity e, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScopedN("createTown");
|
||||
std::cout << "createTown " << e.id() << std::endl;
|
||||
Ogre::MaterialPtr townMaterial = createTownMaterial(e);
|
||||
static std::vector<TownTask *> townTasks;
|
||||
@@ -5920,10 +6011,12 @@ void createTown(flecs::entity e, Ogre::SceneNode *sceneNode,
|
||||
}
|
||||
}
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask([geo]() {
|
||||
ZoneScoped;
|
||||
for (auto m : townTasks)
|
||||
m->wait();
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask(
|
||||
[geo]() {
|
||||
ZoneScopedN("createTown::MainThread");
|
||||
for (auto m : townTasks) {
|
||||
delete m;
|
||||
}
|
||||
|
||||
@@ -16,5 +16,5 @@ find_package(flecs REQUIRED CONFIG)
|
||||
add_library(physics STATIC physics.cpp)
|
||||
target_link_libraries(physics PUBLIC OgreMain Jolt::Jolt)
|
||||
target_include_directories(physics PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_compile_definitions(physics PRIVATE JPH_PROFILE_ENABLED)
|
||||
target_compile_definitions(physics PUBLIC JPH_DEBUG_RENDERER JPH_PROFILE_ENABLED JPH_DOUBLE_PRECISION)
|
||||
|
||||
|
||||
@@ -523,7 +523,6 @@ void ContactListener::update()
|
||||
}
|
||||
|
||||
class Physics {
|
||||
JPH::PhysicsSystem physics_system;
|
||||
// We need a temp allocator for temporary allocations during the physics update. We're
|
||||
// pre-allocating 10 MB to avoid having to do allocations during the physics update.
|
||||
// B.t.w. 10 MB is way too much for this example but it is a typical value you can use.
|
||||
@@ -550,6 +549,7 @@ class Physics {
|
||||
// Also have a look at ObjectLayerPairFilterTable or ObjectLayerPairFilterMask for a simpler interface.
|
||||
ObjectLayerPairFilterImpl object_vs_object_layer_filter;
|
||||
|
||||
JPH::PhysicsSystem physics_system;
|
||||
DebugRenderer *mDebugRenderer;
|
||||
std::map<JPH::BodyID, Ogre::SceneNode *> id2node;
|
||||
std::map<Ogre::SceneNode *, JPH::BodyID> node2id;
|
||||
@@ -573,17 +573,13 @@ public:
|
||||
std::thread::hardware_concurrency() - 1)
|
||||
, mDebugRenderer(new DebugRenderer(scnMgr, cameraNode))
|
||||
, object_vs_broadphase_layer_filter{}
|
||||
, object_vs_object_layer_filter{}
|
||||
, object_vs_object_layer_filter{}
|
||||
, debugDraw(false)
|
||||
{
|
||||
static int instanceCount = 0;
|
||||
OgreAssert(instanceCount == 0, "Bad initialisation");
|
||||
instanceCount++;
|
||||
|
||||
// Register all physics types with the factory and install their collision handlers with the CollisionDispatch class.
|
||||
// If you have your own custom shape types you probably need to register their handlers with the CollisionDispatch before calling this function.
|
||||
// If you implement your own default material (PhysicsMaterial::sDefault) make sure to initialize it before this function or else this function will create one for you.
|
||||
JPH::RegisterTypes();
|
||||
|
||||
// This is the max amount of rigid bodies that you can add to the physics system. If you try to add more you'll get an error.
|
||||
// Note: This value is low because this is a simple test. For a real project use something in the order of 65536.
|
||||
@@ -1510,6 +1506,19 @@ public:
|
||||
}
|
||||
return hadHit;
|
||||
}
|
||||
bool bodyIsCharacter(JPH::BodyID id) const
|
||||
{
|
||||
return characterBodies.find(id) != characterBodies.end();
|
||||
}
|
||||
void destroyCharacter(JPH::Character *ch)
|
||||
{
|
||||
characterBodies.erase(characterBodies.find(ch->GetBodyID()));
|
||||
characters.erase(ch);
|
||||
Ogre::SceneNode *node = id2node[ch->GetBodyID()];
|
||||
id2node.erase(ch->GetBodyID());
|
||||
node2id.erase(node);
|
||||
OGRE_DELETE ch;
|
||||
}
|
||||
};
|
||||
|
||||
void physics()
|
||||
@@ -1518,7 +1527,7 @@ void physics()
|
||||
// physics.update(1.0f / 60.0f);
|
||||
}
|
||||
|
||||
Physics *phys = nullptr;
|
||||
static std::unique_ptr<Physics> phys = nullptr;
|
||||
JoltPhysicsWrapper::JoltPhysicsWrapper(Ogre::SceneManager *scnMgr,
|
||||
Ogre::SceneNode *cameraNode)
|
||||
: Ogre::Singleton<JoltPhysicsWrapper>()
|
||||
@@ -1527,21 +1536,24 @@ JoltPhysicsWrapper::JoltPhysicsWrapper(Ogre::SceneManager *scnMgr,
|
||||
// This needs to be done before any other Jolt function is called.
|
||||
JPH::RegisterDefaultAllocator();
|
||||
|
||||
// Create a factory, this class is responsible for creating instances of classes based on their name or hash and is mainly used for deserialization of saved data.
|
||||
// It is not directly used in this example but still required.
|
||||
JPH::Factory::sInstance = new JPH::Factory();
|
||||
|
||||
// Install trace and assert callbacks
|
||||
JPH::Trace = TraceImpl;
|
||||
JPH_IF_ENABLE_ASSERTS(JPH::AssertFailed = AssertFailedImpl;)
|
||||
|
||||
|
||||
phys = new Physics(scnMgr, cameraNode, nullptr, &contacts);
|
||||
// Create a factory, this class is responsible for creating instances of classes based on their name or hash and is mainly used for deserialization of saved data.
|
||||
// It is not directly used in this example but still required.
|
||||
JPH::Factory::sInstance = new JPH::Factory();
|
||||
// Register all physics types with the factory and install their collision handlers with the CollisionDispatch class.
|
||||
// If you have your own custom shape types you probably need to register their handlers with the CollisionDispatch before calling this function.
|
||||
// If you implement your own default material (PhysicsMaterial::sDefault) make sure to initialize it before this function or else this function will create one for you.
|
||||
JPH::RegisterTypes();
|
||||
|
||||
phys = std::make_unique<Physics>(scnMgr, cameraNode, nullptr, &contacts);
|
||||
}
|
||||
|
||||
JoltPhysicsWrapper::~JoltPhysicsWrapper()
|
||||
{
|
||||
if (phys)
|
||||
delete phys;
|
||||
}
|
||||
|
||||
void JoltPhysicsWrapper::update(float dt)
|
||||
@@ -1806,5 +1818,15 @@ bool JoltPhysicsWrapper::raycastQuery(Ogre::Vector3 startPoint,
|
||||
{
|
||||
return phys->raycastQuery(startPoint, endPoint, position, id);
|
||||
}
|
||||
|
||||
bool JoltPhysicsWrapper::bodyIsCharacter(JPH::BodyID id) const
|
||||
{
|
||||
return phys->bodyIsCharacter(id);
|
||||
}
|
||||
|
||||
void JoltPhysicsWrapper::destroyCharacter(JPH::Character *ch)
|
||||
{
|
||||
phys->destroyCharacter(ch);
|
||||
}
|
||||
template <>
|
||||
JoltPhysicsWrapper *Ogre::Singleton<JoltPhysicsWrapper>::msSingleton = 0;
|
||||
|
||||
@@ -14,6 +14,7 @@ void physics();
|
||||
namespace JPH
|
||||
{
|
||||
class CharacterBase;
|
||||
class Character;
|
||||
class ContactManifold;
|
||||
class ContactSettings;
|
||||
class SubShapeIDPair;
|
||||
@@ -217,5 +218,7 @@ public:
|
||||
void removeContactListener(const JPH::BodyID &id);
|
||||
bool raycastQuery(Ogre::Vector3 startPoint, Ogre::Vector3 endPoint,
|
||||
Ogre::Vector3 &position, JPH::BodyID &id);
|
||||
bool bodyIsCharacter(JPH::BodyID id) const;
|
||||
void destroyCharacter(JPH::Character *ch);
|
||||
};
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user