From 3d4b3d53c3e3c8a47d7691a602539a50f61db65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20=E2=80=98Touky=E2=80=99=20Huet?= Date: Thu, 22 May 2014 04:07:29 +0000 Subject: [PATCH] Added bunch of stuff on threads and images. --- src/image/codec/zed-image.cpp | 295 ++++++++++++++++++++++++++ src/image/codec/zed-palette-image.cpp | 99 +++++++++ src/image/image-private.h | 1 + src/image/image.cpp | 61 +++++- src/input/input.cpp | 2 + src/lol/image/image.h | 3 + src/lol/sys/file.h | 8 +- src/lol/sys/thread.h | 120 +++++++++++ src/lolcore.vcxproj | 2 + src/platform/sdl/sdlinput.cpp | 7 +- src/sys/file.cpp | 108 ++++++++-- src/tiler.cpp | 36 ++++ src/tiler.h | 4 + src/tileset.cpp | 70 +++++- src/tileset.h | 4 + 15 files changed, 789 insertions(+), 31 deletions(-) create mode 100644 src/image/codec/zed-image.cpp create mode 100644 src/image/codec/zed-palette-image.cpp diff --git a/src/image/codec/zed-image.cpp b/src/image/codec/zed-image.cpp new file mode 100644 index 00000000..fed03145 --- /dev/null +++ b/src/image/codec/zed-image.cpp @@ -0,0 +1,295 @@ +// +// Lol Engine +// +// Copyright: (c) 2014 Benjamin Huet +// 2014 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" +#include "../../image/image-private.h" + +using namespace std; + +namespace lol +{ + +/* + * Image implementation class + */ + +DECLARE_IMAGE_LOADER(ZedImageData, 0) +{ +public: + virtual bool Open(char const *); + virtual bool Close(); + + virtual uint8_t *GetData() const; + virtual bool RetrieveTiles(Array& tiles) + { + tiles += m_tiles; + m_tiles.Empty(); + return true; + } + +private: + uint8_t *m_pixels; + // + Array m_tiles; +}; + +/* + * Public Image class + */ + +bool ZedImageData::Open(char const *path) +{ + if (!lol::String(path).EndsWith(".RSC")) + return false; + + File file; + file.Open(path, FileAccess::Read, true); + + //Put file in memory + long file_size = file.GetSize(); + Array file_buffer; + file_buffer.Resize(file_size); + file.Read((uint8_t*)&file_buffer[0], file_size); + file.Close(); + + //Get FileCount + uint32_t file_pos = 0; + uint16_t file_count = 0; + file_count = *((uint16_t*)(&file_buffer[file_pos])); + file_pos += sizeof(uint16_t); + + Array file_offset; + file_offset.Resize(file_count); + //Get all the file offsets + for (int i = 0; i < file_count; i++) + { + file_offset[i] = *((long int*)(&file_buffer[file_pos])); + file_pos += sizeof(long int); + } + file_offset << file_size; + + m_tiles.Reserve(file_count); + struct CompactSecondary + { + CompactSecondary(int32_t size) { m_size = size; } + int32_t m_size; + Array m_tiles; + }; + struct CompactMain + { + CompactMain(int32_t size) { m_size = size; m_count = 0; } + int32_t m_size; + int32_t m_count; + Array m_secondary; + }; + struct Compacter2d + { + void PowSetup(int32_t start, int32_t count) + { + for (int i = 0; i < count; i++) + { + m_primary << CompactMain(start << i); + for (int j = 0; j < count; j++) + m_primary.Last().m_secondary << CompactSecondary(start << j); + } + } + void StepSetup(int32_t start, int32_t interval, int32_t count) + { + for (int i = 0; i < count; i++) + { + m_primary << CompactMain(start + interval * i); + for (int j = 0; j < count; j++) + m_primary.Last().m_secondary << CompactSecondary(start + interval * j); + } + } + void CustomSetup(Array custom_list) + { + for (int i = 0; i < custom_list.Count(); i++) + { + m_primary << CompactMain(custom_list[i]); + for (int j = 0; j < custom_list.Count(); j++) + m_primary.Last().m_secondary << CompactSecondary(custom_list[j]); + } + } + void Store(int32_t tile, ivec2 size) + { + for (int i = 0; i < m_primary.Count(); i++) + { + if (size.y <= m_primary[i].m_size || i == m_primary.Count() - 1) + { + for (int j = 0; j < m_primary[i].m_secondary.Count(); j++) + { + if (size.x <= m_primary[i].m_secondary[j].m_size || j == m_primary[i].m_secondary.Count() - 1) + { + m_primary[i].m_secondary[j].m_tiles << tile; + m_primary[i].m_count++; + break; + } + } + break; + } + } + } + Array m_primary; + }; + + Compacter2d compacter; + compacter.StepSetup(8, 8, 10); + + uint32_t total_size = 0; + Array file_convert; + file_convert.Reserve(file_size); + Array available_sizes; + for (int i = 0; i < file_count; i++) + { + file_pos = file_offset[i]; + + //Get image size + uint8_t size_x = 0; + uint8_t size_y = 0; + size_y = file_buffer[file_pos++]; + size_x = file_buffer[file_pos++]; + + //special tweak + size_x *= 8; + total_size += (size_x * size_y); + + //Prepare read + uint32_t header_length = (size_y + 5) & 0xFC; + uint32_t data_length = (file_offset[i+1] - file_offset[i]) - header_length; + uint32_t data_pos = file_offset[i] + header_length; + + //Prepare buffer and tiles infos + int32_t convert_pos = file_convert.Count(); + ivec2 size = ivec2(size_x, size_y); + compacter.Store(m_tiles.Count(), ivec2(size_x, size_y)); + m_tiles.Push(ivec2(file_convert.Count(), data_length), ivec2(size_x, size_y)); + file_convert.Resize(convert_pos + data_length); + + ivec2 size_16 = size; + int32_t s_16 = 8; + while (1) + { + if (size_16.x <= s_16) + { + size_16.x = s_16; + break; + } + s_16 <<= 1; + } + s_16 = 8; + while (1) + { + if (size_16.y <= s_16) + { + size_16.y = s_16; + break; + } + s_16 <<= 1; + } + int j = 0; + for (; j < available_sizes.Count(); j++) + if (available_sizes[j] == size_16) + break; + if (j >= available_sizes.Count()) + available_sizes << size_16; + + //Retrieve actual datas + file_pos = data_pos; + memcpy(&file_convert[convert_pos], &file_buffer[file_pos], data_length); + file_pos += data_length; + } + + int32_t tex_sqrt = (int32_t)lol::sqrt((float)total_size); + int32_t tex_size = 2; + while (tex_size < tex_sqrt) + tex_size <<= 1; + + //Prepare final imqge + m_size = ivec2(tex_size); + m_format = PixelFormat::Y_8; + m_pixels = new uint8_t[tex_size * tex_size * 1 * sizeof(*m_pixels)]; + uint8_t *image = m_pixels; + + //Data refactor stage + ivec2 pos = ivec2(0); + for (int j = compacter.m_primary.Count() - 1; j >= 0; j--) + { + for (int k = compacter.m_primary[j].m_secondary.Count() - 1; k >= 0; k--) + { + //Try something smaller + if (pos.x + compacter.m_primary[j].m_secondary[k].m_size >= tex_size) + continue; + + while (compacter.m_primary[j].m_secondary[k].m_tiles.Count() > 0) + { + //Try something smaller + if (pos.x + compacter.m_primary[j].m_secondary[k].m_size >= tex_size) + break; + + compacter.m_primary[j].m_count--; + int i = compacter.m_primary[j].m_secondary[k].m_tiles.Pop(); + int32_t file_off = m_tiles[i].m1[0]; + ivec2 t_size = m_tiles[i].m2; + + ASSERT(pos.y + t_size.y < tex_size); + + //Move image to texture + int32_t img_off = pos.x + pos.y * tex_size; + + //At this stage image data consists of 4 vertical interlaced blocks + for (int pass = 0; pass < 4; pass++) + { + for (int y_cur = 0; y_cur < t_size.y; y_cur++) + { + for (int x_cur = 0; x_cur < t_size.x / 4; x_cur++) + { + int32_t img_pos = img_off + pass + 4 * x_cur + y_cur * (int32_t)tex_size; + image[img_pos] = file_convert[file_off++]; + } + } + } + + //Register new pos and move to next + m_tiles[i].m1 = pos; + pos.x += t_size.x; + } + } + + //Do another loop + if (compacter.m_primary[j].m_count > 0) + { + pos.x = 0; + pos.y += compacter.m_primary[j].m_size; + j++; + } + } + return true; +} + +bool ZedImageData::Close() +{ + delete[] m_pixels; + + return true; +} + +uint8_t * ZedImageData::GetData() const +{ + return m_pixels; +} + +} /* namespace lol */ + diff --git a/src/image/codec/zed-palette-image.cpp b/src/image/codec/zed-palette-image.cpp new file mode 100644 index 00000000..775640d2 --- /dev/null +++ b/src/image/codec/zed-palette-image.cpp @@ -0,0 +1,99 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2011 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" +#include "../../image/image-private.h" + +using namespace std; + +namespace lol +{ + +/* + * Image implementation class + */ + +DECLARE_IMAGE_LOADER(ZedPaletteImageData, 0) +{ +public: + virtual bool Open(char const *); + virtual bool Close(); + + virtual uint8_t *GetData() const; + +private: + uint8_t *m_pixels; +}; + +/* + * Public Image class + */ + +bool ZedPaletteImageData::Open(char const *path) +{ + if (!lol::String(path).EndsWith(".pal")) + return false; + + File file; + file.Open(path, FileAccess::Read, true); + + //Put file in memory + long file_size = file.GetSize(); + Array file_buffer; + file_buffer.Resize(file_size); + file.Read((uint8_t*)&file_buffer[0], file_size); + file.Close(); + +#if 0 //2D PALETTE + int32_t tex_sqrt = (int32_t)lol::sqrt((float)file_size / 3); + int32_t tex_size = 2; + while (tex_size < tex_sqrt) + tex_size <<= 1; + m_size = ivec2(tex_size); +#else + int32_t tex_sqrt = file_size / 3; + int32_t tex_size = 2; + while (tex_size < tex_sqrt) + tex_size <<= 1; + m_size = ivec2(tex_size, 1); +#endif + + m_format = PixelFormat::RGBA_8; + m_pixels = new uint8_t[tex_size * tex_size * 4 * sizeof(*m_pixels)]; + uint8_t *parser = m_pixels; + for (int i = 0; i < file_buffer.Count();) + { + *parser++ = file_buffer[i++]; + *parser++ = file_buffer[i++]; + *parser++ = file_buffer[i++]; + *parser++ = (i == 0) ? 0 : 255; + } + + return true; +} + +bool ZedPaletteImageData::Close() +{ + delete[] m_pixels; + + return true; +} + +uint8_t * ZedPaletteImageData::GetData() const +{ + return m_pixels; +} + +} /* namespace lol */ + diff --git a/src/image/image-private.h b/src/image/image-private.h index 439649fb..9786087a 100644 --- a/src/image/image-private.h +++ b/src/image/image-private.h @@ -84,6 +84,7 @@ public: virtual bool Close() = 0; virtual uint8_t *GetData() const = 0; + virtual bool RetrieveTiles(Array& tiles) { return false; } protected: ivec2 m_size; diff --git a/src/image/image.cpp b/src/image/image.cpp index 9d3c655c..d254ba99 100644 --- a/src/image/image.cpp +++ b/src/image/image.cpp @@ -48,6 +48,8 @@ static bool RegisterAllLoaders() #if defined USE_SDL_IMAGE REGISTER_IMAGE_LOADER(SdlImageData) #endif + REGISTER_IMAGE_LOADER(ZedImageData) + REGISTER_IMAGE_LOADER(ZedPaletteImageData) return true; } @@ -59,7 +61,11 @@ static bool RegisterAllLoaders() static class ImageLoader { public: + void Init(); Image *Create(char const *path); + Image *Get(char const *path); + Image *Load(char const *path); + Image *Store(char const *path, Image *image); void Destroy(Image *img); private: @@ -67,11 +73,16 @@ private: } image_loader; -Image *ImageLoader::Create(char const *path) +void ImageLoader::Init() { /* Initialise loaders (see above) */ static bool init = RegisterAllLoaders(); UNUSED(init); +} + +Image *ImageLoader::Create(char const *path) +{ + Init(); /* Is our image already in the bank? If so, no need to create it. */ Image *img; @@ -82,15 +93,42 @@ Image *ImageLoader::Create(char const *path) } else { - img = new Image(); - img->m_data = ImageCodec::Load(path); - m_images[path] = img; + m_images[path] = Load(path); + img = m_images[path]; } ++img->m_data->m_refcount; return img; } +Image *ImageLoader::Get(char const *path) +{ + /* Is our image already in the bank? If so, no need to create it. */ + Image *img; + if (m_images.HasKey(path)) + { + img = m_images[path]; + ++img->m_data->m_refcount; + return img; + } + + return nullptr; +} + +Image *ImageLoader::Load(char const *path) +{ + Image* img = new Image(); + img->m_data = ImageCodec::Load(path); + return img; +} + +Image *ImageLoader::Store(char const *path, Image *image) +{ + m_images[path] = image; + ++image->m_data->m_refcount; + return image; +} + void ImageLoader::Destroy(Image *img) { ASSERT(img->m_data->m_refcount > 0); @@ -116,6 +154,16 @@ Image *Image::Create(char const *path) return image_loader.Create(path); } +Image *Image::Store(char const *path, Image *img) +{ + return image_loader.Store(path, img); +} + +Image *Image::Load(char const *path) +{ + return image_loader.Load(path); +} + void Image::Destroy(Image *img) { return image_loader.Destroy(img); @@ -145,6 +193,11 @@ uint8_t *Image::GetData() const return m_data->GetData(); } +bool Image::RetrieveTiles(Array& tiles) const +{ + return m_data->RetrieveTiles(tiles); +} + Image::~Image() { m_data->Close(); diff --git a/src/input/input.cpp b/src/input/input.cpp index 0affb6ec..09cd798b 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -72,6 +72,8 @@ InputDeviceInternal* InputDeviceInternal::CreateStandardMouse() mouse->AddAxis("X"); mouse->AddAxis("Y"); + mouse->AddAxis("XPixel"); + mouse->AddAxis("YPixel"); mouse->AddAxis("Scroll"); mouse->AddCursor("Cursor"); diff --git a/src/lol/image/image.h b/src/lol/image/image.h index cc2491ea..5d3a5e16 100644 --- a/src/lol/image/image.h +++ b/src/lol/image/image.h @@ -27,11 +27,14 @@ class Image public: static Image *Create(char const *path); + static Image *Store(char const *path, Image *img); + static Image *Load(char const *path); static void Destroy(Image *img); ivec2 GetSize() const; PixelFormat GetFormat() const; uint8_t *GetData() const; + bool RetrieveTiles(Array& tiles) const; private: Image(); diff --git a/src/lol/sys/file.h b/src/lol/sys/file.h index a6ec3e9b..13a1825d 100644 --- a/src/lol/sys/file.h +++ b/src/lol/sys/file.h @@ -41,7 +41,8 @@ struct StreamType StdIn = 0, StdOut, StdErr, - File + File, + FileBinary } m_value; @@ -59,7 +60,7 @@ public: ~File(); void Open(StreamType stream); - void Open(String const &file, FileAccess mode); + void Open(String const &file, FileAccess mode, bool force_binary=false); bool IsValid() const; void Close(); @@ -67,6 +68,9 @@ public: String ReadString(); int Write(uint8_t const *buf, int count); int WriteString(const String &buf); + long int GetPosFromStart(); + void SetPosFromStart(long int pos); + long int GetSize(); private: class FileData *m_data; diff --git a/src/lol/sys/thread.h b/src/lol/sys/thread.h index e4d33cd8..13e4e36a 100644 --- a/src/lol/sys/thread.h +++ b/src/lol/sys/thread.h @@ -44,6 +44,126 @@ public: Thread(void *(*fn)(void *), void *data) : ThreadBase(fn, data) {} virtual ~Thread() {} }; + +struct ThreadCommand +{ + enum Value + { + THREAD_STARTED, + THREAD_STOPPED, + WORK_TODO, + WORK_DONE, + THREAD_STOP, + + MAX + } + m_value; + + inline ThreadCommand() : m_value(ThreadCommand::MAX) {} + inline ThreadCommand(Value v) : m_value(v) {} + bool operator==(const ThreadCommand& v) { return m_value == v.m_value; } +}; + +template +struct JobCommand : public ThreadCommand +{ + T1 m_data; + + inline JobCommand() : ThreadCommand(ThreadCommand::WORK_TODO) {} + inline JobCommand(Value v) : ThreadCommand(v) {} + inline JobCommand(T1 data) : ThreadCommand(ThreadCommand::WORK_TODO) { m_data = data; } + inline JobCommand(Value v, T1 data) : m_value(v) { m_data = data; } + inline void SetData(T1 data) { m_data = data; } + inline T1 GetData() { return m_data; } +}; + +template class ThreadManager +{ +public: + ThreadManager(int thread_count) + { + m_thread_count = thread_count; + } + + //Initialize and start the thread + bool Start() + { + if (m_threads.Count() > 0) + return false; + + /* Spawn worker threads and wait for their readiness. */ + m_threads.Resize(m_thread_count); + for (int i = 0; i < m_thread_count; i++) + m_threads[i] = new Thread(BaseThreadWork, this); + for (int i = 0; i < m_thread_count; i++) + m_spawnqueue.Pop(); + + return true; + } + + bool AddWork(const JobCommand& job) + { + if (m_jobqueue.TryPush(job)) + return true; + return false; + } + bool FetchResult(Array >& results) + { + JobCommand result; + while (m_resultqueue.TryPop(result)) + results << result; + return results.Count() > 0; + } + + static void *BaseThreadWork(void* data) + { + ThreadManager *that = (ThreadManager *)data; + that->m_spawnqueue.Push(ThreadCommand::THREAD_STARTED); + for ( ; ; ) + { + JobCommand job = that->m_jobqueue.Pop(); + if (job == ThreadCommand::THREAD_STOP) + break; + else if (job == ThreadCommand::WORK_TODO) + { + JobCommand result(ThreadCommand::WORK_DONE); + if (that->DoThreadWork(job, result)) + that->m_resultqueue.Push(result); + } + } + that->m_donequeue.Push(ThreadCommand::THREAD_STOPPED); + return NULL; + } + + virtual bool DoThreadWork(JobCommand& job, JobCommand& result) + { + return false; + } + + //Stop the thread + bool Stop() + { + if (m_threads.Count() <= 0) + return false; + + /* Signal worker threads for completion and wait for + * them to quit. */ + for (int i = 0; i < m_thread_count; i++) + m_jobqueue.Push(ThreadCommand::THREAD_STOP); + for (int i = 0; i < m_thread_count; i++) + m_donequeue.Pop(); + + return true; + } + +protected: + /* Worker threads */ + int m_thread_count; + Array m_threads; + Queue m_spawnqueue, m_donequeue; + Queue > m_jobqueue; + Queue > m_resultqueue; +}; #endif } /* namespace lol */ diff --git a/src/lolcore.vcxproj b/src/lolcore.vcxproj index 5d06911e..dedf571f 100644 --- a/src/lolcore.vcxproj +++ b/src/lolcore.vcxproj @@ -144,6 +144,8 @@ + + diff --git a/src/platform/sdl/sdlinput.cpp b/src/platform/sdl/sdlinput.cpp index 2f0b9c6b..ef7ae5cb 100644 --- a/src/platform/sdl/sdlinput.cpp +++ b/src/platform/sdl/sdlinput.cpp @@ -179,7 +179,7 @@ void SdlInputData::Tick(float seconds) } # endif - m_mouse->SetAxis(2, 0); + m_mouse->SetAxis(4, 0); /* Handle keyboard and WM events */ SDL_Event event; @@ -202,7 +202,7 @@ void SdlInputData::Tick(float seconds) if (event.button.button != SDL_BUTTON_WHEELUP && event.button.button != SDL_BUTTON_WHEELDOWN) m_mouse->SetKey(event.button.button - 1, event.type == SDL_MOUSEBUTTONDOWN); else - m_mouse->SetAxis(2, (event.button.button != SDL_BUTTON_WHEELUP) ? (1) : (-1)); + m_mouse->SetAxis(4, (event.button.button != SDL_BUTTON_WHEELUP) ? (1) : (-1)); // TODO: mouse wheel as axis break; } @@ -242,6 +242,9 @@ void SdlInputData::Tick(float seconds) m_mouse->SetAxis(0, (mouse.x - vprevmouse.x) * MOUSE_SPEED_MOD / max_screen_size); // Y Axis is also negated to match the usual joystick Y axis (negatives values are for the upper direction) m_mouse->SetAxis(1,-(mouse.y - vprevmouse.y) * MOUSE_SPEED_MOD / max_screen_size); + //Pixel movement + m_mouse->SetAxis(2, (mouse.x - vprevmouse.x)); + m_mouse->SetAxis(3,-(mouse.y - vprevmouse.y)); } //Mouse is focused, Validate the InScreen Key diff --git a/src/sys/file.cpp b/src/sys/file.cpp index ac14e8d4..739f5a1b 100644 --- a/src/sys/file.cpp +++ b/src/sys/file.cpp @@ -27,6 +27,8 @@ # include #endif +#include + #include "core.h" namespace lol @@ -45,7 +47,8 @@ class FileData void Open(StreamType stream) { - if (m_type == StreamType::File) + if (m_type == StreamType::File || + m_type == StreamType::FileBinary) return; m_type = stream; switch((int)stream) @@ -62,9 +65,9 @@ class FileData } } - void Open(String const &file, FileAccess mode) + void Open(String const &file, FileAccess mode, bool force_binary) { - m_type = StreamType::File; + m_type = (force_binary) ? (StreamType::FileBinary) : (StreamType::File); #if __CELLOS_LV2__ String realfile = String(SYS_APP_HOME) + '/' + file; CellFsErrno err = cellFsOpen(realfile.C(), CELL_FS_O_RDONLY, @@ -76,7 +79,8 @@ class FileData m_asset = AAssetManager_open(g_assets, file.C(), AASSET_MODE_UNKNOWN); #elif HAVE_STDIO_H /* FIXME: no modes, no error checking, no nothing */ - m_fd = fopen(file.C(), "r"); + stat(file.C(), &m_stat); + m_fd = fopen(file.C(), (!force_binary) ? ("r") : ("rb")); #endif } @@ -93,6 +97,26 @@ class FileData #endif } + void Close() + { + if (m_type != StreamType::File && + m_type != StreamType::FileBinary) + return; +#if __CELLOS_LV2__ + if (m_fd >= 0) + cellFsClose(m_fd); + m_fd = -1; +#elif __ANDROID__ + if (m_asset) + AAsset_close(m_asset); + m_asset = nullptr; +#elif HAVE_STDIO_H + if (m_fd) + fclose(m_fd); + m_fd = nullptr; +#endif + } + int Read(uint8_t *buf, int count) { #if __CELLOS_LV2__ @@ -169,25 +193,46 @@ class FileData return Write((uint8_t const *)buf.C(), buf.Count()); } - void Close() + long int GetPosFromStart() { - if (m_type != StreamType::File) - return; #if __CELLOS_LV2__ - if (m_fd >= 0) - cellFsClose(m_fd); - m_fd = -1; + return 0; #elif __ANDROID__ - if (m_asset) - AAsset_close(m_asset); - m_asset = nullptr; + return 0; #elif HAVE_STDIO_H - if (m_fd) - fclose(m_fd); - m_fd = nullptr; + return ftell(m_fd); +#else + return 0; +#endif + } + + void SetPosFromStart(long int pos) + { +#if __CELLOS_LV2__ + //NOT IMPLEMENTED +#elif __ANDROID__ + //NOT IMPLEMENTED +#elif HAVE_STDIO_H + fseek(m_fd, pos, SEEK_SET); +#else + //NOT IMPLEMENTED #endif } + long int GetSize() + { +#if __CELLOS_LV2__ + return 0; +#elif __ANDROID__ + return 0; +#elif HAVE_STDIO_H + return m_stat.st_size; +#else + return 0; +#endif + } + + #if __CELLOS_LV2__ int m_fd; #elif __ANDROID__ @@ -195,8 +240,9 @@ class FileData #elif HAVE_STDIO_H FILE *m_fd; #endif - Atomic m_refcount; - StreamType m_type; + Atomic m_refcount; + StreamType m_type; + struct stat m_stat; }; //-- FILE -- @@ -251,9 +297,9 @@ void File::Open(StreamType stream) } //-- -void File::Open(String const &file, FileAccess mode) +void File::Open(String const &file, FileAccess mode, bool force_binary) { - return m_data->Open(file, mode); + return m_data->Open(file, mode, force_binary); } //-- @@ -262,6 +308,12 @@ bool File::IsValid() const return m_data->IsValid(); } +//-- +void File::Close() +{ + m_data->Close(); +} + //-- int File::Read(uint8_t *buf, int count) { @@ -287,9 +339,21 @@ int File::WriteString(const String &buf) } //-- -void File::Close() +long int File::GetPosFromStart() { - m_data->Close(); + return m_data->GetPosFromStart(); +} + +//-- +void File::SetPosFromStart(long int pos) +{ + m_data->SetPosFromStart(pos); +} + +//-- +long int File::GetSize() +{ + return m_data->GetSize(); } //--------------- diff --git a/src/tiler.cpp b/src/tiler.cpp index 14b22808..3edaa639 100644 --- a/src/tiler.cpp +++ b/src/tiler.cpp @@ -76,6 +76,42 @@ TileSet *Tiler::Register(char const *path) return tileset; } +TileSet *Tiler::Register(String const &path, Image* image, ivec2 size, ivec2 count) +{ + return Tiler::Register(path.C(), image, size, count); +} +TileSet *Tiler::Register(char const *path, Image* image, ivec2 size, ivec2 count) +{ + int id = data->tilesets.MakeSlot(path); + TileSet *tileset = (TileSet *)data->tilesets.GetEntity(id); + + if (!tileset) + { + tileset = new TileSet(path, image, size, count); + data->tilesets.SetEntity(id, tileset); + } + + return tileset; +} + +TileSet *Tiler::Register(String const &path, Image* image) +{ + return Tiler::Register(path.C(), image); +} +TileSet *Tiler::Register(char const *path, Image* image) +{ + int id = data->tilesets.MakeSlot(path); + TileSet *tileset = (TileSet *)data->tilesets.GetEntity(id); + + if (!tileset) + { + tileset = new TileSet(path, image); + data->tilesets.SetEntity(id, tileset); + } + + return tileset; +} + void Tiler::Deregister(TileSet *tileset) { data->tilesets.RemoveSlot(tileset); diff --git a/src/tiler.h b/src/tiler.h index 5381747c..b2ce8f84 100644 --- a/src/tiler.h +++ b/src/tiler.h @@ -31,6 +31,10 @@ public: static TileSet *Register(char const *path, ivec2 size, ivec2 count); static TileSet *Register(String const &path); static TileSet *Register(char const *path); + static TileSet *Register(String const &path, Image* image, ivec2 size, ivec2 count); + static TileSet *Register(char const *path, Image* image, ivec2 size, ivec2 count); + static TileSet *Register(String const &path, Image* image); + static TileSet *Register(char const *path, Image* image); static void Deregister(TileSet *); private: diff --git a/src/tileset.cpp b/src/tileset.cpp index 5c49f1e5..d9d7227d 100644 --- a/src/tileset.cpp +++ b/src/tileset.cpp @@ -60,6 +60,22 @@ TileSet::TileSet(char const *path) : m_data(new TileSetData()) { Init(path); + + Array tiles; + if (m_data->m_image->RetrieveTiles(tiles)) + for (int i = 0; i < tiles.Count(); i++) + AddTile(ibox2(tiles[0].m1, tiles[0].m1 + tiles[0].m2)); +} + +TileSet::TileSet(char const *path, Image* image) + : m_data(new TileSetData()) +{ + Init(path, image); + + Array tiles; + if (m_data->m_image->RetrieveTiles(tiles)) + for (int i = 0; i < tiles.Count(); i++) + AddTile(ibox2(tiles[0].m1, tiles[0].m1 + tiles[0].m2)); } TileSet::TileSet(char const *path, ivec2 size, ivec2 count) @@ -85,14 +101,54 @@ TileSet::TileSet(char const *path, ivec2 size, ivec2 count) AddTile(ibox2(size * ivec2(i, j), size * ivec2(i + 1, j + 1))); } + + Array tiles; + if (m_data->m_image->RetrieveTiles(tiles)) + for (int i = 0; i < tiles.Count(); i++) + AddTile(ibox2(tiles[i].m1, tiles[i].m1 + tiles[i].m2)); +} + +TileSet::TileSet(char const *path, Image* image, ivec2 size, ivec2 count) + : m_data(new TileSetData()) +{ + Init(path, image); + + /* If count is valid, fix size; otherwise, fix count. */ + if (count.x > 0 && count.y > 0) + { + size = m_data->m_image_size / count; + } + else + { + if (size.x <= 0 || size.y <= 0) + size = ivec2(32, 32); + count = max(ivec2(1, 1), m_data->m_image_size / size); + } + + for (int j = 0; j < count.y; ++j) + for (int i = 0; i < count.x; ++i) + { + AddTile(ibox2(size * ivec2(i, j), + size * ivec2(i + 1, j + 1))); + } + + Array tiles; + if (m_data->m_image->RetrieveTiles(tiles)) + for (int i = 0; i < tiles.Count(); i++) + AddTile(ibox2(tiles[i].m1, tiles[i].m1 + tiles[i].m2)); } void TileSet::Init(char const *path) +{ + Init(path, Image::Create(path)); +} + +void TileSet::Init(char const *path, Image* image) { m_data->m_name = String(" ") + path; m_data->m_texture = 0; - m_data->m_image = Image::Create(path); + m_data->m_image = image; m_data->m_image_size = m_data->m_image->GetSize(); m_data->m_texture_size = ivec2(PotUp(m_data->m_image_size.x), PotUp(m_data->m_image_size.y)); @@ -108,6 +164,18 @@ int TileSet::AddTile(ibox2 rect) return m_data->m_tiles.Count() - 1; } +void TileSet::AddTile(ivec2 count) +{ + ivec2 size = m_data->m_image_size / count; + + for (int j = 0; j < count.y; ++j) + for (int i = 0; i < count.x; ++i) + { + AddTile(ibox2(size * ivec2(i, j), + size * ivec2(i + 1, j + 1))); + } +} + TileSet::~TileSet() { delete m_data; diff --git a/src/tileset.h b/src/tileset.h index 97b59e1b..2f12ad1c 100644 --- a/src/tileset.h +++ b/src/tileset.h @@ -32,10 +32,12 @@ class TileSet : public Entity { public: TileSet(char const *path); + TileSet(char const *path, Image* image); virtual ~TileSet(); /* Old style: path to PNG file */ TileSet(char const *path, ivec2 size, ivec2 count); + TileSet(char const *path, Image* image, ivec2 size, ivec2 count); protected: /* Inherited from Entity */ @@ -45,6 +47,7 @@ protected: public: /* New methods */ int AddTile(ibox2 rect); + void AddTile(ivec2 count); int GetTileCount() const; ivec2 GetTileSize(int tileid) const; @@ -58,6 +61,7 @@ public: private: void Init(char const *path); + void Init(char const *path, Image* image); TileSetData *m_data; };