more neurotic changes, triangle IDs are dispatched in collision events, proper footstep sounds (to-do: make use of the physics material), Lua script can handle footsteps too (probably shouldn't because Lua invocations are kinda slow on dreamcast last I checked due to lack of LuaJIT), some other things I forgot already
This commit is contained in:
parent
595e986903
commit
02d98c1176
@ -355,7 +355,7 @@
|
||||
"ngs": true,
|
||||
"percent": 0.2,
|
||||
"slop": 0.01, // 0.005
|
||||
"max": 0.01 // 0.2
|
||||
"max": 0.2 // 0.2
|
||||
},
|
||||
"debug draw": {
|
||||
"static": false,
|
||||
|
||||
@ -31,6 +31,7 @@ if not timer:running() then timer:start() end
|
||||
|
||||
local playSound = function( key )
|
||||
local url = "/ui/" .. key .. ".wav"
|
||||
--local url = "valve://sound/ui/" .. key .. ".wav"
|
||||
soundEmitter:callHook("sound:Emit.%UID%", { filename = url })
|
||||
-- local assetLoader = scene:getComponent("Asset")
|
||||
-- assetLoader:cache(ent:formatHookName("asset:Load.%UID%"), string.resolveURI(url))
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
local ent = ent
|
||||
local scene = entities.currentScene()
|
||||
local graph = scene:getComponent("Graph")
|
||||
local metadataJson = ent:getComponent("Metadata")
|
||||
local transform = ent:getComponent("Transform")
|
||||
local physicsBody = ent:getComponent("PhysicsBody")
|
||||
local camera = ent:getComponent("Camera")
|
||||
local cameraTransform = camera:getTransform()
|
||||
|
||||
local metadata = ent:getComponent("PlayerBehavior::Metadata")
|
||||
local fixedCamera = metadataJson["camera"]["settings"]["fixed"]
|
||||
|
||||
-- setup all timers
|
||||
@ -54,23 +55,28 @@ light.metadata.power = 0
|
||||
--light.entity:setComponent("Metadata", { light = { power = 0 } })
|
||||
|
||||
-- sound emitter
|
||||
local playSound = function( key, loop )
|
||||
local playSound = function( path, loop )
|
||||
if not loop then loop = false end
|
||||
local url = "/ui/" .. key .. ".ogg"
|
||||
local uri = string.resolveURI(path)
|
||||
ent:callHook("sound:Emit.%UID%", {
|
||||
filename = string.resolveURI(url, metadataJson["system"]["root"]),
|
||||
filename = uri,
|
||||
spatial = true,
|
||||
streamed = true,
|
||||
volume = "sfx",
|
||||
loop = loop
|
||||
}, 0)
|
||||
end
|
||||
local stopSound = function( key )
|
||||
local url = "/ui/" .. key .. ".ogg"
|
||||
local stopSound = function( path )
|
||||
ent:callHook("sound:Stop.%UID%", {
|
||||
filename = string.resolveURI(url, metadataJson["system"]["root"])
|
||||
filename = string.resolveURI(path, metadataJson["system"]["root"])
|
||||
}, 0)
|
||||
end
|
||||
local playUiSound = function( key, loop )
|
||||
return playSound("/ui/" .. key .. ".ogg", loop)
|
||||
end
|
||||
local stopUiSound = function( key )
|
||||
return stopSound("/ui/" .. key .. ".ogg", loop)
|
||||
end
|
||||
|
||||
local useDistance = 6
|
||||
local pullDistance = useDistance * 4
|
||||
@ -91,7 +97,7 @@ local function tickFlashlight( transform, axes, inputs )
|
||||
timers.flashlight:reset()
|
||||
light.enabled = (light.metadata.power ~= light.power)
|
||||
light.metadata.power = light.enabled and light.power or 0
|
||||
playSound("flashlight")
|
||||
playUiSound("flashlight")
|
||||
end
|
||||
end
|
||||
|
||||
@ -129,7 +135,7 @@ local function onUse( payload )
|
||||
heldObject.momentum = Vector3f(0,0,0)
|
||||
end
|
||||
|
||||
playSound(validUse and "select" or "deny")
|
||||
playUiSound(validUse and "select" or "deny")
|
||||
end
|
||||
|
||||
local function tickUse( transform, axes, inputs )
|
||||
@ -169,7 +175,7 @@ local function tickGravGun( transform, axes, inputs )
|
||||
if timers.physcannon:elapsed() > 1.0 then
|
||||
timers.physcannon:reset()
|
||||
|
||||
playSound("phys_tooHeavy")
|
||||
playUiSound("phys_tooHeavy")
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -196,7 +202,7 @@ local function tickGravGun( transform, axes, inputs )
|
||||
heldObjectPhysicsBody:enableGravity(true)
|
||||
heldObjectPhysicsBody:applyImpulse( axes.forward * heldObjectPhysicsBody:getMass() * 50 )
|
||||
|
||||
playSound("phys_launch"..math.random(1,4))
|
||||
playUiSound("phys_launch"..math.random(1,4))
|
||||
else
|
||||
-- update rotation
|
||||
if heldObject.rotate then
|
||||
@ -228,6 +234,125 @@ local function tickGravGun( transform, axes, inputs )
|
||||
end
|
||||
end
|
||||
|
||||
local footstepTimer = 0.0
|
||||
local surfaceTypes = {
|
||||
"chainlink",
|
||||
"concrete",
|
||||
"dirt",
|
||||
"duct",
|
||||
"grass",
|
||||
"gravel",
|
||||
"hardboot_generic",
|
||||
"ladder",
|
||||
"metal",
|
||||
"metalgrate",
|
||||
"mud",
|
||||
"sand",
|
||||
"slosh",
|
||||
"snow",
|
||||
"softshoe_generic",
|
||||
"tile",
|
||||
"wade",
|
||||
"wood",
|
||||
"woodpanel"
|
||||
}
|
||||
|
||||
local playFootstepSound = function( surface, isCrouching )
|
||||
local variant = math.random(1, 4)
|
||||
local path = "valve://sound/player/footsteps/" .. surface .. tostring(variant) .. ".wav"
|
||||
local pitch = 0.95 + (math.random() * 0.10)
|
||||
local vol = 1.0
|
||||
|
||||
if isCrouching then vol = 0.5 end
|
||||
|
||||
ent:callHook("sound:Emit.%UID%", {
|
||||
filename = string.resolveURI(path, metadataJson["system"]["root"]),
|
||||
spatial = true,
|
||||
streamed = false,
|
||||
volume = vol,
|
||||
pitch = pitch,
|
||||
loop = false
|
||||
}, 0)
|
||||
end
|
||||
|
||||
local tickFootsteps = function()
|
||||
local isWalking = metadata.states.walking
|
||||
local isRunning = metadata.states.running
|
||||
local isCrouching = metadata.states.crouching
|
||||
local isFloored = metadata.states.floored
|
||||
local isNoclipped = metadata.states.noclipped
|
||||
|
||||
if not isFloored or isNoclipped then return end
|
||||
|
||||
if not isWalking then
|
||||
footstepTimer = 0.0
|
||||
return
|
||||
end
|
||||
|
||||
footstepTimer = footstepTimer - time.delta()
|
||||
if footstepTimer > 0.0 then return end
|
||||
|
||||
local surface = "concrete"
|
||||
local collisionEvents = physicsBody:getCollisionEvents()
|
||||
for i, event in ipairs( collisionEvents ) do
|
||||
if event.normal.y <= -0.7 then
|
||||
local tri = event.featureA or event.featureB
|
||||
local other = event.a == ent and event.a or event.b
|
||||
local collider = other:getCollider()
|
||||
|
||||
if tri ~= nil and collider.type == ShapeType.MESH then
|
||||
local mesh = collider:asMesh()
|
||||
local drawCommand = mesh:fetchDrawCommand( tri )
|
||||
local instance = graph:getInstance( drawCommand.instanceID )
|
||||
local materialName = string.lower( graph:getMaterialName( instance.materialID ) )
|
||||
for _, key in ipairs(surfaceTypes) do
|
||||
if string.find(materialName, key) then
|
||||
surface = key
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
playFootstepSound( surface, isCrouching )
|
||||
|
||||
|
||||
if isRunning then
|
||||
footstepTimer = 0.3
|
||||
elseif isCrouching then
|
||||
footstepTimer = 0.6
|
||||
else
|
||||
footstepTimer = 0.45
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
local tickCollisionEvents = function()
|
||||
local collisionEvents = physicsBody:getCollisionEvents()
|
||||
for i, event in ipairs(collisionEvents) do
|
||||
-- print( event.state, event.a, event.b, event.point, event.normal, event.impulse, event.featureA )
|
||||
local tri = event.featureA or event.featureB
|
||||
local other = event.a == ent and event.a or event.b
|
||||
local collider = other:getCollider()
|
||||
-- technically will always return a triangle ID if there's a mesh collider
|
||||
if tri ~= nil and collider.type == ShapeType.MESH then
|
||||
local mesh = collider:asMesh()
|
||||
local drawCommand = mesh:fetchDrawCommand( tri )
|
||||
local instance = graph:getInstance( drawCommand.instanceID )
|
||||
local material = graph:getMaterial( instance.materialID )
|
||||
local materialName = graph:getMaterialName( instance.materialID )
|
||||
if not materialName:find("tools/") and event.normal.y < -0.7 then
|
||||
local soundKey = getSurfaceSound(materialName)
|
||||
playSound("valve://sound/" .. soundKey .. ".wav", false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
-- on tick
|
||||
ent:bind( "tick", function(self)
|
||||
local inControl = scene:globalFindByName("Gui: Menu"):uid() == 0
|
||||
@ -263,13 +388,8 @@ ent:bind( "tick", function(self)
|
||||
-- update HOLP
|
||||
tickGravGun( flattenedTransform, axes, inputs )
|
||||
|
||||
-- get collision events
|
||||
--[[
|
||||
local collisionEvents = physicsBody:getCollisionEvents()
|
||||
for i, event in ipairs(collisionEvents) do
|
||||
print( event.state, event.a, event.b, event.point, event.normal, event.impulse )
|
||||
end
|
||||
]]
|
||||
-- play footsteps
|
||||
tickFootsteps()
|
||||
end )
|
||||
|
||||
-- on use
|
||||
|
||||
@ -107,6 +107,9 @@ namespace pod {
|
||||
uf::stl::vector<uf::renderer::Texture2D> shadow2Ds;
|
||||
uf::stl::vector<uf::renderer::TextureCube> shadowCubes;
|
||||
|
||||
// flattened variants
|
||||
uf::stl::vector<pod::Primitive> flattenedPrimitives;
|
||||
|
||||
struct Buffer {
|
||||
uf::renderer::Buffer camera;
|
||||
uf::renderer::Buffer drawCommands;
|
||||
@ -207,6 +210,13 @@ namespace uf {
|
||||
void UF_API reload( pod::Graph& graph );
|
||||
void UF_API reload( pod::Graph& graph, pod::Node& node );
|
||||
void UF_API reload();
|
||||
|
||||
// access helpers
|
||||
// to-do: the other storage values (although I don't foresee ever needing more)
|
||||
uf::stl::string UF_API getMaterialName( pod::Graph& graph, size_t id );
|
||||
pod::Material UF_API getMaterial( pod::Graph& graph, size_t id );
|
||||
pod::Primitive UF_API getPrimitive( pod::Graph& graph, size_t id );
|
||||
pod::Instance UF_API getInstance( pod::Graph& graph, size_t id );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -60,5 +60,14 @@ namespace {\
|
||||
#define UF_LUA_REGISTER_USERTYPE_MEMBER(member) UF_NS_GET_LAST(member), &member
|
||||
#define UF_LUA_REGISTER_USERTYPE_MEMBER_FUN(member) UF_NS_GET_LAST(member), UF_LUA_C_FUN(member)
|
||||
|
||||
#define UF_LUA_REGISTER_ENUM(type, ...) \
|
||||
namespace {\
|
||||
static uf::StaticInitialization TOKEN_PASTE(STATIC_INITIALIZATION_, __LINE__)( []{\
|
||||
ext::lua::onInitialization( []{\
|
||||
ext::lua::state.new_enum(UF_NS_GET_LAST(type), __VA_ARGS__);\
|
||||
});\
|
||||
});\
|
||||
}
|
||||
|
||||
#define UF_LUA_C_FUN(x) &x
|
||||
#define UF_LUA_WRAP_FUN(x) UF_LUA_C_FUN(x)
|
||||
@ -107,8 +107,8 @@ namespace ext {
|
||||
|
||||
struct {
|
||||
struct CommandBuffer {
|
||||
std::vector<VkCommandBuffer> commandBuffers;
|
||||
std::vector<VkFence> fences;
|
||||
uf::stl::vector<VkCommandBuffer> commandBuffers;
|
||||
uf::stl::vector<VkFence> fences;
|
||||
};
|
||||
|
||||
uf::stl::unordered_map<QueueEnum, uf::stl::unordered_map<std::thread::id, CommandBuffer>> commandBuffers;
|
||||
|
||||
@ -179,6 +179,9 @@ namespace pod {
|
||||
float accumulatedNormalImpulse = 0.0f;
|
||||
float accumulatedTangentImpulse = 0.0f;
|
||||
float accumulatedPseudoImpulse = 0.0f;
|
||||
|
||||
uint32_t featureA = (uint32_t)(-1);
|
||||
uint32_t featureB = (uint32_t)(-1);
|
||||
};
|
||||
|
||||
struct Manifold {
|
||||
@ -374,9 +377,13 @@ namespace pod {
|
||||
pod::CollisionState state = {};
|
||||
pod::PhysicsBody* a = NULL;
|
||||
pod::PhysicsBody* b = NULL;
|
||||
|
||||
pod::Vector3f point = {};
|
||||
pod::Vector3f normal = {};
|
||||
float impulse = 0;
|
||||
|
||||
uint32_t featureA = (uint32_t)(-1);
|
||||
uint32_t featureB = (uint32_t)(-1);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -62,13 +62,12 @@ bool uf::vector::equals( const T& left, const T& right ) {
|
||||
if constexpr ( simd_able_v<typename T::type_t> ) {
|
||||
return uf::simd::all( uf::simd::equals( left, right ) );
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
bool result = true;
|
||||
FOR_EACH(T::size, {
|
||||
if ( !(left[i] == right[i]) ) result = false;
|
||||
});
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
template<typename T>
|
||||
bool uf::vector::notEquals( const T& left, const T& right ) {
|
||||
@ -76,13 +75,12 @@ bool uf::vector::notEquals( const T& left, const T& right ) {
|
||||
if constexpr ( simd_able_v<typename T::type_t> ) {
|
||||
return uf::simd::all( uf::simd::notEquals( left, right ) );
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
bool result = true;
|
||||
FOR_EACH(T::size, {
|
||||
if ( !(left[i] != right[i]) ) result = false;
|
||||
});
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
template<typename T>
|
||||
bool uf::vector::less( const T& left, const T& right ) {
|
||||
@ -90,13 +88,12 @@ bool uf::vector::less( const T& left, const T& right ) {
|
||||
if constexpr ( simd_able_v<typename T::type_t> ) {
|
||||
return uf::simd::all( uf::simd::less( left, right ) );
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
bool result = true;
|
||||
FOR_EACH(T::size, {
|
||||
if ( !(left[i] < right[i]) ) result = false;
|
||||
});
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
template<typename T>
|
||||
bool uf::vector::lessEquals( const T& left, const T& right ) {
|
||||
@ -104,13 +101,12 @@ bool uf::vector::lessEquals( const T& left, const T& right ) {
|
||||
if constexpr ( simd_able_v<typename T::type_t> ) {
|
||||
return uf::simd::all( uf::simd::lessEquals( left, right ) );
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
bool result = true;
|
||||
FOR_EACH(T::size, {
|
||||
if ( !(left[i] <= right[i]) ) result = false;
|
||||
});
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
template<typename T>
|
||||
bool uf::vector::greater( const T& left, const T& right ) {
|
||||
@ -118,13 +114,12 @@ bool uf::vector::greater( const T& left, const T& right ) {
|
||||
if constexpr ( simd_able_v<typename T::type_t> ) {
|
||||
return uf::simd::all( uf::simd::greater( left, right ) );
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
bool result = true;
|
||||
FOR_EACH(T::size, {
|
||||
if ( !(left[i] > right[i]) ) result = false;
|
||||
});
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
template<typename T>
|
||||
bool uf::vector::greaterEquals( const T& left, const T& right ) {
|
||||
@ -132,13 +127,12 @@ bool uf::vector::greaterEquals( const T& left, const T& right ) {
|
||||
if constexpr ( simd_able_v<typename T::type_t> ) {
|
||||
return uf::simd::all( uf::simd::greaterEquals( left, right ) );
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
bool result = true;
|
||||
FOR_EACH(T::size, {
|
||||
if ( !(left[i] >= right[i]) ) result = false;
|
||||
});
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
template<typename T>
|
||||
bool uf::vector::isValid( const T& v ) {
|
||||
|
||||
@ -194,22 +194,15 @@ namespace uf {
|
||||
uf::Mesh::Input index;
|
||||
int32_t indirectIndex = -1;
|
||||
|
||||
uf::stl::unordered_map<uint32_t, uf::Mesh::AttributeView> attributes;
|
||||
uf::stl::unordered_map<uf::stl::string, uf::Mesh::AttributeView> attributes;
|
||||
|
||||
|
||||
bool has( uint32_t hash ) const {
|
||||
return attributes.count( hash ) > 0;
|
||||
bool has( const uf::stl::string& name ) const {
|
||||
return attributes.count( name ) > 0;
|
||||
}
|
||||
const AttributeView& operator[]( uint32_t hash ) const {
|
||||
if ( auto it = attributes.find( hash ); it != attributes.end() ) return it->second;
|
||||
UF_EXCEPTION("invalid view hash: {}", hash);
|
||||
}
|
||||
// support legacy code
|
||||
bool has( const uf::stl::string_view name ) const {
|
||||
return has( uf::algo::fnv1a( name ) );
|
||||
}
|
||||
const AttributeView& operator[]( const uf::stl::string_view name ) const {
|
||||
return operator[]( uf::algo::fnv1a( name ) );
|
||||
const AttributeView& operator[]( const uf::stl::string& name ) const {
|
||||
if ( auto it = attributes.find( name ); it != attributes.end() ) return it->second;
|
||||
UF_EXCEPTION("invalid view name: {}", name);
|
||||
}
|
||||
};
|
||||
typedef uf::stl::vector<uf::Mesh::View> views_t;
|
||||
@ -615,6 +608,10 @@ namespace uf {
|
||||
pod::Triangle UF_API fetchTriangle( const uf::Mesh::View& view, const uf::Mesh::AttributeView& indices, const uf::Mesh::AttributeView& positions, size_t triID );
|
||||
pod::TriangleWithNormal UF_API fetchTriangle( const uf::Mesh& mesh, size_t triID );
|
||||
|
||||
const pod::DrawCommand& UF_API fetchDrawCommand( const uf::Mesh& mesh, const uf::Mesh::View& view );
|
||||
const pod::DrawCommand& UF_API fetchDrawCommand( const uf::Mesh& mesh, size_t triID );
|
||||
const uf::Mesh::View* UF_API fetchView( const uf::Mesh& mesh, size_t& triID );
|
||||
|
||||
template<typename T> size_t windingOrder( uf::stl::vector<T>& vertices );
|
||||
template<typename T, typename U> size_t windingOrder( uf::stl::vector<T>& vertices, uf::stl::vector<U>& indices );
|
||||
template<typename T> void normals( uf::stl::vector<T>& vertices );
|
||||
@ -637,7 +634,7 @@ namespace uf {
|
||||
return uf::mesh::getIndex<U>( indices.data(view.index.first), index );
|
||||
}
|
||||
template<typename U> inline U& getIndex( const uf::Mesh::View& view, size_t index ) {
|
||||
return uf::mesh::getIndex<U>( view, view["indices"_hash], index );
|
||||
return uf::mesh::getIndex<U>( view, view["indices"], index );
|
||||
}
|
||||
template<typename U> inline U& getIndex( const uf::Mesh::View& view, const uf::stl::string& indices, size_t index ) {
|
||||
return uf::mesh::getIndex<U>( view, view[indices], index );
|
||||
@ -657,13 +654,13 @@ namespace uf {
|
||||
return uf::mesh::fetchIndex( indices.data(view.index.first), indices.stride(), index );
|
||||
}
|
||||
static inline size_t fetchIndex( const uf::Mesh::View& view, size_t index ) {
|
||||
return uf::mesh::fetchIndex( view, view["indices"_hash], index );
|
||||
return uf::mesh::fetchIndex( view, view["indices"], index );
|
||||
}
|
||||
static inline size_t fetchIndex( const uf::Mesh::View& view, const uf::stl::string& indices, size_t index ) {
|
||||
return uf::mesh::fetchIndex( view, view[indices], index );
|
||||
}
|
||||
static inline pod::Vector3f fetchVertex( const uf::Mesh::View& view, size_t index ) {
|
||||
return uf::mesh::fetchVertex( view, view["positions"_hash], index );
|
||||
return uf::mesh::fetchVertex( view, view["positions"], index );
|
||||
}
|
||||
static inline pod::Vector3f fetchVertex( const uf::Mesh::View& view, const uf::stl::string& positions, size_t index ) {
|
||||
return uf::mesh::fetchVertex( view, view[positions], index );
|
||||
@ -672,14 +669,14 @@ namespace uf {
|
||||
return uf::mesh::fetchTriangle( view, view[indices], view[positions], triID );
|
||||
}
|
||||
static inline pod::Triangle fetchTriangle( const uf::Mesh::View& view, size_t triID ) {
|
||||
return uf::mesh::fetchTriangle( view, view["index"_hash], view["position"_hash], triID );
|
||||
return uf::mesh::fetchTriangle( view, view["index"], view["position"], triID );
|
||||
}
|
||||
|
||||
static inline void setIndex( const uf::Mesh::View& view, const uf::Mesh::AttributeView& indices, size_t index, size_t value ) {
|
||||
return uf::mesh::setIndex( const_cast<void*>(indices.data(view.index.first)), indices.stride(), index, value );
|
||||
}
|
||||
static inline void setIndex( const uf::Mesh::View& view, size_t index, size_t value ) {
|
||||
return uf::mesh::setIndex( view, view["indices"_hash], index, value );
|
||||
return uf::mesh::setIndex( view, view["indices"], index, value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,6 +392,11 @@ void UF_API uf::initialize() {
|
||||
UF_MSG_DEBUG("Setting JSON implicit preference: {}.{}", ext::json::PREFERRED_ENCODING, ext::json::PREFERRED_COMPRESSION);
|
||||
}
|
||||
|
||||
{
|
||||
uf::stl::string name = "window:Mouse.CursorVisibility";
|
||||
UF_MSG_DEBUG( "c_str={}, str={}", uf::algo::fnv1a("window:Mouse.CursorVisibility"), uf::algo::fnv1a(name) );
|
||||
}
|
||||
|
||||
/* Arguments */ {
|
||||
bool modified = false;
|
||||
auto& arguments = uf::config["arguments"];
|
||||
|
||||
@ -567,8 +567,8 @@ void ext::GuiBehavior::tick( uf::Object& self ) {
|
||||
pod::Vector2f max = { -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max() };
|
||||
|
||||
for ( const auto& view : mesh.buffer_views ) {
|
||||
auto posView = view["position"_hash];
|
||||
auto offView = view.has("offset"_hash) ? view["offset"_hash] : uf::Mesh::AttributeView{};
|
||||
auto posView = view["position"];
|
||||
auto offView = view.has("offset") ? view["offset"] : uf::Mesh::AttributeView{};
|
||||
for ( auto i = 0; i < view.vertex.count; ++i ) {
|
||||
auto pos = uf::mesh::fetchVertex( view, posView, i );
|
||||
auto off = offView.valid() ? uf::mesh::fetchVertex( view, offView, i ) : pod::Vector3f{};
|
||||
|
||||
@ -135,6 +135,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
|
||||
auto axes = uf::transform::axes( transform );
|
||||
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& graph = scene.getComponent<pod::Graph>();
|
||||
|
||||
auto& metadata = this->getComponent<ext::PlayerBehavior::Metadata>();
|
||||
auto& metadataJson = this->getComponent<uf::Serializer>();
|
||||
@ -166,16 +167,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
|
||||
} keys;
|
||||
|
||||
|
||||
struct {
|
||||
bool deltaCrouch = false;
|
||||
bool walking = false;
|
||||
bool floored = true;
|
||||
bool noclipped = false;
|
||||
uf::stl::string menu = "";
|
||||
uf::stl::string targetAnimation = "";
|
||||
|
||||
pod::Matrix4f previous;
|
||||
} stats;
|
||||
ext::PlayerBehavior::Metadata::States stats;
|
||||
|
||||
struct {
|
||||
float move = 4;
|
||||
@ -447,6 +439,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
|
||||
physicsBody.velocity *= { speed.friction, 1, speed.friction };
|
||||
|
||||
stats.walking = (keys.forward ^ keys.backwards) || (keys.left ^ keys.right);
|
||||
stats.running = keys.running;
|
||||
|
||||
if ( stats.walking ) {
|
||||
float factor = stats.floored ? 1.0f : speed.air;
|
||||
@ -587,21 +580,27 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
|
||||
UF_MSG_DEBUG("count={}", events.size());
|
||||
}
|
||||
#endif
|
||||
|
||||
metadata.states = stats;
|
||||
metadata.states.crouching = metadata.system.crouching;
|
||||
|
||||
#if UF_USE_OPENAL
|
||||
if ( stats.floored && !stats.noclipped ) {
|
||||
if ( false && stats.floored && !stats.noclipped ) {
|
||||
if ( stats.walking ) {
|
||||
auto& emitter = this->getComponent<uf::MappedSoundEmitter>();
|
||||
int cycle = rand() % metadata.audio.footstep.list.size();
|
||||
uf::stl::string filename = metadata.audio.footstep.list[cycle];
|
||||
uf::Audio& footstep = emitter.has(filename) ? emitter.get(filename) : emitter.load(filename);
|
||||
|
||||
#if 0
|
||||
bool playing = false;
|
||||
for ( uint i = 0; i < metadata.audio.footstep.list.size(); ++i ) {
|
||||
if ( !emitter.has(metadata.audio.footstep.list[i]) ) continue;
|
||||
uf::Audio& audio = emitter.get( metadata.audio.footstep.list[i] );
|
||||
if ( audio.playing() ) playing = true;
|
||||
}
|
||||
|
||||
if ( !playing ) {
|
||||
int cycle = rand() % metadata.audio.footstep.list.size();
|
||||
uf::stl::string filename = metadata.audio.footstep.list[cycle];
|
||||
uf::Audio& footstep = emitter.has(filename) ? emitter.get(filename) : emitter.load(filename);
|
||||
|
||||
// [0, 1]
|
||||
float modulation = (rand() % 100) / 100.0;
|
||||
// [0, 0.1]
|
||||
@ -616,10 +615,84 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
|
||||
footstep.setTime( 0 );
|
||||
footstep.play();
|
||||
}
|
||||
#else
|
||||
metadata.audio.footstep.timer -= uf::physics::time::delta;
|
||||
if ( metadata.audio.footstep.timer <= 0.0f ) {
|
||||
// player/footsteps
|
||||
uf::stl::vector<uf::stl::string> surfaces = {
|
||||
"chainlink",
|
||||
"concrete",
|
||||
"dirt",
|
||||
"duct",
|
||||
"grass",
|
||||
"gravel",
|
||||
"ladder",
|
||||
"metal",
|
||||
"metalgrate",
|
||||
"mud",
|
||||
"sand",
|
||||
"slosh",
|
||||
"tile",
|
||||
"wade",
|
||||
"wood",
|
||||
"woodpanel",
|
||||
};
|
||||
uf::stl::string filename = "concrete";
|
||||
|
||||
auto events = uf::physics::getCollisionEvents( physicsBody );
|
||||
for ( const auto& event : events ) {
|
||||
if ( event.normal.y > -0.7f ) continue;
|
||||
auto triID = MIN( event.featureA, event.featureB );
|
||||
auto* other = event.a != &physicsBody ? event.a : event.b;
|
||||
if ( triID == (uint32_t)(-1) ) continue;
|
||||
if ( other->collider.type != pod::ShapeType::MESH ) continue;
|
||||
// to-do: sugar it up with a helper function
|
||||
auto& mesh = *other->collider.mesh.mesh;
|
||||
auto drawCommand = uf::mesh::fetchDrawCommand( mesh, triID );
|
||||
auto instance = uf::graph::getInstance( graph, drawCommand.instanceID );
|
||||
auto materialName = uf::graph::getMaterialName( graph, instance.materialID );
|
||||
|
||||
for ( auto& key : surfaces ) {
|
||||
if ( !uf::string::contains( materialName, key ) ) continue;
|
||||
filename = key;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
filename = ::fmt::format("valve://sound/player/footsteps/{}{}.wav", filename, (rand() % 3) + 1 );
|
||||
uf::Audio& footstep = emitter.has(filename) ? emitter.get(filename) : emitter.load(filename);
|
||||
|
||||
float pitch = 0.95f + ((rand() % 11) / 100.0f);
|
||||
float volume = metadata.audio.footstep.volume;
|
||||
|
||||
if ( metadata.system.crouching ) {
|
||||
volume *= 0.5f;
|
||||
} else if ( keys.running ) {
|
||||
volume *= 1.0f;
|
||||
}
|
||||
|
||||
footstep.setPitch( pitch );
|
||||
footstep.setVolume( volume );
|
||||
footstep.setPosition( transform.position );
|
||||
|
||||
footstep.setTime( 0 );
|
||||
footstep.play();
|
||||
|
||||
if ( keys.running ) {
|
||||
metadata.audio.footstep.timer = 0.3f;
|
||||
} else if ( metadata.system.crouching ) {
|
||||
metadata.audio.footstep.timer = 0.6f;
|
||||
} else {
|
||||
metadata.audio.footstep.timer = 0.45f;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// set animation to walk
|
||||
stats.targetAnimation = "walk";
|
||||
} else if ( !keys.jump ) {
|
||||
stats.targetAnimation = "idle_wank";
|
||||
stats.targetAnimation = "idle";
|
||||
metadata.audio.footstep.timer = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -766,4 +839,22 @@ void ext::PlayerBehavior::Metadata::deserialize( uf::Object& self, uf::Serialize
|
||||
|
||||
/*this->*/use.length = serializer["use"]["length"].as(/*this->*/use.length);
|
||||
}
|
||||
|
||||
// yikes
|
||||
#include <uf/ext/lua/component.h>
|
||||
UF_LUA_REGISTER_USERTYPE(ext::PlayerBehavior::Metadata::States,
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::PlayerBehavior::Metadata::States::walking),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::PlayerBehavior::Metadata::States::running),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::PlayerBehavior::Metadata::States::crouching),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::PlayerBehavior::Metadata::States::floored),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::PlayerBehavior::Metadata::States::noclipped),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::PlayerBehavior::Metadata::States::deltaCrouch),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::PlayerBehavior::Metadata::States::menu),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::PlayerBehavior::Metadata::States::targetAnimation),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::PlayerBehavior::Metadata::States::previous)
|
||||
)
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(ext::PlayerBehavior::Metadata,
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(ext::PlayerBehavior::Metadata::states)
|
||||
)
|
||||
#undef this
|
||||
@ -57,12 +57,25 @@ namespace ext {
|
||||
struct {
|
||||
struct {
|
||||
uf::stl::vector<uf::stl::string> list;
|
||||
float volume;
|
||||
float volume = 1;
|
||||
float timer = 0;
|
||||
} footstep;
|
||||
} audio;
|
||||
struct {
|
||||
float length = 4.0f;
|
||||
} use;
|
||||
struct States {
|
||||
bool walking = false;
|
||||
bool running = false;
|
||||
bool crouching = false;
|
||||
bool floored = true;
|
||||
bool noclipped = false;
|
||||
bool deltaCrouch = false;
|
||||
uf::stl::string menu = "";
|
||||
uf::stl::string targetAnimation = "";
|
||||
|
||||
pod::Matrix4f previous;
|
||||
} states;
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -310,9 +310,9 @@ uf::stl::vector<pod::OBB> uf::graph::obbFromSkin( const pod::Graph& graph, const
|
||||
|
||||
// iterate through mesh to fetch attributes
|
||||
for ( const auto& view : mesh.buffer_views ) {
|
||||
auto posView = view["position"_hash];
|
||||
auto jointsView = view["joints"_hash];
|
||||
auto weightView = view["weights"_hash];
|
||||
auto posView = view["position"];
|
||||
auto jointsView = view["joints"];
|
||||
auto weightView = view["weights"];
|
||||
|
||||
for ( auto i = 0; i < view.vertex.count; ++i ) {
|
||||
auto pos = uf::mesh::fetchVertex( view, posView, i );
|
||||
|
||||
@ -782,6 +782,7 @@ void uf::graph::process( pod::Graph& graph ) {
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& sceneMetadataJson = scene.getComponent<uf::Serializer>();
|
||||
auto& graphMetadataJson = graph.metadata;
|
||||
auto& graphMetadataValve = graphMetadataJson["valve"];
|
||||
auto& storage = uf::graph::getStorage( graph );
|
||||
|
||||
// merge light settings with global settings
|
||||
@ -997,6 +998,15 @@ void uf::graph::process( pod::Graph& graph ) {
|
||||
UF_DEBUG_TIMER_MULTITRACE("Patching textures/materials");
|
||||
for ( auto& name : graph.materials ) {
|
||||
auto& material = storage.materials[name];
|
||||
|
||||
//
|
||||
if ( ext::json::isObject( graphMetadataValve ) ) {
|
||||
// nodraw
|
||||
if ( name.starts_with("tools/") ) {
|
||||
material.colorBase.w = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
auto tag = ext::json::find( name, graphMetadataJson["tags"] );
|
||||
if ( ext::json::isObject( tag ) ) {
|
||||
material.colorBase = uf::vector::decode( tag["material"]["base"], material.colorBase);
|
||||
@ -1264,7 +1274,8 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
|
||||
float baseMass = graph.metadata["valve"]["models"][meshName]["mass"].as<float>(1.0f);
|
||||
float massScale = metadataValve["massScale"].as<float>(1.0f);
|
||||
// flag as static
|
||||
if ( node.name.starts_with("prop_static") || motionDisabled ) massScale = 0;
|
||||
// if ( node.name.starts_with("prop_static") || motionDisabled ) massScale = 0;
|
||||
massScale = 0;
|
||||
float mass = baseMass * massScale;
|
||||
|
||||
node.metadata["physics"]["type"] = "mesh";
|
||||
@ -1622,6 +1633,8 @@ bool uf::graph::tick( pod::Graph::Storage& storage ) {
|
||||
rebuild = storage.buffers.object.update( (const void*) objects.data(), objects.size() * sizeof(pod::Instance::Object) ) || rebuild;
|
||||
|
||||
if ( storage.stale ) {
|
||||
storage.flattenedPrimitives.clear();
|
||||
|
||||
for ( auto& key : storage.primitives.keys ) {
|
||||
auto& primitives = storage.primitives.map[key];
|
||||
auto& grouped = storage.instances.map[key];
|
||||
@ -1651,7 +1664,9 @@ bool uf::graph::tick( pod::Graph::Storage& storage ) {
|
||||
|
||||
for ( size_t i = 0; i < count; ++i ) {
|
||||
size_t strideIndex = (i * primitives.size()) + drawID;
|
||||
instances.emplace_back( grouped[strideIndex] );
|
||||
|
||||
auto& p = storage.flattenedPrimitives.emplace_back( primitive );
|
||||
p.instance = instances.emplace_back( grouped[strideIndex] );
|
||||
addresses.emplace_back( primitive.addresses );
|
||||
}
|
||||
}
|
||||
@ -2398,4 +2413,24 @@ void uf::graph::update( pod::Graph& graph, float delta ) {
|
||||
#endif
|
||||
|
||||
uf::graph::updateAnimation( graph, delta );
|
||||
}
|
||||
|
||||
uf::stl::string uf::graph::getMaterialName( pod::Graph& graph, size_t materialID ) {
|
||||
auto& storage = uf::graph::getStorage( graph );
|
||||
if ( !(0 <= materialID && materialID < storage.materials.keys.size() ) ) return "";
|
||||
return storage.materials.keys[materialID];
|
||||
}
|
||||
pod::Material uf::graph::getMaterial( pod::Graph& graph, size_t materialID ) {
|
||||
auto key = uf::graph::getMaterialName( graph, materialID );
|
||||
return storage.materials.map[key];
|
||||
}
|
||||
|
||||
pod::Primitive uf::graph::getPrimitive( pod::Graph& graph, size_t primitiveID ) {
|
||||
auto& storage = uf::graph::getStorage( graph );
|
||||
if ( !(0 <= primitiveID && primitiveID < storage.flattenedPrimitives.size() ) ) return {};
|
||||
return storage.flattenedPrimitives[primitiveID];
|
||||
}
|
||||
pod::Instance uf::graph::getInstance( pod::Graph& graph, size_t instanceID ) {
|
||||
auto primitive = uf::graph::getPrimitive( graph, instanceID );
|
||||
return primitive.instance;
|
||||
}
|
||||
@ -47,6 +47,8 @@ namespace {
|
||||
targetOffset = offset;
|
||||
} else if ( (int)origin == 1 ) {
|
||||
targetOffset = (long long)ctx->currentOffset + offset;
|
||||
} else if ( (int)origin == 2 ) {
|
||||
targetOffset = (long long)ctx->totalSize + offset;
|
||||
}
|
||||
|
||||
if (targetOffset < 0) targetOffset = 0;
|
||||
@ -177,7 +179,7 @@ void ext::wav::load(uf::Audio::Metadata& metadata) {
|
||||
if (metadata.settings.streamed) return ext::wav::stream(metadata);
|
||||
// read all PCM data
|
||||
size_t totalBytes = (size_t) metadata.info.size;
|
||||
std::vector<uint8_t> bytes(totalBytes);
|
||||
uf::stl::vector<uint8_t> bytes(totalBytes);
|
||||
|
||||
size_t bytesRead = funs::read(bytes.data(), 1, totalBytes, &metadata);
|
||||
if (bytesRead < totalBytes) {
|
||||
|
||||
63
engine/src/ext/lua/usertypes/graph.cpp
Normal file
63
engine/src/ext/lua/usertypes/graph.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include <uf/ext/lua/lua.h>
|
||||
#if UF_USE_LUA
|
||||
#include <uf/engine/graph/graph.h>
|
||||
|
||||
namespace binds {
|
||||
uf::stl::string getMaterialName( pod::Graph& self, size_t id ) {
|
||||
return uf::graph::getMaterialName( self, id );
|
||||
}
|
||||
pod::Material getMaterial( pod::Graph& self, size_t id ) {
|
||||
return uf::graph::getMaterial( self, id );
|
||||
}
|
||||
pod::Primitive getPrimitive( pod::Graph& self, size_t id ) {
|
||||
return uf::graph::getPrimitive( self, id );
|
||||
}
|
||||
pod::Instance getInstance( pod::Graph& self, size_t id ) {
|
||||
return uf::graph::getInstance( self, id );
|
||||
}
|
||||
}
|
||||
|
||||
#include <uf/ext/lua/component.h>
|
||||
UF_LUA_REGISTER_USERTYPE(pod::DrawCommand,
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::DrawCommand::indices),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::DrawCommand::instances),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::DrawCommand::indexID),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::DrawCommand::vertexID),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::DrawCommand::instanceID),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::DrawCommand::materialID)
|
||||
)
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE(pod::Instance,
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Instance::materialID),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Instance::primitiveID),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Instance::objectID)
|
||||
)
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE(pod::Primitive,
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Primitive::drawCommand),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Primitive::instance)
|
||||
)
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE(pod::Material,
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Material::colorBase),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Material::colorEmissive),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Material::factorMetallic),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Material::factorRoughness),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Material::factorOcclusion),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Material::factorAlphaCutoff),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Material::indexAlbedo),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Material::indexNormal),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Material::indexEmissive),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Material::indexOcclusion),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Material::indexMetallicRoughness),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Material::modeCull),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Material::modeAlpha)
|
||||
)
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Graph,
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( getMaterialName, UF_LUA_C_FUN( ::binds::getMaterialName ) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( getMaterial, UF_LUA_C_FUN( ::binds::getMaterial ) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( getPrimitive, UF_LUA_C_FUN( ::binds::getPrimitive ) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( getInstance, UF_LUA_C_FUN( ::binds::getInstance ) )
|
||||
)
|
||||
#endif
|
||||
@ -6,10 +6,56 @@ namespace binds {
|
||||
void updateDescriptor( uf::Mesh& self ) {
|
||||
self.updateDescriptor();
|
||||
}
|
||||
|
||||
std::tuple<const uf::Mesh::View*, size_t> fetchView( uf::Mesh& self, size_t triID ) {
|
||||
const auto* view = uf::mesh::fetchView( self, triID );
|
||||
return std::make_tuple( view, triID );
|
||||
}
|
||||
const pod::DrawCommand& fetchDrawCommand( uf::Mesh& mesh, size_t triID ) {
|
||||
return uf::mesh::fetchDrawCommand( mesh, triID );
|
||||
}
|
||||
|
||||
size_t fetchIndex( const uf::Mesh::View& view, const uf::stl::string& name, size_t index ) {
|
||||
return uf::mesh::fetchIndex( view, name, index );
|
||||
}
|
||||
|
||||
uf::stl::vector<float> fetchVertexAttribute( const uf::Mesh::View& view, const uf::stl::string& name, size_t index ) {
|
||||
uf::stl::vector<float> res;
|
||||
if ( !view.has( name ) ) return res;
|
||||
const auto& attr = view[name];
|
||||
if ( !attr.valid() ) return res;
|
||||
|
||||
size_t comps = attr.components();
|
||||
auto type = attr.type();
|
||||
|
||||
const uint8_t* ptr = static_cast<const uint8_t*>(attr.data(view.vertex.first + index));
|
||||
|
||||
for ( size_t i = 0; i < comps; ++i ) {
|
||||
switch ( type ) {
|
||||
case uf::renderer::enums::Type::BYTE: res.emplace_back( (float)( reinterpret_cast<const int8_t*>(ptr)[i] ) ); break;
|
||||
case uf::renderer::enums::Type::UBYTE: res.emplace_back( (float)( reinterpret_cast<const uint8_t*>(ptr)[i] ) ); break;
|
||||
case uf::renderer::enums::Type::SHORT: res.emplace_back( (float)( reinterpret_cast<const int16_t*>(ptr)[i] ) ); break;
|
||||
case uf::renderer::enums::Type::USHORT: res.emplace_back( (float)( reinterpret_cast<const uint16_t*>(ptr)[i] ) ); break;
|
||||
case uf::renderer::enums::Type::INT: res.emplace_back( (float)( reinterpret_cast<const int32_t*>(ptr)[i] ) ); break;
|
||||
case uf::renderer::enums::Type::UINT: res.emplace_back( (float)( reinterpret_cast<const uint32_t*>(ptr)[i] ) ); break;
|
||||
case uf::renderer::enums::Type::FLOAT: res.emplace_back( (float)( reinterpret_cast<const float*>(ptr)[i] ) ); break;
|
||||
case uf::renderer::enums::Type::DOUBLE: res.emplace_back( (float)( reinterpret_cast<const double*>(ptr)[i] ) ); break;
|
||||
default: res.emplace_back( 0.0 ); break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
#include <uf/ext/lua/component.h>
|
||||
UF_LUA_REGISTER_USERTYPE(uf::Mesh::View,
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(uf::Mesh::View::indirectIndex)
|
||||
)
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(uf::Mesh,
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( updateDescriptor, UF_LUA_C_FUN( ::binds::updateDescriptor ) )
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( updateDescriptor, UF_LUA_C_FUN( ::binds::updateDescriptor ) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( fetchView, UF_LUA_C_FUN( ::binds::fetchView ) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( fetchDrawCommand, UF_LUA_C_FUN( ::binds::fetchDrawCommand ) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( fetchIndex, UF_LUA_C_FUN( ::binds::fetchIndex ) )
|
||||
)
|
||||
#endif
|
||||
@ -5,6 +5,8 @@
|
||||
namespace binds {
|
||||
namespace body {
|
||||
bool initialized( pod::PhysicsBody& self ) { return !!self.world; }
|
||||
uf::Object* getObject( pod::PhysicsBody& self ) { return self.object; }
|
||||
pod::Collider& getCollider( pod::PhysicsBody& self ) { return self.collider; }
|
||||
pod::Vector3f& getVelocity( pod::PhysicsBody& self ) { return self.velocity; }
|
||||
pod::Vector3f& getAngularVelocity( pod::PhysicsBody& self ) { return self.angularVelocity; }
|
||||
|
||||
@ -79,6 +81,32 @@ namespace binds {
|
||||
return uf::physics::unconstrain( body );
|
||||
}
|
||||
}
|
||||
namespace collider {
|
||||
const pod::AABB& asAabb( pod::Collider& self ) {
|
||||
UF_ASSERT( self.type == pod::ShapeType::AABB );
|
||||
return self.aabb;
|
||||
}
|
||||
const pod::OBB& asObb( pod::Collider& self ) {
|
||||
UF_ASSERT( self.type == pod::ShapeType::OBB );
|
||||
return self.obb;
|
||||
}
|
||||
const pod::Sphere& asSphere( pod::Collider& self ) {
|
||||
UF_ASSERT( self.type == pod::ShapeType::SPHERE );
|
||||
return self.sphere;
|
||||
}
|
||||
const pod::Plane& asPlane( pod::Collider& self ) {
|
||||
UF_ASSERT( self.type == pod::ShapeType::PLANE );
|
||||
return self.plane;
|
||||
}
|
||||
const pod::Capsule& asCapsule( pod::Collider& self ) {
|
||||
UF_ASSERT( self.type == pod::ShapeType::CAPSULE );
|
||||
return self.capsule;
|
||||
}
|
||||
const uf::Mesh& asMesh( pod::Collider& self ) {
|
||||
UF_ASSERT( self.type == pod::ShapeType::MESH );
|
||||
return *self.mesh.mesh;
|
||||
}
|
||||
}
|
||||
namespace constraint {
|
||||
void setLimits( pod::Constraint& self, float lower, float upper ) {
|
||||
return uf::physics::setConstraintLimits( self, lower, upper );
|
||||
@ -112,13 +140,38 @@ namespace binds {
|
||||
|
||||
#include <uf/ext/lua/component.h>
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::CollisionEvent,
|
||||
UF_LUA_REGISTER_ENUM(pod::ShapeType,
|
||||
"AABB", pod::ShapeType::AABB,
|
||||
"OBB", pod::ShapeType::OBB,
|
||||
"SPHERE", pod::ShapeType::SPHERE,
|
||||
"PLANE", pod::ShapeType::PLANE,
|
||||
"CAPSULE", pod::ShapeType::CAPSULE,
|
||||
"TRIANGLE", pod::ShapeType::TRIANGLE,
|
||||
"MESH", pod::ShapeType::MESH,
|
||||
"CONVEX_HULL", pod::ShapeType::CONVEX_HULL
|
||||
)
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE(pod::Collider,
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Collider::type),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Collider::category),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Collider::mask),
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asAabb, UF_LUA_C_FUN(::binds::collider::asAabb) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asObb, UF_LUA_C_FUN(::binds::collider::asObb) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asSphere, UF_LUA_C_FUN(::binds::collider::asSphere) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asPlane, UF_LUA_C_FUN(::binds::collider::asPlane) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asCapsule, UF_LUA_C_FUN(::binds::collider::asCapsule) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asMesh, UF_LUA_C_FUN(::binds::collider::asMesh) )
|
||||
)
|
||||
UF_LUA_REGISTER_USERTYPE(pod::CollisionEvent,
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::state),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::a),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::b),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::point),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::normal),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::impulse)
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::impulse),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::featureA),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::featureB)
|
||||
)
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::AABB,
|
||||
sol::call_constructor, sol::initializers(
|
||||
@ -162,7 +215,7 @@ UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::OBB,
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::OBB::extent),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::OBB::center)
|
||||
)
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Sphere,
|
||||
UF_LUA_REGISTER_USERTYPE(pod::Sphere,
|
||||
sol::call_constructor, sol::initializers(
|
||||
[]( pod::Sphere& self ) {
|
||||
return self = {};
|
||||
@ -176,7 +229,7 @@ UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Sphere,
|
||||
),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Sphere::radius)
|
||||
)
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Capsule,
|
||||
UF_LUA_REGISTER_USERTYPE(pod::Capsule,
|
||||
sol::call_constructor, sol::initializers(
|
||||
[]( pod::Capsule& self ) {
|
||||
return self = {};
|
||||
@ -192,7 +245,7 @@ UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Capsule,
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Capsule::radius),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Capsule::up)
|
||||
)
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Plane,
|
||||
UF_LUA_REGISTER_USERTYPE(pod::Plane,
|
||||
sol::call_constructor, sol::initializers(
|
||||
[]( pod::Plane& self ) {
|
||||
return self = {};
|
||||
@ -207,7 +260,7 @@ UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Plane,
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Plane::normal),
|
||||
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Plane::offset)
|
||||
)
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Ray,
|
||||
UF_LUA_REGISTER_USERTYPE(pod::Ray,
|
||||
sol::call_constructor, sol::initializers(
|
||||
[]( pod::Ray& self ) {
|
||||
return self = {};
|
||||
@ -225,6 +278,8 @@ UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Ray,
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::PhysicsBody,
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( initialized, UF_LUA_C_FUN(::binds::body::initialized) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( getObject, UF_LUA_C_FUN(::binds::body::getObject) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( getCollider, UF_LUA_C_FUN(::binds::body::getCollider) ),
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( getVelocity, UF_LUA_C_FUN(::binds::body::getVelocity) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( setVelocity, UF_LUA_C_FUN(::binds::body::setVelocity) ),
|
||||
@ -258,7 +313,7 @@ UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::PhysicsBody,
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( unconstrain, UF_LUA_C_FUN(::binds::body::unconstrain) )
|
||||
)
|
||||
|
||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::Constraint,
|
||||
UF_LUA_REGISTER_USERTYPE(pod::Constraint,
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( setLimits, UF_LUA_C_FUN(::binds::constraint::setLimits) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asBallSocket, UF_LUA_C_FUN(::binds::constraint::asBallSocket) ),
|
||||
UF_LUA_REGISTER_USERTYPE_DEFINE( asConeTwist, UF_LUA_C_FUN(::binds::constraint::asConeTwist) ),
|
||||
|
||||
@ -210,6 +210,7 @@ bool ext::valve::loadVpk( pod::VpkArchive& vpk, const uf::stl::string& path ) {
|
||||
|
||||
// read data
|
||||
auto& entry = vpk.files[fullPath];
|
||||
//UF_MSG_DEBUG("path={}, entry={}", path, fullPath);
|
||||
if ( !readBytes(&entry.metadata, sizeof(pod::VpkData)) ) return false;
|
||||
|
||||
if ( entry.metadata.preloadBytes > 0 ) {
|
||||
|
||||
@ -1142,7 +1142,7 @@ void ext::vulkan::Device::initialize() {
|
||||
uf::stl::vector<VkDeviceQueueCreateInfo> queueCreateInfos{};
|
||||
// Get queue family indices for the requested queue family types
|
||||
// Note that the indices may overlap depending on the implementation
|
||||
std::vector<std::vector<float>> queuePriorities;
|
||||
uf::stl::vector<uf::stl::vector<float>> queuePriorities;
|
||||
|
||||
// Graphics queue
|
||||
if ( requestedQueueTypes & VK_QUEUE_GRAPHICS_BIT ) {
|
||||
@ -1181,7 +1181,7 @@ void ext::vulkan::Device::initialize() {
|
||||
uint32_t maxSupported = queueFamilyProperties[familyIndex].queueCount;
|
||||
uint32_t actualCount = std::min( requestedCount, maxSupported );
|
||||
|
||||
queuePriorities.emplace_back(std::vector<float>(actualCount, 1.0f));
|
||||
queuePriorities.emplace_back(uf::stl::vector<float>(actualCount, 1.0f));
|
||||
|
||||
VkDeviceQueueCreateInfo queueInfo{};
|
||||
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
|
||||
@ -211,7 +211,7 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes
|
||||
const uint32_t sbtSize = groupCount * handleSizeAligned;
|
||||
const VkBufferUsageFlags bufferUsageFlags = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
|
||||
std::vector<uint8_t> shaderHandleStorage(sbtSize);
|
||||
uf::stl::vector<uint8_t> shaderHandleStorage(sbtSize);
|
||||
VK_CHECK_RESULT(vkGetRayTracingShaderGroupHandlesKHR(device, pipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()));
|
||||
|
||||
requestedAlignment = rayTracingPipelineProperties.shaderGroupBaseAlignment;
|
||||
|
||||
@ -213,7 +213,7 @@ uf::stl::string ext::vulkan::retrieveCheckpoint( VkQueue queue ) {
|
||||
uint32_t size = 0;
|
||||
vkGetQueueCheckpointDataNV(queue, &size, 0);
|
||||
|
||||
std::vector<VkCheckpointDataNV> checkpoints(size, { VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV });
|
||||
uf::stl::vector<VkCheckpointDataNV> checkpoints(size, { VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV });
|
||||
vkGetQueueCheckpointDataNV(queue, &size, checkpoints.data());
|
||||
|
||||
uf::stl::vector<uf::stl::string> strings;
|
||||
|
||||
@ -68,9 +68,9 @@ size_t ext::xatlas::unwrap( pod::Graph& graph ) {
|
||||
entry.commandID = viewIdx;
|
||||
|
||||
auto& decl = entry.decl;
|
||||
auto posView = view["position"_hash];
|
||||
auto uvView = view["uv"_hash];
|
||||
auto idxView = view["index"_hash];
|
||||
auto posView = view["position"];
|
||||
auto uvView = view["uv"];
|
||||
auto idxView = view["index"];
|
||||
|
||||
UF_ASSERT( posView.valid() && uvView.valid() );
|
||||
|
||||
|
||||
@ -223,8 +223,8 @@ void impl::buildMeshBVH( pod::BVH& bvh, const uf::Mesh& mesh, pod::BVH::index_t
|
||||
|
||||
// populate initial indices and bounds
|
||||
for ( auto& view : views ) {
|
||||
auto& indices = view["index"_hash];
|
||||
auto& positions = view["position"_hash];
|
||||
auto& indices = view["index"];
|
||||
auto& positions = view["position"];
|
||||
|
||||
auto tris = view.index.count / 3;
|
||||
for ( auto triIndexID = 0; triIndexID < tris; ++triIndexID ) {
|
||||
@ -441,8 +441,8 @@ void impl::refitBVH( pod::BVH& bvh, const uf::Mesh& mesh ) {
|
||||
|
||||
// populate initial indices and bounds
|
||||
for ( auto& view : views ) {
|
||||
auto& indices = view["index"_hash];
|
||||
auto& positions = view["position"_hash];
|
||||
auto& indices = view["index"];
|
||||
auto& positions = view["position"];
|
||||
|
||||
auto tris = view.index.count / 3;
|
||||
for ( auto triIndexID = 0; triIndexID < tris; ++triIndexID ) {
|
||||
|
||||
@ -622,7 +622,7 @@ pod::AABB impl::computeConvexHullAABB( const uf::Mesh::View& view, const uf::Mes
|
||||
return bounds;
|
||||
}
|
||||
pod::AABB impl::computeConvexHullAABB( const uf::Mesh::View& view, pod::AABB bounds ) {
|
||||
return impl::computeConvexHullAABB( view, view["position"_hash], bounds );
|
||||
return impl::computeConvexHullAABB( view, view["position"], bounds );
|
||||
}
|
||||
// combines two AABBs
|
||||
pod::AABB impl::mergeAabb( const pod::AABB& a, const pod::AABB& b ) {
|
||||
@ -741,7 +741,7 @@ pod::AABB impl::computeAABB( const pod::PhysicsBody& body ) {
|
||||
return impl::transformAabbToWorld( body.collider.mesh.bvh->bounds[0], transform );
|
||||
const auto& meshData = *body.collider.mesh.mesh;
|
||||
pod::AABB bounds = { { FLT_MAX, FLT_MAX, FLT_MAX }, { -FLT_MAX, -FLT_MAX, -FLT_MAX } };
|
||||
for ( const auto& view : meshData.buffer_views ) impl::computeConvexHullAABB( view, view["position"_hash], bounds );
|
||||
for ( const auto& view : meshData.buffer_views ) impl::computeConvexHullAABB( view, view["position"], bounds );
|
||||
return impl::transformAabbToWorld( bounds, transform );
|
||||
}
|
||||
default: {
|
||||
|
||||
@ -357,19 +357,37 @@ void impl::solveManifold( uf::stl::vector<pod::Manifold>& manifolds, float dt )
|
||||
}
|
||||
|
||||
void impl::dispatchManifold( pod::Manifold& manifold, pod::CollisionEvent::events_t& events, pod::CollisionEvent::map_t& active, const pod::CollisionEvent::map_t& previous ) {
|
||||
auto pairKey = impl::makePairKey( *manifold.a, *manifold.b );
|
||||
// find largest impulse
|
||||
float maxImpulse = 0.0f;
|
||||
for ( const auto& c : manifold.points ) maxImpulse = std::max( maxImpulse, c.accumulatedNormalImpulse );
|
||||
// mark as an active collision
|
||||
auto pairKey = impl::makePairKey( *manifold.a, *manifold.b );
|
||||
active[pairKey] = { manifold.a, manifold.b };
|
||||
// find largest impulse
|
||||
size_t primaryID = 0;
|
||||
float maxImpulse = -1.0f;
|
||||
for ( auto i = 0; i < manifold.points.size(); ++i ) {
|
||||
auto& c = manifold.points[i];
|
||||
if ( c.accumulatedNormalImpulse <= maxImpulse ) continue;
|
||||
primaryID = i;
|
||||
maxImpulse = c.accumulatedNormalImpulse;
|
||||
}
|
||||
if ( maxImpulse <= EPS ) {
|
||||
float maxPen = -FLT_MAX;
|
||||
for ( int i = 0; i < manifold.points.size(); ++i ) {
|
||||
auto& c = manifold.points[i];
|
||||
if ( c.penetration <= maxPen ) continue;
|
||||
maxPen = c.penetration;
|
||||
primaryID = i;
|
||||
}
|
||||
}
|
||||
auto& contact = manifold.points[primaryID];
|
||||
// dispatch
|
||||
events.emplace_back(pod::CollisionEvent{
|
||||
.state = previous.count( pairKey ) == 0 ? pod::CollisionState::ENTER : pod::CollisionState::SUSTAIN,
|
||||
.a = manifold.a,
|
||||
.b = manifold.b,
|
||||
.point = manifold.points[0].point,
|
||||
.normal = manifold.points[0].normal,
|
||||
.point = contact.point,
|
||||
.normal = contact.normal,
|
||||
.impulse = maxImpulse,
|
||||
.featureA = contact.featureA,
|
||||
.featureB = contact.featureB,
|
||||
});
|
||||
}
|
||||
@ -151,8 +151,8 @@ void impl::getSupportFace( const pod::PhysicsBody& body, const pod::Vector3f& di
|
||||
if ( 0 <= selectedViewIdx && selectedViewIdx != viewIdx ) continue;
|
||||
|
||||
const auto& view = mesh.buffer_views[viewIdx];
|
||||
auto& indices = view["index"_hash];
|
||||
auto& positions = view["position"_hash];
|
||||
auto& indices = view["index"];
|
||||
auto& positions = view["position"];
|
||||
for ( size_t i = 0; i < view.index.count / 3; ++i ) {
|
||||
pod::Triangle tri = uf::mesh::fetchTriangle( view, indices, positions, i );
|
||||
pod::Vector3f normal = impl::triangleNormal( tri );
|
||||
|
||||
@ -66,7 +66,7 @@ pod::Vector3f impl::support( const pod::PhysicsBody& body, const pod::Vector3f&
|
||||
for ( auto viewIdx = 0; viewIdx < mesh.buffer_views.size(); ++viewIdx ) {
|
||||
if ( 0 <= selectedViewIdx && selectedViewIdx != viewIdx ) continue; // cringe, but saves code duplication (could just alter the bounds above)
|
||||
const auto& view = mesh.buffer_views[viewIdx];
|
||||
auto& positions = view["position"_hash];
|
||||
auto& positions = view["position"];
|
||||
for ( size_t i = 0; i < view.vertex.count; ++i ) {
|
||||
pod::Vector3f v = uf::mesh::fetchVertex( view, positions, i );
|
||||
float dist = uf::vector::dot( v, localDir );
|
||||
|
||||
@ -18,6 +18,7 @@ namespace impl {
|
||||
bool hit = false;
|
||||
// do collision per hull
|
||||
for ( auto hullID : candidates ) {
|
||||
size_t previousCount = manifold.points.size();
|
||||
auto hullView = impl::physicsBodyHullView( hull, hullID );
|
||||
|
||||
pod::Simplex simplex;
|
||||
@ -25,6 +26,7 @@ namespace impl {
|
||||
auto result = impl::epa( hullView, body, simplex );
|
||||
if ( !impl::generateClippingManifold( hullView, body, result, manifold ) ) continue;
|
||||
hit = true;
|
||||
for ( size_t i = previousCount; i < manifold.points.size(); ++i ) manifold.points[i].featureA = hullID;
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
@ -69,6 +71,7 @@ bool impl::hullHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
bool hit = false;
|
||||
|
||||
for (auto [ viewIdA, viewIdB ] : pairs ) {
|
||||
size_t previousCount = manifold.points.size();
|
||||
auto viewA = impl::physicsBodyHullView( a, viewIdA );
|
||||
auto viewB = impl::physicsBodyHullView( b, viewIdB );
|
||||
|
||||
@ -78,6 +81,10 @@ bool impl::hullHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
auto result = impl::epa( viewA, viewB, simplex );
|
||||
if ( !impl::generateClippingManifold( viewA, viewB, result, manifold ) ) continue;
|
||||
hit = true;
|
||||
for ( size_t i = previousCount; i < manifold.points.size(); ++i ) {
|
||||
manifold.points[i].featureA = viewIdA;
|
||||
manifold.points[i].featureB = viewIdB;
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
@ -20,9 +20,11 @@ bool impl::meshAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
bool hit = false;
|
||||
// do collision per triangle
|
||||
for ( auto triID : candidates ) {
|
||||
size_t previousCount = manifold.points.size();
|
||||
auto tri = impl::fetchTriangle( meshData, triID, mesh ); // transform triangle to world space
|
||||
if ( !impl::triangleAabb( tri, aabb, manifold ) ) continue;
|
||||
hit = true;
|
||||
for ( size_t i = previousCount; i < manifold.points.size(); ++i ) manifold.points[i].featureA = triID;
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
@ -43,9 +45,11 @@ bool impl::meshObb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::M
|
||||
bool hit = false;
|
||||
// do collision per triangle
|
||||
for ( auto triID : candidates ) {
|
||||
size_t previousCount = manifold.points.size();
|
||||
auto tri = impl::fetchTriangle( meshData, triID, mesh ); // transform triangle to world space
|
||||
if ( !impl::triangleObb( tri, obb, manifold ) ) continue;
|
||||
hit = true;
|
||||
for ( size_t i = previousCount; i < manifold.points.size(); ++i ) manifold.points[i].featureA = triID;
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
@ -66,9 +70,11 @@ bool impl::meshSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod
|
||||
bool hit = false;
|
||||
// do collision per triangle
|
||||
for ( auto triID : candidates ) {
|
||||
size_t previousCount = manifold.points.size();
|
||||
auto tri = impl::fetchTriangle( meshData, triID, mesh ); // transform triangle to world space
|
||||
if ( !impl::triangleSphere( tri, sphere, manifold ) ) continue;
|
||||
hit = true;
|
||||
for ( size_t i = previousCount; i < manifold.points.size(); ++i ) manifold.points[i].featureA = triID;
|
||||
}
|
||||
|
||||
return hit;
|
||||
@ -91,9 +97,11 @@ bool impl::meshPlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod:
|
||||
bool hit = false;
|
||||
// do collision per triangle
|
||||
for ( auto triID : candidates ) {
|
||||
size_t previousCount = manifold.points.size();
|
||||
auto tri = impl::fetchTriangle( meshData, triID, mesh ); // transform triangle to world space
|
||||
if ( !impl::trianglePlane( tri, plane, manifold ) ) continue;
|
||||
hit = true;
|
||||
for ( size_t i = previousCount; i < manifold.points.size(); ++i ) manifold.points[i].featureA = triID;
|
||||
}
|
||||
|
||||
return hit;
|
||||
@ -115,9 +123,11 @@ bool impl::meshCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, po
|
||||
bool hit = false;
|
||||
// do collision per triangle
|
||||
for ( auto triID : candidates ) {
|
||||
size_t previousCount = manifold.points.size();
|
||||
auto tri = impl::fetchTriangle( meshData, triID, mesh ); // transform triangle to world space
|
||||
if ( !impl::triangleCapsule( tri, capsule, manifold ) ) continue;
|
||||
hit = true;
|
||||
for ( size_t i = previousCount; i < manifold.points.size(); ++i ) manifold.points[i].featureA = triID;
|
||||
}
|
||||
|
||||
return hit;
|
||||
@ -144,12 +154,17 @@ bool impl::meshMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
bool hit = false;
|
||||
// do collision per triangle
|
||||
for (auto [idA, idB] : pairs ) {
|
||||
size_t previousCount = manifold.points.size();
|
||||
auto triA = impl::fetchTriangle( meshA, idA, a ); // transform triangles to world space
|
||||
auto triB = impl::fetchTriangle( meshB, idB, b );
|
||||
|
||||
bool collides = impl::triangleTriangle( triA, triB, manifold );
|
||||
if ( !collides ) continue;
|
||||
hit = true;
|
||||
for ( size_t i = previousCount; i < manifold.points.size(); ++i ) {
|
||||
manifold.points[i].featureA = idA;
|
||||
manifold.points[i].featureB = idB;
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
@ -177,6 +192,7 @@ bool impl::meshHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
bool hit = false;
|
||||
// do collision per hull and triangle
|
||||
for (auto [ triID, hullID ] : pairs ) {
|
||||
size_t previousCount = manifold.points.size();
|
||||
auto triView = impl::physicsBodyTriView( mesh, triID );
|
||||
auto hullView = impl::physicsBodyHullView( hull, hullID );
|
||||
|
||||
@ -184,6 +200,10 @@ bool impl::meshHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
|
||||
if ( !collides ) continue;
|
||||
hit = true;
|
||||
for ( size_t i = previousCount; i < manifold.points.size(); ++i ) {
|
||||
manifold.points[i].featureA = triID;
|
||||
manifold.points[i].featureB = hullID;
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
@ -261,6 +261,7 @@ bool impl::rayMesh( const pod::Ray& r, const pod::PhysicsBody& body, pod::RayQue
|
||||
rayHit.contact.point = p;
|
||||
rayHit.contact.normal = n;
|
||||
rayHit.contact.penetration = t;
|
||||
rayHit.contact.featureA = triID;
|
||||
}
|
||||
|
||||
return rayHit.hit;
|
||||
@ -295,6 +296,7 @@ bool impl::rayHull( const pod::Ray& r, const pod::PhysicsBody& body, pod::RayQue
|
||||
rayHit.contact.point = impl::apply( transform, ray.origin + ray.direction * t );
|
||||
rayHit.contact.normal = uf::quaternion::rotate( transform.orientation, normal );
|
||||
rayHit.contact.penetration = t;
|
||||
rayHit.contact.featureA = hullID;
|
||||
}
|
||||
|
||||
return rayHit.hit;
|
||||
|
||||
@ -294,16 +294,16 @@ uf::Mesh::View uf::Mesh::makeView( const uf::stl::vector<uf::stl::string>& wante
|
||||
if ( wanted.size() ) {
|
||||
for ( auto& attr : vertex.attributes ) {
|
||||
if ( std::find(wanted.begin(), wanted.end(), attr.descriptor.name ) == wanted.end() ) continue;
|
||||
view.attributes[uf::algo::fnv1a(attr.descriptor.name)] = { attr };
|
||||
view.attributes[attr.descriptor.name] = { attr };
|
||||
}
|
||||
} else {
|
||||
for ( auto& attr : vertex.attributes ) {
|
||||
view.attributes[uf::algo::fnv1a(attr.descriptor.name)] = { attr };
|
||||
view.attributes[attr.descriptor.name] = { attr };
|
||||
}
|
||||
}
|
||||
|
||||
if ( !index.attributes.empty() ) {
|
||||
view.attributes["index"_hash] = { index.attributes[lod] };
|
||||
view.attributes["index"] = { index.attributes[lod] };
|
||||
}
|
||||
|
||||
return view;
|
||||
@ -317,14 +317,14 @@ uf::Mesh::View uf::Mesh::makeView( size_t i, const uf::stl::vector<uf::stl::stri
|
||||
if ( wanted.size() ) {
|
||||
for (auto& attr : vertex.attributes) {
|
||||
if ( std::find(wanted.begin(), wanted.end(), attr.descriptor.name ) == wanted.end() ) continue;
|
||||
view.attributes[uf::algo::fnv1a(attr.descriptor.name)] = { attr };
|
||||
view.attributes[attr.descriptor.name] = { attr };
|
||||
}
|
||||
} else {
|
||||
for ( auto& attr : vertex.attributes ) view.attributes[uf::algo::fnv1a(attr.descriptor.name)] = { attr };
|
||||
for ( auto& attr : vertex.attributes ) view.attributes[attr.descriptor.name] = { attr };
|
||||
}
|
||||
|
||||
if ( !index.attributes.empty() ) {
|
||||
view.attributes["index"_hash] = { index.attributes[lod] };
|
||||
view.attributes["index"] = { index.attributes[lod] };
|
||||
}
|
||||
|
||||
return view;
|
||||
@ -612,6 +612,16 @@ pod::Triangle uf::mesh::fetchTriangle( const uf::Mesh::View& view, const uf::Mes
|
||||
}
|
||||
|
||||
pod::TriangleWithNormal uf::mesh::fetchTriangle( const uf::Mesh& mesh, size_t triID ) {
|
||||
const auto* view = uf::mesh::fetchView( mesh, triID );
|
||||
UF_ASSERT( view );
|
||||
|
||||
pod::TriangleWithNormal tri = { uf::mesh::fetchTriangle( *view, triID ) };
|
||||
tri.normal = uf::vector::normalize(uf::vector::cross(tri.points[1] - tri.points[0], tri.points[2] - tri.points[0]));
|
||||
|
||||
return tri;
|
||||
}
|
||||
|
||||
const uf::Mesh::View* uf::mesh::fetchView( const uf::Mesh& mesh, size_t& triID ) {
|
||||
const auto& views = mesh.buffer_views;
|
||||
UF_ASSERT(!views.empty());
|
||||
|
||||
@ -627,10 +637,15 @@ pod::TriangleWithNormal uf::mesh::fetchTriangle( const uf::Mesh& mesh, size_t tr
|
||||
}
|
||||
triBase += trisInView;
|
||||
}
|
||||
UF_ASSERT( view );
|
||||
|
||||
pod::TriangleWithNormal tri = { uf::mesh::fetchTriangle( *view, triID ) };
|
||||
tri.normal = uf::vector::normalize(uf::vector::cross(tri.points[1] - tri.points[0], tri.points[2] - tri.points[0]));
|
||||
|
||||
return tri;
|
||||
return view;
|
||||
}
|
||||
const pod::DrawCommand& uf::mesh::fetchDrawCommand( const uf::Mesh& mesh, const uf::Mesh::View& view ) {
|
||||
UF_ASSERT( 0 <= view.indirectIndex && view.indirectIndex < mesh.indirect.count );
|
||||
return ((const pod::DrawCommand*) mesh.getBuffer(mesh.indirect).data())[view.indirectIndex];
|
||||
}
|
||||
const pod::DrawCommand& uf::mesh::fetchDrawCommand( const uf::Mesh& mesh, size_t triID ) {
|
||||
const auto* view = uf::mesh::fetchView( mesh, triID );
|
||||
UF_ASSERT( view );
|
||||
return uf::mesh::fetchDrawCommand( mesh, *view );
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user