Skip to content

Commit

Permalink
* Sprites now have viewing features, such as viewing animations, fram…
Browse files Browse the repository at this point in the history
…es, etc.

* The Asset Browser filter now works.
  • Loading branch information
luciusDXL committed Sep 28, 2023
1 parent 65a58f2 commit 089927f
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 24 deletions.
23 changes: 17 additions & 6 deletions TheForceEngine/TFE_Asset/spriteAsset_Jedi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion TheForceEngine/TFE_Asset/spriteAsset_Jedi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
129 changes: 125 additions & 4 deletions TheForceEngine/TFE_Editor/assetBrowser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand All @@ -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);
}
}
Expand All @@ -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);
}
}
Expand All @@ -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);
}
}
Expand All @@ -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;
Expand Down
32 changes: 20 additions & 12 deletions TheForceEngine/TFE_Editor/editorSprite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
Expand All @@ -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++)
{
Expand All @@ -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);
Expand Down
6 changes: 5 additions & 1 deletion TheForceEngine/TFE_Editor/editorSprite.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 089927f

Please sign in to comment.