more bug fixes (fixed that weird instancing bug where things get rendered at origin because of instanced graphics also rendering, mdl fixes, fixed lightmaps with displacements, fixed trigger physics bodies)
This commit is contained in:
parent
e4ad164203
commit
6ae24419e7
1
.gitignore
vendored
1
.gitignore
vendored
@ -63,6 +63,7 @@ default/
|
|||||||
*.vtf
|
*.vtf
|
||||||
*.ztmp
|
*.ztmp
|
||||||
|
|
||||||
|
maps/
|
||||||
models/
|
models/
|
||||||
llm/
|
llm/
|
||||||
tmp/
|
tmp/
|
||||||
@ -358,8 +358,9 @@
|
|||||||
"max": 0.01 // 0.2
|
"max": 0.01 // 0.2
|
||||||
},
|
},
|
||||||
"debug draw": {
|
"debug draw": {
|
||||||
"static": true,
|
"static": false,
|
||||||
"dynamic": true,
|
"dynamic": false,
|
||||||
|
"trigger": false,
|
||||||
"contacts": false,
|
"contacts": false,
|
||||||
"constraints": true,
|
"constraints": true,
|
||||||
"rays": false,
|
"rays": false,
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"assets": ["./scripts/ambient_generic.lua"],
|
|
||||||
"behaviors": [
|
|
||||||
"SoundEmitterBehavior"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -6,7 +6,6 @@
|
|||||||
"metadata": {
|
"metadata": {
|
||||||
"physics": {
|
"physics": {
|
||||||
"mass": 0,
|
"mass": 0,
|
||||||
// "inertia": [0, 0, 0],
|
|
||||||
"type": "bounding box"
|
"type": "bounding box"
|
||||||
// "type": "mesh"
|
// "type": "mesh"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"assets": ["./scripts/io.lua"]
|
|
||||||
}
|
|
||||||
@ -86,6 +86,8 @@
|
|||||||
"type": "capsule",
|
"type": "capsule",
|
||||||
"radius": 1,
|
"radius": 1,
|
||||||
"height": 2,
|
"height": 2,
|
||||||
|
"category": "player",
|
||||||
|
"mask": "player",
|
||||||
|
|
||||||
// "type": "bounding box",
|
// "type": "bounding box",
|
||||||
// "min": [ -1, -1, -1 ],
|
// "min": [ -1, -1, -1 ],
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
local ent = ent
|
local ent = ent
|
||||||
local metadata = ent:getComponent("Metadata")
|
local metadata = ent:getComponent("Metadata")
|
||||||
local metadataVale = metadata["valve"] or {}
|
local metadataValve = metadata["valve"] or {}
|
||||||
|
|
||||||
local soundFile = metadataVale["message"] or ""
|
local soundFile = metadataValve["message"] or ""
|
||||||
local flags = metadataVale["spawnflags"] or 0
|
local flags = metadataValve["spawnflags"] or 0
|
||||||
|
|
||||||
local volume = tonumber(metadataVale["health"]) or 10.0
|
local volume = tonumber(metadataValve["health"]) or 10.0
|
||||||
volume = volume / 10.0
|
volume = volume / 10.0
|
||||||
|
|
||||||
local playEverywhere = (math.floor(flags / 1) % 2) ~= 0
|
local playEverywhere = (math.floor(flags / 1) % 2) ~= 0
|
||||||
|
|||||||
@ -74,7 +74,6 @@ ent:bind("tick", function(self)
|
|||||||
for i = #pendingOutputs, 1, -1 do
|
for i = #pendingOutputs, 1, -1 do
|
||||||
local job = pendingOutputs[i]
|
local job = pendingOutputs[i]
|
||||||
if currentTime >= job.fireTime then
|
if currentTime >= job.fireTime then
|
||||||
|
|
||||||
local targetUIDs = _G.IOTargets[job.target]
|
local targetUIDs = _G.IOTargets[job.target]
|
||||||
if targetUIDs then
|
if targetUIDs then
|
||||||
for _, targetUID in ipairs(targetUIDs) do
|
for _, targetUID in ipairs(targetUIDs) do
|
||||||
@ -97,18 +96,19 @@ ent:bind("tick", function(self)
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
ent:addHook("io:FireOutput.%UID%", function(payload)
|
ent:addHook("io:FireOutput.%UID%", function(payload)
|
||||||
local outputName = payload.output
|
local output = payload.output
|
||||||
|
|
||||||
for i = 1, #connections do
|
for i = 1, #connections do
|
||||||
local conn = connections[i]
|
local conn = connections[i]
|
||||||
|
|
||||||
if conn.output == outputName then
|
if conn.output == output then
|
||||||
local limit = conn.times or -1
|
local limit = conn.times or -1
|
||||||
|
|
||||||
if limit == -1 or timesFired[i] < limit then
|
if limit == -1 or timesFired[i] < limit then
|
||||||
timesFired[i] = timesFired[i] + 1
|
timesFired[i] = timesFired[i] + 1
|
||||||
|
|
||||||
local delay = conn.delay or 0.0
|
local delay = conn.delay or 0.0
|
||||||
|
|
||||||
table.insert(pendingOutputs, {
|
table.insert(pendingOutputs, {
|
||||||
fireTime = timer:elapsed() + delay,
|
fireTime = timer:elapsed() + delay,
|
||||||
target = conn.target,
|
target = conn.target,
|
||||||
@ -136,8 +136,8 @@ end)
|
|||||||
|
|
||||||
ent:addHook("entity:Use.%UID%", function(payload)
|
ent:addHook("entity:Use.%UID%", function(payload)
|
||||||
if payload.user == ent:uid() then return end
|
if payload.user == ent:uid() then return end
|
||||||
|
|
||||||
ent:callHook("io:FireOutput.%UID%", { output = "OnPlayerUse" })
|
ent:callHook("io:FireOutput.%UID%", { output = "OnPlayerUse" })
|
||||||
ent:callHook("io:FireOutput.%UID%", { output = "OnUse" })
|
ent:callHook("io:FireOutput.%UID%", { output = "OnUse" })
|
||||||
ent:callHook("io:FireOutput.%UID%", { output = "OnPressed" })
|
ent:callHook("io:FireOutput.%UID%", { output = "OnPressed" })
|
||||||
|
ent:callHook("io:FireOutput.%UID%", { output = "OnIn" })
|
||||||
end)
|
end)
|
||||||
@ -138,14 +138,14 @@ local function tickUse( transform, axes, inputs )
|
|||||||
timers.use:reset()
|
timers.use:reset()
|
||||||
local center = transform.position
|
local center = transform.position
|
||||||
local direction = axes.forward * useDistance
|
local direction = axes.forward * useDistance
|
||||||
local prop, depth = physicsBody:rayCast(center, direction)
|
local hit, depth = physicsBody:rayCast(center, direction)
|
||||||
|
|
||||||
local payload = {
|
local payload = {
|
||||||
user = ent:uid(),
|
user = ent:uid(),
|
||||||
uid = prop and prop:uid() or 0,
|
uid = hit and hit:uid() or 0,
|
||||||
depth = depth,
|
depth = depth,
|
||||||
}
|
}
|
||||||
if prop then prop:lazyCallHook("entity:Use.%UID%", payload) end
|
if hit then hit:lazyCallHook("entity:Use.%UID%", payload) end
|
||||||
ent:lazyCallHook("entity:Use.%UID%", payload)
|
ent:lazyCallHook("entity:Use.%UID%", payload)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
20
bin/data/entities/scripts/trigger.lua
Normal file
20
bin/data/entities/scripts/trigger.lua
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
local ent = ent
|
||||||
|
local scene = entities.currentScene()
|
||||||
|
local metadata = ent:getComponent("Metadata")
|
||||||
|
local metadataValve = metadata["valve"] or {}
|
||||||
|
local physicsBody = ent:getComponent("PhysicsBody")
|
||||||
|
|
||||||
|
local timer = Timer.new()
|
||||||
|
if not timer:running() then
|
||||||
|
timer:start()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
ent:bind( "tick", function(self)
|
||||||
|
local collisionEvents = physicsBody:getCollisionEvents()
|
||||||
|
for i, event in ipairs(collisionEvents) do
|
||||||
|
-- do something
|
||||||
|
-- print( event.state, event.a, event.b, event.point, event.normal, event.impulse )
|
||||||
|
end
|
||||||
|
end )
|
||||||
|
]]
|
||||||
@ -27,17 +27,18 @@
|
|||||||
"resolution": 2048
|
"resolution": 2048
|
||||||
} },*/
|
} },*/
|
||||||
|
|
||||||
|
"ambient_generic": { "action": "load", "payload": { "assets": ["ent://scripts/ambient_generic.lua"], "behaviors": ["SoundEmitterBehavior"] } },
|
||||||
|
|
||||||
// automatically handled
|
// automatically handled
|
||||||
// "/^func_door/": { "action": "load", "payload": { "import": "/door.json" } },
|
// "/^func_door/": { "action": "load", "payload": { "import": "/door.json" } },
|
||||||
// "/^prop_door/": { "action": "load", "payload": { "import": "/door.json" } },
|
// "/^prop_door/": { "action": "load", "payload": { "import": "/door.json" } },
|
||||||
|
|
||||||
"/ambient_generic/": { "action": "load", "payload": { "import": "/ambient_generic.json" } },
|
|
||||||
|
|
||||||
// regexp matches
|
// regexp matches
|
||||||
"/^prop_static/": { "action": "load", "payload": { "import": "/prop.json" } },
|
"/^prop_static/": { "action": "load", "payload": { "import": "ent://prop.json" } },
|
||||||
"/^prop_dynamic/": { "action": "load", "payload": { "import": "/prop.json" } },
|
"/^prop_dynamic/": { "action": "load", "payload": { "import": "ent://prop.json" } },
|
||||||
"/^func_physbox/": { "action": "load", "payload": { "import": "/prop.json" } },
|
"/^func_physbox/": { "action": "load", "payload": { "import": "ent://prop.json" } },
|
||||||
"/^prop_physics/": { "action": "load", "payload": { "import": "/prop.json" } },
|
"/^prop_physics/": { "action": "load", "payload": { "import": "ent://prop.json" } },
|
||||||
|
|
||||||
"/^tools\\/toolsnodraw/": { "material": { "base": [ 1.0, 1.0, 1.0, 0.0 ] } }
|
"/^tools\\/toolsnodraw/": { "material": { "base": [ 1.0, 1.0, 1.0, 0.0 ] } }
|
||||||
}
|
}
|
||||||
|
|||||||
15
bin/data/scenes/sourceengine/cs_office.json
Normal file
15
bin/data/scenes/sourceengine/cs_office.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"import": "./base_sourceengine.json",
|
||||||
|
"assets": [
|
||||||
|
{ "filename": "./maps/cs_office.bsp" }
|
||||||
|
// { "filename": "./maps/cs_office/graph.json" }
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"graph": {
|
||||||
|
// realistically shouldn't ever need to define additional tags for BSPs
|
||||||
|
"tags": {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"import": "./base_sourceengine.json",
|
"import": "./base_sourceengine.json",
|
||||||
"assets": [
|
"assets": [
|
||||||
// { "filename": "./models/mds_mcdonalds.bsp" }
|
{ "filename": "./maps/mds_mcdonalds.bsp" }
|
||||||
{ "filename": "./models/mds_mcdonalds/graph.json" }
|
// { "filename": "./maps/mds_mcdonalds/graph.json" }
|
||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"graph": {
|
"graph": {
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
{
|
{
|
||||||
// "import": "./rp_downtown_v2.json"
|
// "import": "./rp_downtown_v2.json"
|
||||||
// "import": "./ss2_medsci1.json"
|
// "import": "./ss2_medsci1.json"
|
||||||
// "import": "./test_grid.json"
|
// "import": "./mds_mcdonalds.json"
|
||||||
// "import": "./sh2_mcdonalds.json"
|
"import": "./cs_office.json"
|
||||||
// "import": "./animal_crossing.json"
|
|
||||||
"import": "./mds_mcdonalds.json"
|
|
||||||
// "import": "./gm_construct.json"
|
// "import": "./gm_construct.json"
|
||||||
}
|
}
|
||||||
@ -86,9 +86,8 @@ namespace pod {
|
|||||||
GLOBAL,
|
GLOBAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
uf::stl::KeyMap<uf::stl::vector<pod::Instance>> groupedInstances;
|
|
||||||
uf::stl::KeyMap<uf::stl::vector<pod::Instance::Addresses>> addresses;
|
|
||||||
uf::stl::KeyMap<uf::stl::vector<pod::Primitive>> primitives;
|
uf::stl::KeyMap<uf::stl::vector<pod::Primitive>> primitives;
|
||||||
|
uf::stl::KeyMap<uf::stl::vector<pod::Instance>> instances;
|
||||||
uf::stl::KeyMap<uf::Mesh> meshes;
|
uf::stl::KeyMap<uf::Mesh> meshes;
|
||||||
|
|
||||||
uf::stl::KeyMap<pod::ImageTexture> images;
|
uf::stl::KeyMap<pod::ImageTexture> images;
|
||||||
|
|||||||
@ -333,9 +333,9 @@ namespace pod {
|
|||||||
enum CollisionMask : uint32_t {
|
enum CollisionMask : uint32_t {
|
||||||
MASK_NONE = 0,
|
MASK_NONE = 0,
|
||||||
MASK_STATIC = CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC | CATEGORY_PROJECTILE,
|
MASK_STATIC = CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC | CATEGORY_PROJECTILE,
|
||||||
MASK_DYNAMIC = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC,
|
MASK_DYNAMIC = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC | CATEGORY_TRIGGER,
|
||||||
MASK_PLAYER = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_NPC | CATEGORY_PROJECTILE,
|
MASK_PLAYER = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_NPC | CATEGORY_PROJECTILE | CATEGORY_TRIGGER,
|
||||||
MASK_NPC = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_PROJECTILE,
|
MASK_NPC = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_PROJECTILE | CATEGORY_TRIGGER,
|
||||||
MASK_TRIGGER = CATEGORY_PLAYER | CATEGORY_NPC,
|
MASK_TRIGGER = CATEGORY_PLAYER | CATEGORY_NPC,
|
||||||
MASK_PROJECTILE = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC,
|
MASK_PROJECTILE = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC,
|
||||||
MASK_CHARACTER = MASK_PLAYER | MASK_NPC,
|
MASK_CHARACTER = MASK_PLAYER | MASK_NPC,
|
||||||
|
|||||||
@ -426,8 +426,8 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
|
|||||||
metadata.system.noclipped = state;
|
metadata.system.noclipped = state;
|
||||||
if ( !state ) {
|
if ( !state ) {
|
||||||
uf::physics::setGravity( physicsBody );
|
uf::physics::setGravity( physicsBody );
|
||||||
uf::physics::setColliderCategory( physicsBody, "DYNAMIC");
|
uf::physics::setColliderCategory( physicsBody, "PLAYER");
|
||||||
uf::physics::setColliderMask( physicsBody, "DYNAMIC");
|
uf::physics::setColliderMask( physicsBody, "PLAYER");
|
||||||
} else {
|
} else {
|
||||||
uf::physics::setGravity( physicsBody, pod::Vector3f{0,0,0});
|
uf::physics::setGravity( physicsBody, pod::Vector3f{0,0,0});
|
||||||
uf::physics::setColliderCategory( physicsBody, "NONE");
|
uf::physics::setColliderCategory( physicsBody, "NONE");
|
||||||
|
|||||||
@ -734,7 +734,7 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
|
|||||||
// query materials if culling needs to be disabled
|
// query materials if culling needs to be disabled
|
||||||
for ( auto& primitive : primitives ) {
|
for ( auto& primitive : primitives ) {
|
||||||
auto materialID = primitive.instance.materialID;
|
auto materialID = primitive.instance.materialID;
|
||||||
if ( 0 < materialID && materialID <= graph.materials.size() ) {
|
if ( 0 <= materialID && materialID <= graph.materials.size() ) {
|
||||||
auto& materialName = graph.materials[materialID];
|
auto& materialName = graph.materials[materialID];
|
||||||
auto& material = storage.materials[materialName];
|
auto& material = storage.materials[materialName];
|
||||||
if ( material.modeCull == 0 ) {
|
if ( material.modeCull == 0 ) {
|
||||||
@ -1121,7 +1121,7 @@ void uf::graph::process( pod::Graph& graph ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( auto& instance : storage.groupedInstances.map[name] ) {
|
for ( auto& instance : storage.instances.map[name] ) {
|
||||||
if ( 0 <= instance.materialID && instance.materialID < graph.materials.size() ) {
|
if ( 0 <= instance.materialID && instance.materialID < graph.materials.size() ) {
|
||||||
auto& keys = storage.materials.keys;
|
auto& keys = storage.materials.keys;
|
||||||
auto& indices = storage.materials.indices;
|
auto& indices = storage.materials.indices;
|
||||||
@ -1228,18 +1228,49 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
|
|||||||
metadataJson["system"]["graph"]["index"] = index;
|
metadataJson["system"]["graph"]["index"] = index;
|
||||||
|
|
||||||
uf::Serializer loadJson;
|
uf::Serializer loadJson;
|
||||||
|
|
||||||
// convert metadata["valve"] into internal values:
|
// convert metadata["valve"] into internal values:
|
||||||
auto& metadataValve = node.metadata["valve"];
|
auto& metadataValve = node.metadata["valve"];
|
||||||
if ( ext::json::isObject( metadataValve ) ) {
|
if ( ext::json::isObject( metadataValve ) ) {
|
||||||
// bind door script
|
// bind door script
|
||||||
if ( ext::json::isObject( metadataValve["door"] ) ) {
|
if ( ext::json::isObject( metadataValve["door"] ) ) {
|
||||||
node.metadata["door"] = metadataValve["door"];
|
node.metadata["door"] = metadataValve["door"];
|
||||||
loadJson["imports"].emplace_back("/door.json");
|
loadJson["imports"].emplace_back("ent://door.json");
|
||||||
}
|
}
|
||||||
// bind io connectivity
|
// bind io connectivity
|
||||||
if ( ext::json::isArray( metadataValve["connections"] ) || metadataValve["targetname"].is<uf::stl::string>() ) {
|
if ( ext::json::isArray( metadataValve["connections"] ) || metadataValve["targetname"].is<uf::stl::string>() ) {
|
||||||
node.metadata["connections"] = metadataValve["connections"];
|
node.metadata["connections"] = metadataValve["connections"];
|
||||||
loadJson["imports"].emplace_back("/io.json");
|
loadJson["assets"].emplace_back("ent://scripts/io.lua");
|
||||||
|
}
|
||||||
|
|
||||||
|
// assume all funcs are to have a physics body
|
||||||
|
if ( node.name.starts_with("func_") ) {
|
||||||
|
if ( ext::json::isNull( node.metadata["physics"] ) ) {
|
||||||
|
//node.metadata["physics"]["type"] = "bounding box";
|
||||||
|
node.metadata["physics"]["type"] = "mesh";
|
||||||
|
node.metadata["physics"]["category"] = "trigger";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if trigger
|
||||||
|
if ( 0 <= node.mesh && node.mesh < graph.meshes.size() ) {
|
||||||
|
auto& primitives = storage.primitives.map[graph.primitives[node.mesh]];
|
||||||
|
for ( auto& primitive : primitives ) {
|
||||||
|
auto materialID = primitive.instance.materialID;
|
||||||
|
if ( 0 <= materialID && materialID <= graph.materials.size() ) {
|
||||||
|
auto& materialName = graph.materials[materialID];
|
||||||
|
// attach trigger script + physics body
|
||||||
|
if ( materialName == "tools/toolstrigger" ) {
|
||||||
|
loadJson["assets"].emplace_back("ent://scripts/trigger.lua");
|
||||||
|
// signal to assign a physics body
|
||||||
|
if ( ext::json::isNull( node.metadata["physics"] ) ) {
|
||||||
|
node.metadata["physics"]["type"] = "bounding box";
|
||||||
|
node.metadata["physics"]["category"] = "trigger";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1382,18 +1413,9 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
|
|||||||
auto primitiveName = graph.primitives[node.mesh];
|
auto primitiveName = graph.primitives[node.mesh];
|
||||||
auto& primitives = storage.primitives.map[primitiveName];
|
auto& primitives = storage.primitives.map[primitiveName];
|
||||||
|
|
||||||
node.object = ::allocateObjectID( storage );
|
|
||||||
auto objectKeyName = std::to_string( node.object );
|
|
||||||
|
|
||||||
storage.entities[objectKeyName] = &entity;
|
|
||||||
storage.objects[objectKeyName] = pod::Instance::Object{
|
|
||||||
.model = model,
|
|
||||||
.previous = model,
|
|
||||||
};
|
|
||||||
|
|
||||||
pod::Instance::Bounds bounds = {};
|
pod::Instance::Bounds bounds = {};
|
||||||
|
|
||||||
auto& grouped = storage.groupedInstances[primitiveName];
|
auto& grouped = storage.instances[primitiveName];
|
||||||
for ( auto drawID = 0; drawID < primitives.size(); ++drawID ) {
|
for ( auto drawID = 0; drawID < primitives.size(); ++drawID ) {
|
||||||
pod::Instance newInstance = primitives[drawID].instance;
|
pod::Instance newInstance = primitives[drawID].instance;
|
||||||
newInstance.objectID = node.object;
|
newInstance.objectID = node.object;
|
||||||
@ -1412,41 +1434,6 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
|
||||||
auto& mesh = storage.meshes.map[graph.meshes[node.mesh]];
|
|
||||||
auto& primitives = storage.primitives.map[graph.primitives[node.mesh]];
|
|
||||||
|
|
||||||
pod::Instance::Bounds bounds = {};
|
|
||||||
size_t baseInstanceID = ::allocateInstanceID( storage, graph.primitives[node.mesh] );
|
|
||||||
// setup instances
|
|
||||||
for ( auto drawID = 0; drawID < primitives.size(); ++drawID ) {
|
|
||||||
auto& primitive = primitives[drawID];
|
|
||||||
auto& instance = primitive.instance;
|
|
||||||
size_t instanceID = baseInstanceID + drawID;
|
|
||||||
|
|
||||||
instance.objectID = node.object;
|
|
||||||
instance.jointID = graphMetadataJson["renderer"]["skinned"].as<bool>() ? 0 : -1;
|
|
||||||
|
|
||||||
primitive.drawCommand.instanceID = instanceID;
|
|
||||||
|
|
||||||
bounds.min = uf::vector::min( bounds.min, instance.bounds.min );
|
|
||||||
bounds.max = uf::vector::max( bounds.max, instance.bounds.max );
|
|
||||||
|
|
||||||
if ( mesh.indirect.count && mesh.indirect.count <= primitives.size() ) {
|
|
||||||
auto& attribute = mesh.indirect.attributes.front();
|
|
||||||
auto& buffer = mesh.buffers[attribute.buffer];
|
|
||||||
pod::DrawCommand* drawCommands = (pod::DrawCommand*) buffer.data();
|
|
||||||
auto& drawCommand = drawCommands[drawID];
|
|
||||||
drawCommand.instanceID = instanceID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if !UF_GRAPH_EXTENDED
|
|
||||||
if ( graphMetadataJson["renderer"]["render"].as<bool>() ) {
|
|
||||||
uf::graph::initializeGraphics( graph, entity, mesh, addresses );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto phyziks = tag["physics"];
|
auto phyziks = tag["physics"];
|
||||||
if ( !ext::json::isObject( phyziks ) ) phyziks = metadataJson["physics"];
|
if ( !ext::json::isObject( phyziks ) ) phyziks = metadataJson["physics"];
|
||||||
@ -1608,7 +1595,7 @@ bool uf::graph::tick( pod::Graph::Storage& storage ) {
|
|||||||
if ( storage.stale ) {
|
if ( storage.stale ) {
|
||||||
for ( auto& key : storage.primitives.keys ) {
|
for ( auto& key : storage.primitives.keys ) {
|
||||||
auto& primitives = storage.primitives.map[key];
|
auto& primitives = storage.primitives.map[key];
|
||||||
auto& grouped = storage.groupedInstances.map[key];
|
auto& grouped = storage.instances.map[key];
|
||||||
|
|
||||||
auto& mesh = storage.meshes.map[key];
|
auto& mesh = storage.meshes.map[key];
|
||||||
pod::DrawCommand* commands = nullptr;
|
pod::DrawCommand* commands = nullptr;
|
||||||
@ -1641,11 +1628,13 @@ bool uf::graph::tick( pod::Graph::Storage& storage ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( commands && !grouped.empty() ) {
|
if ( commands && !grouped.empty() ) {
|
||||||
auto hostKeyName = std::to_string(grouped.front().objectID);
|
auto objectKeyName = std::to_string(grouped.front().objectID);
|
||||||
if (storage.entities.map.count(hostKeyName) > 0) {
|
if ( storage.entities.map.count(objectKeyName) > 0 ) {
|
||||||
auto* hostEntity = storage.entities.map[hostKeyName];
|
auto& entity = *storage.entities.map[objectKeyName];
|
||||||
if (hostEntity && hostEntity->hasComponent<uf::renderer::Graphic>()) {
|
if ( entity.hasComponent<uf::renderer::Graphic>() ) {
|
||||||
hostEntity->getComponent<uf::renderer::Graphic>().updateMesh(mesh);
|
auto& graphic = entity.getComponent<uf::renderer::Graphic>();
|
||||||
|
auto& attr = mesh.indirect.attributes.front();
|
||||||
|
graphic.updateBuffer( (const void*) attr.pointer, attr.length, graphic.metadata.buffers["indirect["+attr.descriptor.name+"]"] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1754,12 +1743,9 @@ void uf::graph::aggregate( uf::Object& object, pod::Graph::Storage& storage ) {
|
|||||||
drawCommands.emplace_back( primitive.drawCommand );
|
drawCommands.emplace_back( primitive.drawCommand );
|
||||||
instances.emplace_back( primitive.instance );
|
instances.emplace_back( primitive.instance );
|
||||||
lodMetadata.emplace_back( primitive.lod );
|
lodMetadata.emplace_back( primitive.lod );
|
||||||
|
addresses.emplace_back( primitive.addresses );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( auto& key : storage.addresses.keys ) {
|
|
||||||
addresses.insert( addresses.end(), storage.addresses.map[key].begin(), storage.addresses.map[key].end() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rebuild = false;
|
bool rebuild = false;
|
||||||
@ -2281,8 +2267,13 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) {
|
|||||||
|
|
||||||
storage.stale = true; // force rebuffering the draw commands
|
storage.stale = true; // force rebuffering the draw commands
|
||||||
|
|
||||||
|
bool graphicOwner = graphMetadataJson["renderer"]["render"].as<bool>();
|
||||||
|
if ( graphicOwner ) {
|
||||||
|
auto objectKeyName = std::to_string(storage.instances.map[graph.primitives[node.mesh]].front().objectID);
|
||||||
|
graphicOwner = storage.entities[objectKeyName] == &entity;
|
||||||
|
}
|
||||||
// update graphic
|
// update graphic
|
||||||
if ( graphMetadataJson["renderer"]["render"].as<bool>() ) {
|
if ( graphicOwner ) {
|
||||||
bool exists = entity.hasComponent<uf::renderer::Graphic>();
|
bool exists = entity.hasComponent<uf::renderer::Graphic>();
|
||||||
if ( exists ) {
|
if ( exists ) {
|
||||||
auto& graphic = entity.getComponent<uf::renderer::Graphic>();
|
auto& graphic = entity.getComponent<uf::renderer::Graphic>();
|
||||||
|
|||||||
@ -219,7 +219,7 @@ void ext::vorbis::stream(uf::Audio::Metadata& metadata) {
|
|||||||
totalRead += result;
|
totalRead += result;
|
||||||
}
|
}
|
||||||
if ( totalRead == 0 ) {
|
if ( totalRead == 0 ) {
|
||||||
UF_MSG_WARNING("Vorbis: consumed file stream before buffers are filled: {} {}", (int)queuedBuffers, metadata.filename);
|
if ( queuedBuffers == 0 ) UF_MSG_WARNING("Vorbis: consumed file stream before {} buffers were filled: {}", (int)queuedBuffers, metadata.filename);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
AL_CHECK_RESULT(alBufferData(metadata.al.buffer.getIndex(queuedBuffers), metadata.info.format, buffer, totalRead, metadata.info.frequency));
|
AL_CHECK_RESULT(alBufferData(metadata.al.buffer.getIndex(queuedBuffers), metadata.info.format, buffer, totalRead, metadata.info.frequency));
|
||||||
|
|||||||
@ -216,7 +216,7 @@ void ext::wav::stream(uf::Audio::Metadata& metadata) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bytesRead == 0) {
|
if (bytesRead == 0) {
|
||||||
UF_MSG_WARNING("WAV: consumed file stream before buffers are filled: {} {}", (int)queuedBuffers, metadata.filename);
|
if ( queuedBuffers == 0 ) UF_MSG_WARNING("WAV: consumed file stream before {} buffers were filled: {}", (int) queuedBuffers, metadata.filename);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -117,21 +117,46 @@ namespace impl {
|
|||||||
uint16_t smoothingGroups;
|
uint16_t smoothingGroups;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
struct BspDispSubNeighbor {
|
||||||
|
uint16_t neighbor;
|
||||||
|
uint8_t neighborOrientation;
|
||||||
|
uint8_t span;
|
||||||
|
uint8_t neighborSpan;
|
||||||
|
uint8_t padding;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BspDispNeighbor {
|
||||||
|
BspDispSubNeighbor subNeighbors[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BspDispCornerNeighbors {
|
||||||
|
uint16_t neighbors[4];
|
||||||
|
uint8_t numNeighbors;
|
||||||
|
uint8_t padding;
|
||||||
|
};
|
||||||
|
|
||||||
struct BspDispInfo {
|
struct BspDispInfo {
|
||||||
pod::Vector3f startPosition;
|
pod::Vector3f startPosition;
|
||||||
int32_t dispVertStart;
|
int32_t dispVertStart;
|
||||||
int32_t dispTriStart;
|
int32_t dispTriStart;
|
||||||
int32_t power;
|
int32_t power;
|
||||||
int32_t minTess;
|
int32_t minTess;
|
||||||
int32_t maxTess;
|
float smoothingAngle;
|
||||||
int32_t smoothingAngle;
|
|
||||||
int32_t contents;
|
int32_t contents;
|
||||||
uint16_t mapFace;
|
uint16_t mapFace;
|
||||||
int16_t lightmapAlphaStart;
|
uint16_t padding;
|
||||||
|
int32_t lightmapAlphaStart;
|
||||||
int32_t lightmapSamplePositionStart;
|
int32_t lightmapSamplePositionStart;
|
||||||
uint8_t padding[130];
|
|
||||||
|
BspDispNeighbor edgeNeighbors[4];
|
||||||
|
BspDispCornerNeighbors cornerNeighbors[4];
|
||||||
|
uint32_t allowedVerts[10];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
struct BspDispVert {
|
struct BspDispVert {
|
||||||
pod::Vector3f vec;
|
pod::Vector3f vec;
|
||||||
float dist;
|
float dist;
|
||||||
@ -259,8 +284,8 @@ namespace impl {
|
|||||||
corners[i].uv.x = uf::vector::dot( v, texInfo.textureVecs[0] ) / texWidth;
|
corners[i].uv.x = uf::vector::dot( v, texInfo.textureVecs[0] ) / texWidth;
|
||||||
corners[i].uv.y = uf::vector::dot( v, texInfo.textureVecs[1] ) / texHeight;
|
corners[i].uv.y = uf::vector::dot( v, texInfo.textureVecs[1] ) / texHeight;
|
||||||
|
|
||||||
corners[i].st.x = (uf::vector::dot( v, texInfo.lightmapVecs[0] ) - face.lightmapTextureMins.x) / (face.lightmapTextureSize.x + 1.0f);
|
corners[i].st.x = (uf::vector::dot( v, texInfo.lightmapVecs[0] ) + 0.5f - face.lightmapTextureMins.x) / (face.lightmapTextureSize.x + 1.0f);
|
||||||
corners[i].st.y = (uf::vector::dot( v, texInfo.lightmapVecs[1] ) - face.lightmapTextureMins.y) / (face.lightmapTextureSize.y + 1.0f);
|
corners[i].st.y = (uf::vector::dot( v, texInfo.lightmapVecs[1] ) + 0.5f - face.lightmapTextureMins.y) / (face.lightmapTextureSize.y + 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
int startIndex = 0;
|
int startIndex = 0;
|
||||||
@ -283,13 +308,36 @@ namespace impl {
|
|||||||
pod::Vector2f uvE1 = uf::vector::lerp( corners[3].uv, corners[2].uv, ty );
|
pod::Vector2f uvE1 = uf::vector::lerp( corners[3].uv, corners[2].uv, ty );
|
||||||
pod::Vector2f stE0 = uf::vector::lerp( corners[0].st, corners[1].st, ty );
|
pod::Vector2f stE0 = uf::vector::lerp( corners[0].st, corners[1].st, ty );
|
||||||
pod::Vector2f stE1 = uf::vector::lerp( corners[3].st, corners[2].st, ty );
|
pod::Vector2f stE1 = uf::vector::lerp( corners[3].st, corners[2].st, ty );
|
||||||
|
/*
|
||||||
|
pod::Vector3f posE0 = uf::vector::lerp( corners[0].pos, corners[1].pos, ty );
|
||||||
|
pod::Vector3f posE1 = uf::vector::lerp( corners[3].pos, corners[2].pos, ty );
|
||||||
|
pod::Vector2f uvE0 = uf::vector::lerp( corners[0].uv, corners[1].uv, ty );
|
||||||
|
pod::Vector2f uvE1 = uf::vector::lerp( corners[3].uv, corners[2].uv, ty );
|
||||||
|
pod::Vector2f stE0 = uf::vector::lerp( corners[0].st, corners[1].st, ty );
|
||||||
|
pod::Vector2f stE1 = uf::vector::lerp( corners[3].st, corners[2].st, ty );
|
||||||
|
*/
|
||||||
|
|
||||||
for ( int x = 0; x < side; ++x ) {
|
for ( int x = 0; x < side; ++x ) {
|
||||||
float tx = (float)x / (side - 1);
|
float tx = (float)x / (side - 1);
|
||||||
|
|
||||||
pod::Vector3f basePos = uf::vector::lerp( posE0, posE1, tx );
|
pod::Vector3f basePos = uf::vector::lerp( posE0, posE1, tx );
|
||||||
pod::Vector2f finalUv = uf::vector::lerp( uvE0, uvE1, tx );
|
|
||||||
pod::Vector2f finalSt = uf::vector::lerp( stE0, stE1, tx );
|
pod::Vector4f vBase = basePos;
|
||||||
|
vBase.w = 1.0f;
|
||||||
|
|
||||||
|
pod::Vector2f finalUv;
|
||||||
|
finalUv.x = uf::vector::dot( vBase, texInfo.textureVecs[0] ) / texWidth;
|
||||||
|
finalUv.y = uf::vector::dot( vBase, texInfo.textureVecs[1] ) / texHeight;
|
||||||
|
|
||||||
|
pod::Vector2f finalSt;
|
||||||
|
finalSt.x = tx;
|
||||||
|
finalSt.y = ty;
|
||||||
|
/*
|
||||||
|
finalSt.x = (uf::vector::dot( vBase, texInfo.lightmapVecs[0] ) + 0.5f - face.lightmapTextureMins.x) / (face.lightmapTextureSize.x + 1.0f);
|
||||||
|
finalSt.y = (uf::vector::dot( vBase, texInfo.lightmapVecs[1] ) + 0.5f - face.lightmapTextureMins.y) / (face.lightmapTextureSize.y + 1.0f);
|
||||||
|
//finalSt.x = 1.0f - finalSt.x; // ?
|
||||||
|
finalSt.y = 1.0f - finalSt.y; // ?
|
||||||
|
*/
|
||||||
|
|
||||||
int dispIdx = info.dispVertStart + y * side + x;
|
int dispIdx = info.dispVertStart + y * side + x;
|
||||||
const auto& dVert = context.dispverts[dispIdx];
|
const auto& dVert = context.dispverts[dispIdx];
|
||||||
@ -321,14 +369,24 @@ namespace impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto isVertAllowed = [&](int x, int y) -> bool {
|
||||||
|
int index = y * side + x;
|
||||||
|
int arrayIndex = index / 32;
|
||||||
|
int bitIndex = index % 32;
|
||||||
|
return ( info.allowedVerts[arrayIndex] & (1 << bitIndex) ) != 0;
|
||||||
|
};
|
||||||
|
|
||||||
for ( int y = 0; y < side - 1; ++y ) {
|
for ( int y = 0; y < side - 1; ++y ) {
|
||||||
for ( int x = 0; x < side - 1; ++x ) {
|
for ( int x = 0; x < side - 1; ++x ) {
|
||||||
|
if ( !isVertAllowed(x, y) || !isVertAllowed(x + 1, y) || !isVertAllowed(x, y + 1) || !isVertAllowed(x + 1, y + 1) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t v0 = startVertexID + y * side + x;
|
uint32_t v0 = startVertexID + y * side + x;
|
||||||
uint32_t v1 = startVertexID + y * side + (x + 1);
|
uint32_t v1 = startVertexID + y * side + (x + 1);
|
||||||
uint32_t v2 = startVertexID + (y + 1) * side + x;
|
uint32_t v2 = startVertexID + (y + 1) * side + x;
|
||||||
uint32_t v3 = startVertexID + (y + 1) * side + (x + 1);
|
uint32_t v3 = startVertexID + (y + 1) * side + (x + 1);
|
||||||
|
|
||||||
// might need to flip winding order
|
|
||||||
meshlet.indices.emplace_back(v0); meshlet.indices.emplace_back(v2); meshlet.indices.emplace_back(v1);
|
meshlet.indices.emplace_back(v0); meshlet.indices.emplace_back(v2); meshlet.indices.emplace_back(v1);
|
||||||
meshlet.indices.emplace_back(v1); meshlet.indices.emplace_back(v2); meshlet.indices.emplace_back(v3);
|
meshlet.indices.emplace_back(v1); meshlet.indices.emplace_back(v2); meshlet.indices.emplace_back(v3);
|
||||||
}
|
}
|
||||||
@ -418,6 +476,7 @@ namespace impl {
|
|||||||
auto classname = metadata["classname"].as<uf::stl::string>("");
|
auto classname = metadata["classname"].as<uf::stl::string>("");
|
||||||
//UF_MSG_INFO("Entity found: {}", classname);
|
//UF_MSG_INFO("Entity found: {}", classname);
|
||||||
node.name = classname;
|
node.name = classname;
|
||||||
|
node.mesh = -1;
|
||||||
|
|
||||||
// parse origin
|
// parse origin
|
||||||
auto origin = metadata["origin"].as<uf::stl::string>("");
|
auto origin = metadata["origin"].as<uf::stl::string>("");
|
||||||
@ -445,8 +504,9 @@ namespace impl {
|
|||||||
} else if ( model.length() > 4 && model.ends_with(".mdl") ) {
|
} else if ( model.length() > 4 && model.ends_with(".mdl") ) {
|
||||||
auto it = std::find(graph.meshes.begin(), graph.meshes.end(), model);
|
auto it = std::find(graph.meshes.begin(), graph.meshes.end(), model);
|
||||||
if ( it == graph.meshes.end() ) {
|
if ( it == graph.meshes.end() ) {
|
||||||
|
auto meshID = graph.meshes.size();
|
||||||
if ( ext::valve::loadMdl(graph, model) ) {
|
if ( ext::valve::loadMdl(graph, model) ) {
|
||||||
node.mesh = (int32_t)(graph.meshes.size() - 1);
|
node.mesh = meshID;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
node.mesh = (int32_t)std::distance(graph.meshes.begin(), it);
|
node.mesh = (int32_t)std::distance(graph.meshes.begin(), it);
|
||||||
@ -554,7 +614,7 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co
|
|||||||
|
|
||||||
const impl::BspHeader* header = (const impl::BspHeader*)(buffer.data());
|
const impl::BspHeader* header = (const impl::BspHeader*)(buffer.data());
|
||||||
if ( header->magic != 0x50534256 ) {
|
if ( header->magic != 0x50534256 ) {
|
||||||
UF_MSG_ERROR("Invalid VBSP magic number: {}", filename);
|
UF_MSG_ERROR("Invalid VBSP magic number: {:X}", header->magic);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -856,6 +916,8 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co
|
|||||||
image.loadFromBuffer( missing_pixels, { 2, 2 }, 8, 4 );
|
image.loadFromBuffer( missing_pixels, { 2, 2 }, 8, 4 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// disable exporting if loaded from a VPK
|
||||||
|
if ( filename.starts_with("valve://") ) graph.metadata["exporter"]["enabled"] = false;
|
||||||
graph.metadata["exporter"]["unwrap"] = false; // not necessary to unwrap
|
graph.metadata["exporter"]["unwrap"] = false; // not necessary to unwrap
|
||||||
|
|
||||||
uf::graph::postprocess( graph );
|
uf::graph::postprocess( graph );
|
||||||
|
|||||||
@ -6,6 +6,41 @@
|
|||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
struct mstudiomesh_t {
|
||||||
|
int32_t material;
|
||||||
|
int32_t modelindex;
|
||||||
|
int32_t numvertices;
|
||||||
|
int32_t vertexoffset;
|
||||||
|
int32_t flexes;
|
||||||
|
int32_t flexindex;
|
||||||
|
int32_t materialtype;
|
||||||
|
int32_t materialparam;
|
||||||
|
int32_t meshid;
|
||||||
|
pod::Vector3f center;
|
||||||
|
int32_t vertexdata_ptr;
|
||||||
|
int32_t vertexdata_lod[8];
|
||||||
|
uint8_t pad[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mstudiomodel_t {
|
||||||
|
char name[64];
|
||||||
|
int32_t type;
|
||||||
|
float boundingradius;
|
||||||
|
int32_t nummeshes;
|
||||||
|
int32_t meshindex;
|
||||||
|
int32_t numvertices;
|
||||||
|
int32_t vertexindex;
|
||||||
|
int32_t tangentsindex;
|
||||||
|
uint8_t pad[56];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mstudiobodyparts_t {
|
||||||
|
int32_t sznameindex;
|
||||||
|
int32_t nummodels;
|
||||||
|
int32_t base;
|
||||||
|
int32_t modelindex;
|
||||||
|
};
|
||||||
|
|
||||||
struct vertexFileHeader_t {
|
struct vertexFileHeader_t {
|
||||||
int32_t magic;
|
int32_t magic;
|
||||||
int32_t version;
|
int32_t version;
|
||||||
@ -18,6 +53,12 @@ namespace impl {
|
|||||||
int32_t tangentDataStart;
|
int32_t tangentDataStart;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct vertexFileFixup_t {
|
||||||
|
int32_t lod;
|
||||||
|
int32_t sourceVertexID;
|
||||||
|
int32_t numVertexes;
|
||||||
|
};
|
||||||
|
|
||||||
struct mstudioboneweight_t {
|
struct mstudioboneweight_t {
|
||||||
float weight[3];
|
float weight[3];
|
||||||
int8_t bone[3];
|
int8_t bone[3];
|
||||||
@ -68,8 +109,7 @@ namespace impl {
|
|||||||
|
|
||||||
// etc
|
// etc
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
struct vtxVertex_t {
|
struct vtxVertex_t {
|
||||||
uint8_t boneWeightIndex[3];
|
uint8_t boneWeightIndex[3];
|
||||||
uint8_t numBones;
|
uint8_t numBones;
|
||||||
@ -196,9 +236,24 @@ bool ext::valve::loadMdl( pod::Graph& graph, const uf::stl::string& filename ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract LOD0 ertices from VVD
|
// extract LOD0 vertices from VVD
|
||||||
const impl::mstudiovertex_t* vvdVertices = (const impl::mstudiovertex_t*)(vvdBuffer.data() + vvdHdr->vertexDataStart);
|
const impl::mstudiovertex_t* vvdVertices = (const impl::mstudiovertex_t*)(vvdBuffer.data() + vvdHdr->vertexDataStart);
|
||||||
int numLOD0Verts = vvdHdr->numLODVertexes[0];
|
uf::stl::vector<impl::mstudiovertex_t> lod0Vertices;
|
||||||
|
if ( vvdHdr->numFixups == 0 ) {
|
||||||
|
lod0Vertices.assign(vvdVertices, vvdVertices + vvdHdr->numLODVertexes[0]);
|
||||||
|
} else {
|
||||||
|
lod0Vertices.resize(vvdHdr->numLODVertexes[0]);
|
||||||
|
const impl::vertexFileFixup_t* fixups = (const impl::vertexFileFixup_t*)(vvdBuffer.data() + vvdHdr->fixupTableStart);
|
||||||
|
int targetIndex = 0;
|
||||||
|
for ( int i = 0; i < vvdHdr->numFixups; ++i ) {
|
||||||
|
if ( fixups[i].lod >= 0 ) {
|
||||||
|
std::memcpy(&lod0Vertices[targetIndex], &vvdVertices[fixups[i].sourceVertexID], fixups[i].numVertexes * sizeof(impl::mstudiovertex_t));
|
||||||
|
targetIndex += fixups[i].numVertexes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
|
||||||
// read VTX file
|
// read VTX file
|
||||||
uf::stl::string vtxPath = filename.substr(0, filename.find_last_of('.')) + ".dx90.vtx";
|
uf::stl::string vtxPath = filename.substr(0, filename.find_last_of('.')) + ".dx90.vtx";
|
||||||
@ -213,18 +268,22 @@ bool ext::valve::loadMdl( pod::Graph& graph, const uf::stl::string& filename ) {
|
|||||||
|
|
||||||
// traverse: BodyPart -> Model -> LOD0 -> Mesh -> StripGroup -> Indices
|
// traverse: BodyPart -> Model -> LOD0 -> Mesh -> StripGroup -> Indices
|
||||||
const impl::vtxBodyPart_t* bodyParts = (const impl::vtxBodyPart_t*)(vtxBuffer.data() + vtxHdr->bodyPartOffset);
|
const impl::vtxBodyPart_t* bodyParts = (const impl::vtxBodyPart_t*)(vtxBuffer.data() + vtxHdr->bodyPartOffset);
|
||||||
|
const impl::mstudiobodyparts_t* mdlBodyParts = (const impl::mstudiobodyparts_t*)((uint8_t*)mdlHdr + mdlHdr->bodypartindex);
|
||||||
|
|
||||||
for ( int bp = 0; bp < vtxHdr->numBodyParts; ++bp ) {
|
for ( int bp = 0; bp < vtxHdr->numBodyParts; ++bp ) {
|
||||||
const impl::vtxModel_t* models = (const impl::vtxModel_t*)((uint8_t*)&bodyParts[bp] + bodyParts[bp].modelOffset);
|
const impl::vtxModel_t* models = (const impl::vtxModel_t*)((uint8_t*)&bodyParts[bp] + bodyParts[bp].modelOffset);
|
||||||
|
const impl::mstudiomodel_t* mdlModels = (const impl::mstudiomodel_t*)((uint8_t*)&mdlBodyParts[bp] + mdlBodyParts[bp].modelindex);
|
||||||
|
|
||||||
for ( int m = 0; m < bodyParts[bp].numModels; ++m ) {
|
for ( int m = 0; m < bodyParts[bp].numModels; ++m ) {
|
||||||
const impl::vtxModelLOD_t* lods = (const impl::vtxModelLOD_t*)((uint8_t*)&models[m] + models[m].lodOffset);
|
const impl::vtxModelLOD_t* lods = (const impl::vtxModelLOD_t*)((uint8_t*)&models[m] + models[m].lodOffset);
|
||||||
const impl::vtxModelLOD_t& lod0 = lods[0];
|
const impl::vtxModelLOD_t& lod0 = lods[0];
|
||||||
|
|
||||||
const impl::vtxMesh_t* meshes = (const impl::vtxMesh_t*)((uint8_t*)&lod0 + lod0.meshOffset);
|
const impl::vtxMesh_t* meshes = (const impl::vtxMesh_t*)((uint8_t*)&lod0 + lod0.meshOffset);
|
||||||
|
const impl::mstudiomesh_t* mdlMeshes = (const impl::mstudiomesh_t*)((uint8_t*)&mdlModels[m] + mdlModels[m].meshindex);
|
||||||
|
|
||||||
for ( int meshID = 0; meshID < lod0.numMeshes; ++meshID ) {
|
for ( int meshID = 0; meshID < lod0.numMeshes; ++meshID ) {
|
||||||
const impl::vtxMesh_t& mesh = meshes[meshID];
|
const impl::vtxMesh_t& mesh = meshes[meshID];
|
||||||
|
const impl::mstudiomesh_t& mdlMesh = mdlMeshes[meshID];
|
||||||
|
|
||||||
auto& meshlet = meshlets.emplace_back();
|
auto& meshlet = meshlets.emplace_back();
|
||||||
uf::stl::unordered_map<uint16_t, uint32_t> vertRemap;
|
uf::stl::unordered_map<uint16_t, uint32_t> vertRemap;
|
||||||
@ -245,7 +304,7 @@ bool ext::valve::loadMdl( pod::Graph& graph, const uf::stl::string& filename ) {
|
|||||||
vertRemap[originalVvdID] = meshlet.vertices.size();
|
vertRemap[originalVvdID] = meshlet.vertices.size();
|
||||||
auto& vert = meshlet.vertices.emplace_back();
|
auto& vert = meshlet.vertices.emplace_back();
|
||||||
|
|
||||||
const auto& srcVert = vvdVertices[originalVvdID];
|
const auto& srcVert = lod0Vertices[mdlMesh.vertexoffset + originalVvdID];
|
||||||
|
|
||||||
vert.position = impl::convertPos( srcVert.m_vecPosition );
|
vert.position = impl::convertPos( srcVert.m_vecPosition );
|
||||||
vert.normal = uf::vector::normalize( impl::convertPos( srcVert.m_vecNormal, 1.0f ) );
|
vert.normal = uf::vector::normalize( impl::convertPos( srcVert.m_vecNormal, 1.0f ) );
|
||||||
@ -277,16 +336,13 @@ bool ext::valve::loadMdl( pod::Graph& graph, const uf::stl::string& filename ) {
|
|||||||
|
|
||||||
size_t materialID = 0;
|
size_t materialID = 0;
|
||||||
uf::stl::string matName = "missing_texture";
|
uf::stl::string matName = "missing_texture";
|
||||||
if ( meshID < materials.size() ) matName = materials[meshID];
|
if ( mdlMesh.material < materials.size() ) matName = materials[mdlMesh.material];
|
||||||
if ( storage.materials.map.count(matName) > 0 ) {
|
auto it = std::find(graph.materials.begin(), graph.materials.end(), matName);
|
||||||
// to-do: add an indexOf
|
if ( it == graph.materials.end() ) {
|
||||||
for ( ; materialID < graph.materials.size(); ++materialID ) {
|
|
||||||
if ( graph.materials[materialID] == matName ) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
materialID = graph.materials.size();
|
materialID = graph.materials.size();
|
||||||
auto& material = impl::addMaterial( graph, matName );
|
auto& material = impl::addMaterial( graph, matName );
|
||||||
|
} else {
|
||||||
|
materialID = (int32_t)std::distance(graph.materials.begin(), it);
|
||||||
}
|
}
|
||||||
|
|
||||||
meshlet.primitive.instance.materialID = materialID;
|
meshlet.primitive.instance.materialID = materialID;
|
||||||
@ -294,7 +350,11 @@ bool ext::valve::loadMdl( pod::Graph& graph, const uf::stl::string& filename ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !meshlets.empty() ) {
|
if ( meshlets.empty() ) {
|
||||||
|
UF_MSG_DEBUG("Empty mesh={}", filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto meshName = filename;
|
auto meshName = filename;
|
||||||
graph.meshes.emplace_back(meshName);
|
graph.meshes.emplace_back(meshName);
|
||||||
graph.primitives.emplace_back(meshName);
|
graph.primitives.emplace_back(meshName);
|
||||||
@ -303,7 +363,6 @@ bool ext::valve::loadMdl( pod::Graph& graph, const uf::stl::string& filename ) {
|
|||||||
auto& primitives = storage.primitives[meshName];
|
auto& primitives = storage.primitives[meshName];
|
||||||
|
|
||||||
mesh.compile( meshlets, primitives );
|
mesh.compile( meshlets, primitives );
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -9,6 +9,9 @@ void impl::solvePositions( uf::stl::vector<pod::Manifold>& manifolds, float dt,
|
|||||||
for ( auto& manifold : manifolds ) {
|
for ( auto& manifold : manifolds ) {
|
||||||
auto& a = *manifold.a;
|
auto& a = *manifold.a;
|
||||||
auto& b = *manifold.b;
|
auto& b = *manifold.b;
|
||||||
|
|
||||||
|
if ( (a.collider.category & pod::Collider::CATEGORY_TRIGGER) || (b.collider.category & pod::Collider::CATEGORY_TRIGGER) ) return;
|
||||||
|
|
||||||
auto tA = impl::getTransform( a );
|
auto tA = impl::getTransform( a );
|
||||||
auto tB = impl::getTransform( b );
|
auto tB = impl::getTransform( b );
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user