Add spritesheet and change image format

This commit is contained in:
Pk11
2021-08-26 11:12:27 -05:00
parent ad6e5c4d2d
commit a1ac060ce3
8 changed files with 336 additions and 162 deletions
+4 -9
View File
@@ -87,8 +87,8 @@ void Gui::clearTextBufs(void) {
DefaultFont->clear();
}
void Gui::DrawSprite(Image image, size_t imgindex, int x, int y, float ScaleX, float ScaleY) {
image.drawSpecial(x, y, ScaleX, ScaleY);
void Gui::DrawSprite(Spritesheet &sheet, size_t imgindex, int x, int y, float ScaleX, float ScaleY) {
sheet[imgindex].draw(x, y, 0x20, ScaleX, ScaleY);
}
bool Gui::loadFont(Font &fnt, const char *Path) {
@@ -98,18 +98,13 @@ bool Gui::loadFont(Font &fnt, const char *Path) {
return true;
}
bool Gui::loadSheet(const char *Path, Image &image) {
bool Gui::loadSheet(const char *Path, Spritesheet &sheet) {
if(Path && access(Path, F_OK) == 0) // Only load if found.
image = Image(Path);
sheet = Spritesheet(Path);
return true;
}
/*
Reinitialize the GUI.
fontRegion: The region to use for the system font.
*/
bool Gui::reinit(const char *FontPath) {
return Gui::init(FontPath);
}
+132 -103
View File
@@ -27,10 +27,37 @@
#include "image.hpp"
#include "screenCommon.hpp"
#include "tonccpy.h"
Image::Image(const std::vector<std::string> &paths) {
#include <nds/bios.h>
void Image::decompressGrf(void *dst, const void *src) {
if(!src || !dst)
return;
u32 header = *(u32*)src;
u32 size = header >> 8;
switch(header & 0xF0) {
case 0x00: // No compression
tonccpy(dst, (u8*)src + 4, size);
break;
case 0x10: // LZ77
decompress(src, dst, LZ77);
break;
case 0x20: // Huffman
decompress(src, dst, HUFF);
break;
case 0x30: // RLE
decompress(src, dst, RLE);
break;
default:
break;
}
}
Image::Image(const std::vector<std::string> &paths, u8 paletteStart) {
// Attempt to load from the given paths
FILE *file = nullptr;
for(const auto &path : paths) {
@@ -43,136 +70,138 @@ Image::Image(const std::vector<std::string> &paths) {
if(!file)
return;
// Return if not in the correct format
char magic[5] = {0};
fread(magic, 1, 4, file);
if(strcmp(magic, ".GFX"))
return;
fseek(file, 0, SEEK_END);
long size = ftell(file);
fseek(file, 0, SEEK_SET);
// Read image
fread(&_width, 1, 2, file);
fread(&_height, 1, 2, file);
_bitmap = std::vector<u8>(_width * _height);
fread(_bitmap.data(), 1, _bitmap.size(), file);
u16 palCount;
fread(&palCount, 1, 2, file);
fread(&_palOfs, 1, 2, file);
_palette = std::vector<u16>(palCount);
fread(_palette.data(), 2, palCount, file);
fclose(file);
}
u8 *grf = new u8[size];
if(grf) {
fread(grf, 1, size, file);
Image::Image(FILE *file) {
// Return if no file
if(!file)
return;
load(grf, paletteStart);
// Return if not in the correct format
char magic[5];
fread(magic, 1, 4, file);
if(strcmp(magic, ".GFX"))
return;
// Read image
fread(&_width, 1, 2, file);
fread(&_height, 1, 2, file);
_bitmap = std::vector<u8>(_width * _height);
fread(_bitmap.data(), 1, _bitmap.size(), file);
u16 palCount;
fread(&palCount, 1, 2, file);
fread(&_palOfs, 1, 2, file);
_palette = std::vector<u16>(palCount);
fread(_palette.data(), 2, palCount, file);
fclose(file);
}
void Image::draw(int x, int y, bool copyPal) {
SCALE_3DS(x);
SCALE_3DS(y);
if(copyPal)
tonccpy((currentScreen ? BG_PALETTE : BG_PALETTE_SUB) + _palOfs, _palette.data(), _palette.size() * 2);
u8 *dst = (u8 *)bgGetGfxPtr(currentScreen ? 3 : 7) + y * 256 + x;
// If full width and X is 0, copy it all in one go
if(_width == 256 && x == 0) {
tonccpy(dst, _bitmap.data(), _width * _height);
} else {
for(int i = 0; i < _height; i++) {
tonccpy(dst + i * 256, _bitmap.data() + i * _width, _width);
}
delete[] grf;
}
}
void Image::drawSpecial(int x, int y, float scaleX, float scaleY, int paletteOffset,
bool copyPal) {
Image::Image(const u8 *grf, u8 paletteStart) {
load(grf, paletteStart);
}
void Image::load(const u8 *grf, u8 paletteStart) {
const u32 *ptr = (u32 *)grf;
if(!ptr || ptr[0] != 0x46464952 || ptr[2] != 0x20465247) {
return;
}
u32 size = ptr[1]; // RIFF size
ptr += 3; // Skip to first section
while((u8 *)ptr < grf + size) {
switch(*ptr) {
case 0x20524448: { // 'HDR '
memcpy(&_width, ptr + 4, 4);
memcpy(&_height, ptr + 5, 4);
break;
} case 0x20584647: { // 'GFX '
_bitmap = std::vector<u8>(ptr[2] >> 8);
decompressGrf(_bitmap.data(), ptr + 2);
changePaletteStart(paletteStart);
break;
} case 0x204C4150: { // 'PAL '
_palette = std::vector<u16>((ptr[2] >> 8) / 2);
decompressGrf(_palette.data(), ptr + 2);
break;
} default: {
// Not supported yet
break;
}
}
ptr += 2 + ptr[1] / 4;
}
}
void Image::changePaletteStart(u8 paletteStart) {
int moveBy = paletteStart - _paletteStart;
if(moveBy != 0) {
for(u8 &px : _bitmap) {
px += moveBy;
}
_paletteStart = paletteStart;
}
}
void Image::copyPalette(int paletteStart) {
tonccpy((currentScreen ? BG_PALETTE : BG_PALETTE_SUB) + paletteStart, _palette.data(), _palette.size() * 2);
}
void Image::draw(int x, int y, float scaleX, float scaleY, bool skipAlpha) {
SCALE_3DS(x);
SCALE_3DS(y);
if(copyPal)
tonccpy((currentScreen ? BG_PALETTE : BG_PALETTE_SUB) + _palOfs + paletteOffset, _palette.data(), _palette.size() * 2);
u8 *dst = (u8 *)bgGetGfxPtr(currentScreen ? 3 : 7) + y * 256 + x;
char s[64];
// _bitmap[0] = 39;
snprintf(s, sizeof(s), "%lu, %lu, %u, %u, 0x%X", _width, _height, _bitmap.size(), _bitmap[0], 0);
// If the scale is 1 use faster integer math
if(scaleX == 1.0f && scaleY == 1.0f) {
for(int i = 0; i < _height; i++) {
for(int j = 0; j < _width; j++) {
u8 px = _bitmap[i * _width + j];
if(_palette[px - _palOfs] & 0x8000)
toncset(dst + i * 256 + j, px + paletteOffset, 1);
if(skipAlpha) {
for(u32 i = 0; i < _height; i++) {
u8 *src = _bitmap.data() + i * _width;
u8 *dst = (u8 *)bgGetGfxPtr(currentScreen ? 3 : 7) + (y + i) * 256 + x;
for(u32 j = 0; j < _width; j++) {
if(_palette[src[j] - _paletteStart] != 0x7C1F)
toncset(dst + j, src[j], 1);
}
}
} else {
u8 *dst = (u8 *)bgGetGfxPtr(currentScreen ? 3 : 7) + y * 256 + x;
for(u32 i = 0; i < _height; i++) {
tonccpy(dst + i * 256, _bitmap.data() + i * _width, _width);
}
}
} else {
for(int i = 0; i < _height * scaleY; i++) {
for(int j = 0; j < _width * scaleX; j++) {
for(u32 i = 0; i < _height * scaleY; i++) {
u8 *dst = (u8 *)bgGetGfxPtr(currentScreen ? 3 : 7) + (y + i) * 256 + x;
for(u32 j = 0; j < _width * scaleX; j++) {
u8 px = _bitmap[int(i / scaleY) * _width + int(j / scaleX)];
if(_palette[px - _palOfs] & 0x8000)
toncset(dst + i * 256 + j, px + paletteOffset, 1);
if(_palette[px - _paletteStart] != 0x7C1F || !skipAlpha)
toncset(dst + j, px, 1);
}
}
}
}
void Image::drawSegment(int x, int y, int imageX, int imageY, int w, int h, bool copyPal) {
void Image::drawSegment(int x, int y, int imageX, int imageY, int w, int h, float scaleX, float scaleY, bool skipAlpha) {
SCALE_3DS(x);
SCALE_3DS(y);
if(copyPal)
tonccpy((currentScreen ? BG_PALETTE : BG_PALETTE_SUB) + _palOfs, _palette.data(), _palette.size() * 2);
for(int i = 0; i < h; i++) {
tonccpy((u8 *)bgGetGfxPtr(currentScreen ? 3 : 7) + (y + i) * 256 + x,
_bitmap.data() + (imageY + i) * _width + imageX, w);
}
}
void Image::drawSegmentSpecial(int x, int y, int imageX, int imageY, int w, int h, float scaleX,
float scaleY, int paletteOffset, bool copyPal) {
SCALE_3DS(x);
SCALE_3DS(y);
if(copyPal)
tonccpy((currentScreen ? BG_PALETTE : BG_PALETTE_SUB) + _palOfs + paletteOffset, _palette.data(), _palette.size() * 2);
u8 *dst = (u8 *)bgGetGfxPtr(currentScreen ? 3 : 7) + y * 256 + x;
// If the scale is 1 use faster integer math
if(scaleX == 1.0f && scaleY == 1.0f) {
for(int i = 0; i < h; i++) {
for(int j = 0; j < w; j++) {
u8 px = _bitmap[i * _width + j];
if(_palette[px - _palOfs] & 0x8000)
toncset(dst + i * 256 + j, px + paletteOffset, 1);
if(skipAlpha) {
for(int i = 0; i < h; i++) {
u8 *src = _bitmap.data() + i * _width;
u8 *dst = (u8 *)bgGetGfxPtr(currentScreen ? 3 : 7) + (y + i) * 256 + x;
for(int j = 0; j < w; j++) {
if(_palette[src[j] - _paletteStart] != 0x7C1F)
toncset(dst + j, src[j], 1);
}
}
} else {
for(int i = 0; i < h; i++) {
tonccpy((u8 *)bgGetGfxPtr(currentScreen ? 3 : 7) + (y + i) * 256 + x,
_bitmap.data() + (imageY + i) * _width + imageX, w);
}
}
} else {
for(int i = 0; i < h * scaleY; i++) {
for(int j = 0; j < w * scaleX; j++) {
for(u32 i = 0; i < h * scaleY; i++) {
u8 *dst = (u8 *)bgGetGfxPtr(currentScreen ? 3 : 7) + (y + i) * 256 + x;
for(u32 j = 0; j < w * scaleX; j++) {
u8 px = _bitmap[(imageY + int(i / scaleY)) * _width + imageX + int(j / scaleX)];
if(_palette[px - _palOfs] & 0x8000)
toncset(dst + i * 256 + j, px + paletteOffset, 1);
if(_palette[px - _paletteStart] != 0x7C1F || !skipAlpha)
toncset(dst + j, px, 1);
}
}
}
+4 -4
View File
@@ -194,7 +194,7 @@ void Sprite::drawImage(int x, int y, const Image &image, float scaleX, float sca
if(scaleX == 1.0f && scaleY == 1.0f) {
for(int i = 0; i < image.height(); i++) {
for(int j = 0; j < image.width(); j++) {
u16 px = image.palette()[image.bitmap()[i * image.width() + j] - image.palOfs()];
u16 px = image.palette()[image.bitmap()[i * image.width() + j] - image.paletteStart()];
if(px & 0x8000)
_gfx[(y + i) * _height + x + j] = px;
}
@@ -203,7 +203,7 @@ void Sprite::drawImage(int x, int y, const Image &image, float scaleX, float sca
for(int i = 0; i < image.height() * scaleY; i++) {
for(int j = 0; j < image.width() * scaleX; j++) {
u16 px =
image.palette()[image.bitmap()[int(i / scaleY) * image.width() + int(j / scaleX)] - image.palOfs()];
image.palette()[image.bitmap()[int(i / scaleY) * image.width() + int(j / scaleX)] - image.paletteStart()];
if(px & 0x8000)
_gfx[(y + i) * _height + j + x] = px;
}
@@ -217,7 +217,7 @@ void Sprite::drawImageSegment(int x, int y, int imageX, int imageY, int w, int h
if(scaleX == 1.0f && scaleY == 1.0f) {
for(int i = 0; i < h; i++) {
for(int j = 0; j < w; j++) {
u16 px = image.palette()[image.bitmap()[(imageY + i) * image.width() + imageX + j] - image.palOfs()];
u16 px = image.palette()[image.bitmap()[(imageY + i) * image.width() + imageX + j] - image.paletteStart()];
if(px & 0x8000)
_gfx[(y + i) * _height + x + j] = px;
}
@@ -227,7 +227,7 @@ void Sprite::drawImageSegment(int x, int y, int imageX, int imageY, int w, int h
for(int j = 0; j < w * scaleX; j++) {
u16 px = image.palette()[image.bitmap()[(imageY + int(i / scaleY)) * image.width() + imageX +
int(j / scaleX)] -
image.palOfs()];
image.paletteStart()];
if(px & 0x8000)
_gfx[(y + i) * _height + x + j] = px;
}
+92
View File
@@ -0,0 +1,92 @@
/*
* This file is part of Universal-Core
* Copyright (C) 2021 Universal-Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include "spritesheet.hpp"
#include <nds.h>
Image Spritesheet::_blank = Image(nullptr, 0);
Spritesheet::Spritesheet(const std::vector<std::string> &paths, const std::vector<u32> indexes) {
// Attempt to load from the given paths
FILE *file = nullptr;
for(const auto &path : paths) {
file = fopen(path.c_str(), "rb");
if(file)
break;
}
// Return if no file found
if(!file)
return;
u32 magic;
fread(&magic, 4, 1, file);
if(magic != 0x5844542E) // '.TDX'
return;
u32 imageCount;
fread(&imageCount, 4, 1, file);
_images.resize(imageCount);
for(u32 i = 0; i < imageCount; i++) {
nocashMessage(std::to_string(std::find(indexes.begin(), indexes.end(), i) - indexes.begin()).c_str());
if(indexes.size() == 0 || std::find(indexes.begin(), indexes.end(), i) != indexes.end()) {
fseek(file, 0x10 + i * 8, SEEK_SET);
u32 offset, size;
fread(&offset, 4, 1, file);
fread(&size, 4, 1, file);
u8 *grf = new u8[size];
fseek(file, offset, SEEK_SET);
fread(grf, 1, size, file);
_images[i] = new Image(grf, 0);
delete[] grf;
} else {
_images[i] = nullptr;
}
}
fclose(file);
}
Spritesheet::~Spritesheet(void) {
for(Image *image : _images) {
if(image)
delete image;
}
}
Image &Spritesheet::operator[](size_t index) {
if(_images[index] && index < _images.size())
return *_images[index];
else
return _blank;
}