#include "common.h" #include "hybrid.h" template struct hqrSubEntryStruct { s16 key; s16 size; unsigned int lastTimeUsed; T* ptr; }; template struct hqrEntryStruct { std::string string; u16 maxFreeData; u16 sizeFreeData; u16 numMaxEntry; u16 numUsedEntry; std::vector> entries; }; template hqrSubEntryStruct* quickFindEntry(int index, int numMax, std::vector>& ptr) // no RE. Original was probably faster { for(int i=0;i hqrEntryStruct* HQR_InitRessource(const char* name, int size, int numEntries) { hqrEntryStruct* dest = new hqrEntryStruct(); if(!dest) return NULL; numEntries = 2000; dest->string = name; dest->sizeFreeData = size; dest->maxFreeData = size; dest->numMaxEntry = numEntries; dest->numUsedEntry = 0; dest->entries.resize(numEntries); for(int i=0;ientries[i].ptr = nullptr; } return(dest); } int HQ_Malloc(hqrEntryStruct* hqrPtr,int size) { int key; int entryNum; if(hqrPtr->sizeFreeDatanumUsedEntry; key = hqrKeyGen; hqrPtr->entries[entryNum].key = key; // dataPtr1[entryNum].offset = hqrPtr->maxFreeData - hqrPtr->sizeFreeData; hqrPtr->entries[entryNum].size = size; hqrPtr->entries[entryNum].ptr = (char*)malloc(size); hqrPtr->numUsedEntry++; hqrPtr->sizeFreeData -= size; hqrKeyGen++; return(key); } char* HQ_PtrMalloc(hqrEntryStruct* hqrPtr, int index) { if(index<0) return NULL; hqrSubEntryStruct* ptr = quickFindEntry(index, hqrPtr->numUsedEntry, hqrPtr->entries); if(!ptr) return NULL; return(ptr->ptr); } sAnimation* createAnimationFromPtr(void* ptr, int size) { u8* animPtr = (u8*)ptr; sAnimation* pAnimation = new sAnimation; pAnimation->m_raw = ptr; pAnimation->m_numFrames = READ_LE_U16(animPtr); animPtr += 2; pAnimation->m_numGroups = READ_LE_U16(animPtr); animPtr += 2; int fullSizeNoOptim = 2 + 2 + pAnimation->m_numFrames * (2 + 2 + 2 + 2 + pAnimation->m_numGroups * (2 + 2 + 2 + 2)); int fullSizeWithOptim = 2 + 2 + pAnimation->m_numFrames * (2 + 2 + 2 + 2 + pAnimation->m_numGroups * (2 + 2 + 2 + 2 + 2 + 2 + 2 + 2)); bool bUseOptim = false; if (size == fullSizeWithOptim) { bUseOptim = true; } else { assert(size == fullSizeNoOptim); } pAnimation->m_frames.resize(pAnimation->m_numFrames); for (int i = 0; i < pAnimation->m_numFrames; i++) { sFrame* pFrame = &pAnimation->m_frames[i]; pFrame->m_timestamp = READ_LE_U16(animPtr); animPtr += 2; pFrame->m_animStep.x = READ_LE_S16(animPtr); animPtr += 2; pFrame->m_animStep.y = READ_LE_S16(animPtr); animPtr += 2; pFrame->m_animStep.z = READ_LE_S16(animPtr); animPtr += 2; pFrame->m_groups.resize(pAnimation->m_numGroups); for (int i = 0; i < pAnimation->m_numGroups; i++) { sGroupState* pGroup = &pFrame->m_groups[i]; pGroup->m_type = READ_LE_S16(animPtr); animPtr += 2; pGroup->m_delta.x = READ_LE_S16(animPtr); animPtr += 2; pGroup->m_delta.y = READ_LE_S16(animPtr); animPtr += 2; pGroup->m_delta.z = READ_LE_S16(animPtr); animPtr += 2; if (bUseOptim) { pGroup->m_rotateDelta.emplace(); pGroup->m_rotateDelta.value().x = READ_LE_S16(animPtr); animPtr += 2; pGroup->m_rotateDelta.value().y = READ_LE_S16(animPtr); animPtr += 2; pGroup->m_rotateDelta.value().z = READ_LE_S16(animPtr); animPtr += 2; animPtr += 2; } } } return pAnimation; } sBody* createBodyFromPtr(void* ptr) { u8* bodyBuffer = (u8*)ptr; sBody* newBody = new sBody; newBody->m_raw = ptr; newBody->m_flags = READ_LE_U16(bodyBuffer); bodyBuffer += 2; newBody->m_zv.ZVX1 = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_zv.ZVX2 = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_zv.ZVY1 = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_zv.ZVY2 = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_zv.ZVZ1 = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_zv.ZVZ2 = READ_LE_S16(bodyBuffer); bodyBuffer += 2; u16 scratchBufferSize = READ_LE_U16(bodyBuffer); bodyBuffer += 2; newBody->m_scratchBuffer.resize(scratchBufferSize); for (int i = 0; i < scratchBufferSize; i++) { newBody->m_scratchBuffer[i] = READ_LE_U8(bodyBuffer); bodyBuffer += 1; } u16 numVertices = READ_LE_U16(bodyBuffer); bodyBuffer += 2; newBody->m_vertices.resize(numVertices); for (int i = 0; i < numVertices; i++) { newBody->m_vertices[i].x = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_vertices[i].y = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_vertices[i].z = READ_LE_S16(bodyBuffer); bodyBuffer += 2; } if (newBody->m_flags & INFO_TORTUE) { assert(0); // never used } if (newBody->m_flags & INFO_ANIM) { u16 numGroups = READ_LE_U16(bodyBuffer); bodyBuffer += 2; newBody->m_groupOrder.reserve(numGroups); newBody->m_groups.resize(numGroups); if (newBody->m_flags & INFO_OPTIMISE) // AITD2+ { for (int i = 0; i < numGroups; i++) { u16 offset = READ_LE_U16(bodyBuffer); assert(offset % 0x18 == 0); newBody->m_groupOrder.push_back(offset / 0x18); bodyBuffer += 2; } for (int i = 0; i < numGroups; i++) { newBody->m_groups[i].m_start = READ_LE_S16(bodyBuffer) / 6; bodyBuffer += 2; newBody->m_groups[i].m_numVertices = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_groups[i].m_baseVertices = READ_LE_S16(bodyBuffer) / 6; bodyBuffer += 2; newBody->m_groups[i].m_orgGroup = READ_LE_S8(bodyBuffer); bodyBuffer += 1; newBody->m_groups[i].m_numGroup = READ_LE_S8(bodyBuffer); bodyBuffer += 1; newBody->m_groups[i].m_state.m_type = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_groups[i].m_state.m_delta.x = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_groups[i].m_state.m_delta.y = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_groups[i].m_state.m_delta.z = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_groups[i].m_state.m_rotateDelta.emplace(); newBody->m_groups[i].m_state.m_rotateDelta.value().x = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_groups[i].m_state.m_rotateDelta.value().y = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_groups[i].m_state.m_rotateDelta.value().z = READ_LE_S16(bodyBuffer); bodyBuffer += 2; bodyBuffer += 2; } } else { for (int i = 0; i < numGroups; i++) { u16 offset = READ_LE_U16(bodyBuffer); assert(offset % 0x10 == 0); newBody->m_groupOrder.push_back(offset / 0x10); bodyBuffer += 2; } for (int i = 0; i < numGroups; i++) { newBody->m_groups[i].m_start = READ_LE_S16(bodyBuffer) / 6; bodyBuffer += 2; newBody->m_groups[i].m_numVertices = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_groups[i].m_baseVertices = READ_LE_S16(bodyBuffer) / 6; bodyBuffer += 2; newBody->m_groups[i].m_orgGroup = READ_LE_S8(bodyBuffer); bodyBuffer += 1; newBody->m_groups[i].m_numGroup = READ_LE_S8(bodyBuffer); bodyBuffer += 1; newBody->m_groups[i].m_state.m_type = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_groups[i].m_state.m_delta.x = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_groups[i].m_state.m_delta.y = READ_LE_S16(bodyBuffer); bodyBuffer += 2; newBody->m_groups[i].m_state.m_delta.z = READ_LE_S16(bodyBuffer); bodyBuffer += 2; } } } u16 numPrimitives = READ_LE_U16(bodyBuffer); bodyBuffer += 2; newBody->m_primitives.resize(numPrimitives); for (int i = 0; i < numPrimitives; i++) { newBody->m_primitives[i].m_type = (primTypeEnum)READ_LE_U8(bodyBuffer); bodyBuffer += 1; switch (newBody->m_primitives[i].m_type) { case primTypeEnum_Line: newBody->m_primitives[i].m_material = READ_LE_U8(bodyBuffer); bodyBuffer += 1; newBody->m_primitives[i].m_color = READ_LE_U8(bodyBuffer); bodyBuffer += 1; newBody->m_primitives[i].m_even = READ_LE_U8(bodyBuffer); bodyBuffer += 1; newBody->m_primitives[i].m_points.resize(2); for (int j = 0; j < newBody->m_primitives[i].m_points.size(); j++) { newBody->m_primitives[i].m_points[j] = READ_LE_U16(bodyBuffer) / 6; bodyBuffer += 2; } break; case primTypeEnum_Poly: newBody->m_primitives[i].m_points.resize(READ_LE_U8(bodyBuffer)); bodyBuffer += 1; newBody->m_primitives[i].m_material = READ_LE_U8(bodyBuffer); bodyBuffer += 1; newBody->m_primitives[i].m_color = READ_LE_U8(bodyBuffer); bodyBuffer += 1; for (int j = 0; j < newBody->m_primitives[i].m_points.size(); j++) { newBody->m_primitives[i].m_points[j] = READ_LE_U16(bodyBuffer) / 6; bodyBuffer += 2; } break; case primTypeEnum_Point: case primTypeEnum_BigPoint: case primTypeEnum_Zixel: newBody->m_primitives[i].m_material = READ_LE_U8(bodyBuffer); bodyBuffer += 1; newBody->m_primitives[i].m_color = READ_LE_U8(bodyBuffer); bodyBuffer += 1; newBody->m_primitives[i].m_even = READ_LE_U8(bodyBuffer); bodyBuffer += 1; newBody->m_primitives[i].m_points.resize(1); for (int j = 0; j < newBody->m_primitives[i].m_points.size(); j++) { newBody->m_primitives[i].m_points[j] = READ_LE_U16(bodyBuffer) / 6; bodyBuffer += 2; } break; case primTypeEnum_Sphere: newBody->m_primitives[i].m_material = READ_LE_U8(bodyBuffer); bodyBuffer += 1; newBody->m_primitives[i].m_color = READ_LE_U8(bodyBuffer); bodyBuffer += 1; newBody->m_primitives[i].m_even = READ_LE_U8(bodyBuffer); bodyBuffer += 1; newBody->m_primitives[i].m_size = READ_LE_U16(bodyBuffer); bodyBuffer += 2; newBody->m_primitives[i].m_points.resize(1); for (int j = 0; j < newBody->m_primitives[i].m_points.size(); j++) { newBody->m_primitives[i].m_points[j] = READ_LE_U16(bodyBuffer) / 6; bodyBuffer += 2; } break; case processPrim_PolyTexture8: newBody->m_primitives[i].m_points.resize(READ_LE_U8(bodyBuffer)); bodyBuffer += 1; newBody->m_primitives[i].m_material = READ_LE_U8(bodyBuffer); bodyBuffer += 1; newBody->m_primitives[i].m_color = READ_LE_U8(bodyBuffer); bodyBuffer += 1; for (int j = 0; j < newBody->m_primitives[i].m_points.size(); j++) { newBody->m_primitives[i].m_points[j] = READ_LE_U16(bodyBuffer) / 6; bodyBuffer += 2; } break; case processPrim_PolyTexture9: case processPrim_PolyTexture10: newBody->m_primitives[i].m_points.resize(READ_LE_U8(bodyBuffer)); bodyBuffer += 1; newBody->m_primitives[i].m_material = READ_LE_U8(bodyBuffer); bodyBuffer += 1; newBody->m_primitives[i].m_color = READ_LE_U8(bodyBuffer); bodyBuffer += 1; for (int j = 0; j < newBody->m_primitives[i].m_points.size(); j++) { newBody->m_primitives[i].m_points[j] = READ_LE_U16(bodyBuffer) / 6; bodyBuffer += 2; } // load UVS? for (int j = 0; j < newBody->m_primitives[i].m_points.size(); j++) { READ_LE_U8(bodyBuffer); bodyBuffer += 1; READ_LE_U8(bodyBuffer); bodyBuffer += 1; } break; default: assert(0); break; } } return newBody; } template T* HQR_Get(hqrEntryStruct* hqrPtr, int index) { hqrSubEntryStruct* foundEntry; if(index<0) return NULL; foundEntry = quickFindEntry(index,hqrPtr->numUsedEntry,hqrPtr->entries); if(foundEntry) { foundEntry->lastTimeUsed = timer; HQ_Load = 0; return(foundEntry->ptr); } else { SaveTimerAnim(); int size = getPakSize(hqrPtr->string.c_str(),index); if(size == 0) return NULL; if(size>=hqrPtr->maxFreeData) { fatalError(1,hqrPtr->string.c_str()); } unsigned int time = timer; for(int i=0;inumMaxEntry;i++) { if(hqrPtr->entries[i].ptr == NULL) { foundEntry = &hqrPtr->entries[i]; break; } } ASSERT(foundEntry); // foundEntry = hqrSubPtr; HQ_Load = 1; foundEntry->key = index; foundEntry->lastTimeUsed = timer; //foundEntry[hqrPtr->numUsedEntry].offset = hqrPtr->maxFreeData - hqrPtr->sizeFreeData; foundEntry->size = size; char* buffer = new char[size]; LoadPak(hqrPtr->string.c_str(), index, buffer); if constexpr (std::is_same_v) { foundEntry->ptr = buffer; } else if constexpr (std::is_same_v) { foundEntry->ptr = createBodyFromPtr(buffer); delete[] buffer; } else if constexpr (std::is_same_v) { foundEntry->ptr = createAnimationFromPtr(buffer, size); delete[] buffer; } else if constexpr (std::is_same_v) { foundEntry->ptr = new sHybrid((uint8_t*)buffer, size); delete[] buffer; } else { assert(0); } hqrPtr->numUsedEntry++; hqrPtr->sizeFreeData -= size; RestoreTimerAnim(); return(foundEntry->ptr); } } hqrEntryStruct* HQR_Init(int size,int numEntry) { ASSERT(size > 0); ASSERT(numEntry > 0); hqrEntryStruct* dest = new hqrEntryStruct(); numEntry = 2000; ASSERT_PTR(dest); if(!dest) return NULL; dest->string = "_MEMORY_"; dest->sizeFreeData = size; dest->maxFreeData = size; dest->numMaxEntry = numEntry; dest->numUsedEntry = 0; dest->entries.resize(numEntry); for(int i=0;ientries[i].ptr = nullptr; } return(dest); } template void HQR_Reset(hqrEntryStruct* hqrPtr) { hqrPtr->sizeFreeData = hqrPtr->maxFreeData; hqrPtr->numUsedEntry = 0; for(int i =0;inumMaxEntry;i++) { if (hqrPtr->entries[i].ptr) { if constexpr (std::is_same_v) { delete[] hqrPtr->entries[i].ptr; } else { delete hqrPtr->entries[i].ptr; } hqrPtr->entries[i].ptr = nullptr; } } } template void HQR_Free(hqrEntryStruct* hqrPtr) { HQR_Reset(hqrPtr); delete hqrPtr; } template void configureHqrHero(hqrEntryStruct* hqrPtr, const char* name) { hqrPtr->string = name; } void HQ_Free_Malloc(hqrEntryStruct* hqrPtr, int index) { } template hqrEntryStruct* HQR_InitRessource(const char* name, int size, int numEntries); template char* HQR_Get(hqrEntryStruct* hqrPtr, int index); template void HQR_Free(hqrEntryStruct* hqrPtr); template void HQR_Reset(hqrEntryStruct* hqrPtr); template void configureHqrHero(hqrEntryStruct* hqrPtr, const char* name); /// body template hqrEntryStruct* HQR_InitRessource(const char* name, int size, int numEntries); template sBody* HQR_Get(hqrEntryStruct* hqrPtr, int index); template void HQR_Free(hqrEntryStruct* hqrPtr); template void configureHqrHero(hqrEntryStruct* hqrPtr, const char* name); /// anim template hqrEntryStruct* HQR_InitRessource(const char* name, int size, int numEntries); template sAnimation* HQR_Get(hqrEntryStruct* hqrPtr, int index); template void HQR_Free(hqrEntryStruct* hqrPtr); template void HQR_Reset(hqrEntryStruct* hqrPtr); template void configureHqrHero(hqrEntryStruct* hqrPtr, const char* name); /// hybrids template hqrEntryStruct* HQR_InitRessource(const char* name, int size, int numEntries); template sHybrid* HQR_Get(hqrEntryStruct* hqrPtr, int index); template void HQR_Free(hqrEntryStruct* hqrPtr);