diff --git a/src/assets/ui.cpp b/src/assets/ui.cpp index 8810490..e2066af 100644 --- a/src/assets/ui.cpp +++ b/src/assets/ui.cpp @@ -33,9 +33,28 @@ void UI_loadFromPackage(CPakFileBuilder* const pak, const PakGuid_t assetGuid, c } pak->AddPointer(hdrChunk,offsetof(RuiHeader_v30_s,dataStructInitData),defaultValuesChunk,0); - PakPageLump_s transformDataChunk = pak->CreatePageLump(rui.transformData.size(),SF_CPU|SF_CLIENT,8); - memcpy(transformDataChunk.data,rui.transformData.data(),rui.transformData.size()); - pak->AddPointer(hdrChunk,offsetof(RuiHeader_v30_s,transformData),transformDataChunk,0); + if (!rui.keyframingMappings.empty()) + { + PakPageLump_s keyframingChunk = pak->CreatePageLump(rui.RuntimeKeyframingSize(), SF_CPU | SF_CLIENT, 8); + const size_t keyframingValuesOffset = rui.keyframingMappings.size() * sizeof(RuiMapping_v30_s); + + if (!rui.keyframingValues.empty()) + memcpy(&keyframingChunk.data[keyframingValuesOffset], rui.keyframingValues.data(), rui.keyframingValues.size()); + + for (size_t i = 0; i < rui.keyframingMappings.size(); ++i) + { + const RuiPackageMapping_v1_t& packageMapping = rui.keyframingMappings[i]; + RuiMapping_v30_s* const mapping = reinterpret_cast(&keyframingChunk.data[i * sizeof(RuiMapping_v30_s)]); + + mapping->dataCount = packageMapping.dataCount; + mapping->nestedMappingCount = packageMapping.nestedMappingCount; + mapping->cublicSpline = packageMapping.cublicSpline != 0; + + pak->AddPointer(keyframingChunk, (i * sizeof(RuiMapping_v30_s)) + offsetof(RuiMapping_v30_s, data), keyframingChunk, keyframingValuesOffset + rui.keyframingValueOffsets[i]); + } + + pak->AddPointer(hdrChunk, offsetof(RuiHeader_v30_s, keyframings), keyframingChunk, 0); + } PakPageLump_s argClustersChunk = pak->CreatePageLump(rui.argCluster.size()*sizeof(ArgCluster_s),SF_CPU|SF_CLIENT,8); memcpy(argClustersChunk.data,rui.argCluster.data(),rui.argCluster.size()*sizeof(ArgCluster_s)); @@ -55,6 +74,10 @@ void UI_loadFromPackage(CPakFileBuilder* const pak, const PakGuid_t assetGuid, c memcpy(renderJobChunk.data,rui.renderJobs.data(),rui.renderJobs.size()); pak->AddPointer(hdrChunk,offsetof(RuiHeader_v30_s,renderJobData),renderJobChunk,0); + PakPageLump_s transformDataChunk = pak->CreatePageLump(rui.transformData.size(),SF_CPU|SF_CLIENT,8); + memcpy(transformDataChunk.data,rui.transformData.data(),rui.transformData.size()); + pak->AddPointer(hdrChunk,offsetof(RuiHeader_v30_s,transformData),transformDataChunk,0); + asset.InitAsset(hdrChunk.GetPointer(),sizeof(RuiHeader_v30_s), PagePtr_t::NullPtr(),R2_UI_VERSION,AssetType::UI); asset.SetHeaderPointer(hdrChunk.data); @@ -68,4 +91,4 @@ void Assets::AddRuiAsset_v30(CPakFileBuilder* const pak, const PakGuid_t assetGu { UNUSED(mapEntry); UI_loadFromPackage(pak,assetGuid,assetPath); -} \ No newline at end of file +} diff --git a/src/logic/pakfile.cpp b/src/logic/pakfile.cpp index b15f105..537cbce 100644 --- a/src/logic/pakfile.cpp +++ b/src/logic/pakfile.cpp @@ -774,6 +774,13 @@ void CPakFileBuilder::BuildFromMap(const js::Document& doc) Log("*** building pak file \"%s\".\n", m_pakFilePath.c_str()); + // If this is set and we have "example.rpak", the runtime will load the + // library `example.dll` during the load of `example.rpak`, from the same + // directory the pak is being loaded from. The loading of the library + // happens before the individual assets are being loaded and parsed. + if (JSON_GetValueOrDefault(doc, "hasDynamicLibrary", false)) + m_Header.flags |= PAK_HEADER_FLAGS_HAS_MODULE; + // Skip the header data at first so we can come back and fill it in when we have all of the info out.Pad(GetVersion() >= 8 ? PAK_HEADER_SIZE_V8 : PAK_HEADER_SIZE_V6); @@ -847,12 +854,6 @@ void CPakFileBuilder::BuildFromMap(const js::Document& doc) // set header descriptors this->SetFileTime(Utils::GetSystemFileTime()); - // If this is set and we have "example.rpak", the runtime will load the - // library `example.dll` during the load of `example.rpak`, from the same - // directory the pak is being loaded from. The loading of the library - // happens before the individual assets are being loaded and parsed. - if (JSON_GetValueOrDefault(doc, "hasDynamicLibrary", false)) - m_Header.flags |= PAK_HEADER_FLAGS_HAS_MODULE; // Go back to the start of the file since now we can write the header successfully out.SeekPut(0); diff --git a/src/public/rui_package.h b/src/public/rui_package.h index fe9e04c..3d3885c 100644 --- a/src/public/rui_package.h +++ b/src/public/rui_package.h @@ -45,6 +45,14 @@ struct RuiPackageHeader_v1_t { }; #pragma pack(pop) +struct RuiPackageMapping_v1_t { + uint32_t dataCount; + uint16_t nestedMappingCount; + uint16_t cublicSpline; +}; + +static_assert(sizeof(RuiPackageMapping_v1_t) == 8); + struct RuiPackage { @@ -95,6 +103,11 @@ struct RuiPackage { argCluster.resize(hdr.argClusterCount); fread(argCluster.data(),sizeof(ArgCluster_s),hdr.argClusterCount,f); + fseek(f, (long)hdr.keyframingOffset, 0); + std::vector keyframingData; + keyframingData.resize(hdr.keyframingSize); + fread(keyframingData.data(), 1, hdr.keyframingSize, f); + ParseKeyframingData(keyframingData); fclose(f); } else { @@ -103,7 +116,7 @@ struct RuiPackage { } RuiHeader_v30_s CreateRuiHeader_v30() { - RuiHeader_v30_s ruiHdr; + RuiHeader_v30_s ruiHdr{}; ruiHdr.elementWidth = hdr.elementWidth; ruiHdr.elementHeight = hdr.elementHeight; @@ -122,6 +135,45 @@ struct RuiPackage { return ruiHdr; } + void ParseKeyframingData(const std::vector& keyframingData) { + const size_t mappingDataSize = static_cast(hdr.keyframingCount) * sizeof(RuiPackageMapping_v1_t); + + if (hdr.keyframingSize < mappingDataSize) + Error("RUI package keyframing data is too small for %u mappings (%u bytes, expected at least %zu).\n", + hdr.keyframingCount, hdr.keyframingSize, mappingDataSize); + + keyframingMappings.resize(hdr.keyframingCount); + + if (!keyframingMappings.empty()) + memcpy(keyframingMappings.data(), keyframingData.data(), mappingDataSize); + + const size_t valuesSize = static_cast(hdr.keyframingSize) - mappingDataSize; + keyframingValues.resize(valuesSize); + keyframingValueOffsets.clear(); + + if (valuesSize > 0) + memcpy(keyframingValues.data(), &keyframingData[mappingDataSize], valuesSize); + + size_t valueOffset = 0; + + for (const RuiPackageMapping_v1_t& mapping : keyframingMappings) + { + keyframingValueOffsets.push_back(valueOffset); + + const size_t nestedValueCount = static_cast(mapping.dataCount) * mapping.nestedMappingCount; + const size_t valueFloatCount = static_cast(mapping.dataCount) + nestedValueCount + (mapping.cublicSpline ? nestedValueCount : 0); + const size_t valueSize = valueFloatCount * sizeof(float); + + + + valueOffset += valueSize; + } + } + + size_t RuntimeKeyframingSize() const { + return (keyframingMappings.size() * sizeof(RuiMapping_v30_s)) + keyframingValues.size(); + } + RuiPackageHeader_v1_t hdr{}; std::vector name; @@ -133,4 +185,7 @@ struct RuiPackage { std::vector arguments; std::vector argCluster; std::vector styleDescriptors; -}; \ No newline at end of file + std::vector keyframingMappings; + std::vector keyframingValueOffsets; + std::vector keyframingValues; +}; diff --git a/src/public/ui.h b/src/public/ui.h index 1f8bece..da90c12 100644 --- a/src/public/ui.h +++ b/src/public/ui.h @@ -72,6 +72,16 @@ struct StyleDescriptor_v30_s { uint16_t val_32; }; +struct RuiMapping_v30_s +{ + uint32_t dataCount; + uint16_t nestedMappingCount; + bool cublicSpline; + uint8_t pad; + float* data; +}; +static_assert(sizeof(RuiMapping_v30_s) == 16); + struct RuiHeader_v30_s { const char* name; @@ -94,6 +104,6 @@ struct RuiHeader_v30_s uint16_t argClusterCount; StyleDescriptor_v30_s* styleDescriptors; uint8_t* renderJobData; - void* keyframings; // maps values to others through linar/qubicSpline regression + RuiMapping_v30_s* keyframings; // maps values to others through linear/cubic spline regression };