diff --git a/TheForceEngine/TFE_Asset/spriteAsset_Jedi.cpp b/TheForceEngine/TFE_Asset/spriteAsset_Jedi.cpp index 7d536198c..5164325bf 100644 --- a/TheForceEngine/TFE_Asset/spriteAsset_Jedi.cpp +++ b/TheForceEngine/TFE_Asset/spriteAsset_Jedi.cpp @@ -391,7 +391,7 @@ namespace TFE_Sprite_Jedi return asset; } - JediWax* loadWaxFromMemory(const u8* data, size_t size) + JediWax* loadWaxFromMemory(const u8* data, size_t size, bool transformOffsets) { const Wax* srcWax = (Wax*)data; @@ -471,8 +471,16 @@ namespace TFE_Sprite_Jedi WaxFrame* dstFrame = (WaxFrame*)((u8*)asset + frameOffset[f]); // Some frames are shared between animations, so we need to read from the source, unmodified data. - dstFrame->offsetX = round16(mul16(dstAnim->worldWidth, intToFixed16(srcFrame->offsetX))); - dstFrame->offsetY = round16(mul16(dstAnim->worldHeight, intToFixed16(srcFrame->offsetY))); + if (transformOffsets) + { + dstFrame->offsetX = round16(mul16(dstAnim->worldWidth, intToFixed16(srcFrame->offsetX))); + dstFrame->offsetY = round16(mul16(dstAnim->worldHeight, intToFixed16(srcFrame->offsetY))); + } + else + { + dstFrame->offsetX = srcFrame->offsetX; + dstFrame->offsetY = srcFrame->offsetY; + } WaxCell* dstCell = dstFrame->cellOffset ? (WaxCell*)((u8*)asset + dstFrame->cellOffset) : nullptr; if (dstCell) @@ -503,9 +511,12 @@ namespace TFE_Sprite_Jedi } } - dstFrame->offsetX = div16(-intToFixed16(dstFrame->offsetX), SPRITE_SCALE_FIXED); - const s32 adjOffsetY = mul16(intToFixed16(dstCell->sizeY), dstAnim->worldHeight) + intToFixed16(dstFrame->offsetY); - dstFrame->offsetY = div16(adjOffsetY, SPRITE_SCALE_FIXED); + if (transformOffsets) + { + dstFrame->offsetX = div16(-intToFixed16(dstFrame->offsetX), SPRITE_SCALE_FIXED); + const s32 adjOffsetY = mul16(intToFixed16(dstCell->sizeY), dstAnim->worldHeight) + intToFixed16(dstFrame->offsetY); + dstFrame->offsetY = div16(adjOffsetY, SPRITE_SCALE_FIXED); + } } } if (v == 0) diff --git a/TheForceEngine/TFE_Asset/spriteAsset_Jedi.h b/TheForceEngine/TFE_Asset/spriteAsset_Jedi.h index 2987737a8..896e9eb05 100644 --- a/TheForceEngine/TFE_Asset/spriteAsset_Jedi.h +++ b/TheForceEngine/TFE_Asset/spriteAsset_Jedi.h @@ -96,7 +96,7 @@ namespace TFE_Sprite_Jedi void freeLevelData(); JediFrame* loadFrameFromMemory(const u8* data, size_t size); - JediWax* loadWaxFromMemory(const u8* data, size_t size); + JediWax* loadWaxFromMemory(const u8* data, size_t size, bool transformOffsets = true); const std::vector<JediWax*>& getWaxList(AssetPool pool = POOL_LEVEL); const std::vector<JediFrame*>& getFrameList(AssetPool pool = POOL_LEVEL); diff --git a/TheForceEngine/TFE_Editor/assetBrowser.cpp b/TheForceEngine/TFE_Editor/assetBrowser.cpp index d021c05e9..6eeb91ab4 100644 --- a/TheForceEngine/TFE_Editor/assetBrowser.cpp +++ b/TheForceEngine/TFE_Editor/assetBrowser.cpp @@ -366,6 +366,90 @@ namespace AssetBrowser ImGui::Image(TFE_RenderBackend::getGpuPtr(frame->texGpu), ImVec2((f32)texW, (f32)texH), ImVec2(0.0f, 1.0f), ImVec2(1.0f, 0.0f)); } + else if (asset->type == TYPE_SPRITE) + { + EditorSprite* sprite = (EditorSprite*)getAssetData(asset->handle); + ImGui::LabelText("##Dim", "World Dim: %0.3f x %0.3f", sprite->frame[0].widthWS, sprite->frame[0].heightWS); + ImGui::LabelText("##AnimCount", "Animation Count: %d", (s32)sprite->anim.size()); + ImGui::LabelText("##CellCount", "Cell Count: %d", (s32)sprite->cell.size()); + ImGui::Separator(); + bool reloadRequired = false; + s32 newPaletteIndex = sprite->paletteIndex; + listSelectionPalette("Palette", s_palettes, &newPaletteIndex); + if (newPaletteIndex != sprite->paletteIndex) + { + reloadRequired = true; + } + + s32 newLightLevel = sprite->lightLevel; + if (s_palettes[newPaletteIndex].hasColormap) + { + ImGui::SliderInt("Light Level", &newLightLevel, 0, 32); + } + else + { + newLightLevel = 32; + } + if (newLightLevel != sprite->lightLevel) + { + reloadRequired = true; + } + + if (reloadRequired) + { + reloadAsset(asset, newPaletteIndex, newLightLevel); + sprite = (EditorSprite*)getAssetData(asset->handle); + } + ImGui::Separator(); + if (sprite->anim.size() > 1) + { + s32 animId = (s32)sprite->animId; + if (ImGui::SliderInt("Anim", &animId, 0, (s32)sprite->anim.size() - 1)) + { + sprite->frameId = 0; + } + sprite->animId = (u8)animId; + } + const SpriteAnim* anim = &sprite->anim[sprite->animId]; + if (anim->frameCount > 1) + { + s32 frameId = (s32)sprite->frameId; + ImGui::SliderInt("Frame", &frameId, 0, (s32)anim->frameCount - 1); + sprite->frameId = (u8)frameId; + } + // View + { + s32 viewId = (s32)sprite->viewId; + ImGui::SliderInt("View Angle", &viewId, 0, 31); + sprite->viewId = (u8)viewId; + } + ImGui::Separator(); + // Get the actual cell... + s32 frameIndex = sprite->anim[sprite->animId].views[sprite->viewId].frameIndex[sprite->frameId]; + SpriteFrame* frame = &sprite->frame[frameIndex]; + SpriteCell* cell = &sprite->cell[frame->cellIndex]; + + s32 texW = cell->w; + s32 texH = cell->h; + s32 scale = max(1, min(4, s32(w) / (sprite->rect[2] - sprite->rect[0]))); + texW *= scale; + texH *= scale; + + f32 u0 = f32(cell->u) / (f32)sprite->texGpu->getWidth(); + f32 v1 = f32(cell->v) / (f32)sprite->texGpu->getHeight(); + f32 u1 = f32(cell->u + cell->w) / (f32)sprite->texGpu->getWidth(); + f32 v0 = f32(cell->v + cell->h) / (f32)sprite->texGpu->getHeight(); + if (frame->flip) { std::swap(u0, u1); } + + // Handle the offset. + ImVec2 cursor = ImGui::GetCursorPos(); + cursor.x += f32((frame->offsetX - sprite->rect[0]) * scale); + cursor.y += f32((frame->offsetY - sprite->rect[1]) * scale); + ImGui::SetCursorPos(cursor); + + ImGui::Image(TFE_RenderBackend::getGpuPtr(sprite->texGpu), + ImVec2((f32)texW, (f32)texH), ImVec2(u0, v0), ImVec2(u1, v1)); + } else if (asset->type == TYPE_PALETTE) { EditorTexture* tex = (EditorTexture*)getAssetData(asset->handle); @@ -1079,6 +1163,39 @@ namespace AssetBrowser s_viewAssetList.push_back(asset); } + // Return true if 'str' matches the 'filter', taking into account special symbols. + bool editorStringFilter(const char* str, const char* filter, size_t filterLength) + { + for (size_t i = 0; i < filterLength; i++) + { + if (filter[i] == '?') { continue; } + if (tolower(str[i]) != tolower(filter[i])) { return false; } + } + return true; + } + + // Returns true if it passes the filter. + bool editorFilter(const char* name) + { + // No filter applied. + if (s_viewInfo.assetFilter[0] == 0 || s_viewInfo.filterLen == 0) { return true; } + + // Make sure the name is at least as long as the filter. + const size_t nameLength = strlen(name); + if (nameLength < s_viewInfo.filterLen) { return false; } + + // See if there is a match... + const size_t validLength = nameLength - s_viewInfo.filterLen + 1; + for (size_t i = 0; i < validLength; i++) + { + if (editorStringFilter(&name[i], s_viewInfo.assetFilter, s_viewInfo.filterLen)) + { + return true; + } + } + return false; + } + void updateAssetList() { // Only Dark Forces for now. @@ -1097,7 +1214,8 @@ namespace AssetBrowser const Asset* projAsset = s_projectAssetList[TYPE_TEXTURE].data(); for (u32 i = 0; i < count; i++, projAsset++) { - if (!isLevelTexture(projAsset->name.c_str())) { continue; } + const char* name = projAsset->name.c_str(); + if (!editorFilter(name) || !isLevelTexture(name)) { continue; } loadAsset(projAsset); } } @@ -1107,7 +1225,8 @@ namespace AssetBrowser const Asset* projAsset = s_projectAssetList[TYPE_FRAME].data(); for (u32 i = 0; i < count; i++, projAsset++) { - if (!isLevelFrame(projAsset->name.c_str())) { continue; } + const char* name = projAsset->name.c_str(); + if (!editorFilter(name) || !isLevelFrame(name)) { continue; } loadAsset(projAsset); } } @@ -1117,7 +1236,8 @@ namespace AssetBrowser const Asset* projAsset = s_projectAssetList[TYPE_SPRITE].data(); for (u32 i = 0; i < count; i++, projAsset++) { - if (!isLevelSprite(projAsset->name.c_str())) { continue; } + const char* name = projAsset->name.c_str(); + if (!editorFilter(name) || !isLevelSprite(name)) { continue; } loadAsset(projAsset); } } @@ -1127,7 +1247,8 @@ namespace AssetBrowser const Asset* projAsset = s_projectAssetList[TYPE_PALETTE].data(); for (u32 i = 0; i < count; i++, projAsset++) { - if (!isLevelPalette(projAsset->name.c_str())) { continue; } + const char* name = projAsset->name.c_str(); + if (!editorFilter(name) || !isLevelPalette(name)) { continue; } Archive* archive = getArchive(projAsset->archiveName.c_str(), projAsset->gameId); Asset asset; diff --git a/TheForceEngine/TFE_Editor/editorSprite.cpp b/TheForceEngine/TFE_Editor/editorSprite.cpp index c69750a94..f3e91e39d 100644 --- a/TheForceEngine/TFE_Editor/editorSprite.cpp +++ b/TheForceEngine/TFE_Editor/editorSprite.cpp @@ -117,11 +117,8 @@ namespace TFE_Editor if (type == SPRITE_WAX) { - JediWax* wax = TFE_Sprite_Jedi::loadWaxFromMemory(buffer.data(), len); - if (!wax) - { - return -1; - } + JediWax* wax = TFE_Sprite_Jedi::loadWaxFromMemory(buffer.data(), len, false); + if (!wax) { return -1; } // Allocate if (id < 0) { id = allocateSprite(filename); } @@ -134,15 +131,21 @@ namespace TFE_Editor // First gather all of the cells. s_waxDataMap.clear(); s_waxDataList.clear(); + + outSprite->rect[0] = INT_MAX; + outSprite->rect[1] = INT_MAX; + outSprite->rect[2] = -INT_MAX; + outSprite->rect[3] = -INT_MAX; + for (s32 animId = 0; animId < wax->animCount; animId++) { WaxAnim* anim = WAX_AnimPtr(wax, animId); if (!anim) { continue; } - + SpriteAnim outAnim; - outAnim.frameRate = anim->frameRate; - outAnim.frameCount = anim->frameCount; - outAnim.worldWidth = fixed16ToFloat(anim->worldWidth); + outAnim.frameRate = anim->frameRate; + outAnim.frameCount = anim->frameCount; + outAnim.worldWidth = fixed16ToFloat(anim->worldWidth); outAnim.worldHeight = fixed16ToFloat(anim->worldHeight); for (s32 v = 0; v < WAX_MAX_VIEWS; v++) { @@ -167,11 +170,16 @@ namespace TFE_Editor SpriteFrame outFrame; outFrame.cellIndex = id; outFrame.flip = frame->flip; - outFrame.offsetX = frame->offsetX; - outFrame.offsetY = frame->offsetY; - outFrame.widthWS = fixed16ToFloat(frame->widthWS); + outFrame.offsetX = frame->offsetX; + outFrame.offsetY = frame->offsetY; + outFrame.widthWS = fixed16ToFloat(frame->widthWS); outFrame.heightWS = fixed16ToFloat(frame->heightWS); outSprite->frame.push_back(outFrame); + + outSprite->rect[0] = min(outSprite->rect[0], frame->offsetX); + outSprite->rect[1] = min(outSprite->rect[1], frame->offsetY); + outSprite->rect[2] = max(outSprite->rect[2], frame->offsetX + cell->sizeX); + outSprite->rect[3] = max(outSprite->rect[3], frame->offsetY + cell->sizeY); } } outSprite->anim.push_back(outAnim); diff --git a/TheForceEngine/TFE_Editor/editorSprite.h b/TheForceEngine/TFE_Editor/editorSprite.h index 5561f623c..aaf3be053 100644 --- a/TheForceEngine/TFE_Editor/editorSprite.h +++ b/TheForceEngine/TFE_Editor/editorSprite.h @@ -51,9 +51,13 @@ namespace TFE_Editor std::vector<SpriteFrame> frame; std::vector<SpriteCell> cell; + s32 rect[4]; + u8 paletteIndex = 0; u8 lightLevel = 32; - u8 pad[2]; + u8 animId = 0; + u8 viewId = 0; + u32 frameId = 0; char name[64] = ""; }; enum SpriteSourceType