Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

optimize aggressive tile reduce features in Tileset Editor and Graphic Manager #397

Merged
merged 4 commits into from
Jul 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 76 additions & 29 deletions Dialog/GraphicManagerDialog.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "GraphicManagerDialog.h"
#include "GraphicManagerDialog.h"
#include "ui_GraphicManagerDialog.h"

#include <QMessageBox>
Expand Down Expand Up @@ -554,27 +554,36 @@ void GraphicManagerDialog::DeltmpEntryTile(int tileId)
}
QByteArray data;
int old_tilenum = tmpEntry.TileDataSizeInByte / 32;
data = tmpEntry.tileData.mid(0, 32 * (tileId - startid)) +
tmpEntry.tileData.mid(32 * (tileId + 1 - startid), 32 * (old_tilenum + startid - tileId - 1));
data = tmpEntry.tileData.left(32 * (tileId - startid)) + tmpEntry.tileData.right(32 * (old_tilenum + startid - tileId - 1));
tmpEntry.tileData = data;

tmpEntry.TileDataRAMOffsetNum += 1;
tmpEntry.TileDataSizeInByte -= 32;

// update mapping data
int width = tmpEntry.optionalGraphicWidth;
for (int h = 0; h < tmpEntry.optionalGraphicHeight; h++)
bool find_bug = false;
for (int w = 0; w < tmpEntry.mappingData.size(); w++)
{
for (int w = 0; w < width; w++)
unsigned short data = tmpEntry.mappingData[w];
unsigned short id = data & 0x3FF;
if (id < tileId)
{
unsigned short data = tmpEntry.mappingData[w + h * width];
int id = data & 0x3FF;
if ((tmpEntry.mappingData[w + h * width] & 0x3FF) <= tileId)
{
tmpEntry.mappingData[w + h * width] = (data & 0xFC00) | ((id + 1) & 0x3FF);
}
tmpEntry.mappingData[w] = (data & 0xFC00) | ((id + 1) & 0x3FF);
}
else if (id == tileId)
{
// something went wrong in the previous code if this part of code gets executed
shinespeciall marked this conversation as resolved.
Show resolved Hide resolved
// there should be no existance of the current tile when calling this function
// we just set it to use the default 0x3FF Tile8x8 and use the palette 0xF
tmpEntry.mappingData[w] = 0xF000 | 0x3FF;
find_bug = true;
}
}
if (find_bug)
{
QMessageBox::critical(this, tr("Warning"), tr("Something went wrong when reducing tiles.\n"
"Contact developers for more details."));
}

}
case AssortedGraphicUtils::AssortedGraphicTileDataType::Tile8x8_4bpp_no_comp:
Expand Down Expand Up @@ -1518,10 +1527,11 @@ void GraphicManagerDialog::on_pushButton_ReduceTiles_clicked()
// ask user if eliminate similar tiles to reduce more tiles
bool ok;
int diff_upbound = QInputDialog::getInt(this,
tr("WL4Editor"),
tr("Input a number to eliminate similar tiles to reducing tiles aggressively.\n"
"use a bigger number to reduce more tiles. but Tile16s' quality will drop more.\n"
"do strictly tile reduce by set 0 here."),
tr("WL4Editor"),
tr("Input a tolerance value for the number of different pixels between 2 Tile8x8s.\n"
"The editor will merge similar Tile8x8s to reduce tile count aggressively.\n"
"Use a bigger value to reduce more tiles. However, the quality of the combined tiles will drop.\n"
"To perform regular tile reduction, use a value of 0."),
0, 0, 64, 1, &ok);
if (!ok) return;

Expand Down Expand Up @@ -1558,45 +1568,81 @@ void GraphicManagerDialog::on_pushButton_ReduceTiles_clicked()
int result2 = FileIOUtils::quasi_memcmp(newtmpYFlipdata, tile_data, 32);
int result3 = FileIOUtils::quasi_memcmp(newtmpXYFlipdata, tile_data, 32);
bool find_eqaul = false;
int tileid = j + constoffset;
int find_tileid = j + constoffset;
int reserved_tileid = find_tileid;

int x_flip = 0;
int y_flip = 0;

unsigned short mappingdata;
if (result0 <= diff_upbound)
{
find_eqaul = true;
mappingdata = 0xF << 12 | (0 << 11) | (0 << 10) | (tileid & 0x3FF);
if (newtmpdata == FileIOUtils::find_less_feature_buff(newtmpdata, tile_data, 32))
{
reserved_tileid = old_tileid;
}
}
else if (result1 <= diff_upbound)
{
find_eqaul = true;
mappingdata = 0xF << 12 | (0 << 11) | (1 << 10) | (tileid & 0x3FF);
if (newtmpXFlipdata == FileIOUtils::find_less_feature_buff(newtmpXFlipdata, tile_data, 32))
{
reserved_tileid = old_tileid;
}
x_flip = 1 << 10;
}
else if (result2 <= diff_upbound)
{
find_eqaul = true;
mappingdata = 0xF << 12 | (1 << 11) | (0 << 10) | (tileid & 0x3FF);
if (newtmpYFlipdata == FileIOUtils::find_less_feature_buff(newtmpYFlipdata, tile_data, 32))
{
reserved_tileid = old_tileid;
}
y_flip = 1 << 11;
}
else if (result3 <= diff_upbound)
{
find_eqaul = true;
mappingdata = 0xF << 12 | (1 << 11) | (1 << 10) | (tileid & 0x3FF);
if (newtmpXYFlipdata == FileIOUtils::find_less_feature_buff(newtmpXYFlipdata, tile_data, 32))
{
reserved_tileid = old_tileid;
}
x_flip = 1 << 10;
y_flip = 1 << 11;
}

if (find_eqaul)
{
int width = tmpEntry.optionalGraphicWidth;
for (int h = 0; h < tmpEntry.optionalGraphicHeight; h++)
// always replace the old_tileid instance with the find_tileid instance
for (int w = 0; w < tmpEntry.mappingData.size(); w++)
{
for (int w = 0; w < width; w++)
if ((tmpEntry.mappingData[w] & 0x3FF) == old_tileid)
{
if ((tmpEntry.mappingData[w + h * width] & 0x3FF) == old_tileid)
{
tmpEntry.mappingData[w + h * width] = mappingdata;
}
int old_x_flip_state = tmpEntry.mappingData[w] & (1 << 10);
int old_y_flip_state = tmpEntry.mappingData[w] & (1 << 11);
mappingdata = 0xF << 12 |
(y_flip ^ old_y_flip_state) |
(x_flip ^ old_x_flip_state) |
(find_tileid & 0x3FF);
tmpEntry.mappingData[w] = mappingdata;
}
}

// we need to change the tmp_current_tile8x8_data and tmpEntry.tileData
// if the old_tileid needs to be reserved
if (reserved_tileid == old_tileid)
{
memcpy(&tmp_current_tile8x8_data[32 * j], newtmpdata, 32);

int startid = tmpEntry.TileDataRAMOffsetNum;
for (int k = 0; k < 32; k++)
{
tmpEntry.tileData[32 * (find_tileid - startid) + k] = newtmpdata[k];
}
}

// delete the Tile8x8 from the Tile8x8 set
// delete the Tile8x8 from the tmpEntry's Tile8x8 set
DeltmpEntryTile(old_tileid);
break;
}
Expand All @@ -1608,6 +1654,7 @@ void GraphicManagerDialog::on_pushButton_ReduceTiles_clicked()
// set tmpEntry if everything looks correct
tmpEntry.TileDataAddress = 0;
tmpEntry.MappingDataAddress = 0;
tmpEntry.MappingDataSizeAfterCompressionInByte = 0;

// UI reset
CleanTilesInstances();
Expand Down
60 changes: 48 additions & 12 deletions Dialog/TilesetEditDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1125,11 +1125,12 @@ void TilesetEditDialog::on_pushButton_CleanUpDuplicatedTile8x8_clicked()
// ask user if eliminate similar tiles to reduce more tiles
bool ok;
int diff_upbound = QInputDialog::getInt(this,
tr("WL4Editor"),
tr("Input a number to eliminate similar tiles to reducing tiles aggressively.\n"
"use a bigger number to reduce more tiles. but Tile16s' quality will drop more.\n"
"do strictly tile reduce by set 0 here."),
0, 0, 64, 1, &ok);
tr("WL4Editor"),
tr("Input a tolerance value for the number of different pixels between 2 Tile8x8s.\n"
"The editor will merge similar Tile8x8s to reduce tile count aggressively.\n"
"Use a bigger value to reduce more tiles. However, the quality of the Tile16s will drop.\n"
"To perform regular tile reduction, use a value of 0."),
0, 0, 64, 1, &ok);
if (!ok) return;

LevelComponents::Tileset *tmp_newTilesetPtr = tilesetEditParams->newTileset;
Expand Down Expand Up @@ -1157,51 +1158,86 @@ void TilesetEditDialog::on_pushButton_CleanUpDuplicatedTile8x8_clicked()
ROMUtils::Tile8x8DataXFlip(newtmpdata, newtmpXFlipdata);
ROMUtils::Tile8x8DataYFlip(newtmpdata, newtmpYFlipdata);
ROMUtils::Tile8x8DataYFlip(newtmpXFlipdata, newtmpXYFlipdata);
int old_tileid = i + 0x40;

// loop from the first blank tile to the tile right before the current tile being checked, excluding those animated tiles
for (int j = 0; j < i; j++)
{
int result0 = FileIOUtils::quasi_memcmp(newtmpdata, &tmp_current_tile8x8_data[j * 32], 32);
int result1 = FileIOUtils::quasi_memcmp(newtmpXFlipdata, &tmp_current_tile8x8_data[j * 32], 32);
int result2 = FileIOUtils::quasi_memcmp(newtmpYFlipdata, &tmp_current_tile8x8_data[j * 32], 32);
int result3 = FileIOUtils::quasi_memcmp(newtmpXYFlipdata, &tmp_current_tile8x8_data[j * 32], 32);
unsigned char tile_data[32];
memcpy(tile_data, &tmp_current_tile8x8_data[32 * j], 32);

int result0 = FileIOUtils::quasi_memcmp(newtmpdata, tile_data, 32);
int result1 = FileIOUtils::quasi_memcmp(newtmpXFlipdata, tile_data, 32);
int result2 = FileIOUtils::quasi_memcmp(newtmpYFlipdata, tile_data, 32);
int result3 = FileIOUtils::quasi_memcmp(newtmpXYFlipdata, tile_data, 32);
bool find_eqaul = false;
bool xflip = false;
bool yflip = false;
auto tile16array = tmp_newTilesetPtr->GetMap16arrayPtr();
auto tile8x8array = tmp_newTilesetPtr->GetTile8x8arrayPtr();

int find_tileid = j + 0x40;
int reserved_tileid = find_tileid;

if (result0 <= diff_upbound)
{
find_eqaul = true;
if (newtmpdata == FileIOUtils::find_less_feature_buff(newtmpdata, tile_data, 32))
{
reserved_tileid = old_tileid;
}
}
else if (result1 <= diff_upbound)
{
find_eqaul = true;
if (newtmpXFlipdata == FileIOUtils::find_less_feature_buff(newtmpXFlipdata, tile_data, 32))
{
reserved_tileid = old_tileid;
}
xflip = true;
}
else if (result2 <= diff_upbound)
{
find_eqaul = true;
if (newtmpYFlipdata == FileIOUtils::find_less_feature_buff(newtmpYFlipdata, tile_data, 32))
{
reserved_tileid = old_tileid;
}
yflip = true;
}
else if (result3 <= diff_upbound)
{
find_eqaul = true;
if (newtmpXYFlipdata == FileIOUtils::find_less_feature_buff(newtmpXYFlipdata, tile_data, 32))
{
reserved_tileid = old_tileid;
}
xflip = true;
yflip = true;
}

if (find_eqaul)
{
// we need to change the tmp_current_tile8x8_data and tile8x8array
// if the old_tileid needs to be reserved
if (reserved_tileid == old_tileid)
{
memcpy(&tmp_current_tile8x8_data[32 * j], newtmpdata, 32);

LevelComponents::Tile8x8 *tmptile = tile8x8array[old_tileid];
tile8x8array[old_tileid] = tile8x8array[find_tileid];
tile8x8array[find_tileid] = tmptile;
}

// always replace the old_tileid instance with the find_tileid instance
for (int k = 0; k < Tile16DefaultNum; k++)
{
for (int pos = 0; pos < 4; pos++)
{
bool tmp_xflip = xflip;
bool tmp_yflip = yflip;
auto tile8 = tile16array[k]->GetTile8X8(pos);
if (tile8->GetIndex() == (i + 0x40))
if (tile8->GetIndex() == old_tileid)
{
if (tile8->GetFlipX())
{
Expand All @@ -1211,14 +1247,14 @@ void TilesetEditDialog::on_pushButton_CleanUpDuplicatedTile8x8_clicked()
{
tmp_yflip = !yflip;
}
tile16array[k]->ResetTile8x8(tile8x8array[j + 0x40], pos, j + 0x40,
tile16array[k]->ResetTile8x8(tile8x8array[find_tileid], pos, find_tileid,
tile8->GetPaletteIndex(), tmp_xflip, tmp_yflip);
}
}
}

// delete the Tile8x8 from the Tile8x8 set
tilesetEditParams->newTileset->DelTile8x8(i + 0x40);
tilesetEditParams->newTileset->DelTile8x8(old_tileid);
break;
}
}
Expand Down
60 changes: 60 additions & 0 deletions FileIOUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,3 +542,63 @@ int FileIOUtils::quasi_memcmp(unsigned char *_Buf1, unsigned char *_Buf2, size_t
}
return diff_counter;
}

/// <summary>
/// find the Tile8x8 data with less features by any means
/// </summary>
/// <param name="_Buf1">
/// The pointer point to the first buff.
/// </param>
/// <param name="_Buf2">
/// The pointer point to the second buff.
/// </param>
/// <param name="_Size">
/// The byte number to compare.
/// </param>
/// <return>
/// the different byte number.
/// </return>
unsigned char *FileIOUtils::find_less_feature_buff(unsigned char *_Buf1, unsigned char *_Buf2, size_t _Size)
{
// test method, find the buff changed less time thru the whole data array
size_t change_counter_1 = 0;
size_t change_counter_2 = 0;
unsigned char last_id_1 = -1;
unsigned char last_id_2 = -1;
for (size_t i = 0; i < _Size; i++)
{
// process buff 1
if (unsigned char cur_id = ((_Buf1[i] & 0xF0) >> 4) & 0xF; last_id_1 != cur_id)
{
last_id_1 = cur_id;
change_counter_1++;
}
if (unsigned char cur_id = _Buf1[i] & 0xF; last_id_1 != cur_id)
{
last_id_1 = cur_id;
change_counter_1++;
}

// process buff 2
if (unsigned char cur_id = ((_Buf2[i] & 0xF0) >> 4) & 0xF; last_id_2 != cur_id)
{
last_id_2 = cur_id;
change_counter_2++;
}
if (unsigned char cur_id = _Buf2[i] & 0xF; last_id_2 != cur_id)
{
last_id_2 = cur_id;
change_counter_2++;
}
}

// return the buff pointer with less changed time in pixel index
if (change_counter_1 >= change_counter_2)
{
return _Buf2;
}
else
{
return _Buf1;
}
}
1 change: 1 addition & 0 deletions FileIOUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace FileIOUtils

// helper functions
int quasi_memcmp(unsigned char *_Buf1, unsigned char *_Buf2, size_t _Size);
unsigned char *find_less_feature_buff(unsigned char *_Buf1, unsigned char *_Buf2, size_t _Size);
} // namespace FileIOUtils

#endif // FILEIOUTILS_H