Added demo project to research root motion

This commit is contained in:
2026-03-26 12:19:51 +03:00
parent 0bd98ea3e2
commit 9c2adbb698
14 changed files with 1482 additions and 1 deletions

View File

@@ -78,6 +78,7 @@ add_subdirectory(assets/blender/buildings/parts)
add_subdirectory(assets/blender/characters)
add_subdirectory(resources)
add_subdirectory(src/text_editor)
add_subdirectory(src/features)
add_executable(Game Game.cpp ${WATER_SRC})
target_include_directories(Game PRIVATE src/gamedata)

View File

@@ -13,6 +13,17 @@ foreach(DIR_NAME ${DIRECTORY_LIST})
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${DIR_NAME})
list(APPEND TARGET_PATHS ${CMAKE_CURRENT_BINARY_DIR}/${DIR_NAME})
endforeach()
set(COPY_FILES main/flare.png)
set(TARGET_FILES)
foreach(PFILE ${COPY_FILES})
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PFILE}
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/${PFILE}
${CMAKE_CURRENT_BINARY_DIR}/${PFILE}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${PFILE}
)
list(APPEND TARGET_FILES ${CMAKE_CURRENT_BINARY_DIR}/${PFILE})
endforeach()
#add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/terrain/world_map.png
# COMMAND unzip -o ${CMAKE_CURRENT_SOURCE_DIR}/world_map.kra mergedimage.png -d ${CMAKE_CURRENT_BINARY_DIR}/world_map
@@ -31,4 +42,4 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/terrain/brushes.png
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/brushes.kra)
list(APPEND TARGET_PATHS ${CMAKE_CURRENT_BINARY_DIR}/terrain/brushes.png)
add_custom_target(stage_resources ALL DEPENDS ${TARGET_PATHS})
add_custom_target(stage_resources ALL DEPENDS ${TARGET_PATHS} ${TARGET_FILES})

BIN
resources/main/flare.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

@@ -0,0 +1,19 @@
material Examples/Flare
{
technique
{
pass
{
lighting off
scene_blend add
depth_write off
diffuse vertexcolour
texture_unit
{
texture flare.png
}
}
}
}

View File

@@ -0,0 +1,3 @@
project(features)
# ...
add_subdirectory(characters)

View File

@@ -0,0 +1,33 @@
project(characters)
find_package(OGRE REQUIRED COMPONENTS Bites Paging Terrain CONFIG)
find_package(ZLIB)
find_package(SDL2)
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_executable(demo main.cpp TimeEvents.cpp)
target_link_libraries(demo OgreMain OgreBites)
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/resources.cfg"
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
add_custom_command(TARGET demo POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_BINARY_DIR}/resources"
"${CMAKE_CURRENT_BINARY_DIR}/resources"
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_CURRENT_SOURCE_DIR}/resources/main/jaiqua.mesh"
"${CMAKE_CURRENT_BINARY_DIR}/resources/main/jaiqua.mesh"
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_CURRENT_SOURCE_DIR}/resources/main/jaiqua.skeleton"
"${CMAKE_CURRENT_BINARY_DIR}/resources/main/jaiqua.skeleton"
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_CURRENT_SOURCE_DIR}/resources/main/jaiqua.material"
"${CMAKE_CURRENT_BINARY_DIR}/resources/main/jaiqua.material"
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_CURRENT_SOURCE_DIR}/resources/main/blue_jaiqua.jpg"
"${CMAKE_CURRENT_BINARY_DIR}/resources/main/blue_jaiqua.jpg"
DEPENDS "${CMAKE_BINARY_DIR}/resources"
COMMENT "Copying generated resources from root build dir to local build dir"
)

View File

@@ -0,0 +1,207 @@
//
// TimeEvents.cpp
// OGRE
//
// Created by Chilly Willy on 11/29/25.
//
#include "TimeEvents.h"
#include <algorithm>
void TimeEventDispatcher::addEventList(const TimeEventList * list)
{
if (std::find(mEventLists.begin(), mEventLists.end(), list) == mEventLists.end())
{
mEventLists.push_back(list);
}
}
void TimeEventDispatcher::removeEventList(const TimeEventList * list)
{
auto i = std::find(mEventLists.begin(), mEventLists.end(), list);
if (i != mEventLists.end())
{
mEventLists.erase(i);
}
}
void TimeEventDispatcher::addListener(TimeEventListener * listener)
{
if (std::find(mListeners.begin(), mListeners.end(), listener) == mListeners.end())
{
mListeners.push_back(listener);
}
}
void TimeEventDispatcher::removeListener(TimeEventListener * listener)
{
auto i = std::find(mListeners.begin(), mListeners.end(), listener);
if (i != mListeners.end())
{
mListeners.erase(i);
}
}
/*
lastTime, thisTime, n=loops
lastTime is the thisTime from the last frame and thisTime will be the lastTime in the next frame.
Events at those times should only be dispatched once so we should include one and exclude the other.
If we include thisTime and exclude lastTime, then we need to dispatch events before we start playing,
eg when we call setTimePosition(), and we would need to somehow know whether it should be dispatched
as Forward or Backward.
If we include lastTime and exclude thisTime, then we don't need to do anything before playing but
we need to include the length/0 when we loop or finish, which requires special handling anyway.
Looping Forward:
next lastTime
thisTime < length thisTime lastTime <= t < thisTime
thisTime = length 0 lastTime <= t <= length
thisTime > length thisTime - n * length lastTime <= t <= length ... 0 <= t < thisTime
... 0 <= t <= length
Looping Backward:
next lastTime
thisTime > 0 thisTime lastTime >= t > thisTime
thisTime = 0 0 !!! lastTime >= t >= 0
thisTime < 0 thisTime + n * length lastTime >= t >= 0 ... length >= t > thisTime
... length >= t >= 0
Not-Looping Forward:
next lastTime
thisTime < length thisTime lastTime <= t < thisTime
thisTime = length length lastTime <= t <= length
thisTime > length length lastTime <= t <= length
Not-Looping Backward:
next lastTime
thisTime > 0 thisTime lastTime >= t > thisTime
thisTime = 0 0 lastTime >= t >= 0
thisTime < 0 0 lastTime >= t >= 0
*/
void TimeEventDispatcher::dispatch(float lastTime, float thisTime, int loops, float length)
{
if ((loops > 0) || (thisTime > lastTime))
{
while (loops--)
{
dispatchForwardInclusive(lastTime, length);
lastTime = 0.0f;
}
if (thisTime >= length)
{
dispatchForwardInclusive(lastTime, length);
}
else
{
dispatchForwardExclusive(lastTime, thisTime);
}
}
else if ((loops < 0) || (thisTime < lastTime))
{
if (lastTime == 0.0f)
{
/* length mod length = 0 mod length
Either we've already been looping backward and the last frame just happened
to stop on 0, in which case we already triggered its events, or we are just
starting to to loop backward, in which case we should not trigger events at
0 until we do a full backward run through the animation. If we haven't been
looping then we would not get in here because thisTime == lastTime == 0.0f.
For the same reason we also know loops < 0.
*/
lastTime = length;
++loops;
}
while (loops++)
{
dispatchBackwardInclusive(lastTime, 0.0f);
lastTime = length;
}
if (thisTime <= 0.0f)
{
dispatchBackwardInclusive(lastTime, 0.0f);
}
else
{
dispatchBackwardExclusive(lastTime, thisTime);
}
}
else
{
// Nothing doing
}
}
void TimeEventDispatcher::dispatchForwardInclusive(float lastTime, float thisTime)
{
for (const TimeEventList * events : mEventLists)
{
for (auto ie = events->begin(); ie != events->end(); ++ie)
{
if (ie->first >= lastTime && ie->first <= thisTime)
{
dispatchEvent(ie->second, TED_FORWARD);
}
}
}
}
void TimeEventDispatcher::dispatchForwardExclusive(float lastTime, float thisTime)
{
for (const TimeEventList * events : mEventLists)
{
for (auto ie = events->begin(); ie != events->end(); ++ie)
{
if (ie->first >= lastTime && ie->first < thisTime)
{
dispatchEvent(ie->second, TED_FORWARD);
}
}
}
}
void TimeEventDispatcher::dispatchBackwardInclusive(float lastTime, float thisTime)
{
for (const TimeEventList * events : mEventLists)
{
for (auto ie = events->rbegin(); ie != events->rend(); ++ie)
{
if (ie->first <= lastTime && ie->first >= thisTime)
{
dispatchEvent(ie->second, TED_BACKWARD);
}
}
}
}
void TimeEventDispatcher::dispatchBackwardExclusive(float lastTime, float thisTime)
{
for (const TimeEventList * events : mEventLists)
{
for (auto ie = events->rbegin(); ie != events->rend(); ++ie)
{
if (ie->first <= lastTime && ie->first > thisTime)
{
dispatchEvent(ie->second, TED_BACKWARD);
}
}
}
}
void TimeEventDispatcher::dispatchEvent(const std::string & name, TimeEventDirection direction)
{
for (TimeEventListener * listener : mListeners)
{
listener->eventOccurred(name, direction);
}
}

View File

@@ -0,0 +1,58 @@
//
// TimeEvents.h
// OGRE
//
// Created by Chilly Willy on 11/29/25.
//
#ifndef INCLUDE_OGRE_TIME_EVENTS_H
#define INCLUDE_OGRE_TIME_EVENTS_H
#include <map>
#include <vector>
#include <string>
typedef std::multimap<float, std::string> TimeEventList;
enum TimeEventDirection
{
TED_FORWARD,
TED_BACKWARD,
};
class TimeEventListener
{
public:
virtual void eventOccurred(const std::string & name, TimeEventDirection direction) {}
};
class TimeEventDispatcher
{
public:
void addEventList(const TimeEventList * list);
void removeEventList(const TimeEventList * list);
void addListener(TimeEventListener * listener);
void removeListener(TimeEventListener * listener);
void dispatch(float lastTime, float thisTime, int loops, float length);
private:
void dispatchForwardInclusive(float lastTime, float thisTime);
void dispatchForwardExclusive(float lastTime, float thisTime);
void dispatchBackwardInclusive(float lastTime, float thisTime);
void dispatchBackwardExclusive(float lastTime, float thisTime);
void dispatchEvent(const std::string & name, TimeEventDirection direction);
std::vector<const TimeEventList *> mEventLists;
std::vector<TimeEventListener *> mListeners;
};
#endif /* INCLUDE_OGRE_TIME_EVENTS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,82 @@
# Ogre Core Resources
[OgreInternal]
#FileSystem=./Media/Main
FileSystem=resources/main
FileSystem=resources/shaderlib
#FileSystem=./Media/RTShaderLib
FileSystem=resources/terrain
# Resources required by OgreBites::Trays
[Essential]
#Zip=./Media/packs/SdkTrays.zip
#Zip=./Media/packs/profiler.zip
## this line will end up in the [Essential] group
#FileSystem=./Media/thumbnails
# Common sample resources needed by many of the samples.
# Rarely used resources should be separately loaded by the
# samples which require them.
[General]
FileSystem=skybox
FileSystem=resources/buildings
FileSystem=resources/buildings/parts/pier
FileSystem=resources/buildings/parts/furniture
FileSystem=resources/vehicles
FileSystem=resources/debug
FileSystem=resources/fonts
# PBR media must come before the scripts that reference it
#FileSystem=./Media/PBR
#FileSystem=./Media/PBR/filament
#FileSystem=./Media/materials/programs/GLSL
#FileSystem=./Media/materials/programs/GLSL120
#FileSystem=./Media/materials/programs/GLSL150
#FileSystem=./Media/materials/programs/GLSL400
#FileSystem=./Media/materials/programs/GLSLES
#FileSystem=./Media/materials/programs/SPIRV
#FileSystem=./Media/materials/programs/Cg
#FileSystem=./Media/materials/programs/HLSL
#FileSystem=./Media/materials/programs/HLSL_Cg
#FileSystem=./Media/materials/scripts
#FileSystem=./Media/materials/textures
#FileSystem=./Media/materials/textures/terrain
#FileSystem=./Media/models
#FileSystem=./Media/particle
#FileSystem=./Media/DeferredShadingMedia
#FileSystem=./Media/DeferredShadingMedia/DeferredShading/post
#FileSystem=./Media/PCZAppMedia
#FileSystem=./Media/materials/scripts/SSAO
#FileSystem=./Media/materials/textures/SSAO
#FileSystem=./Media/volumeTerrain
#FileSystem=./Media/CSMShadows
#Zip=./Media/packs/cubemap.zip
#Zip=./Media/packs/cubemapsJS.zip
#Zip=./Media/packs/dragon.zip
#Zip=./Media/packs/fresneldemo.zip
#Zip=./Media/packs/ogredance.zip
#Zip=./Media/packs/Sinbad.zip
#Zip=./Media/packs/skybox.zip
#Zip=./Media/volumeTerrain/volumeTerrainBig.zip
#Zip=./Media/packs/DamagedHelmet.zip
#Zip=./Media/packs/filament_shaders.zip
#[BSPWorld]
#Zip=./Media/packs/oa_rpg3dm2.pk3
#Zip=./Media/packs/ogretestmap.zip
# Materials for visual tests
#[Tests]
#FileSystem=/media/slapin/library/ogre/ogre-sdk/Tests/Media
[LuaScripts]
FileSystem=lua-scripts
#[Characters]
#FileSystem=./characters
[Audio]
FileSystem=./audio/gui
[Water]
FileSystem=water

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -0,0 +1,24 @@
material jaiqua
{
technique
{
pass
{
texture_unit
{
texture blue_jaiqua.jpg
tex_address_mode clamp
}
rtshader_system
{
// In case the system uses the RTSS, the following line will ensure
// that hardware animation is used.
// Alternatively, you can derive this information programatically via
// HardwareSkinningFactory::prepareEntityForSkinning
hardware_skinning 38 2 dual_quaternion true false
}
}
}
}

Binary file not shown.

Binary file not shown.