mirror of
https://github.com/izzy2lost/Diddy-Kong-Racing.git
synced 2026-06-19 01:16:26 -07:00
DKR Assets Tool v0.5.2 (Basic glTF support) (#610)
* Removed old unused files * Added gltf support * Reverted dkr_assets_tool_settings.json to previous * Added animated model example * document audio_vehicle.c (#588) * wip * wip * wip * wip * document audio_vehicle.c * update score once again * unify function prefix * small tweaks * match func_80060910 and func_80060AC8 (#589) * match func_80060AC8 * reworked func_80060C58 * match func_80060910 * non equivalent func_8006017C * format * match calc_env_mapping_for_object * Homogenate batch flags and render flags and begin the painful task of documenting waves. (#590) * part one of wave pain * 2 * littel bit more * m * h * l * aagghh * yeah * :) * bruh * b * m * faith * z * b * rename batch flags * Update waves.c * fix conflicts * match func_8000B38C (#592) * match func_8000B38C * format code * update score * match calc_dynamic_lighting_for_object_1 (#594) * match calc_dynamic_lighting_for_object_1 * format and score * update score * update score again * Document some Boost data (#593) * Run formatter * Document some boost info * decompile and document math_util.c (#595) * Match func_8002F440 (#596) * Add a WIP attempt of func_8004447C, and add some scratch links * match func_8002F440 and run formatter * Cleanup some comments * Update score, fix warnings, and run formatter again * Remove some bad comments * match: func_8007FFEC (#599) * feat: allow score script to generate treemap file for decomp progress (#598) * Various touchups here and there, some renames in camera.c (#597) * the beginning of the void * update asset tool * void :) * there * cam * model * more * fix warns * ok * whoops missed a rename * Add a few NON_EQUIVALENT functions from scratches to keep them up to date (#602) * WIP func_800101AC * WIP func_800452A0 * cleanup * Formatter and func_8004CC20 near match * func_8004CC20 better score and documentation * func_80049794 WIP and compilable * Major cleanup of func_80049794 * Formatter * Update scratch * Add func_80019808 from scratch * Cleanup func_80019808 * func_80019808 score improvment * Improve func_80049794 score (Thanks Dominik!) * func_8001C6C4 WIP * func_8001E93C WIP * small documenting * Eliminate a lot of Obj64 casts. * fix: do not pass default to treemap arg (#604) * Quick fix for score script (#606) * WIP func_80060EA8 * Quick fix for score script * name and document lights, CC modes and textures (#607) * improve match for func_800BDC80 & match func_80060EA8, func_8002F2AC (#609) * improve match for func_800BDC80 & match func_80060EA8 * match: func_8002F2AC * match: func_800452A0 & func_80042D20 (#611) * partial match: func_800452A0, improve from non equiv to non matching * match: func_800452A0 & func_80042D20 * document: remaining funcs, add decomp.me links (#612) * match func_8004447C (#615) * Document camera and sprites (#614) * Cleanup, and use constants where possible (#617) * Update func_80060EA8 WIP * formatter * More func_80060EA8 * More func_80060EA8 * WIP func_80060EA8 * Minor cleanups and documenting * minot cleanup * Define some constant flags properly * Misc documenting and cleanup * formatter * Fix the scratch link for vsprintf (It was DP's) * Add the WIP version of vsprintf that's 95.82% matching. * Fix score script (#619) * Added gltf support * Allow either commas or vertical pipes for splitting render flags --------- Co-authored-by: Unnunu <serge_zorkin@mail.ru> Co-authored-by: Fazana <52551480+FazanaJ@users.noreply.github.com> Co-authored-by: Ryan Myers <ryan.p.myers@gmail.com> Co-authored-by: Dominik Peters <github@d-peters.com>
This commit is contained in:
co-authored by
Unnunu
Fazana
Ryan Myers
Dominik Peters
parent
bb9ed5ea5d
commit
e30f1c535a
@@ -410,7 +410,7 @@ endif
|
||||
|
||||
build_assets:
|
||||
$(info Building Assets...)
|
||||
@$(TOOLS_DIR)/dkr_assets_tool build -o $(ASSETS_OUTPUT) -dkrv $(REGION).$(VERSION) $(MODDED_ARG) >&2 || echo FAIL
|
||||
@$(TOOLS_DIR)/dkr_assets_tool build -o $(ASSETS_OUTPUT) -dkrv $(REGION).$(VERSION) $(MODDED_ARG) >&2 || exit 1
|
||||
|
||||
###############################
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ All versions are supported, and the US 1.0 version (SHA1 = 0cb115d8716dbbc2922fd
|
||||
<!-- README_SCORE_SUMMARY_BEGIN -->
|
||||
As of June 11, 2025, this is our current score:
|
||||
|
||||
    Decomp progress: 90.62%
|
||||
    Decomp progress: 90.87%
|
||||
|
||||
    Documentation progress: 59.08%
|
||||
    Documentation progress: 59.40%
|
||||
<!-- README_SCORE_SUMMARY_END -->
|
||||
|
||||
---
|
||||
@@ -119,28 +119,28 @@ s32 is_drumstick_unlocked(void) {
|
||||
<!-- README_SCORE_BEGIN -->
|
||||
As of June 11, 2025, this is our current score:
|
||||
```
|
||||
===================================================================
|
||||
ADVENTURE ONE (ASM -> C Decompilation)
|
||||
-------------- 90.62% Complete (91.40% NON_MATCHING) --------------
|
||||
# Decompiled functions: 1912
|
||||
# GLOBAL_ASM remaining: 32
|
||||
====================================================================
|
||||
ADVENTURE ONE (ASM -> C Decompilation)
|
||||
-------------- 90.87% Complete (91.65% NON_MATCHING) ---------------
|
||||
# Decompiled functions: 1913
|
||||
# GLOBAL_ASM remaining: 37
|
||||
# NON_MATCHING functions: 4
|
||||
# NON_EQUIVALENT WIP functions: 28
|
||||
--------------------------- Game Status ---------------------------
|
||||
# NON_EQUIVALENT WIP functions: 30
|
||||
--------------------------- Game Status ----------------------------
|
||||
Balloons: 42/47, Keys: 4/4, Trophies: 4/5
|
||||
T.T. Amulets: 4/4, Wizpig Amulets: 4/4
|
||||
-------------------------------------------------------------------
|
||||
T.T. Amulets: 4/4, Wizpig Amulets: 4/4
|
||||
--------------------------------------------------------------------
|
||||
We are racing in Star City. (Lap 3/3)
|
||||
===================================================================
|
||||
====================================================================
|
||||
ADVENTURE TWO (Cleanup & Documentation)
|
||||
------------------------- 59.08% Complete -------------------------
|
||||
# Documented functions: 1207
|
||||
# Undocumented remaining: 440
|
||||
--------------------------- Game Status ---------------------------
|
||||
Balloons: 28/47, Keys: 3/4, Trophies: 2/5
|
||||
T.T. Amulets: 3/4, Wizpig Amulets: 2/4
|
||||
-------------------------------------------------------------------
|
||||
We are collecting silver coins in Pirate Lagoon. (8/8 silver coins)
|
||||
===================================================================
|
||||
------------------------- 59.40% Complete --------------------------
|
||||
# Documented functions: 1208
|
||||
# Undocumented remaining: 445
|
||||
--------------------------- Game Status ----------------------------
|
||||
Balloons: 29/47, Keys: 3/4, Trophies: 2/5
|
||||
T.T. Amulets: 3/4, Wizpig Amulets: 2/4
|
||||
--------------------------------------------------------------------
|
||||
We are collecting silver coins in Treasure Caves. (1/8 silver coins)
|
||||
====================================================================
|
||||
```
|
||||
<!-- README_SCORE_END -->
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"files": {
|
||||
"order": [
|
||||
"ASSET_CUSTOM_ANIMATED_TESTCUBE"
|
||||
],
|
||||
"sections": {
|
||||
"ASSET_CUSTOM_ANIMATED_TESTCUBE": {
|
||||
"filename": "animatedBox.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "Custom Animated Model Test",
|
||||
"authors" : ["Example"],
|
||||
"description": "A simple cube model with a custom animation."
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,288 @@
|
||||
{
|
||||
"asset":{
|
||||
"generator":"Khronos glTF Blender I/O v4.2.70",
|
||||
"version":"2.0"
|
||||
},
|
||||
"scene":0,
|
||||
"scenes":[
|
||||
{
|
||||
"name":"Scene",
|
||||
"nodes":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes":[
|
||||
{
|
||||
"mesh":0,
|
||||
"name":"Cube"
|
||||
}
|
||||
],
|
||||
"animations":[
|
||||
{
|
||||
"channels":[
|
||||
{
|
||||
"sampler":0,
|
||||
"target":{
|
||||
"node":0,
|
||||
"path":"weights"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name":"Key.001Action",
|
||||
"samplers":[
|
||||
{
|
||||
"input":9,
|
||||
"interpolation":"LINEAR",
|
||||
"output":10
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials":[
|
||||
{
|
||||
"doubleSided":true,
|
||||
"name":"Material.001",
|
||||
"pbrMetallicRoughness":{
|
||||
"baseColorTexture":{
|
||||
"index":0
|
||||
},
|
||||
"metallicFactor":0,
|
||||
"roughnessFactor":0.5
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes":[
|
||||
{
|
||||
"extras":{
|
||||
"targetNames":[
|
||||
"Key 1",
|
||||
"Key 2"
|
||||
]
|
||||
},
|
||||
"name":"Cube.001",
|
||||
"primitives":[
|
||||
{
|
||||
"attributes":{
|
||||
"POSITION":0,
|
||||
"NORMAL":1,
|
||||
"TEXCOORD_0":2,
|
||||
"COLOR_0":3
|
||||
},
|
||||
"indices":4,
|
||||
"material":0,
|
||||
"targets":[
|
||||
{
|
||||
"POSITION":5,
|
||||
"NORMAL":6
|
||||
},
|
||||
{
|
||||
"POSITION":7,
|
||||
"NORMAL":8
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"weights":[
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures":[
|
||||
{
|
||||
"sampler":0,
|
||||
"source":0
|
||||
}
|
||||
],
|
||||
"images":[
|
||||
{
|
||||
"mimeType":"image/png",
|
||||
"name":"logo",
|
||||
"uri":"logo.png"
|
||||
}
|
||||
],
|
||||
"accessors":[
|
||||
{
|
||||
"bufferView":0,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"max":[
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"min":[
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":1,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":2,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"type":"VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView":3,
|
||||
"componentType":5123,
|
||||
"count":24,
|
||||
"normalized":true,
|
||||
"type":"VEC4"
|
||||
},
|
||||
{
|
||||
"bufferView":4,
|
||||
"componentType":5123,
|
||||
"count":36,
|
||||
"type":"SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView":5,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"max":[
|
||||
0.5727667212486267,
|
||||
0,
|
||||
0.9693711996078491
|
||||
],
|
||||
"min":[
|
||||
-1.1323010921478271,
|
||||
0,
|
||||
-0.820482611656189
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":6,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":7,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"max":[
|
||||
0.8063837289810181,
|
||||
0,
|
||||
1.0958211421966553
|
||||
],
|
||||
"min":[
|
||||
-0.9761124849319458,
|
||||
0,
|
||||
-0.6933281421661377
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":8,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":9,
|
||||
"componentType":5126,
|
||||
"count":25,
|
||||
"max":[
|
||||
1
|
||||
],
|
||||
"min":[
|
||||
0
|
||||
],
|
||||
"type":"SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView":10,
|
||||
"componentType":5126,
|
||||
"count":50,
|
||||
"type":"SCALAR"
|
||||
}
|
||||
],
|
||||
"bufferViews":[
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":0,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":288,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":192,
|
||||
"byteOffset":576,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":192,
|
||||
"byteOffset":768,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":72,
|
||||
"byteOffset":960,
|
||||
"target":34963
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":1032,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":1320,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":1608,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":1896,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":100,
|
||||
"byteOffset":2184
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":200,
|
||||
"byteOffset":2284
|
||||
}
|
||||
],
|
||||
"samplers":[
|
||||
{
|
||||
"magFilter":9729,
|
||||
"minFilter":9987
|
||||
}
|
||||
],
|
||||
"buffers":[
|
||||
{
|
||||
"byteLength":2484,
|
||||
"uri":"animatedBox.bin"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"model": "animatedBox.gltf",
|
||||
"type": "ObjectModel",
|
||||
"scale": 10.0,
|
||||
"animation": {
|
||||
"seconds-per-keyframe": 0.25
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 288 B |
@@ -6490,12 +6490,10 @@ void func_80019808(s32 updateRate) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((currentLevelHeader->race_type != RACETYPE_CHALLENGE_BATTLE && numFinishedRacers > 0) ||
|
||||
((((numHumanRacers == 1 && numHumanRacersFinished == 1) ||
|
||||
(numHumanRacers >= 2 && numHumanRacersFinished >= numHumanRacers)) ||
|
||||
numFinishedRacers >= 3))) {
|
||||
|
||||
for (i = 0; i < gNumRacers; i++) {
|
||||
if (currentLevelHeader->race_type == RACETYPE_CHALLENGE_BATTLE) {
|
||||
sp5C[i] = 10 - racer[i]->bananas;
|
||||
@@ -6542,7 +6540,6 @@ void func_80019808(s32 updateRate) {
|
||||
} while (racerIndex != -1);
|
||||
|
||||
gSwapLeadPlayer = FALSE;
|
||||
|
||||
if (!is_in_tracks_mode() &&
|
||||
(racer[0]->finishPosition == 1 ||
|
||||
is_in_two_player_adventure() && racer[1]->finishPosition == 1) &&
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Make `OPT` -g for better debugging info.
|
||||
OPT := -O2
|
||||
|
||||
# If -g option was set, then add some debugging flags for the stack tracer.
|
||||
ifneq (,$(findstring -g,$(OPT)))
|
||||
OPT += -rdynamic -ldl -lelf -ldwarf -DDEBUG -I/usr/include/libdwarf
|
||||
endif
|
||||
|
||||
CC := gcc
|
||||
CXX := g++
|
||||
CFLAGS := -I . -Wall -Wextra -Wno-unused-parameter -pedantic -std=c99 $(OPT) -s
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"build-subpath" : "build/",
|
||||
"data-subpath" : "data/",
|
||||
"model-scale": 0.001,
|
||||
"threads" : 0,
|
||||
"threads" : 1,
|
||||
"debug": {
|
||||
"keep-uncompressed": true,
|
||||
"write-assets-map": false
|
||||
|
||||
@@ -29,8 +29,9 @@ BuildInfo::BuildInfo(std::string buildId, std::string buildSectionId, const Json
|
||||
_type = jsonFile.get_string("/type", "NoType");
|
||||
}
|
||||
|
||||
BuildInfo::BuildInfo(std::string buildId, std::string buildSectionId, const std::vector<uint8_t> &outData, size_t fileIndex, const fs::path &dir, const BuildInfoContext &infoContext)
|
||||
: out(outData), _dstPath(""), _localDirectory(dir), _jsonFile(std::nullopt), _infoContext(infoContext), _buildId(buildId), _buildSectionId(buildSectionId), _type("Binary"), _fileIndex(fileIndex) {
|
||||
BuildInfo::BuildInfo(std::string buildId, std::string buildSectionId, std::string deferredFromBuildId, std::string deferredFromSectionId, const std::vector<uint8_t> &outData,
|
||||
size_t fileIndex, const fs::path &dir, const BuildInfoContext &infoContext) : out(outData), _dstPath(""), _localDirectory(dir), _jsonFile(std::nullopt), _infoContext(infoContext),
|
||||
_buildId(buildId), _buildSectionId(buildSectionId), _deferredFromBuildId(deferredFromBuildId), _deferredFromSectionId(deferredFromSectionId), _type("Binary"), _fileIndex(fileIndex) {
|
||||
_buildType = BUILD_TO_BINARY;
|
||||
}
|
||||
|
||||
@@ -116,10 +117,22 @@ std::string BuildInfo::get_section_build_id() const {
|
||||
return _buildSectionId;
|
||||
}
|
||||
|
||||
std::string BuildInfo::get_deferred_from_build_id() const {
|
||||
return _deferredFromBuildId;
|
||||
}
|
||||
|
||||
std::string BuildInfo::get_deferred_from_section_build_id() const {
|
||||
return _deferredFromSectionId;
|
||||
}
|
||||
|
||||
size_t BuildInfo::get_file_index() const {
|
||||
return _fileIndex;
|
||||
}
|
||||
|
||||
bool BuildInfo::is_deferred() const {
|
||||
return !_deferredFromSectionId.empty();
|
||||
}
|
||||
|
||||
bool BuildInfo::is_complete() const {
|
||||
return _complete;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ public:
|
||||
//BuildInfo(std::string buildId, JsonFile *src, const fs::path &dst, const fs::path &dir); // BUILD_TO_FILE, TODO
|
||||
//BuildInfo(std::string buildId, JsonFile *src, const fs::path &dir); // BUILD_TO_BINARY
|
||||
BuildInfo(std::string buildId, std::string buildSectionId, const JsonFile &src, size_t fileIndex, const fs::path &dir, const BuildInfoContext &infoContext);
|
||||
BuildInfo(std::string buildId, std::string buildSectionId, const std::vector<uint8_t> &outData, size_t fileIndex, const fs::path &dir, const BuildInfoContext &infoContext);
|
||||
BuildInfo(std::string buildId, std::string buildSectionId, std::string deferredFromBuildId, std::string deferredFromSectionId, const std::vector<uint8_t> &outData,
|
||||
size_t fileIndex, const fs::path &dir, const BuildInfoContext &infoContext);
|
||||
~BuildInfo();
|
||||
|
||||
std::vector<uint8_t> out;
|
||||
@@ -56,8 +57,12 @@ public:
|
||||
std::string get_type() const;
|
||||
std::string get_build_id() const;
|
||||
std::string get_section_build_id() const;
|
||||
std::string get_deferred_from_build_id() const;
|
||||
std::string get_deferred_from_section_build_id() const;
|
||||
size_t get_file_index() const;
|
||||
|
||||
bool is_deferred() const; // Returns true if this asset was deferred from another section.
|
||||
|
||||
bool is_complete() const;
|
||||
void done();
|
||||
|
||||
@@ -75,6 +80,8 @@ private:
|
||||
|
||||
std::string _buildId;
|
||||
std::string _buildSectionId;
|
||||
std::string _deferredFromBuildId;
|
||||
std::string _deferredFromSectionId;
|
||||
std::string _type;
|
||||
size_t _fileIndex;
|
||||
BuildInfoType _buildType;
|
||||
|
||||
@@ -46,7 +46,8 @@ void BuildInfoCollection::add_build_info(std::string sectionBuildId, std::string
|
||||
_buildInfoMutex.unlock();
|
||||
}
|
||||
|
||||
size_t BuildInfoCollection::add_deferred_build_info(std::string sectionBuildId, std::string buildId, const std::vector<uint8_t> &out, const fs::path &dir, const BuildInfoContext &infoContext) {
|
||||
size_t BuildInfoCollection::add_deferred_build_info(std::string sectionBuildId, std::string buildId, std::string deferredFromBuildId, std::string deferredFromSectionId,
|
||||
const std::vector<uint8_t> &out, const fs::path &dir, const BuildInfoContext &infoContext) {
|
||||
_buildInfoMutex.lock();
|
||||
|
||||
if(_buildInfoSections.find(sectionBuildId) == _buildInfoSections.end()) {
|
||||
@@ -59,7 +60,7 @@ size_t BuildInfoCollection::add_deferred_build_info(std::string sectionBuildId,
|
||||
"(BuildInfoCollection::add_build_info) Max number of assets reached! Limit was ", MAX_NUMBER_OF_BUILD_INFOS);
|
||||
|
||||
size_t fileIndex = _buildInfoSections[sectionBuildId].size();
|
||||
_buildInfos.emplace_back(buildId, sectionBuildId, out, fileIndex, dir, infoContext);
|
||||
_buildInfos.emplace_back(buildId, sectionBuildId, deferredFromBuildId, deferredFromSectionId, out, fileIndex, dir, infoContext);
|
||||
|
||||
// Do not process deferred assets.
|
||||
_buildInfos.back().done();
|
||||
@@ -72,8 +73,8 @@ size_t BuildInfoCollection::add_deferred_build_info(std::string sectionBuildId,
|
||||
return fileIndex;
|
||||
}
|
||||
|
||||
void BuildInfoCollection::add_deferred_build_info(std::string sectionBuildId, std::string buildId, size_t fileIndex, const std::vector<uint8_t> &out,
|
||||
const fs::path &dir, const BuildInfoContext &infoContext) {
|
||||
void BuildInfoCollection::add_deferred_build_info(std::string sectionBuildId, std::string buildId, std::string deferredFromBuildId, std::string deferredFromSectionId,
|
||||
size_t fileIndex, const std::vector<uint8_t> &out, const fs::path &dir, const BuildInfoContext &infoContext) {
|
||||
_buildInfoMutex.lock();
|
||||
|
||||
if(_buildInfoSections.find(sectionBuildId) == _buildInfoSections.end()) {
|
||||
@@ -89,7 +90,7 @@ void BuildInfoCollection::add_deferred_build_info(std::string sectionBuildId, st
|
||||
DebugHelper::assert_(index < MAX_NUMBER_OF_BUILD_INFOS,
|
||||
"(BuildInfoCollection::add_build_info) Max number of assets reached! Limit was ", MAX_NUMBER_OF_BUILD_INFOS);
|
||||
|
||||
_buildInfos.emplace_back(buildId, sectionBuildId, out, fileIndex, dir, infoContext);
|
||||
_buildInfos.emplace_back(buildId, sectionBuildId, deferredFromBuildId, deferredFromSectionId, out, fileIndex, dir, infoContext);
|
||||
|
||||
// Do not process deferred assets.
|
||||
_buildInfos.back().done();
|
||||
|
||||
@@ -19,12 +19,12 @@ public:
|
||||
void add_build_info(std::string sectionBuildId, std::string buildId, const JsonFile &src, const fs::path &dir, const BuildInfoContext &infoContext);
|
||||
|
||||
// Adds deferred info to the end of the list. Returns the fileIndex of the added asset.
|
||||
size_t add_deferred_build_info(std::string sectionBuildId, std::string buildId, const std::vector<uint8_t> &out,
|
||||
const fs::path &dir, const BuildInfoContext &infoContext);
|
||||
size_t add_deferred_build_info(std::string sectionBuildId, std::string buildId, std::string deferredFromBuildId, std::string deferredFromSectionId,
|
||||
const std::vector<uint8_t> &out, const fs::path &dir, const BuildInfoContext &infoContext);
|
||||
|
||||
// Adds deferred info to a specific file index.
|
||||
void add_deferred_build_info(std::string sectionBuildId, std::string buildId, size_t fileIndex, const std::vector<uint8_t> &out,
|
||||
const fs::path &dir, const BuildInfoContext &infoContext);
|
||||
void add_deferred_build_info(std::string sectionBuildId, std::string buildId, std::string deferredFromBuildId, std::string deferredFromSectionId,
|
||||
size_t fileIndex, const std::vector<uint8_t> &out, const fs::path &dir, const BuildInfoContext &infoContext);
|
||||
|
||||
void run_builds(std::function<void(BuildInfo &info)> callbackFunction, const std::vector<std::string> §ionsOrder);
|
||||
|
||||
|
||||
@@ -121,8 +121,8 @@ void build_v77_beta_font(BuildInfo &info, const JsonFile &jsonFile) {
|
||||
//outJpFontTableView.print(0, outJpFontTable.size());
|
||||
|
||||
// Add jp font table to build collection.
|
||||
collection.add_deferred_build_info("ASSET_JAPANESE_FONTS_TABLE", "ASSET_JAPANESE_FONTS_TABLE", outJpFontTable,
|
||||
info.get_dst_folder() / deferInfo.outputPath, info.get_info_context());
|
||||
collection.add_deferred_build_info("ASSET_JAPANESE_FONTS_TABLE", "ASSET_JAPANESE_FONTS_TABLE", info.get_build_id(),
|
||||
info.get_section_build_id(), outJpFontTable,info.get_dst_folder() / deferInfo.outputPath, info.get_info_context());
|
||||
|
||||
}
|
||||
|
||||
@@ -282,8 +282,8 @@ void build_v79_jp_fonts(BuildInfo &info, const JsonFile &jsonFile) {
|
||||
}
|
||||
|
||||
// Add jp font table to build collection.
|
||||
collection.add_deferred_build_info("ASSET_JAPANESE_FONTS_TABLE", "ASSET_JAPANESE_FONTS_TABLE", outJpFontTable,
|
||||
info.get_dst_folder() / deferInfo.outputPath, info.get_info_context());
|
||||
collection.add_deferred_build_info("ASSET_JAPANESE_FONTS_TABLE", "ASSET_JAPANESE_FONTS_TABLE", info.get_build_id(),
|
||||
info.get_section_build_id(), outJpFontTable,info.get_dst_folder() / deferInfo.outputPath, info.get_info_context());
|
||||
}
|
||||
|
||||
void BuildJPFonts::build(BuildInfo &info) {
|
||||
|
||||
@@ -89,8 +89,8 @@ void build_level_name(BuildInfo &info, const JsonFile &jsonFile) {
|
||||
BuildInfoCollection &collection = info.get_collection();
|
||||
std::string buildId = info.get_build_id() + deferInfo.idPostfix;
|
||||
|
||||
collection.add_deferred_build_info(levelNamesSectionBuildId, buildId, info.get_file_index(),
|
||||
out, info.get_dst_folder() / deferInfo.outputPath, info.get_info_context());
|
||||
collection.add_deferred_build_info(levelNamesSectionBuildId, buildId, info.get_build_id(), info.get_section_build_id(),
|
||||
info.get_file_index(), out, info.get_dst_folder() / deferInfo.outputPath, info.get_info_context());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,29 +10,42 @@
|
||||
#include "fileTypes/vertex.hpp"
|
||||
#include "fileTypes/textureInfo.hpp"
|
||||
|
||||
#include "libs/bytes_view.hpp"
|
||||
|
||||
#include "misc/globalSettings.h"
|
||||
|
||||
#include "builder/buildInfoCollection.h"
|
||||
|
||||
using namespace DkrAssetsTool;
|
||||
|
||||
void BuildModel::generate_object_model(BuildInfo &info) {
|
||||
const JsonFile &modelJson = info.get_src_json_file();
|
||||
float modelScale = modelJson.get_float("/scale", 1000.0f);
|
||||
|
||||
size_t numberOfTriangles = _total_number_of_triangles();
|
||||
size_t numberOfVertices = _total_number_of_vertices();
|
||||
size_t numberOfAnimatedVertices = _total_number_of_animated_vertices();
|
||||
size_t numberOfBatches = _total_number_of_batches();
|
||||
size_t numberOfBatchesToAllocate = _total_number_of_batches_to_allocate();
|
||||
size_t numberOfTextures = _total_number_of_textures();
|
||||
size_t numberOfAttachPoints = _attachPoints.size();
|
||||
|
||||
size_t sizeOfHeader = DataHelper::align16(sizeof(ObjectModel));
|
||||
size_t sizeOfTextures = DataHelper::align16(sizeof(DkrTextureInfo) * numberOfTextures);
|
||||
size_t sizeOfVertices = DataHelper::align16(sizeof(DkrVertex) * numberOfVertices);
|
||||
size_t sizeOfVertices = DataHelper::align16(sizeof(DkrVertex) * (numberOfVertices + numberOfAttachPoints));
|
||||
size_t sizeOfTriangles = DataHelper::align16(sizeof(DkrTriangle) * numberOfTriangles);
|
||||
size_t sizeOfBatches = DataHelper::align16(sizeof(DkrBatch) * numberOfBatchesToAllocate);
|
||||
size_t sizeOfAnimatedVertexIndices = _animations.empty() ? 0 : DataHelper::align16(sizeof(int16_t) * numberOfVertices);
|
||||
size_t sizeOfAttachPoints = DataHelper::align16(sizeof(be_int16_t) * numberOfAttachPoints);
|
||||
|
||||
// Calculated the file size for the binary model file.
|
||||
size_t calculatedFileSize = sizeOfHeader +
|
||||
sizeOfTextures +
|
||||
sizeOfVertices +
|
||||
sizeOfTriangles +
|
||||
sizeOfBatches;
|
||||
sizeOfBatches +
|
||||
sizeOfAnimatedVertexIndices +
|
||||
sizeOfAttachPoints;
|
||||
|
||||
info.out.resize(calculatedFileSize);
|
||||
|
||||
@@ -42,27 +55,47 @@ void BuildModel::generate_object_model(BuildInfo &info) {
|
||||
objectModelHeader->vertices = objectModelHeader->textures + sizeOfTextures;
|
||||
objectModelHeader->triangles = objectModelHeader->vertices + sizeOfVertices;
|
||||
objectModelHeader->batches = objectModelHeader->triangles + sizeOfTriangles;
|
||||
objectModelHeader->numberOfTextures= (int16_t)numberOfTextures;
|
||||
objectModelHeader->animatedVertexIndices = objectModelHeader->batches + sizeOfBatches;
|
||||
objectModelHeader->attachPoints = objectModelHeader->animatedVertexIndices + sizeOfAnimatedVertexIndices;
|
||||
objectModelHeader->numberOfTextures = (int16_t)numberOfTextures;
|
||||
objectModelHeader->numberOfTriangles = (int16_t)numberOfTriangles;
|
||||
objectModelHeader->numberOfVertices = (int16_t)numberOfVertices;
|
||||
objectModelHeader->numberOfBatches = (int16_t)numberOfBatches;
|
||||
objectModelHeader->numberOfAttachPoints = (int16_t)numberOfAttachPoints;
|
||||
objectModelHeader->fileSize = (int16_t)calculatedFileSize;
|
||||
objectModelHeader->numberOfAnimatedVertices = (int16_t)numberOfAnimatedVertices;
|
||||
|
||||
DkrTextureInfo *textures = reinterpret_cast<DkrTextureInfo *>(&info.out[objectModelHeader->textures]);
|
||||
DkrVertex *vertices = reinterpret_cast<DkrVertex *>(&info.out[objectModelHeader->vertices]);
|
||||
DkrTriangle *triangles = reinterpret_cast<DkrTriangle *>(&info.out[objectModelHeader->triangles]);
|
||||
DkrBatch *batches = reinterpret_cast<DkrBatch *>(&info.out[objectModelHeader->batches]);
|
||||
be_int16_t *animatedVertexIndices = reinterpret_cast<be_int16_t *>(&info.out[objectModelHeader->animatedVertexIndices]);
|
||||
be_int16_t *attachPoints = reinterpret_cast<be_int16_t *>(&info.out[objectModelHeader->attachPoints]);
|
||||
|
||||
bool hasAnimatedTexture = false;
|
||||
for(size_t materialIndex = 0; materialIndex < numberOfTextures; materialIndex++) {
|
||||
BuildModelMaterial &material = _materials[materialIndex];
|
||||
|
||||
material.write_to(&textures[materialIndex], info);
|
||||
hasAnimatedTexture = hasAnimatedTexture || material.is_texture_animated();
|
||||
}
|
||||
objectModelHeader->hasAnimatedTexture = (int)hasAnimatedTexture;
|
||||
|
||||
for(auto &block : _blocks) {
|
||||
block.write_batches(_materialIds, _materials, batches, vertices, triangles);
|
||||
block.write_batches(_materialIds, _materials, batches, vertices, triangles, modelScale);
|
||||
}
|
||||
|
||||
// Does nothing with static models.
|
||||
_generate_animations(info, objectModelHeader, animatedVertexIndices);
|
||||
|
||||
vertices = reinterpret_cast<DkrVertex *>(&info.out[objectModelHeader->vertices]);
|
||||
for(size_t i = 0; i < numberOfAttachPoints; i++) {
|
||||
attachPoints[i] = numberOfVertices + i;
|
||||
|
||||
DkrVertex *vertex = &vertices[numberOfVertices + i];
|
||||
vertex->x = static_cast<int16_t>(_attachPoints[i].x * modelScale);
|
||||
vertex->y = static_cast<int16_t>(_attachPoints[i].y * modelScale);
|
||||
vertex->z = static_cast<int16_t>(_attachPoints[i].z * modelScale);
|
||||
}
|
||||
|
||||
bool debugKeepUncompressed = GlobalSettings::get_value<bool>("/debug/keep-uncompressed", false);
|
||||
@@ -105,7 +138,16 @@ void BuildModel::_add_material(std::string id, fs::path texturePath) {
|
||||
return;
|
||||
}
|
||||
_materialIds[id] = _materials.size();
|
||||
_materials.emplace_back(texturePath);
|
||||
_materials.emplace_back(texturePath, id);
|
||||
}
|
||||
|
||||
void BuildModel::_add_material(std::string id, uint8_t *imgData, size_t imgDataLength, std::string mimeType) {
|
||||
if(imgData == nullptr || imgDataLength == 0) {
|
||||
_materialIds[id] = -1;
|
||||
return;
|
||||
}
|
||||
_materialIds[id] = _materials.size();
|
||||
_materials.emplace_back(imgData, imgDataLength, mimeType, id);
|
||||
}
|
||||
|
||||
void BuildModel::_set_material(std::string id) {
|
||||
@@ -145,6 +187,24 @@ size_t BuildModel::_total_number_of_vertices() {
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t BuildModel::_total_number_of_animated_vertices() {
|
||||
if(_animations.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
for(auto &block : _blocks) {
|
||||
block.process_vertices([&count](BuildModelVertex &vertex) {
|
||||
if(vertex.is_animated()) {
|
||||
count++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t BuildModel::_total_number_of_textures() {
|
||||
size_t count = 0;
|
||||
|
||||
@@ -176,3 +236,148 @@ size_t BuildModel::_total_number_of_batches_to_allocate() {
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template<typename T, typename T2>
|
||||
inline void process_keyframe(T *keyframe, size_t &animDataOffset, const std::vector<std::reference_wrapper<BuildModelVertex>> &animatedVertices, AnimWeights &weights,
|
||||
std::optional<AnimWeights> previousWeights, float modelScale) {
|
||||
size_t numberOfAnimatedVertices = animatedVertices.size();
|
||||
Vec3f vertexDelta;
|
||||
|
||||
for(size_t i = 0; i < numberOfAnimatedVertices; i++) {
|
||||
const BuildModelVertex &vertex = animatedVertices.at(i);
|
||||
if(previousWeights.has_value()) {
|
||||
vertexDelta = vertex.animated_position(weights) - vertex.animated_position(previousWeights.value());
|
||||
} else {
|
||||
vertexDelta = vertex.animated_position(weights) - vertex.position();
|
||||
}
|
||||
|
||||
keyframe[i].offsetX = static_cast<T2>(vertexDelta.x * modelScale);
|
||||
keyframe[i].offsetY = static_cast<T2>(vertexDelta.y * modelScale);
|
||||
keyframe[i].offsetZ = static_cast<T2>(vertexDelta.z * modelScale);
|
||||
}
|
||||
|
||||
animDataOffset += sizeof(T) * numberOfAnimatedVertices;
|
||||
}
|
||||
|
||||
void BuildModel::_generate_animations(BuildInfo &info, ObjectModel *objectModelHeader, be_int16_t *outAnimatedIndicesPtr) {
|
||||
if((_animations.empty()) || (objectModelHeader->numberOfAnimatedVertices < 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<int16_t> animatedVertexIndices;
|
||||
std::vector<std::reference_wrapper<BuildModelVertex>> animatedVertices;
|
||||
|
||||
animatedVertexIndices.reserve(objectModelHeader->numberOfVertices);
|
||||
animatedVertices.reserve(objectModelHeader->numberOfVertices); // Should have no more than the number of vertices.
|
||||
|
||||
for(auto &block : _blocks) {
|
||||
block.process_vertices([&animatedVertexIndices, &animatedVertices](BuildModelVertex &vertex) {
|
||||
if(!vertex.is_animated()) {
|
||||
animatedVertexIndices.emplace_back(-1);
|
||||
return; // Don't include this vertex.
|
||||
}
|
||||
animatedVertexIndices.emplace_back(animatedVertices.size());
|
||||
animatedVertices.emplace_back(vertex);
|
||||
});
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < objectModelHeader->numberOfVertices; i++) {
|
||||
outAnimatedIndicesPtr[i] = animatedVertexIndices[i];
|
||||
}
|
||||
|
||||
std::optional<AnimWeights> weights = std::nullopt;
|
||||
std::optional<AnimTranslations> translations = std::nullopt;
|
||||
std::optional<AnimRotations> rotations = std::nullopt;
|
||||
std::optional<AnimScales> scales = std::nullopt;
|
||||
|
||||
std::optional<AnimWeights> previousWeights = std::nullopt;
|
||||
|
||||
size_t numberOfAnimatedVertices = animatedVertices.size();
|
||||
|
||||
bool debugKeepUncompressed = GlobalSettings::get_value<bool>("/debug/keep-uncompressed", false);
|
||||
|
||||
BuildInfoCollection &collection = info.get_collection();
|
||||
|
||||
std::vector<size_t> animationIndices;
|
||||
|
||||
const JsonFile &modelJson = info.get_src_json_file();
|
||||
float secondsPerKeyframe = modelJson.get_float("/animation/seconds-per-keyframe", 0.267f);
|
||||
float modelScale = modelJson.get_float("/scale", 1000.0f);
|
||||
|
||||
size_t animIndex = 0;
|
||||
for(BuildModelAnimation &anim : _animations) {
|
||||
size_t numberOfKeyframes = std::floor(anim.get_max_time() / secondsPerKeyframe) + 1;
|
||||
|
||||
size_t animationDataSize = sizeof(ObjectModelAnimationHeader) +
|
||||
(sizeof(ObjectModelAnimationKeyframeHeader) * numberOfKeyframes) + // Each keyframe has a header that is 12-bytes long. Mainly used for head tilting?
|
||||
(sizeof(ObjectModelAnimationKeyframeVertexS16) * numberOfAnimatedVertices) + // First keyframe uses 16-bit values.
|
||||
(sizeof(ObjectModelAnimationKeyframeVertexS8) * (numberOfAnimatedVertices - 1) * numberOfKeyframes); // Following keyframes use 8-bit values.
|
||||
|
||||
std::vector<uint8_t> animationData(animationDataSize);
|
||||
BytesView animDataView(animationData);
|
||||
size_t animDataOffset = 0;
|
||||
|
||||
ObjectModelAnimationHeader *animHeader = animDataView.data_cast<ObjectModelAnimationHeader>(animDataOffset);
|
||||
animHeader->keyframeCount = numberOfKeyframes;
|
||||
|
||||
animDataOffset += sizeof(ObjectModelAnimationHeader);
|
||||
|
||||
bool skipAnimation = false;
|
||||
|
||||
for(size_t keyframe = 0; keyframe < numberOfKeyframes; keyframe++) {
|
||||
//ObjectModelAnimationKeyframeHeader *keyframeHeader = animDataView.data_cast<ObjectModelAnimationKeyframeHeader>(animDataOffset);
|
||||
animDataOffset += sizeof(ObjectModelAnimationKeyframeHeader);
|
||||
|
||||
float keyframeTime = keyframe * secondsPerKeyframe;
|
||||
anim.get_inputs_for_time(keyframeTime, weights, translations, rotations, scales);
|
||||
|
||||
if(keyframe == 0) {
|
||||
if(translations.has_value() || rotations.has_value() || scales.has_value()) {
|
||||
DebugHelper::warn("Only morph target/shape key animation is supported at the moment.");
|
||||
}
|
||||
if(!weights.has_value()) {
|
||||
skipAnimation = true;
|
||||
break; // Only Morph Targets are supported at the moment.
|
||||
}
|
||||
|
||||
ObjectModelAnimationKeyframeVertexS16 *firstKeyframe = animDataView.data_cast<ObjectModelAnimationKeyframeVertexS16>(animDataOffset);
|
||||
process_keyframe<ObjectModelAnimationKeyframeVertexS16, int16_t>(firstKeyframe, animDataOffset, animatedVertices,
|
||||
weights.value(), std::nullopt, modelScale);
|
||||
} else {
|
||||
ObjectModelAnimationKeyframeVertexS8 *followingKeyframe = animDataView.data_cast<ObjectModelAnimationKeyframeVertexS8>(animDataOffset);
|
||||
process_keyframe<ObjectModelAnimationKeyframeVertexS8, int8_t>(followingKeyframe, animDataOffset, animatedVertices,
|
||||
weights.value(), previousWeights, modelScale);
|
||||
}
|
||||
|
||||
previousWeights = weights;
|
||||
}
|
||||
|
||||
if(skipAnimation) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while((animationData.size() % 16) != 0) {
|
||||
animationData.emplace_back(0);
|
||||
}
|
||||
|
||||
std::string buildId = info.get_build_id() + "_ANIM_" + std::to_string(animIndex);
|
||||
|
||||
if(debugKeepUncompressed) {
|
||||
fs::path outUncompressedPath = GlobalSettings::get_decomp_path("build_subpath", "build/");
|
||||
outUncompressedPath /= "debug/custom-animations";
|
||||
outUncompressedPath /= buildId + ".bin";
|
||||
FileHelper::write_binary_file(animationData, outUncompressedPath, true);
|
||||
}
|
||||
|
||||
animationData = GzipHelper::compress_gzip(animationData);
|
||||
|
||||
size_t newAnimId = collection.add_deferred_build_info("ASSET_OBJECT_ANIMATIONS", buildId, info.get_build_id(), info.get_section_build_id(),
|
||||
animationData, info.get_path_to_directory(), info.get_info_context());
|
||||
|
||||
animationIndices.emplace_back(newAnimId);
|
||||
|
||||
animIndex++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
|
||||
#include "helpers/fileHelper.h"
|
||||
#include "fileTypes/batch.hpp"
|
||||
#include "fileTypes/objectModel.hpp"
|
||||
|
||||
#include "buildModelBlock.h"
|
||||
#include "buildModelMaterial.h"
|
||||
#include "buildModelAnimation.h"
|
||||
|
||||
namespace DkrAssetsTool {
|
||||
|
||||
@@ -26,21 +28,29 @@ protected:
|
||||
std::vector<BuildModelMaterial> _materials;
|
||||
std::map<std::string, int> _materialIds;
|
||||
|
||||
std::vector<BuildModelAnimation> _animations;
|
||||
|
||||
std::vector<Vec3f> _attachPoints;
|
||||
|
||||
void _add_new_triangle_to_current_block(const BuildModelVertex& vertA, const BuildModelVertex& vertB, const BuildModelVertex& vertC,
|
||||
Vec2f uv0, Vec2f uv1, Vec2f uv2);
|
||||
void _add_new_triangle_to_current_block(const BuildModelVertex& vertA, const BuildModelVertex& vertB, const BuildModelVertex& vertC);
|
||||
void _new_block();
|
||||
|
||||
void _add_material(std::string id, fs::path texturePath="");
|
||||
void _add_material(std::string id, uint8_t *imgData, size_t imgDataLength, std::string mimeType);
|
||||
void _set_material(std::string id);
|
||||
|
||||
std::optional<std::reference_wrapper<BuildModelMaterial>> _try_get_material(std::string id);
|
||||
|
||||
size_t _total_number_of_triangles();
|
||||
size_t _total_number_of_vertices();
|
||||
size_t _total_number_of_animated_vertices();
|
||||
size_t _total_number_of_textures();
|
||||
size_t _total_number_of_batches();
|
||||
size_t _total_number_of_batches_to_allocate();
|
||||
|
||||
void _generate_animations(BuildInfo &info, ObjectModel *objectModelHeader, be_int16_t *outAnimatedIndicesPtr);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
#include "buildModelAnimation.h"
|
||||
|
||||
#include "helpers/dataHelper.h"
|
||||
#include "helpers/debugHelper.h"
|
||||
#include "helpers/gltf/gltfHelper.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace DkrAssetsTool;
|
||||
|
||||
/***************************************************************************************************************/
|
||||
|
||||
AnimWeights BuildModelAnimationInputs::get_weights_at_time(float time) {
|
||||
if(time < 0) {
|
||||
time = 0;
|
||||
}
|
||||
|
||||
if(!weights.has_value()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::map<float, AnimWeights> &inputWeights = weights.value();
|
||||
|
||||
if(inputWeights.find(time) != inputWeights.end()) {
|
||||
// No need to interpolate!
|
||||
return inputWeights.at(time);
|
||||
}
|
||||
|
||||
auto upperBound = inputWeights.upper_bound(time);
|
||||
auto lowerBound = std::prev(upperBound);
|
||||
|
||||
float lowerTime = lowerBound->first;
|
||||
float upperTime = upperBound->first;
|
||||
|
||||
DebugHelper::info(time, " is between ", lowerTime, " and ", upperTime);
|
||||
|
||||
// Should handle the edgecases of time being outside timeline range.
|
||||
if(lowerTime == upperTime) {
|
||||
return upperBound->second;
|
||||
}
|
||||
|
||||
AnimWeights &lowerWeights = lowerBound->second;
|
||||
AnimWeights &upperWeights = upperBound->second;
|
||||
|
||||
// Percentage of interpolation.
|
||||
float t = (time - lowerTime) / (upperTime - lowerTime);
|
||||
|
||||
AnimWeights out(lowerWeights.size());
|
||||
|
||||
for(size_t i = 0; i < lowerWeights.size(); i++) {
|
||||
// Linear interpolation of weights.
|
||||
out[i] = lowerWeights[i] + t * (upperWeights[i] - lowerWeights[i]);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
AnimTranslations BuildModelAnimationInputs::get_translations_at_time(float time) {
|
||||
return {};
|
||||
}
|
||||
|
||||
AnimRotations BuildModelAnimationInputs::get_rotations_at_time(float time) {
|
||||
return {};
|
||||
}
|
||||
|
||||
AnimScales BuildModelAnimationInputs::get_scales_at_time(float time) {
|
||||
return {};
|
||||
}
|
||||
|
||||
/***************************************************************************************************************/
|
||||
|
||||
BuildModelAnimation::BuildModelAnimation() {
|
||||
}
|
||||
|
||||
BuildModelAnimation::BuildModelAnimation(GltfFile &gltf, tinygltf::Animation &animation) {
|
||||
for(size_t i = 0; i < animation.channels.size(); i++) {
|
||||
tinygltf::AnimationChannel &channel = animation.channels[i];
|
||||
|
||||
if(channel.sampler < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tinygltf::AnimationSampler &sampler = animation.samplers[channel.sampler];
|
||||
|
||||
if(sampler.interpolation != "LINEAR") {
|
||||
DebugHelper::warn(sampler.interpolation + " is currently not supported. Will use LINEAR instead.");
|
||||
}
|
||||
|
||||
// I believe animation inputs are always floats? Couldn't find anything 100% definitive in the spec.
|
||||
std::vector<float> inputTimes = GltfHelper::get_data_from_accessor<float>(gltf, sampler.input);
|
||||
size_t numberOfInputs = inputTimes.size();
|
||||
|
||||
if(channel.target_path == "weights") {
|
||||
// morph targets
|
||||
auto tryGetWeights = GltfHelper::get_weights_from_accessor(gltf, sampler.output);
|
||||
DebugHelper::assert_(tryGetWeights.has_value(),
|
||||
"(BuildModelAnimation::BuildModelAnimation) Failed to get weights from gltf accessor ", sampler.output);
|
||||
std::vector<float> &weights = tryGetWeights.value();
|
||||
size_t numberOfWeights = weights.size() / numberOfInputs;
|
||||
|
||||
for(size_t j = 0; j < numberOfInputs; j++) {
|
||||
add_weights_input(inputTimes[j], weights, j * numberOfWeights, numberOfWeights);
|
||||
}
|
||||
} else if(channel.target_path == "translation") {
|
||||
DebugHelper::warn("(BuildModelAnimation::BuildModelAnimation) TODO: Support translation channel.path");
|
||||
} else if(channel.target_path == "rotation") {
|
||||
DebugHelper::warn("(BuildModelAnimation::BuildModelAnimation) TODO: Support rotation channel.path");
|
||||
} else if(channel.target_path == "scale") {
|
||||
DebugHelper::warn("(BuildModelAnimation::BuildModelAnimation) TODO: Support scale channel.path");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BuildModelAnimation::add_weights_input(float time, std::vector<float> &values, std::optional<size_t> offset, std::optional<size_t> length) {
|
||||
if(offset == std::nullopt) {
|
||||
offset = 0;
|
||||
}
|
||||
if(length == std::nullopt) {
|
||||
length = values.size() - offset.value();
|
||||
}
|
||||
|
||||
if(_inputs.weights == std::nullopt) {
|
||||
_inputs.weights = std::map<float, std::vector<float>>();
|
||||
}
|
||||
|
||||
_inputs.weights.value()[time] = std::vector<float>(values.begin() + offset.value(), values.begin() + offset.value() + length.value());
|
||||
|
||||
if(time > _maxTime) {
|
||||
_maxTime = time;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<float> BuildModelAnimation::get_timeline() {
|
||||
std::vector<float> timeline;
|
||||
int numberOfSections = 0;
|
||||
|
||||
if(_inputs.weights.has_value()) {
|
||||
for(auto &pair : _inputs.weights.value()) {
|
||||
timeline.emplace_back(pair.first);
|
||||
}
|
||||
numberOfSections++;
|
||||
}
|
||||
|
||||
if(_inputs.translations.has_value()) {
|
||||
for(auto &pair : _inputs.translations.value()) {
|
||||
if(DataHelper::vector_has(timeline, pair.first)) {
|
||||
continue;
|
||||
}
|
||||
timeline.emplace_back(pair.first);
|
||||
}
|
||||
numberOfSections++;
|
||||
}
|
||||
|
||||
if(_inputs.rotations.has_value()) {
|
||||
for(auto &pair : _inputs.rotations.value()) {
|
||||
if(DataHelper::vector_has(timeline, pair.first)) {
|
||||
continue;
|
||||
}
|
||||
timeline.emplace_back(pair.first);
|
||||
}
|
||||
numberOfSections++;
|
||||
}
|
||||
|
||||
if(_inputs.scales.has_value()) {
|
||||
for(auto &pair : _inputs.scales.value()) {
|
||||
if(DataHelper::vector_has(timeline, pair.first)) {
|
||||
continue;
|
||||
}
|
||||
timeline.emplace_back(pair.first);
|
||||
}
|
||||
numberOfSections++;
|
||||
}
|
||||
|
||||
if(numberOfSections > 1) {
|
||||
std::sort(timeline.begin(), timeline.end());
|
||||
}
|
||||
|
||||
return timeline;
|
||||
}
|
||||
|
||||
float BuildModelAnimation::get_max_time() const {
|
||||
return _maxTime;
|
||||
}
|
||||
|
||||
// Returns weights/translations/rotations/scales for a specific time input. Values will be set to std::nullopt if there is no data.
|
||||
// Values will be interpolated if there is data, but the time input was not specified.
|
||||
void BuildModelAnimation::get_inputs_for_time(float time, std::optional<AnimWeights> &outWeights, std::optional<AnimTranslations> &outTranslations,
|
||||
std::optional<AnimRotations> &outRotations, std::optional<AnimScales> &outScales) {
|
||||
// Set new data
|
||||
if(_inputs.weights.has_value()) {
|
||||
outWeights = _inputs.get_weights_at_time(time);
|
||||
} else {
|
||||
outWeights = std::nullopt;
|
||||
}
|
||||
if(_inputs.translations.has_value()) {
|
||||
outTranslations = _inputs.get_translations_at_time(time);
|
||||
} else {
|
||||
outTranslations = std::nullopt;
|
||||
}
|
||||
if(_inputs.rotations.has_value()) {
|
||||
outRotations = _inputs.get_rotations_at_time(time);
|
||||
} else {
|
||||
outRotations = std::nullopt;
|
||||
}
|
||||
if(_inputs.scales.has_value()) {
|
||||
outScales = _inputs.get_scales_at_time(time);
|
||||
} else {
|
||||
outScales = std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
bool BuildModelAnimation::only_has_morph_targets() const {
|
||||
return _inputs.weights.has_value() && !_inputs.translations.has_value() &&
|
||||
!_inputs.rotations.has_value() && !_inputs.scales.has_value();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user