소스 검색

Merge branch 'piaf_integration' into merge

Dan Elkouby 10 년 전
부모
커밋
293f8fddc1

+ 1 - 1
Makefile

@@ -14,7 +14,7 @@ CFLAGS = $(CFLAGS_COMMON) -std=gnu11
 
 CPPFLAGS = $(CFLAGS_COMMON) -std=gnu++11
 
-LDFLAGS = $(CFLAGS_COMMON) -Wl,--gc-sections
+LDFLAGS = $(CFLAGS_COMMON) -Wl,--gc-sections -lz
 
 SRCS_C :=
 SRCS_CPP :=

BIN
data/out.wrf


+ 1 - 1
info/archive_structure.md

@@ -4,7 +4,7 @@
 WRPG_PIAF_MAGIC_HEADER       : "WRPGPIAF"          <=> 8 bytes (not \0 terminated)
 WRPG_PIAF_HEADER_CHECKSUM    :  unsigned int       <=> 4 bytes (This checksum covers the version, number of files and the data size).
 WRPG_PIAF_FILETABLE_CHECKSUM :  unsigned int       <=> 4 bytes (This checksum covers the whole filetable data part).
-WRPG_PIAF_VERSION            :  unsigned int       <=> 4 bytes (Stored in this form : 0xAABBCCDDD, where A = major version, B = minor version, C = hotfix)
+WRPG_PIAF_VERSION            :  unsigned int       <=> 4 bytes (Stored in this form : 0xAABBCCDD, where A = major version, B = minor version, C = hotfix)
 WRPG_PIAF_NB_FILES           :  unsigned int       <=> 4 bytes
 WRPG_PIAF_DATA_SIZE          :  unsigned int       <=> 4 bytes
 <padding>                    :  <filler>           <=> 4 bytes

+ 8 - 1
platform/include/Quirks.h

@@ -1,12 +1,19 @@
 #ifndef INCLUDE_QUIRKS_H
 #define INCLUDE_QUIRKS_H
 
+#include <memory>
+#include <TINYSTL/string.h>
+
 namespace WalrusRPG
 {
     namespace Quirks
     {
-        void init();
+        void init(const char *argv_0);
         void deinit();
+
+        // Relative path to absolute path resolving.
+        // Exists because at this time Ndless doesn't support relative paths.
+        std::unique_ptr<char> solve_absolute_path(const char *path);
     }
 }
 

+ 2 - 0
platform/include/Texture.h

@@ -9,6 +9,7 @@
 #include "utility/Rect.h"
 #include "platform.h"
 #include "render/Pixel.h"
+#include "piaf/Archive.h"
 //#include "PLATFORM/texture_type.h"
 
 namespace WalrusRPG
@@ -22,6 +23,7 @@ namespace WalrusRPG
           public:
             texture_data_t data;
 
+            Texture(WalrusRPG::PIAF::File entry);
             Texture(char *data);
             ~Texture();
             // Getters

+ 39 - 1
platform/nspire/Quirks.cpp

@@ -1,15 +1,53 @@
+#include <cstddef>
+#include <cstring>
+#include <memory>
+#include <TINYSTL/string.h>
 #include "Quirks.h"
 #include "Interrupts.h"
 
+
 using namespace WalrusRPG;
 using namespace Nspire;
+using tinystl::string;
+
+namespace
+{
+    static char *base_path = nullptr;
+}
 
-void Quirks::init()
+void Quirks::init(const char *argv_0)
 {
     Interrupts::init();
+    // Find last '/' occurence and remove the trailing characters
+    // so we get rid of the executable name.
+    int last_slash_occurence = -1;
+    for (unsigned i = 0; argv_0[i] != '\0'; i++)
+    {
+        if (argv_0[i] == '/')
+            last_slash_occurence = i;
+    }
+    if (last_slash_occurence > 0)
+    {
+        base_path = new char[last_slash_occurence + 2];
+        strncpy(base_path, argv_0, last_slash_occurence);
+        base_path[last_slash_occurence] = '/';
+        base_path[last_slash_occurence + 1] = '\0';
+    }
 }
 
 void Quirks::deinit()
 {
     Interrupts::off();
+    delete[] base_path;
+}
+
+std::unique_ptr<char> Quirks::solve_absolute_path(const char *path)
+{
+    const char nspire_suffix[] = ".tns";
+    std::unique_ptr<char> result(new char[strlen(base_path) + strlen(path) + strlen(nspire_suffix)+1]);
+    strcpy(result.get(), base_path);
+    strcpy(&result.get()[strlen(base_path)], path);
+    strcpy(&result.get()[strlen(base_path)+strlen(path)], nspire_suffix);
+    result.get()[strlen(base_path) + strlen(path) + strlen(nspire_suffix)] = '\0';
+    return result;
 }

+ 44 - 1
platform/nspire/Texure.cpp

@@ -1,12 +1,16 @@
 #include "Texture.h"
+#include "piaf/Archive.h"
 #include "utility/Rect.h"
 #include "render/Pixel.h"
 #include "utility/misc.h"
-
+#include "lodepng.h"
+#include "Input.h"
+#include "Graphics.h"
 using WalrusRPG::Graphics::Black;
 using WalrusRPG::Graphics::Pixel;
 using WalrusRPG::Graphics::Texture;
 using WalrusRPG::Utils::Rect;
+using WalrusRPG::PIAF::File;
 
 namespace
 {
@@ -20,6 +24,45 @@ namespace
     */
 }
 
+Texture::Texture(File entry)
+{
+    unsigned char *pic;
+    unsigned width, height;
+
+    signed result =
+        lodepng_decode_memory(&pic, &width, &height, (unsigned char *) entry.get(),
+                              entry.file_size, LCT_RGBA, 8);
+    UNUSED(result);
+
+    data = new uint16_t[width * height + 3];
+    data[0] = width;
+    data[1] = height;
+    bool transparency_set(false);
+    for (unsigned y = 0; y < height; y++)
+    {
+        for (unsigned x = 0; x < width; x++)
+        {
+            bool is_transparent = (pic[(y * width + x) * 4 + 3] == 0);
+            if (is_transparent && transparency_set)
+            {
+                data[y * width + x + 3] = data[2];
+                continue;
+            }
+            uint16_t color = (pic[(y * width + x) * 4] >> 3) << 11;
+            color |= (pic[(y * width + x) * 4 + 1] >> 2) << 5;
+            color |= (pic[(y * width + x) * 4 + 2] >> 3);
+            if (is_transparent && !transparency_set)
+            {
+                data[2] = color;
+                transparency_set = true;
+            }
+            data[y * width + x + 3] = color;
+        }
+    }
+    delete[] pic;
+}
+
+
 Texture::Texture(char *data) : data((texture_data_t) data)
 {
 }

+ 1 - 0
platform/nspire/rules.mk

@@ -14,6 +14,7 @@ ZEHN = genzehn
 ZEHNFLAGS = --name "$(NAME)" --compress
 
 EXE = $(OUT)/$(NAME).tns
+DATA_FILE_SUFFIX=.tns
 
 $(EXE): $(ELF)
 	@mkdir -p $(dir $@)

+ 12 - 1
platform/sfml/Quirks.cpp

@@ -1,11 +1,22 @@
+#include <cstring>
 #include "Quirks.h"
+#include "utility/misc.h"
 
 using namespace WalrusRPG;
+using tinystl::string;
 
-void Quirks::init()
+void Quirks::init(const char *argv_0)
 {
+    UNUSED(argv_0);
 }
 
 void Quirks::deinit()
 {
 }
+
+std::unique_ptr<char> Quirks::solve_absolute_path(const char *path)
+{
+    std::unique_ptr<char> result(new char[strlen(path)]);
+    strcpy(result.get(), path);
+    return result;
+}

+ 10 - 6
platform/sfml/Texture.cpp

@@ -3,6 +3,7 @@
 #include <SFML/OpenGL.hpp>
 #include <SFML/Graphics/Rect.hpp>
 #include <cstdint>
+#include <cstdlib>
 #include "utility/misc.h"
 #include "render/Pixel.h"
 
@@ -12,12 +13,7 @@ using WalrusRPG::Graphics::Pixel;
 
 TEXTURE::Texture(char *data) : data()
 {
-    // UNUSED(data);
     uint16_t *data_16 = (uint16_t *) data;
-    // TOOD : load from PIAF
-    // this->data.loadFromFile("art/overworld.png");
-    // this->data.loadFromMemory(data+6, data_16[0]*data_16[1], sf::IntRect(0, 0,
-    // data_16[0], data_16[1]));
     this->data.create(data_16[0], data_16[1]);
     sf::Uint8 *pixels = new sf::Uint8[data_16[0] * data_16[1] * 4];
     for (unsigned y = 0; y < data_16[1]; y++)
@@ -34,7 +30,15 @@ TEXTURE::Texture(char *data) : data()
     }
     this->data.update(pixels);
 
-    delete[] pixels;
+    free(pixels);
+}
+
+TEXTURE::Texture(WalrusRPG::PIAF::File entry) : data()
+{
+    // UNUSED(data);
+    // TOOD : load from PIAF
+    // this->data.loadFromFile("art/overworld.png");
+    this->data.loadFromMemory(entry.get(), entry.file_size);
 }
 
 TEXTURE::~Texture()

+ 13 - 4
rules.mk

@@ -5,6 +5,7 @@ all: $(EXE)
 include $(wildcard */rules.mk)
 
 RELEASE_DIRECTORY=release/$(PLATFORM)
+RELEASE_FILES=$(addprefix $(RELEASE_DIRECTORY)/, $(addsuffix $(DATA_FILE_SUFFIX), $(wildcard data/*)))
 
 # Object dependency files
 -include $(OBJS:%.o=%.d)
@@ -35,12 +36,20 @@ $(ELF): $(OBJS)
 clean:
 	@echo "RM: $(OUT)"
 	@rm -rf $(OUT)
+	@echo "RM : $(RELEASE_DIRECTORY)"
+	@rm -rf $(RELEASE_DIRECTORY)
 
-release: $(ELF)
-	@echo "Packing binary and data files into $(RELEASE_DIRECTORY)"
-	@mkdir -p "$(RELEASE_DIRECTORY)"
+make_release_dirs:
+	@mkdir -p "$(RELEASE_DIRECTORY)/data"
+
+release/$(PLATFORM)/%$(DATA_FILE_SUFFIX) : % | make_release_dirs
+	@echo "$^=> $@"
+	@cp -u "$^" "$@"
+
+
+release: $(ELF) $(RELEASE_FILES)
 	@cp $(ELF) "$(RELEASE_DIRECTORY)"
-	@cp -ru data "$(RELEASE_DIRECTORY)" 2>/dev/null || :
+
 
 bundle: release
 	@echo "Tar-zipping"

+ 4 - 4
src/engine/StateMachine.cpp

@@ -2,7 +2,7 @@
 #include "Timing.h"
 #include "platform.h"
 #include "Graphics.h"
-#include "render/Text.h"
+// #include "render/Text.h"
 #include "version.h"
 #include "Input.h"
 
@@ -101,11 +101,11 @@ void STATEMACHINE::run()
             stack.back()->render(100 * frame_time / TIMER_FREQ);
             last_frame = frame_stamp;
 
-            Text::print_format(0, 0, "WalrusRPG test build %s", git_version);
+            // Text::print_format(0, 0,0 "WalrusRPG test build %s", git_version);
             if (frame_time != 0 && update_time != 0)
             {
-                Text::print_format(0, 240 - 8, "%ufps, %uups", TIMER_FREQ / frame_time,
-                                   TIMER_FREQ / update_time);
+                // Text::print_format(0, 240 - 8, "%ufps, %uups", TIMER_FREQ / frame_time,
+                //                    TIMER_FREQ / update_time);
             }
             draw_buttons();
             Graphics::frame_end();

+ 27 - 51
src/engine/main.cpp

@@ -4,69 +4,41 @@
 #include "Quirks.h"
 #include "map/Map.h"
 #include "map/StateMap.h"
+#include "piaf/Archive.h"
 #include "utility/misc.h"
+#include "sprites.h"
 
 using namespace WalrusRPG;
+using WalrusRPG::PIAF::Archive;
+using WalrusRPG::Graphics::Texture;
 
 int main(int argc, char *argv[])
 {
     UNUSED(argc);
-    UNUSED(argv);
 
     Graphics::init();
     Timing::init();
-    Quirks::init();
+    Quirks::init(argv[0]);
 
-    uint16_t dungeonTest[] = {
-        21, 21,  1,   1,   1,   1,   21,  22,  21,  22, 21,  22,  21,  21,  1,   22,  21,
-        1,  22,  22,  22,  1,   21,  2,   3,   3,   3,  3,   3,   4,   21,  1,   22,  21,
-        22, 22,  21,  21,  21,  1,   22,  22,  22,  23, 108, 109, 109, 109, 24,  87,  4,
-        21, 21,  22,  5,   6,   6,   7,   1,   1,   22, 21,  21,  23,  66,  67,  108, 109,
-        24, 109, 25,  21,  22,  5,   132, 43,  43,  28, 1,   1,   21,  22,  1,   23,  25,
-        23, 109, 109, 108, 108, 25,  1,   1,   26,  42, 110, 48,  49,  22,  21,  1,   21,
-        21, 23,  87,  88,  109, 24,  109, 109, 25,  1,  1,   26,  43,  131, 6,   7,   21,
-        1,  22,  1,   21,  44,  67,  109, 24,  24,  24, 66,  46,  1,   22,  26,  27,  43,
-        42, 131, 7,   21,  22,  1,   22,  21,  44,  45, 45,  45,  45,  46,  1,   22,  1,
-        26, 27,  27,  43,  27,  28,  22,  21,  22,  21, 1,   21,  1,   22,  22,  21,  1,
-        21, 22,  1,   47,  48,  111, 42,  27,  28,  21, 21,  1,   21,  21,  22,  2,   3,
-        3,  4,   1,   2,   3,   4,   1,   5,   132, 27, 27,  28,  1,   1,   22,  1,   22,
-        21, 23,  24,  66,  46,  1,   23,  24,  25,  1,  26,  42,  42,  110, 49,  21,  22,
-        21, 22,  22,  2,   88,  24,  25,  2,   3,   88, 24,  87,  4,   26,  43,  110, 49,
-        21, 21,  1,   1,   1,   2,   88,  24,  24,  87, 88,  108, 24,  24,  109, 25,  47,
-        48, 49,  1,   22,  22,  21,  1,   21,  23,  24, 24,  24,  24,  24,  24,  24,  24,
-        24, 87,  4,   21,  21,  22,  22,  22,  22,  1,  21,  23,  24,  24,  109, 24,  24,
-        24, 24,  24,  108, 109, 25,  21,  21,  22,  22, 22,  22,  21,  21,  44,  45,  45,
-        67, 24,  24,  24,  66,  45,  45,  45,  46,  1,  22,  1,   22,  22,  22,  21,  22,
-        22, 22,  1,   44,  67,  108, 108, 25,  22,  22, 1,   22,  21,  22,  21,  21,  1,
-        21, 22,  1,   22,  22,  1,   22,  44,  45,  45, 46,  1,   1,   1,   1,   21,  21,
-        21, 21,  21,  21,  22,  21,  21,  21,  1,   21, 1,   22,  22,  22,  1,   21,  22,
-        21, 1,   1,   22,  21,  1,   1,   21,  1,   1,  21,  21,  21,  1,   22,  22,  1,
-        21, 22,  21,  22,  1,   22,  21,  21,  21,
-    };
-    uint16_t dungeonTest2[] = {
-        0, 0, 0, 0, 0,   0,   0,   0,   0,   0,  0,  0,  0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 0,   0,   0,   0,   0,   0,  0,  0,  0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 0,   52,  53,  54,  55,  0,  0,  0,  0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 0,   73,  74,  75,  76,  0,  0,  0,  0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 0,   157, 158, 140, 160, 0,  0,  0,  0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 0,   178, 179, 161, 181, 0,  12, 14, 12, 14, 162, 163, 164, 0,   0, 0,
-        0, 0, 0, 0, 0,   0,   0,   0,   0,   0,  0,  0,  0,  0,  183, 184, 185, 0,   0, 0,
-        0, 0, 0, 0, 0,   0,   0,   0,   0,   0,  0,  0,  0,  0,  166, 0,   0,   186, 0, 0,
-        0, 0, 0, 0, 0,   0,   0,   0,   0,   0,  0,  0,  0,  0,  0,   0,   145, 167, 0, 0,
-        0, 0, 0, 0, 0,   0,   0,   0,   0,   0,  0,  0,  0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 0,   0,   0,   0,   0,   0,  0,  0,  0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 133, 134, 134, 135, 0,   0,  0,  0,  0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 154, 155, 155, 71,  135, 39, 40, 41, 0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 154, 155, 155, 155, 156, 60, 61, 62, 0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 175, 176, 51,  155, 156, 81, 82, 83, 0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 0,   0,   175, 176, 177, 0,  0,  0,  0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 0,   0,   0,   0,   0,   0,  0,  0,  0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 0,   0,   0,   0,   0,   0,  0,  0,  0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 0,   0,   0,   0,   0,   0,  0,  0,  0,  0,  0,   0,   0,   0,   0, 0,
-        0, 0, 0, 0, 0,   0,   0,   0,   0,   0,  0,  0,  0,  0,  0,   0,   0,   0,   0, 0,
-    };
+    Archive arc("data/out.wrf");
+    Texture tex(arc.get("ov.png"));
+    WalrusRPG::PIAF::File f1 = arc.get("l1.bin");
+    WalrusRPG::PIAF::File f2 = arc.get("l2.bin");
 
-    Map map(20, 20, dungeonTest, dungeonTest2);
+    const uint8_t *l1 = f1.get();
+    const uint8_t *l2 = f2.get();
+
+    // TODO better map reading.
+    uint16_t *dungeonTest = new uint16_t[f1.file_size / 2 + 1];
+    uint16_t *dungeonTest2 = new uint16_t[f1.file_size / 2 + 1];
+
+    for (unsigned i = 0; i < f1.file_size / 2; i++)
+    {
+        dungeonTest[i] = read_big_endian_value<uint16_t>(&l1[i * 2]);
+        dungeonTest2[i] = read_big_endian_value<uint16_t>(&l2[i * 2]);
+    }
+
+    Map map(20, 20, dungeonTest, dungeonTest2, tex);
     tinystl::vector<Frame> stripe21;
     tinystl::vector<Frame> stripe22;
     stripe21.push_back({21, 23});
@@ -82,5 +54,9 @@ int main(int argc, char *argv[])
     Quirks::deinit();
     Timing::deinit();
     Graphics::deinit();
+
+    delete[] dungeonTest;
+    delete[] dungeonTest2;
+
     return 0;
 }

+ 5 - 3
src/map/Map.cpp

@@ -8,12 +8,14 @@
 #define MAP WalrusRPG::Map
 using namespace WalrusRPG;
 using namespace WalrusRPG::Utils;
+using WalrusRPG::Graphics::Texture;
 
-Graphics::Texture tex_overworld((char *) overworld);
+// Graphics::Texture tex_overworld((char *) overworld);
 
-MAP::Map(int width, int height, uint16_t *layer0, uint16_t *layer1) : anim()
+MAP::Map(int width, int height, uint16_t *layer0, uint16_t *layer1, Texture &tex)
+    : anim(), tex(tex)
 {
-    this->renderer = new TileRenderer(tex_overworld, 16, 16);
+    this->renderer = new TileRenderer(tex, 16, 16);
     this->width = width;
     this->height = height;
     this->layer0 = layer0;

+ 4 - 1
src/map/Map.h

@@ -2,6 +2,7 @@
 #define INCLUDE_MAP_H
 
 #include <stdint.h>
+#include "Texture.h"
 #include "render/Camera.h"
 #include "render/TileRenderer.h"
 #include "render/Animator.h"
@@ -20,10 +21,12 @@ namespace WalrusRPG
         int height;
         uint16_t *layer0;
         uint16_t *layer1;
+        WalrusRPG::Graphics::Texture tex;
         TileRenderer *renderer;
         // TODO?: add a boolean/getter to know if a second layer exist?
       public:
-        Map(int width, int height, uint16_t *layer0, uint16_t *layer1);
+        Map(int width, int height, uint16_t *layer0, uint16_t *layer1,
+            WalrusRPG::Graphics::Texture &tex);
         ~Map();
         void render(Camera &camera, unsigned dt);
         void update(unsigned dt);

+ 279 - 0
src/piaf/Archive.cpp

@@ -0,0 +1,279 @@
+#include <cstring>
+#include <cstdio>
+#include <memory>
+#include <zlib.h>
+#if NSPIRE
+#include "../../platform/nspire/Interrupts.h"
+#endif
+#include "Archive.h"
+#include "Quirks.h"
+#include "utility/misc.h"
+
+using tinystl::string;
+using WalrusRPG::PIAF::ARCHIVE_VERSION;
+using WalrusRPG::PIAF::Archive;
+using WalrusRPG::PIAF::File;
+using WalrusRPG::PIAF::FileType;
+using WalrusRPG::PIAF::CompressionType;
+using namespace WalrusRPG::PIAF;
+
+#if NSPIRE
+using namespace Nspire;
+#endif
+namespace
+{
+    // Must get a pointer on the file table.
+    /**
+     * Reads the file table from given data pointer to an empty FileEntry
+     * array long enough and a given number of files to load.
+     * The pointer must directly access the file entry region of the archive.
+     */
+    void load_file_table(File *entries, uint32_t *data_offsets, char *data,
+                         uint32_t nb_files)
+    {
+        for (unsigned index = 0; index < nb_files; index++)
+        {
+            // Offsetting the data pointer to the current file entry.
+            char *current_entry_data = &data[index * 24];
+
+            // Copying the filename to the FileEntry
+            memcpy(entries[index].filename, current_entry_data, 8);
+            // Making sure there is a terminating \0 character in the filename.
+            entries[index].filename[8] = '\0';
+            // /!\ Parsing a value to an enumeration.
+            // Parses the file type and store it.
+            entries[index].file_type =
+                (FileType) read_big_endian_value<uint32_t>(&current_entry_data[8]);
+            // /!\ Parsing a value to an enumeration.
+            // Parses the compression type and store it.
+            entries[index].compression_type =
+                (CompressionType) read_big_endian_value<uint32_t>(
+                    &current_entry_data[12]);
+            // Parsign the file size and storing it.
+            entries[index].file_size =
+                read_big_endian_value<uint32_t>(&current_entry_data[16]);
+            // Reading the file's data position in the archive data section.
+            data_offsets[index] =
+                read_big_endian_value<uint32_t>(&current_entry_data[20]);
+        }
+    }
+}
+
+Archive::Archive(string &filepath) : Archive(filepath.c_str())
+{
+}
+
+
+Archive::Archive(const char *filepath)
+    : file(nullptr), entries(nullptr), files_data(nullptr), files_loaded(nullptr)
+{
+#if NSPIRE
+    Interrupts::off();
+#endif
+    // Null pointer exception trigger
+    if (filepath == nullptr)
+    {
+        throw PIAF::PIAFException("%s: Null path given", __FILE__);
+    }
+    // Solves the absolute path for given relative path.
+    // Must be needed in targets like Ndless as it doesn't support environment
+    // vars and thus PATH.
+    std::unique_ptr<char> real_filename(Quirks::solve_absolute_path(filepath));
+
+    // Open the archive
+    file = fopen(real_filename.get(), "rb");
+    // Again another null pointer trigger
+    if (file == nullptr || file == NULL)
+    {
+        throw PIAF::PIAFException("%s: Missing file : %s", __FILE__, filepath);
+    }
+
+    // Loading stuff happens NOW
+    // Checking if the file is long enough to have a header
+    fseek(file, 0L, SEEK_END);
+    uint64_t filesize = ftell(file);
+    fseek(file, 0L, SEEK_SET);
+    // File to small exception trigger
+    if (filesize < 32)
+    {
+        throw PIAF::PIAFException("%s: File too small (%s): %d", __FILE__, filepath, filesize);
+    }
+
+    // Tempoary buffer to contain the header.
+    char header_container[32] = {0};
+    // Read the headers and trigger exceptions on errors
+    if (fread(header_container, sizeof(char), 32, file) != 32)
+    {
+        throw PIAF::PIAFException("%s: Errorneous header : %s", __FILE__, filepath);
+    }
+    // Check if the magic cookie is the same.
+    // It's a first way to detect if the file is correctly an archive.
+    if (strncmp(header_container, "WRPGPIAF", 8) != 0)
+    {
+        // TODO throw bad header
+        // fprintf(stderr, "Bad header magic word\n");
+        throw PIAF::PIAFException("%s: Magic cookie mismatch : %s", __FILE__, filepath);
+    }
+    // Checksum time! Let's check if the header hasn"t been altered.
+    uint32_t expected_checksum = read_big_endian_value<uint32_t>(&header_container[8]);
+    uint32_t calculated_checksum = crc32(0L, (unsigned char *) &header_container[16], 16);
+    if (expected_checksum != calculated_checksum)
+    {
+        // TODO throw bad checksum
+        // fprintf(stderr, "Bad header checksum : %x != %x\n", expected_checksum,
+        // calculated_checksum);
+        throw PIAF::PIAFException("%s: Bad checksum : %s", __FILE__, filepath);
+    }
+
+    // TODO : version checking
+    version = read_big_endian_value<uint32_t>(&header_container[16]);
+    if (version != ARCHIVE_VERSION)
+    {
+        // std::exception up;
+        // throw up; // haha
+        throw PIAF::PIAFException("%s: Wrong(%s) : %08x is not supported by %08x", __FILE__, filepath, version, ARCHIVE_VERSION);
+    }
+
+
+    // At this point, the archive header looks unaltered and we finally can parse
+    // and load the header.
+
+    // Read the archive's number of files
+    nb_files = read_big_endian_value<uint32_t>(&header_container[20]);
+    // printf("nb_files : %u\n", nb_files);
+
+    data_size = read_big_endian_value<uint32_t>(&header_container[24]);
+    uint64_t calculated_data_size = filesize - 32 - 24 * nb_files;
+    if (data_size != calculated_data_size)
+    {
+        // T0D0 : throw wrong size exception
+        // fprintf(stderr, "Bad data size : expected %u, got %lld\n", data_size,
+        // calculated_data_size);
+        throw PIAF::PIAFException("Data size mismatch", __LINE__, filepath);
+    }
+    // Check if there are files to manage.
+    if (nb_files != 0)
+    {
+        // So, the file table is not empty. let's check if it's
+        // not altered.
+        uint32_t expected_filetable_checksum =
+            read_big_endian_value<uint32_t>(&header_container[12]);
+        char *file_entry_data = new char[24 * nb_files];
+        fseek(file, 32, SEEK_SET);
+        fread(file_entry_data, sizeof(char), 24 * nb_files, file);
+        // Compare and trigger an exception if the checksum doesn't match.
+        if (expected_filetable_checksum !=
+            crc32(0L, (unsigned char *) file_entry_data, 24 * nb_files))
+        {
+            // TODO : checksum exception
+            // fprintf(stderr, "Bad filetable checksum\n");
+            throw PIAF::PIAFException("Bad Filetable checksum", __LINE__, filepath);
+        }
+        // Create the filetable.
+        entries = new File[nb_files];
+        // Parse and story the filetable.
+
+        files_data = new uint8_t *[nb_files];
+        files_loaded = new bool[nb_files];
+        files_data_offset = new uint32_t[nb_files];
+        for (unsigned i = 0; i < nb_files; i++)
+        {
+            files_data[i] = nullptr;
+            files_loaded[i] = false;
+            files_data_offset[i] = 0;
+        }
+
+        load_file_table(entries, files_data_offset, file_entry_data, nb_files);
+        delete[] file_entry_data;
+    }
+#if NSPIRE
+    Interrupts::init();
+#endif
+
+}
+
+Archive::~Archive()
+{
+    if (file != nullptr)
+        fclose(file);
+    if (entries != nullptr)
+        delete[] entries;
+
+    if (files_data != nullptr)
+    {
+        for (unsigned i = 0; i < nb_files; i++)
+        {
+            if (files_data[i] != nullptr)
+            {
+                delete[] files_data[i];
+            }
+        }
+    }
+    delete[] files_data;
+    delete[] files_loaded;
+    delete[] files_data_offset;
+}
+
+bool Archive::has(const char *filename)
+{
+    for (unsigned index = 0; index < nb_files; index++)
+        if (strncmp(filename, entries[index].filename, 8) == 0)
+            return true;
+    return false;
+}
+
+/**
+ * Returns the stored file's data from giving a filename.
+ */
+File Archive::get(const char *filename)
+{
+    for (unsigned index = 0; index < nb_files; index++)
+    {
+        if (strncmp(filename, entries[index].filename, 8) == 0)
+        {
+            // On demand load
+            if (!files_loaded[index])
+            {
+#if NSPIRE
+                Interrupts::off();
+#endif
+                uint8_t *data = new uint8_t[entries[index].file_size];
+                fseek(file, files_data_offset[index] + 32 + 24 * nb_files, SEEK_SET);
+                if (fread(data, sizeof(uint8_t), entries[index].file_size, file) !=
+                    entries[index].file_size)
+                {
+                    throw PIAF::PIAFException("%s: couldn't load %s from an archive.", filename);
+                }
+                else
+                {
+                    files_data[index] = data;
+                    entries[index].data = data;
+                }
+                files_loaded[index] = true;
+#if NSPIRE
+                Interrupts::init();
+#endif
+            }
+            return entries[index];
+        }
+    }
+    return File();
+}
+
+File::File(uint8_t *data) : data(data)
+{
+}
+
+File::File() : data(nullptr)
+{
+}
+
+
+File::~File()
+{
+}
+
+const uint8_t *File::get()
+{
+    return data;
+}

+ 88 - 0
src/piaf/Archive.h

@@ -0,0 +1,88 @@
+#ifndef INCLUDE_ARCHIVE_H
+#define INCLUDE_ARCHIVE_H
+
+#include <exception>
+#include <cstdint>
+#include <cstdio>
+#include <cstdarg>
+#include <TINYSTL/string.h>
+
+namespace WalrusRPG
+{
+    namespace PIAF
+    {
+        constexpr uint32_t ARCHIVE_VERSION = 0x01000000;
+        enum FileType : uint32_t
+        {
+            UNKNOWN,
+            MAP,
+            EVENT_LIST,
+            TEXT,
+            TEXTURE
+        };
+        enum CompressionType : uint32_t
+        {
+            UNKNWOWN,
+            RAW,
+            ZLIB,
+            RLE
+        };
+
+        class File
+        {
+          protected:
+            const uint8_t *data;
+
+          public:
+            friend class Archive;
+            char filename[9]; // 8 + a \0 in case of printing
+            FileType file_type;
+            CompressionType compression_type;
+            uint32_t file_size;
+            std::size_t size;
+
+            File(uint8_t *data);
+            File();
+            ~File();
+            const uint8_t *get();
+        };
+
+        class Archive
+        {
+          private:
+            FILE *file;
+            uint32_t version;
+            uint32_t nb_files;
+            uint32_t data_size;
+            File *entries;
+            uint8_t **files_data;
+            bool *files_loaded;
+            uint32_t *files_data_offset;
+
+
+          public:
+            // RAII stuff
+            // Archive(std::unique_ptr<char> *filepath);
+            Archive(const char *filepath);
+            Archive(tinystl::string &filepath);
+            ~Archive();
+            bool has(const char *filename);
+            File get(const char *filename);
+        };
+
+        class PIAFException : public std::exception
+        {
+            private:
+                char msg[1024];
+
+            public:
+            PIAFException(const char *format, ...);
+            virtual ~PIAFException();
+
+            const char* what() const throw();
+        };
+
+    }
+}
+
+#endif

+ 25 - 0
src/piaf/Exceptions.cpp

@@ -0,0 +1,25 @@
+#include "Archive.h"
+#include <cmath>
+#include <cstring>
+#include <cstdarg>
+
+using WalrusRPG::PIAF::PIAFException;
+using namespace WalrusRPG::PIAF;
+
+PIAFException::PIAFException(const char *format, ...)
+	: msg("")
+{
+	va_list list;
+	va_start(list, format);
+	vsnprintf(msg, 1024, format, list);
+	va_end(list);
+}
+
+PIAFException::~PIAFException()
+{
+}
+
+const char* PIAFException::what() const throw()
+{
+	return msg;
+}

+ 1 - 1
src/render/SpriteRenderer.cpp

@@ -23,7 +23,7 @@ void SPRITERENDERER::render(const unsigned id, const Rect &rect)
     Graphics::put_sprite(tilesheet, rect.x, rect.y, sprites[id]);
 }
 
-void SPRITERENDERER::render(const unsigned id, const Rect &rect, const Pixel& tint)
+void SPRITERENDERER::render(const unsigned id, const Rect &rect, const Pixel &tint)
 {
     Graphics::put_sprite_tint(tilesheet, rect.x, rect.y, sprites[id], tint);
 }

+ 2 - 1
src/render/SpriteRenderer.h

@@ -18,7 +18,8 @@ namespace WalrusRPG
         SpriteRenderer(WalrusRPG::Graphics::Texture tilesheet);
         void add_sprite(unsigned id, WalrusRPG::Utils::Rect rect);
         virtual void render(const unsigned id, const WalrusRPG::Utils::Rect &rect);
-        void render(const unsigned id, const WalrusRPG::Utils::Rect &rect, const WalrusRPG::Graphics::Pixel& tint);
+        void render(const unsigned id, const WalrusRPG::Utils::Rect &rect,
+                    const WalrusRPG::Graphics::Pixel &tint);
     };
 }
 

+ 1 - 1
src/render/TileRenderer.cpp

@@ -5,7 +5,7 @@
 using namespace WalrusRPG;
 using namespace WalrusRPG::Utils;
 
-TILERENDERER::TileRenderer(WalrusRPG::Graphics::Texture _tilesheet, unsigned tile_width,
+TILERENDERER::TileRenderer(WalrusRPG::Graphics::Texture &_tilesheet, unsigned tile_width,
                            unsigned tile_height)
     : tilesheet(_tilesheet), tile_width(tile_width), tile_height(tile_height)
 {

+ 1 - 1
src/render/TileRenderer.h

@@ -15,7 +15,7 @@ namespace WalrusRPG
         unsigned tile_height;
 
       public:
-        TileRenderer(WalrusRPG::Graphics::Texture tilesheet, unsigned tile_width,
+        TileRenderer(WalrusRPG::Graphics::Texture &tilesheet, unsigned tile_width,
                      unsigned tile_height);
         void render(const unsigned id, const WalrusRPG::Utils::Rect &rect);
 

+ 2 - 0
src/utility/misc.cpp

@@ -0,0 +1,2 @@
+#include "misc.h"
+#include <cstdint>

+ 19 - 0
src/utility/misc.h

@@ -1,10 +1,29 @@
 #ifndef INCLUDE_MISC_H
 #define INCLUDE_MISC_H
 
+#include <cstdint>
+
 #define UNUSED(expr) (void)(expr)
 
 #define abs(x) ((x) < 0 ? -(x) : (x))
 
 #define in_range(x, a, b) (((x) >= (a)) && ((x) < (b)))
 
+/**
+ * Read big endian integer value in binary data array. Depends on the size
+ * of the given type, so using standardized types like stdint's is highly
+ * suggested.
+ *
+ * Also doesn't check for being in bounds of the array.
+ */
+template <typename T> T read_big_endian_value(const void *ptr)
+{
+    T result = 0;
+    uint8_t *data = (uint8_t *) ptr;
+    // No, memcpy isn't working here because endianness issues.
+    for (unsigned i = 0; i < sizeof(T); i++)
+        // Writing each byte of value in order
+        result |= data[i] << (8 * (sizeof(T) - 1 - i));
+    return result;
+}
 #endif