Skip to content

Commit

Permalink
ace sprite
Browse files Browse the repository at this point in the history
  • Loading branch information
Ghabry committed Apr 17, 2024
1 parent befa72a commit 476bd51
Show file tree
Hide file tree
Showing 10 changed files with 1,563 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ add_library(${PROJECT_NAME} OBJECT
src/hslrgb.cpp
src/hslrgb.h
src/icon.h
src/image_ace.cpp
src/image_ace.h
src/image_bmp.cpp
src/image_bmp.h
src/image_png.cpp
Expand Down
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ libeasyrpg_player_a_SOURCES = \
src/hslrgb.cpp \
src/hslrgb.h \
src/icon.h \
src/image_ace.cpp \
src/image_ace.h \
src/image_bmp.cpp \
src/image_bmp.h \
src/image_png.cpp \
Expand Down
86 changes: 79 additions & 7 deletions src/bitmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "image_xyz.h"
#include "image_bmp.h"
#include "image_png.h"
#include "image_ace.h"
#include "transform.h"
#include "font.h"
#include "output.h"
Expand Down Expand Up @@ -103,32 +104,64 @@ Bitmap::Bitmap(Filesystem_Stream::InputStream stream, bool transparent, uint32_t
int h = 0;
void* pixels = nullptr;

uint8_t data[4] = {};
size_t bytes = stream.read(reinterpret_cast<char*>(data), 4).gcount();
uint8_t data[6] = {};
size_t bytes = stream.read(reinterpret_cast<char*>(data), 6).gcount();
stream.seekg(0, std::ios::ios_base::beg);

bool img_okay = false;

std::vector<ImageACE::Frame> ace_frames;

if (bytes >= 4 && strncmp((char*)data, "XYZ1", 4) == 0)
img_okay = ImageXYZ::ReadXYZ(stream, transparent, w, h, pixels);
else if (bytes > 2 && strncmp((char*)data, "BM", 2) == 0)
img_okay = ImageBMP::ReadBMP(stream, transparent, w, h, pixels);
else if (bytes >= 4 && strncmp((char*)(data + 1), "PNG", 3) == 0)
img_okay = ImagePNG::ReadPNG(stream, transparent, w, h, pixels);
else if (bytes >= 6 && memcmp((char*)(data + 4), "\xE0\xA5", 2) == 0) {
std::vector<ImageACE::Animation> ace_anims;
img_okay = ImageACE::ReadACE(stream, transparent, w, h, ace_frames, ace_anims);

// FIXME: Reduce copying
animations.clear();
frames.clear();
animations.resize(ace_anims.size());
frames.resize(ace_frames.size());

for (size_t i = 0; i < ace_anims.size(); ++i) {
animations[i].frame_beg = ace_anims[i].frame_beg;
animations[i].frame_end = ace_anims[i].frame_end;
animations[i].name = ace_anims[i].name;
}

for (size_t i = 0; i < ace_frames.size(); ++i) {
frames[i].duration = ace_frames[i].duration_ms;
}
}
else
Output::Warning("Unsupported image file {} (Magic: {:02X})", stream.GetName(), *reinterpret_cast<uint32_t*>(data));

if (!img_okay) {
free(pixels);
// TODO: Free acesprite memory
pixels = nullptr;
return;
}

Init(w, h, nullptr);

ConvertImage(w, h, pixels, transparent);

CheckPixels(flags);
if (IsAnimated()) {
InitAnimated(w, h);
for (size_t i = 0; i < frames.size(); ++i) {
SetActiveFrame(i);
ConvertImage(w, h, ace_frames[i].pixels, transparent);
}
SetActiveFrame(0);
// FIXME: Only implemented for first frame
CheckPixels(flags);
} else {
Init(w, h, nullptr);
ConvertImage(w, h, pixels, transparent);
CheckPixels(flags);
}

filename = ToString(stream.GetName());
}
Expand Down Expand Up @@ -251,6 +284,32 @@ ImageOpacity Bitmap::ComputeImageOpacity(Rect rect) const {
ImageOpacity::Alpha_8Bit;
}

bool Bitmap::IsAnimated() const {
return frames.size() > 1;
}

int Bitmap::GetFrameCount() const {
return frames.size();
}

int Bitmap::GetActiveFrame() const {
return frame_index;
}

void Bitmap::SetActiveFrame(unsigned frame) {
assert(frame < frames.size());
frame_index = frame;
bitmap = frames[frame_index].bitmap;
}

int Bitmap::GetFrameDuration() const {
return frames[frame_index].duration;
}

const std::vector<Bitmap::AnimationInfo>& Bitmap::GetAnimationInfo() const {
return animations;
}

void Bitmap::CheckPixels(uint32_t flags) {
if (flags & Flag_System) {
DynamicFormat format(32,8,24,8,16,8,8,8,0,PF::Alpha);
Expand Down Expand Up @@ -530,6 +589,19 @@ void Bitmap::Init(int width, int height, void* data, int pitch, bool destroy) {
pixman_image_set_destroy_function(bitmap.get(), destroy_func, data);
}

void Bitmap::InitAnimated(int width, int height) {
int pitch = width * format.bytes;

for (auto& frame: frames) {
frame.bitmap.reset(pixman_image_create_bits(pixman_format, width, height, nullptr, pitch));
if (frame.bitmap == NULL) {
Output::Error("Couldn't create {}x{} image.", width, height);
}
}

bitmap = frames[0].bitmap;
}

void Bitmap::ConvertImage(int& width, int& height, void*& pixels, bool transparent) {
const DynamicFormat& img_format = transparent ? image_format : opaque_image_format;

Expand Down
25 changes: 25 additions & 0 deletions src/bitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,25 @@ class Bitmap {
ImageOpacity ComputeImageOpacity() const;
ImageOpacity ComputeImageOpacity(Rect rect) const;

bool IsAnimated() const;
int GetFrameCount() const;
int GetActiveFrame() const;
void SetActiveFrame(unsigned frame);
int GetFrameDuration() const;

struct FrameInfo {
PixmanImagePtr bitmap;
int duration;
};

struct AnimationInfo {
std::string name;
int frame_beg;
int frame_end;
};

const std::vector<AnimationInfo>& GetAnimationInfo() const;

protected:
DynamicFormat format;

Expand All @@ -603,7 +622,13 @@ class Bitmap {
PixmanImagePtr bitmap;
pixman_format_code_t pixman_format;

/** Animation data */
int frame_index = 0;
std::vector<FrameInfo> frames = {{nullptr, 0}};
std::vector<AnimationInfo> animations;

void Init(int width, int height, void* data, int pitch = 0, bool destroy = true);
void InitAnimated(int width, int height);
void ConvertImage(int& width, int& height, void*& pixels, bool transparent);

static PixmanImagePtr GetSubimage(Bitmap const& src, const Rect& src_rect);
Expand Down
Loading

0 comments on commit 476bd51

Please sign in to comment.