From 3afe76c70e3d78eefa33991d313ffc6315bb156e Mon Sep 17 00:00:00 2001 From: Antidote Date: Sat, 25 Jan 2014 20:56:04 -0800 Subject: [PATCH] * Added Sakura Sprite * Renamed SSFile* and SSQuest to SkywardSword* --- include/SSFileReader.hpp | 24 --- include/{SSFile.hpp => SkywardSwordFile.hpp} | 18 +- include/SkywardSwordFileReader.hpp | 24 +++ ...eWriter.hpp => SkywardSwordFileWriter.hpp} | 10 +- .../{SSQuest.hpp => SkywardSwordQuest.hpp} | 8 +- include/Sprite.hpp | 64 +++++++ include/SpriteFile.hpp | 181 ++++++++++++++++++ include/SpriteFileReader.hpp | 29 +++ include/SpriteFileWriter.hpp | 29 +++ include/SpriteFrame.hpp | 152 +++++++++++++++ include/SpritePart.hpp | 56 ++++++ include/Types.hpp | 27 +++ src/{SSFile.cpp => SkywardSwordFile.cpp} | 20 +- ...eReader.cpp => SkywardSwordFileReader.cpp} | 22 +-- ...eWriter.cpp => SkywardSwordFileWriter.cpp} | 20 +- src/{SSQuest.cpp => SkywardSwordQuest.cpp} | 10 +- src/Sprite.cpp | 136 +++++++++++++ src/SpriteFile.cpp | 180 +++++++++++++++++ src/SpriteFileReader.cpp | 148 ++++++++++++++ src/SpriteFileWriter.cpp | 81 ++++++++ src/SpriteFrame.cpp | 109 +++++++++++ src/SpritePart.cpp | 128 +++++++++++++ 22 files changed, 1398 insertions(+), 78 deletions(-) delete mode 100644 include/SSFileReader.hpp rename include/{SSFile.hpp => SkywardSwordFile.hpp} (56%) create mode 100644 include/SkywardSwordFileReader.hpp rename include/{SSFileWriter.hpp => SkywardSwordFileWriter.hpp} (52%) rename include/{SSQuest.hpp => SkywardSwordQuest.hpp} (69%) create mode 100644 include/Sprite.hpp create mode 100644 include/SpriteFile.hpp create mode 100644 include/SpriteFileReader.hpp create mode 100644 include/SpriteFileWriter.hpp create mode 100644 include/SpriteFrame.hpp create mode 100644 include/SpritePart.hpp rename src/{SSFile.cpp => SkywardSwordFile.cpp} (55%) rename src/{SSFileReader.cpp => SkywardSwordFileReader.cpp} (62%) rename src/{SSFileWriter.cpp => SkywardSwordFileWriter.cpp} (54%) rename src/{SSQuest.cpp => SkywardSwordQuest.cpp} (57%) create mode 100644 src/Sprite.cpp create mode 100644 src/SpriteFile.cpp create mode 100644 src/SpriteFileReader.cpp create mode 100644 src/SpriteFileWriter.cpp create mode 100644 src/SpriteFrame.cpp create mode 100644 src/SpritePart.cpp diff --git a/include/SSFileReader.hpp b/include/SSFileReader.hpp deleted file mode 100644 index c0f2684..0000000 --- a/include/SSFileReader.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __SSFILEREADER_HPP__ -#define __SSFILEREADER_HPP__ - -#include "BinaryReader.hpp" - -namespace zelda -{ -class SSFile; -namespace io -{ -class SSFileReader : public BinaryReader -{ - BINARYREADER_BASE -public: - - SSFileReader(Uint8* data, Uint64 length); - SSFileReader(const std::string& filename); - - SSFile* read(); -}; -} // io -} // zelda - -#endif // __SSFILEREADER_HPP__ diff --git a/include/SSFile.hpp b/include/SkywardSwordFile.hpp similarity index 56% rename from include/SSFile.hpp rename to include/SkywardSwordFile.hpp index 35dba35..660ae6e 100644 --- a/include/SSFile.hpp +++ b/include/SkywardSwordFile.hpp @@ -8,9 +8,9 @@ namespace zelda { -class SSQuest; +class SkywardSwordQuest; -class SSFile +class SkywardSwordFile { public: enum MagicNumbers @@ -20,20 +20,20 @@ public: EUMagic = 0x534F5550 }; - SSFile(); - SSFile(std::vector quests); - ~SSFile(); + SkywardSwordFile(); + SkywardSwordFile(std::vector quests); + ~SkywardSwordFile(); - void addQuest(SSQuest* q); - SSQuest* quest(Uint32 id); - std::vector questList() const; + void addQuest(SkywardSwordQuest* q); + SkywardSwordQuest* quest(Uint32 id); + std::vector questList() const; void setRegion(Region region); Region region() const; private: Region m_region; // A vector is a bit overkill - std::vector m_quests; + std::vector m_quests; Uint32 m_numQuests; }; diff --git a/include/SkywardSwordFileReader.hpp b/include/SkywardSwordFileReader.hpp new file mode 100644 index 0000000..eee4c76 --- /dev/null +++ b/include/SkywardSwordFileReader.hpp @@ -0,0 +1,24 @@ +#ifndef __SSFILEREADER_HPP__ +#define __SSFILEREADER_HPP__ + +#include "BinaryReader.hpp" + +namespace zelda +{ +class SkywardSwordFile; +namespace io +{ +class SkywardSwordFileReader : public BinaryReader +{ + BINARYREADER_BASE +public: + + SkywardSwordFileReader(Uint8* data, Uint64 length); + SkywardSwordFileReader(const std::string& filename); + + SkywardSwordFile* read(); +}; +} // io +} // zelda + +#endif // __SSFILEREADER_HPP__ diff --git a/include/SSFileWriter.hpp b/include/SkywardSwordFileWriter.hpp similarity index 52% rename from include/SSFileWriter.hpp rename to include/SkywardSwordFileWriter.hpp index dbdc792..9e86821 100644 --- a/include/SSFileWriter.hpp +++ b/include/SkywardSwordFileWriter.hpp @@ -5,20 +5,20 @@ namespace zelda { -class SSFile; +class SkywardSwordFile; namespace io { -class SSFileWriter : public BinaryWriter +class SkywardSwordFileWriter : public BinaryWriter { // Why does this fuck up my formatting in Qt Creator? BINARYWRITER_BASE public: - SSFileWriter(Uint8* data, Uint64 len); - SSFileWriter(const std::string& filename); + SkywardSwordFileWriter(Uint8* data, Uint64 len); + SkywardSwordFileWriter(const std::string& filename); - void write(SSFile* file); + void write(SkywardSwordFile* file); }; } } diff --git a/include/SSQuest.hpp b/include/SkywardSwordQuest.hpp similarity index 69% rename from include/SSQuest.hpp rename to include/SkywardSwordQuest.hpp index fed9b89..00f9934 100644 --- a/include/SSQuest.hpp +++ b/include/SkywardSwordQuest.hpp @@ -1,5 +1,5 @@ -#ifndef SSQUEST_HPP -#define SSQUEST_HPP +#ifndef SKYWARDSWORDQUEST_HPP +#define SKYWARDSWORDQUEST_HPP #include "ZQuestFile.hpp" @@ -7,10 +7,10 @@ namespace zelda { // TODO: Handle game specific data -class SSQuest : public ZQuestFile +class SkywardSwordQuest : public ZQuestFile { public: - SSQuest(Uint8* data, Uint32 len); + SkywardSwordQuest(Uint8* data, Uint32 len); // TODO: Is len really needed? void setSkipData(const Uint8* data, Uint32 len = 0x24); diff --git a/include/Sprite.hpp b/include/Sprite.hpp new file mode 100644 index 0000000..6a50966 --- /dev/null +++ b/include/Sprite.hpp @@ -0,0 +1,64 @@ +#ifndef SSPRITE_HPP +#define SSPRITE_HPP + +#include +#include +#include +#include + +namespace zelda +{ +namespace Sakura +{ +class SpriteFile; +class SpritePart; + +class Sprite +{ +public: + Sprite(SpriteFile* root); + Sprite(SpriteFile* root, const std::string& name); + virtual ~Sprite(); + + virtual void setPosition(const float x, const float y); + virtual void setPosition(const Vector2Df& pos); + Vector2Df position() const; + void setName(const std::string& name); + std::string name() const; + + void addStateId(int id); + + /*! + * \brief Returns the texture id of a given state + * \param index The index of the id. + * \return return the state id if it exists, -1 otherwise + */ + int stateId(int index) const; + void setStateIds(std::vector ids); + std::vector stateIds() const; + Uint32 stateCount() const; + void setCurrentState(const Uint32 id); + + void addPart(SpritePart* part); + SpritePart* part(const std::string& name); + void setParts(std::vector parts); + Uint32 partCount() const; + + std::vector parts() const; + + SpriteFile* container() const; +private: + SpriteFile* m_root; + std::string m_name; + Vector2Df m_position; + + std::vector m_stateIds; //!< Stores the texture id's for each state. + std::vector m_parts; + Uint32 m_currentState; +}; + + +} // Sakura +} // zelda + +#endif // SSPRITE_HPP diff --git a/include/SpriteFile.hpp b/include/SpriteFile.hpp new file mode 100644 index 0000000..dc79d7b --- /dev/null +++ b/include/SpriteFile.hpp @@ -0,0 +1,181 @@ +#ifndef SSPRITEFILE_HPP +#define SSPRITEFILE_HPP + +#include +#include +#include +#include + +namespace zelda +{ +namespace Sakura +{ +struct STexture +{ + std::string Filepath; + bool Preload; +}; + +class Sprite; +class SpriteFile +{ +public: + /*! + * \brief Major + */ + static const Uint32 Major; + + /*! + * \brief Minor + */ + static const Uint32 Minor; + + /*! + * \brief Revision + */ + static const Uint32 Revision; + + /*! + * \brief Patch + */ + static const Uint32 Build; + + /*! + * \brief Version + */ + static const Uint32 Version; + + /*! + * \brief Magic + */ + static const Uint32 Magic; + + /*! + * \brief SSprite + */ + SpriteFile(); + + /*! + * \brief SSpriteFile + * \param width + * \param height + * \param originX + * \param originY + */ + SpriteFile(Uint32 width, Uint32 height, float originX, float originY); + + /*! + * \brief SSpriteFile + * \param size + * \param origin + */ + SpriteFile(const Vector2Di& size, const Vector2Df& origin); + + /*! + * \brief setSize + * \param width + * \param height + */ + void setSize(Uint32 width, Uint32 height); + + /*! + * \brief setSize + * \param size + */ + void setSize(const Vector2Di& size); + + /*! + * \brief size + * \return + */ + Vector2Di size() const; + + /*! + * \brief width + * \return + */ + Uint32 width() const; + + /*! + * \brief height + * \return + */ + Uint32 height() const; + + /*! + * \brief setOrigin + * \param x + * \param y + */ + void setOrigin(const float x, const float y); + + /*! + * \brief setOrigin + * \param origin + */ + void setOrigin(const Vector2Df& origin); + + /*! + * \brief origin + * \return + */ + Vector2Df origin() const; + + /*! + * \brief originX + * \return + */ + float originX() const; + + /*! + * \brief originY + * \return + */ + float originY() const; + + /*! + * \brief addTexture + * \param texture + */ + void addTexture(STexture* texture); + + /*! + * \brief removeTexture + * \param id + */ + void removeTexture(int id); + + /*! + * \brief texture + * \param id + * \return + */ + STexture* texture(Uint32 id); + + std::vector textures() const; + Uint32 textureCount() const; + /*! + * \brief setTextures + * \param textures + */ + void setTextures(std::vector textures); + + void addSprite(Sprite* sprite); + + void setSprites(std::unordered_map sprites); + + Sprite* sprite(const std::string& name); + + std::unordered_map sprites() const; + Uint32 spriteCount() const; + +private: + std::vector m_textures; + Vector2Di m_size; + Vector2Df m_origin; + std::unordered_map m_sprites; +}; +} // Sakura +} // Zelda + +#endif // SSPRITE_HPP diff --git a/include/SpriteFileReader.hpp b/include/SpriteFileReader.hpp new file mode 100644 index 0000000..5e7b684 --- /dev/null +++ b/include/SpriteFileReader.hpp @@ -0,0 +1,29 @@ +#ifndef SSPRITEFILEREADER_HPP +#define SSPRITEFILEREADER_HPP + +#include + +namespace zelda +{ +namespace Sakura +{ +class SpriteFile; +} // Sakura + +namespace io +{ + +class SpriteFileReader : public zelda::io::BinaryReader +{ + BINARYREADER_BASE; +public: + SpriteFileReader(Uint8* data, Uint64 length); + SpriteFileReader(const std::string& filepath); + + Sakura::SpriteFile* readFile(); +}; +} // io +} // zelda + + +#endif // SSPRITEFILEREADER_HPP diff --git a/include/SpriteFileWriter.hpp b/include/SpriteFileWriter.hpp new file mode 100644 index 0000000..a375e5f --- /dev/null +++ b/include/SpriteFileWriter.hpp @@ -0,0 +1,29 @@ +#ifndef SSPRITEFILEWRITER_HPP +#define SSPRITEFILEWRITER_HPP + +#include + +namespace zelda +{ +namespace Sakura +{ +class SpriteFile; +} // Sakura + +namespace io +{ + +class SpriteFileWriter : public zelda::io::BinaryWriter +{ + BINARYWRITER_BASE; +public: + SpriteFileWriter(Uint8* data, Uint64 length); + + SpriteFileWriter(const std::string& filepath); + + void writeFile(Sakura::SpriteFile* file); +}; + +} // io +} // zelda +#endif // SSPRITEFILEWRITER_HPP diff --git a/include/SpriteFrame.hpp b/include/SpriteFrame.hpp new file mode 100644 index 0000000..9d05f57 --- /dev/null +++ b/include/SpriteFrame.hpp @@ -0,0 +1,152 @@ +#ifndef SSPRITEFRAME_HPP +#define SSPRITEFRAME_HPP + + +#include + +#include + +namespace zelda +{ +namespace Sakura +{ + +class SpriteFrame +{ +public: + /*! + * \brief SSpriteFrame + */ + SpriteFrame(); + + /*! + * \brief SSpriteFrame + * \param offX + * \param offY + * \param texX + * \param texY + * \param width + * \param height + * \param frameTime + * \param flippedH + * \param flippedV + */ + SpriteFrame(float offX, float offY, float texX, float texY, Uint32 width, Uint32 height, float frameTime, bool flippedH = false, bool flippedV = false); + + /*! + * \brief SSpriteFrame + * \param frameOff + * \param texOff + * \param size + * \param frameTime + * \param flippedH + * \param flippedV + */ + SpriteFrame(const Vector2Df& frameOff, const Vector2Df& texOff, const Vector2Di& size, float frameTime, bool flippedH = false, bool flippedV = false); + + /*! + * \brief setOffset + * \param x + * \param y + */ + void setOffset(float x, float y); + + /*! + * \brief setOffset + * \param offset + */ + void setOffset(const Vector2Df& offset); + + /*! + * \brief offset + * \return + */ + Vector2Df offset() const; + + /*! + * \brief setTextureOffset + * \param x + * \param y + */ + void setTextureOffset(float x, float y); + + /*! + * \brief setTextureOffset + * \param texOff + */ + void setTextureOffset(const Vector2Df& texOff); + + /*! + * \brief textureOffset + * \return + */ + Vector2Df textureOffset() const; + + /*! + * \brief setSize + * \param width + * \param height + */ + void setSize(Uint32 width, Uint32 height); + + /*! + * \brief setSize + * \param size + */ + void setSize(const Vector2Di& size); + + /*! + * \brief size + * \return + */ + Vector2Di size() const; + + /*! + * \brief setFlippedHorizontally + * \param val + */ + void setFlippedHorizontally(const bool val); + + /*! + * \brief flippedHorizontally + * \return + */ + bool flippedHorizontally() const; + + /*! + * \brief setFlippedVertically + * \param val + */ + void setFlippedVertically(const bool val); + + /*! + * \brief flippedVertically + * \return + */ + bool flippedVertically() const; + + /*! + * \brief setFrameTime + * \param frameTime + */ + void setFrameTime(float frameTime); + + /*! + * \brief frameTime + * \return + */ + float frameTime() const; + +private: + Vector2Df m_offset; + Vector2Df m_textureOffset; + Vector2Di m_size; + float m_frameTime; + bool m_flippedH; + bool m_flippedV; +}; + +} // Sakura +} // zelda + +#endif // SSpRITEFRAME_HPP diff --git a/include/SpritePart.hpp b/include/SpritePart.hpp new file mode 100644 index 0000000..a5651dd --- /dev/null +++ b/include/SpritePart.hpp @@ -0,0 +1,56 @@ +#ifndef SSPRITEPART_HPP +#define SSPRITEPART_HPP + +#include +#include +#include +#include + +namespace zelda +{ +namespace Sakura +{ +class Sprite; +class SpriteFrame; + +class SpritePart +{ +public: + SpritePart(Sprite* root); + SpritePart(Sprite* root, const std::string& name, bool hasCollision = false); + virtual ~SpritePart(); + + void setName(const std::string& name); + std::string name() const; + + void setCollision(bool col); + bool hasCollision() const; + + void addFrame(SpriteFrame* frame); + void advanceFrame(); + void retreatFrame(); + SpriteFrame* frame(int id); + void setFrames(std::vector frames); + SpriteFrame* currentFrame(); + int currentFrameID(); + std::vector frames() const; + Uint32 frameCount() const; + + + void setRoot(Sprite* root); +private: + void updateTexture(); + Sprite* m_root; + std::string m_name; + bool m_hasCollision; + SpriteFrame* m_currentFrame; + Uint32 m_frameIndex; + + // The collection of frames for this part + std::vector m_frames; +}; + +} +} + +#endif // SSpRITEPART_HPP diff --git a/include/Types.hpp b/include/Types.hpp index 23ff221..88d69b9 100644 --- a/include/Types.hpp +++ b/include/Types.hpp @@ -37,6 +37,33 @@ enum Region NTSCJRegion, PALRegion }; + +namespace Sakura +{ + +template +class Vector2D +{ +public: + T x; + T y; + + Vector2D() + : x(0), + y(0) + { + } + + Vector2D(T x, T y) + : x(x), + y(y) + { + } +}; + +typedef Vector2D Vector2Di; +typedef Vector2D Vector2Df; +} // Sakura } // zelda #endif diff --git a/src/SSFile.cpp b/src/SkywardSwordFile.cpp similarity index 55% rename from src/SSFile.cpp rename to src/SkywardSwordFile.cpp index 7e43e99..4d8a90b 100644 --- a/src/SSFile.cpp +++ b/src/SkywardSwordFile.cpp @@ -1,26 +1,26 @@ -#include "SSFile.hpp" -#include "SSQuest.hpp" +#include "SkywardSwordFile.hpp" +#include "SkywardSwordQuest.hpp" #include "InvalidOperationException.hpp" namespace zelda { -SSFile::SSFile() +SkywardSwordFile::SkywardSwordFile() : m_numQuests(0) { } -SSFile::SSFile(std::vector quests) +SkywardSwordFile::SkywardSwordFile(std::vector quests) : m_numQuests(0) { m_quests = quests; } -SSFile::~SSFile() +SkywardSwordFile::~SkywardSwordFile() { } -void SSFile::addQuest(zelda::SSQuest *q) +void SkywardSwordFile::addQuest(zelda::SkywardSwordQuest *q) { // Do not allow more than 3 quests if (m_quests.size() >= 3) @@ -29,7 +29,7 @@ void SSFile::addQuest(zelda::SSQuest *q) m_quests.push_back(q); } -SSQuest *SSFile::quest(Uint32 id) +SkywardSwordQuest *SkywardSwordFile::quest(Uint32 id) { if (id > m_quests.size() - 1) throw zelda::error::InvalidOperationException("SSFile::quest -> id cannot be " @@ -38,17 +38,17 @@ SSQuest *SSFile::quest(Uint32 id) return m_quests[id]; } -std::vector SSFile::questList() const +std::vector SkywardSwordFile::questList() const { return m_quests; } -void SSFile::setRegion(Region region) +void SkywardSwordFile::setRegion(Region region) { m_region = region; } -Region SSFile::region() const +Region SkywardSwordFile::region() const { return m_region; } diff --git a/src/SSFileReader.cpp b/src/SkywardSwordFileReader.cpp similarity index 62% rename from src/SSFileReader.cpp rename to src/SkywardSwordFileReader.cpp index c9f2b3d..8257e07 100644 --- a/src/SSFileReader.cpp +++ b/src/SkywardSwordFileReader.cpp @@ -1,6 +1,6 @@ -#include "SSFileReader.hpp" -#include "SSFile.hpp" -#include "SSQuest.hpp" +#include "SkywardSwordFileReader.hpp" +#include "SkywardSwordFile.hpp" +#include "SkywardSwordQuest.hpp" #include "InvalidOperationException.hpp" #include @@ -9,27 +9,27 @@ namespace zelda namespace io { -SSFileReader::SSFileReader(Uint8* data, Uint64 length) +SkywardSwordFileReader::SkywardSwordFileReader(Uint8* data, Uint64 length) : base(data, length) { base::setEndianess(BigEndian); } -SSFileReader::SSFileReader(const std::string& filename) +SkywardSwordFileReader::SkywardSwordFileReader(const std::string& filename) : base(filename) { base::setEndianess(BigEndian); } -SSFile* SSFileReader::read() +SkywardSwordFile* SkywardSwordFileReader::read() { - SSFile* file = NULL; + SkywardSwordFile* file = NULL; if (base::length() != 0xFBE0) throw zelda::error::InvalidOperationException("SSFileReader::read -> File not the expected size of 0xFBE0"); Uint32 magic = base::readUInt32(); - if (magic != SSFile::USMagic && magic != SSFile::JAMagic && magic != SSFile::EUMagic) + if (magic != SkywardSwordFile::USMagic && magic != SkywardSwordFile::JAMagic && magic != SkywardSwordFile::EUMagic) throw zelda::error::InvalidOperationException("SSFileReader::read -> Not a valid Skyward Sword save file"); base::seek(0x01C, base::Beginning); @@ -39,11 +39,11 @@ SSFile* SSFileReader::read() throw zelda::error::InvalidOperationException("SSFileHeader::read -> Invalid header size, Corrupted data?"); // Time to read in each slot - file = new SSFile; - file->setRegion((magic == SSFile::USMagic ? NTSCURegion : (magic == SSFile::JAMagic ? NTSCJRegion : PALRegion))); + file = new SkywardSwordFile; + file->setRegion((magic == SkywardSwordFile::USMagic ? NTSCURegion : (magic == SkywardSwordFile::JAMagic ? NTSCJRegion : PALRegion))); for (int i = 0; i < 3; i++) { - SSQuest* q = new SSQuest((Uint8*)base::readBytes(0x53C0), 0x53C0); + SkywardSwordQuest* q = new SkywardSwordQuest((Uint8*)base::readBytes(0x53C0), 0x53C0); Uint64 pos = base::position(); // seek to the skip data for this particular quest base::seek(0xFB60 + (i * 0x24), base::Beginning); diff --git a/src/SSFileWriter.cpp b/src/SkywardSwordFileWriter.cpp similarity index 54% rename from src/SSFileWriter.cpp rename to src/SkywardSwordFileWriter.cpp index 9db8cf9..0336f9f 100644 --- a/src/SSFileWriter.cpp +++ b/src/SkywardSwordFileWriter.cpp @@ -1,36 +1,36 @@ -#include "SSFileWriter.hpp" -#include "SSFile.hpp" -#include "SSQuest.hpp" +#include "SkywardSwordFileWriter.hpp" +#include "SkywardSwordFile.hpp" +#include "SkywardSwordQuest.hpp" namespace zelda { namespace io { -SSFileWriter::SSFileWriter(Uint8 *data, Uint64 len) +SkywardSwordFileWriter::SkywardSwordFileWriter(Uint8 *data, Uint64 len) : base(data, len) { base::setEndianess(BigEndian); } -SSFileWriter::SSFileWriter(const std::string &filename) +SkywardSwordFileWriter::SkywardSwordFileWriter(const std::string &filename) : base(filename) { base::setEndianess(BigEndian); } -void SSFileWriter::write(SSFile *file) +void SkywardSwordFileWriter::write(SkywardSwordFile *file) { - Uint32 magic = (file->region() == NTSCURegion ? SSFile::USMagic : - (file->region() == NTSCJRegion ? SSFile::JAMagic : SSFile::EUMagic)); + Uint32 magic = (file->region() == NTSCURegion ? SkywardSwordFile::USMagic : + (file->region() == NTSCJRegion ? SkywardSwordFile::JAMagic : SkywardSwordFile::EUMagic)); base::writeUInt32(magic); base::seek(0x1C, base::Beginning); base::writeUInt32(0x1D); - std::vector quests = file->questList(); + std::vector quests = file->questList(); int i = 0; - for (SSQuest* q : quests) + for (SkywardSwordQuest* q : quests) { // Write the save data base::writeUBytes(q->data(), q->length()); diff --git a/src/SSQuest.cpp b/src/SkywardSwordQuest.cpp similarity index 57% rename from src/SSQuest.cpp rename to src/SkywardSwordQuest.cpp index 2e33c2e..0c75f86 100644 --- a/src/SSQuest.cpp +++ b/src/SkywardSwordQuest.cpp @@ -1,15 +1,15 @@ -#include "SSQuest.hpp" +#include "SkywardSwordQuest.hpp" namespace zelda { -SSQuest::SSQuest(Uint8 *data, Uint32 len) +SkywardSwordQuest::SkywardSwordQuest(Uint8 *data, Uint32 len) : ZQuestFile(ZQuestFile::SS, BigEndian, data, len), m_skipData(NULL), m_skipLength(0) { } -void SSQuest::setSkipData(const Uint8 *data, Uint32 len) +void SkywardSwordQuest::setSkipData(const Uint8 *data, Uint32 len) { if (m_skipData) { @@ -21,12 +21,12 @@ void SSQuest::setSkipData(const Uint8 *data, Uint32 len) m_skipLength = len; } -Uint8 *SSQuest::skipData() const +Uint8 *SkywardSwordQuest::skipData() const { return m_skipData; } -Uint32 SSQuest::skipLength() const +Uint32 SkywardSwordQuest::skipLength() const { return m_skipLength; } diff --git a/src/Sprite.cpp b/src/Sprite.cpp new file mode 100644 index 0000000..45f06bd --- /dev/null +++ b/src/Sprite.cpp @@ -0,0 +1,136 @@ +#include "Sprite.hpp" +#include "SpritePart.hpp" +#include "SpriteFile.hpp" +#include + +namespace zelda +{ +namespace Sakura +{ +Sprite::Sprite(SpriteFile* root) + : m_root(root), + m_currentState(0) +{ +} + +Sprite::Sprite(SpriteFile* root, const std::string& name) + : m_root(root), + m_name(name), + m_currentState(0) +{ +} + +Sprite::~Sprite() +{ + +} + +void Sprite::setPosition(const float x, const float y) +{ + setPosition(Vector2Df(x, y)); +} + +void Sprite::setPosition(const Vector2Df& pos) +{ + m_position = pos; +} + +Vector2Df Sprite::position() const +{ + return m_position; +} + +void Sprite::setName(const std::string& name) +{ + m_name = name; +} + +std::string Sprite::name() const +{ + return m_name; +} + +void Sprite::addStateId(int id) +{ + if (m_stateIds.size() >= 65536) + return; + + if (std::find(m_stateIds.begin(), m_stateIds.end(), id) == m_stateIds.end()) + m_stateIds.push_back(id); +} + +int Sprite::stateId(int index) const +{ + if (index >= (int)m_stateIds.size()) + return -1; + + return m_stateIds[index]; +} + +void Sprite::setStateIds(std::vector ids) +{ + if (ids.size() == 0) + return; + + m_stateIds = ids; +} + +std::vector Sprite::stateIds() const +{ + return m_stateIds; +} + +Uint32 Sprite::stateCount() const +{ + return m_stateIds.size(); +} + +void Sprite::setCurrentState(const Uint32 id) +{ + m_currentState = id; +} + +void Sprite::addPart(SpritePart* part) +{ + for (SpritePart* tmp : m_parts) + { + if (tmp == part) + return; + } + m_parts.push_back(part); +} + +void Sprite::setParts(std::vector parts) +{ + if (parts.size() == 0) + return; + + if (m_parts.size() > 0) + { + for (SpritePart* part : m_parts) + { + delete part; + part = NULL; + } + m_parts.clear(); + } + + m_parts = parts; +} + +Uint32 Sprite::partCount() const +{ + return m_parts.size(); +} + +std::vector Sprite::parts() const +{ + return m_parts; +} + +SpriteFile* Sprite::container() const +{ + return m_root; +} +} +} diff --git a/src/SpriteFile.cpp b/src/SpriteFile.cpp new file mode 100644 index 0000000..a7a9073 --- /dev/null +++ b/src/SpriteFile.cpp @@ -0,0 +1,180 @@ +#include "SpriteFile.hpp" +#include "Sprite.hpp" +#include + + +namespace zelda +{ +namespace Sakura +{ +const Uint32 SpriteFile::Major = 1; +const Uint32 SpriteFile::Minor = 0; +const Uint32 SpriteFile::Revision = 1; +const Uint32 SpriteFile::Build = 0; +const Uint32 SpriteFile::Version = Major | (Minor << 8) | (Revision << 16) | (Build << 24); + +const Uint32 SpriteFile::Magic = 'S' | ('P' << 8) | ('R' << 16) | ('S' << 24); + + +SpriteFile::SpriteFile() + : m_size(Vector2Di(1, 1)) +{ +} + +SpriteFile::SpriteFile(Uint32 width, Uint32 height, float originX, float originY) + : m_size(Vector2Di(width, height)), + m_origin(Vector2Df(originX, originY)) +{ +} + +SpriteFile::SpriteFile(const Vector2Di& size, const Vector2Df& origin) + : m_size(size), + m_origin(origin) +{ +} + +void SpriteFile::setSize(Uint32 width, Uint32 height) +{ + setSize(Vector2Di(width, height)); +} + +void SpriteFile::setSize(const Vector2Di& size) +{ + m_size = size; +} + +Vector2Di SpriteFile::size() const +{ + return m_size; +} + +Uint32 SpriteFile::width() const +{ + return m_size.x; +} + +Uint32 SpriteFile::height() const +{ + return m_size.y; +} + +void SpriteFile::setOrigin(const float x, const float y) +{ + setOrigin(Vector2Df(x, y)); +} + +void SpriteFile::setOrigin(const Vector2Df& origin) +{ + m_origin = origin; +} + +Vector2Df SpriteFile::origin() const +{ + return m_origin; +} + +float SpriteFile::originX() const +{ + return m_origin.x; +} + +float SpriteFile::originY() const +{ + return m_origin.y; +} + +void SpriteFile::addTexture(STexture* texture) +{ + m_textures.push_back(texture); +} + +void SpriteFile::removeTexture(int id) +{ + if (id > (int)m_textures.size() || id < 0) + return; + + STexture* tex = m_textures[id]; + m_textures.erase(m_textures.begin() + id); + delete tex; +} + +STexture* SpriteFile::texture(Uint32 id) +{ + if (id >= m_textures.size()) + return NULL; + + return m_textures[id]; +} + +std::vector SpriteFile::textures() const +{ + return m_textures; +} + +Uint32 SpriteFile::textureCount() const +{ + return m_textures.size(); +} + +void SpriteFile::addSprite(Sprite* sprite) +{ + if (m_sprites.find(sprite->name()) != m_sprites.end()) + return; + + m_sprites[sprite->name()] = sprite; +} + +void SpriteFile::setSprites(std::unordered_map sprites) +{ + if (sprites.size() == 0) + return; + if (m_sprites.size() > 0) + { + for (std::pair sprite : m_sprites) + { + delete sprite.second; + sprite.second = NULL; + } + m_sprites.clear(); + } + + m_sprites = sprites; +} + +Sprite* SpriteFile::sprite(const std::string& name) +{ + if (m_sprites.find(name) == m_sprites.end()) + return NULL; + + return m_sprites[name]; +} + +std::unordered_map SpriteFile::sprites() const +{ + return m_sprites; +} + +Uint32 SpriteFile::spriteCount() const +{ + return m_sprites.size(); +} + +void SpriteFile::setTextures(std::vector textures) +{ + if (textures.size() == 0) + return; + + if (m_textures.size() > 0) + { + for(STexture* tex : m_textures) + { + delete tex; + tex = NULL; + } + m_textures.clear(); + } + + m_textures = textures; +} +} // Sakura +} // zelda diff --git a/src/SpriteFileReader.cpp b/src/SpriteFileReader.cpp new file mode 100644 index 0000000..4016ea6 --- /dev/null +++ b/src/SpriteFileReader.cpp @@ -0,0 +1,148 @@ +#include "SpriteFileReader.hpp" +#include "SpriteFile.hpp" +#include "Sprite.hpp" +#include "SpritePart.hpp" +#include "SpriteFrame.hpp" +#include "InvalidOperationException.hpp" +#include "IOException.hpp" + +namespace zelda +{ +namespace io +{ +SpriteFileReader::SpriteFileReader(Uint8* data, Uint64 length) + : base(data, length) +{ +} + +SpriteFileReader::SpriteFileReader(const std::string& filepath) + : base(filepath) +{ + +} + +Sakura::SpriteFile* SpriteFileReader::readFile() +{ + Uint32 magic = base::readUInt32(); + + if (magic != Sakura::SpriteFile::Magic) + throw zelda::error::InvalidOperationException("Not a valid Sakura Sprite container"); + + Uint32 version = base::readUInt32(); + + // TODO: Make this more verbose + if (version != Sakura::SpriteFile::Version) + throw zelda::error::InvalidOperationException("Unsupported version"); + + // After reading in the magic and version we need to load some + // metadata about the file. + // Such as the texture count, it's dimensions, and it's origin. + // After that we have the number of sprites contained in this + // sprite container. + Uint16 textureCount = base::readUInt16(); // Having it as a Uint16 gives us the ability to have up to 65536 different states + // This is probably overkill, but it's better safe than sorry. + Uint32 width = base::readUInt32(); + Uint32 height = base::readUInt32(); + float originX = base::readFloat(); + float originY = base::readFloat(); + Uint16 spriteCount = base::readUInt16(); + + // Lets go ahead and create or new container. + Sakura::SpriteFile* ret = new Sakura::SpriteFile(width, height, originX, originY); + + // The next four bytes are reserved to keep the header 32 byte aligned. + // This isn't necessary for most systems, but it's eventually planned + // to migrate this code to Big Endian based systems, such as the wii + // which require data to be 32 byte aligned, or it causes some issues. + // It's also convenient to have this, for later expansion. + Uint32 reserved = base::readUInt32(); + UNUSED(reserved); + + // Next we have to load the textures + // If we tried to add them one at a time to the sprite container + // it will be slow as hell, so we store them in a vector locally + // then give that vector the the container, this bypasses the de-reference + // for each texture + std::vector textures; + + for (Uint16 i = 0; i < textureCount; i++) + { + Sakura::STexture* texture = new Sakura::STexture; + texture->Filepath = base::readString(); + texture->Preload = base::readBool(); + textures.push_back(texture); + } + + ret->setTextures(textures); + + // Now for the sprites + // The sprites are a bit more difficult, they are stored in an unordered_map + // with it's name as the key, this means we can't have two sprites with the same name + // Normally this isn't a problem, but someone may decide to copy and paste a sprite + // and forget to change the name, that needs to be handled, but it's outside the scope + // of this reader. + std::unordered_map sprites; + + for (Uint16 i = 0; i < spriteCount; i++) + { + Sakura::Sprite* sprite = new Sakura::Sprite(ret); + sprite->setName(base::readString()); + Uint16 partCount = base::readUInt16(); + Uint16 stateCount = base::readUInt16(); + + // Each state id corresponds to a texture held in the parent class + std::vector stateIds; + for (int j = 0; j < stateCount; j++) + stateIds.push_back(base::readUInt16()); + + + sprite->setStateIds(stateIds); + + // Now to read the sprite parts. + // The parts allow us to build retro style sprites very easily + // making it possible to use one texture atlas for all possible + // frame combinations, this reduces the amount of memory overhead + // and the storage footprint, while Sakura supports packs and zips + // it's still a bad idea to have a metric ton of texture resources + // littering the place + std::vector parts; + for (Uint8 j = 0; j < partCount; j++) + { + Sakura::SpritePart* part = new Sakura::SpritePart(sprite); + part->setName(base::readString()); + part->setCollision(base::readBool()); + + Uint32 frameCount = base::readUInt32(); + std::vector frames; + + for (Uint32 k = 0; k < frameCount; k++) + { + float xOff = base::readFloat(); + float yOff = base::readFloat(); + float texXOff = base::readFloat(); + float texYOff = base::readFloat(); + Uint32 width = base::readUInt32(); + Uint32 height = base::readUInt32(); + float frameTime = base::readFloat(); + bool flippedH = base::readBool(); + bool flippedV = base::readBool(); + + frames.push_back(new Sakura::SpriteFrame(xOff, yOff, texXOff, texYOff, width, height, frameTime, flippedH, flippedV)); + } + part->setFrames(frames); + parts.push_back(part); + } + + sprite->setParts(parts); + if (sprite->name() != std::string()) + sprites[sprite->name()] = sprite; + else + throw zelda::error::IOException("SSpriteFileReader::readFile -> Sprite names cannot be empty"); + } + + ret->setSprites(sprites); + + return ret; +} +} // io +} // zelda diff --git a/src/SpriteFileWriter.cpp b/src/SpriteFileWriter.cpp new file mode 100644 index 0000000..f2c709c --- /dev/null +++ b/src/SpriteFileWriter.cpp @@ -0,0 +1,81 @@ +#include "SpriteFileWriter.hpp" +#include "SpriteFile.hpp" +#include "Sprite.hpp" +#include "SpritePart.hpp" +#include "SpriteFrame.hpp" +#include "InvalidOperationException.hpp" + +namespace zelda +{ +namespace io +{ +SpriteFileWriter::SpriteFileWriter(Uint8 *data, Uint64 length) + : base(data, length) +{ +} + +SpriteFileWriter::SpriteFileWriter(const std::string& filepath) + : base(filepath) +{ +} + +void SpriteFileWriter::writeFile(Sakura::SpriteFile* file) +{ + if (!file) + throw zelda::error::InvalidOperationException("SSpriteFileWriter::writeFile -> file cannot be NULL"); + + base::writeUInt32(Sakura::SpriteFile::Magic); + base::writeUInt32(Sakura::SpriteFile::Version); + + base::writeUInt16(file->textureCount()); + base::writeUInt32(file->width()); + base::writeUInt32(file->height()); + base::writeFloat(file->originX()); + base::writeFloat(file->originY()); + base::writeUInt16(file->spriteCount()); + + base::writeUInt32(0xFFFFFFFF); + + for (Sakura::STexture* texture : file->textures()) + { + base::writeString(texture->Filepath); + base::writeBool(texture->Preload); + } + + for (std::pair spritePair : file->sprites()) + { + Sakura::Sprite* sprite = spritePair.second; + + base::writeString(sprite->name()); + base::writeUInt16(sprite->partCount()); + base::writeUInt16(sprite->stateCount()); + + for (int id : sprite->stateIds()) + base::writeUInt16(id); + + for (Sakura::SpritePart* part : sprite->parts()) + { + base::writeString(part->name()); + base::writeBool(part->hasCollision()); + base::writeUInt32(part->frameCount()); + + for (Sakura::SpriteFrame* frame : part->frames()) + { + base::writeFloat(frame->offset().x); + base::writeFloat(frame->offset().y); + base::writeFloat(frame->textureOffset().x); + base::writeFloat(frame->textureOffset().y); + base::writeUInt32(frame->size().x); + base::writeUInt32(frame->size().y); + base::writeFloat(frame->frameTime()); + base::writeBool(frame->flippedHorizontally()); + base::writeBool(frame->flippedVertically()); + } + } + } + + save(); +} + +} // io +} // zelda diff --git a/src/SpriteFrame.cpp b/src/SpriteFrame.cpp new file mode 100644 index 0000000..8f07d1a --- /dev/null +++ b/src/SpriteFrame.cpp @@ -0,0 +1,109 @@ +#include "SpriteFrame.hpp" +#include "SpritePart.hpp" + +namespace zelda +{ +namespace Sakura +{ + +SpriteFrame::SpriteFrame() +{ +} + +SpriteFrame::SpriteFrame(float offX, float offY, float texX, float texY, Uint32 width, Uint32 height, float frameTime, bool flippedH, bool flippedV) + : m_offset(Vector2Df(offX, offY)), + m_textureOffset(Vector2Df(texX, texY)), + m_size(Vector2Di(width, height)), + m_frameTime(frameTime), + m_flippedH(flippedH), + m_flippedV(flippedV) +{ +} + +SpriteFrame::SpriteFrame(const Vector2Df& frameOff, const Vector2Df& texOff, const Vector2Di& size, float frameTime, bool flippedH, bool flippedV) + : m_offset(frameOff), + m_textureOffset(texOff), + m_size(size), + m_frameTime(frameTime), + m_flippedH(flippedH), + m_flippedV(flippedV) +{ +} + +void SpriteFrame::setOffset(float x, float y) +{ + setOffset(Vector2Df(x, y)); +} + +void SpriteFrame::setOffset(const Vector2Df& offset) +{ + m_offset = offset; +} + +Vector2Df SpriteFrame::offset() const +{ + return m_offset; +} + +void SpriteFrame::setTextureOffset(float x, float y) +{ + setTextureOffset(Vector2Df(x, y)); +} + +void SpriteFrame::setTextureOffset(const Vector2Df& texOff) +{ + m_textureOffset = texOff; +} + +Vector2Df SpriteFrame::textureOffset() const +{ + return m_textureOffset; +} + +void SpriteFrame::setSize(Uint32 width, Uint32 height) +{ + setSize(Vector2Di(width, height)); +} + +void SpriteFrame::setSize(const Vector2Di& size) +{ + m_size = size; +} + +Vector2Di SpriteFrame::size() const +{ + return m_size; +} + +void SpriteFrame::setFlippedHorizontally(const bool val) +{ + m_flippedH = val; +} + +bool SpriteFrame::flippedHorizontally() const +{ + return m_flippedH; +} + +void SpriteFrame::setFlippedVertically(const bool val) +{ + m_flippedV = val; +} + +bool SpriteFrame::flippedVertically() const +{ + return m_flippedV; +} + +void SpriteFrame::setFrameTime(float frameTime) +{ + m_frameTime = frameTime; +} + +float SpriteFrame::frameTime() const +{ + return m_frameTime; +} + +} // Sakura +} // zelda diff --git a/src/SpritePart.cpp b/src/SpritePart.cpp new file mode 100644 index 0000000..d692fdb --- /dev/null +++ b/src/SpritePart.cpp @@ -0,0 +1,128 @@ +#include "SpritePart.hpp" +#include "SpriteFrame.hpp" +#include "Sprite.hpp" + +namespace zelda +{ +namespace Sakura +{ + +SpritePart::SpritePart(Sprite* root) + : m_root(root), + m_hasCollision(false), + m_currentFrame(NULL), + m_frameIndex(0) +{ +} + +SpritePart::SpritePart(Sprite* root, const std::string& name, bool hasCollision) + : m_root(root), + m_name(name), + m_hasCollision(hasCollision), + m_currentFrame(NULL), + m_frameIndex(0) +{ +} + +SpritePart::~SpritePart() +{ + +} + +void SpritePart::setName(const std::string& name) +{ + m_name = name; +} + +std::string SpritePart::name() const +{ + return m_name; +} + +void SpritePart::setCollision(bool col) +{ + m_hasCollision = col; +} + +bool SpritePart::hasCollision() const +{ + return m_hasCollision; +} + +void SpritePart::addFrame(SpriteFrame* frame) +{ + m_frames.push_back(frame); +} + +void SpritePart::advanceFrame() +{ + if (m_frameIndex < m_frames.size() - 1) + { + m_frameIndex++; + m_currentFrame = m_frames[m_frameIndex]; + } +} + +void SpritePart::retreatFrame() +{ + if (m_frameIndex > 0) + { + m_frameIndex--; + m_currentFrame = m_frames[m_frameIndex]; + } +} + +SpriteFrame* SpritePart::frame(int id) +{ + if (id < 0 || id >= (int)m_frames.size()) + return NULL; + + return m_frames[id]; +} + +void SpritePart::setFrames(std::vector frames) +{ + if (frames.size() == 0) + return; + + if (m_frames.size() > 0) + { + for (SpriteFrame* frame : m_frames) + { + delete frame; + frame = NULL; + } + m_frames.clear(); + } + + if (!m_currentFrame) + { + m_currentFrame = frames[0]; + updateTexture(); + } + + m_frames = frames; +} + +SpriteFrame* SpritePart::currentFrame() +{ + return m_currentFrame; +} + +int SpritePart::currentFrameID() +{ + return m_frameIndex; +} + +std::vector SpritePart::frames() const +{ + return m_frames; +} + +Uint32 SpritePart::frameCount() const +{ + return m_frames.size(); +} + +} +}