| @@ -0,0 +1,295 @@ | |||||
| // | |||||
| // Lol Engine | |||||
| // | |||||
| // Copyright: (c) 2014 Benjamin Huet <huet.benjamin@gmail.com> | |||||
| // 2014 Sam Hocevar <sam@hocevar.net> | |||||
| // 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<ivec2, ivec2>& tiles) | |||||
| { | |||||
| tiles += m_tiles; | |||||
| m_tiles.Empty(); | |||||
| return true; | |||||
| } | |||||
| private: | |||||
| uint8_t *m_pixels; | |||||
| //<Pos, Size> | |||||
| Array<ivec2, ivec2> 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<uint8_t> 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<long int> 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<int32_t> m_tiles; | |||||
| }; | |||||
| struct CompactMain | |||||
| { | |||||
| CompactMain(int32_t size) { m_size = size; m_count = 0; } | |||||
| int32_t m_size; | |||||
| int32_t m_count; | |||||
| Array<CompactSecondary> 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<int32_t> 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<CompactMain> m_primary; | |||||
| }; | |||||
| Compacter2d compacter; | |||||
| compacter.StepSetup(8, 8, 10); | |||||
| uint32_t total_size = 0; | |||||
| Array<uint8_t> file_convert; | |||||
| file_convert.Reserve(file_size); | |||||
| Array<ivec2> 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 */ | |||||
| @@ -0,0 +1,99 @@ | |||||
| // | |||||
| // Lol Engine | |||||
| // | |||||
| // Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net> | |||||
| // 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<uint8_t> 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 */ | |||||
| @@ -84,6 +84,7 @@ public: | |||||
| virtual bool Close() = 0; | virtual bool Close() = 0; | ||||
| virtual uint8_t *GetData() const = 0; | virtual uint8_t *GetData() const = 0; | ||||
| virtual bool RetrieveTiles(Array<ivec2, ivec2>& tiles) { return false; } | |||||
| protected: | protected: | ||||
| ivec2 m_size; | ivec2 m_size; | ||||
| @@ -48,6 +48,8 @@ static bool RegisterAllLoaders() | |||||
| #if defined USE_SDL_IMAGE | #if defined USE_SDL_IMAGE | ||||
| REGISTER_IMAGE_LOADER(SdlImageData) | REGISTER_IMAGE_LOADER(SdlImageData) | ||||
| #endif | #endif | ||||
| REGISTER_IMAGE_LOADER(ZedImageData) | |||||
| REGISTER_IMAGE_LOADER(ZedPaletteImageData) | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -59,7 +61,11 @@ static bool RegisterAllLoaders() | |||||
| static class ImageLoader | static class ImageLoader | ||||
| { | { | ||||
| public: | public: | ||||
| void Init(); | |||||
| Image *Create(char const *path); | 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); | void Destroy(Image *img); | ||||
| private: | private: | ||||
| @@ -67,11 +73,16 @@ private: | |||||
| } | } | ||||
| image_loader; | image_loader; | ||||
| Image *ImageLoader::Create(char const *path) | |||||
| void ImageLoader::Init() | |||||
| { | { | ||||
| /* Initialise loaders (see above) */ | /* Initialise loaders (see above) */ | ||||
| static bool init = RegisterAllLoaders(); | static bool init = RegisterAllLoaders(); | ||||
| UNUSED(init); | UNUSED(init); | ||||
| } | |||||
| Image *ImageLoader::Create(char const *path) | |||||
| { | |||||
| Init(); | |||||
| /* Is our image already in the bank? If so, no need to create it. */ | /* Is our image already in the bank? If so, no need to create it. */ | ||||
| Image *img; | Image *img; | ||||
| @@ -82,15 +93,42 @@ Image *ImageLoader::Create(char const *path) | |||||
| } | } | ||||
| else | 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; | ++img->m_data->m_refcount; | ||||
| return img; | 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) | void ImageLoader::Destroy(Image *img) | ||||
| { | { | ||||
| ASSERT(img->m_data->m_refcount > 0); | ASSERT(img->m_data->m_refcount > 0); | ||||
| @@ -116,6 +154,16 @@ Image *Image::Create(char const *path) | |||||
| return image_loader.Create(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) | void Image::Destroy(Image *img) | ||||
| { | { | ||||
| return image_loader.Destroy(img); | return image_loader.Destroy(img); | ||||
| @@ -145,6 +193,11 @@ uint8_t *Image::GetData() const | |||||
| return m_data->GetData(); | return m_data->GetData(); | ||||
| } | } | ||||
| bool Image::RetrieveTiles(Array<ivec2, ivec2>& tiles) const | |||||
| { | |||||
| return m_data->RetrieveTiles(tiles); | |||||
| } | |||||
| Image::~Image() | Image::~Image() | ||||
| { | { | ||||
| m_data->Close(); | m_data->Close(); | ||||
| @@ -72,6 +72,8 @@ InputDeviceInternal* InputDeviceInternal::CreateStandardMouse() | |||||
| mouse->AddAxis("X"); | mouse->AddAxis("X"); | ||||
| mouse->AddAxis("Y"); | mouse->AddAxis("Y"); | ||||
| mouse->AddAxis("XPixel"); | |||||
| mouse->AddAxis("YPixel"); | |||||
| mouse->AddAxis("Scroll"); | mouse->AddAxis("Scroll"); | ||||
| mouse->AddCursor("Cursor"); | mouse->AddCursor("Cursor"); | ||||
| @@ -27,11 +27,14 @@ class Image | |||||
| public: | public: | ||||
| static Image *Create(char const *path); | 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); | static void Destroy(Image *img); | ||||
| ivec2 GetSize() const; | ivec2 GetSize() const; | ||||
| PixelFormat GetFormat() const; | PixelFormat GetFormat() const; | ||||
| uint8_t *GetData() const; | uint8_t *GetData() const; | ||||
| bool RetrieveTiles(Array<ivec2, ivec2>& tiles) const; | |||||
| private: | private: | ||||
| Image(); | Image(); | ||||
| @@ -41,7 +41,8 @@ struct StreamType | |||||
| StdIn = 0, | StdIn = 0, | ||||
| StdOut, | StdOut, | ||||
| StdErr, | StdErr, | ||||
| File | |||||
| File, | |||||
| FileBinary | |||||
| } | } | ||||
| m_value; | m_value; | ||||
| @@ -59,7 +60,7 @@ public: | |||||
| ~File(); | ~File(); | ||||
| void Open(StreamType stream); | 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; | bool IsValid() const; | ||||
| void Close(); | void Close(); | ||||
| @@ -67,6 +68,9 @@ public: | |||||
| String ReadString(); | String ReadString(); | ||||
| int Write(uint8_t const *buf, int count); | int Write(uint8_t const *buf, int count); | ||||
| int WriteString(const String &buf); | int WriteString(const String &buf); | ||||
| long int GetPosFromStart(); | |||||
| void SetPosFromStart(long int pos); | |||||
| long int GetSize(); | |||||
| private: | private: | ||||
| class FileData *m_data; | class FileData *m_data; | ||||
| @@ -44,6 +44,126 @@ public: | |||||
| Thread(void *(*fn)(void *), void *data) : ThreadBase(fn, data) {} | Thread(void *(*fn)(void *), void *data) : ThreadBase(fn, data) {} | ||||
| virtual ~Thread() {} | 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<typename T1> | |||||
| 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<typename T1, typename T2> 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<T1>& job) | |||||
| { | |||||
| if (m_jobqueue.TryPush(job)) | |||||
| return true; | |||||
| return false; | |||||
| } | |||||
| bool FetchResult(Array<JobCommand<T2> >& results) | |||||
| { | |||||
| JobCommand<T2> 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<T1> job = that->m_jobqueue.Pop(); | |||||
| if (job == ThreadCommand::THREAD_STOP) | |||||
| break; | |||||
| else if (job == ThreadCommand::WORK_TODO) | |||||
| { | |||||
| JobCommand<T2> 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<T1>& job, JobCommand<T2>& 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<Thread*> m_threads; | |||||
| Queue<ThreadCommand> m_spawnqueue, m_donequeue; | |||||
| Queue<JobCommand<T1> > m_jobqueue; | |||||
| Queue<JobCommand<T2> > m_resultqueue; | |||||
| }; | |||||
| #endif | #endif | ||||
| } /* namespace lol */ | } /* namespace lol */ | ||||
| @@ -144,6 +144,8 @@ | |||||
| <ClCompile Include="image\codec\ios-image.cpp" /> | <ClCompile Include="image\codec\ios-image.cpp" /> | ||||
| <ClCompile Include="image\codec\ps3-image.cpp" /> | <ClCompile Include="image\codec\ps3-image.cpp" /> | ||||
| <ClCompile Include="image\codec\sdl-image.cpp" /> | <ClCompile Include="image\codec\sdl-image.cpp" /> | ||||
| <ClCompile Include="image\codec\zed-image.cpp" /> | |||||
| <ClCompile Include="image\codec\zed-palette-image.cpp" /> | |||||
| <ClCompile Include="image\color\cie1931.cpp" /> | <ClCompile Include="image\color\cie1931.cpp" /> | ||||
| <ClCompile Include="image\color\color.cpp" /> | <ClCompile Include="image\color\color.cpp" /> | ||||
| <ClCompile Include="image\image.cpp" /> | <ClCompile Include="image\image.cpp" /> | ||||
| @@ -179,7 +179,7 @@ void SdlInputData::Tick(float seconds) | |||||
| } | } | ||||
| # endif | # endif | ||||
| m_mouse->SetAxis(2, 0); | |||||
| m_mouse->SetAxis(4, 0); | |||||
| /* Handle keyboard and WM events */ | /* Handle keyboard and WM events */ | ||||
| SDL_Event event; | 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) | if (event.button.button != SDL_BUTTON_WHEELUP && event.button.button != SDL_BUTTON_WHEELDOWN) | ||||
| m_mouse->SetKey(event.button.button - 1, event.type == SDL_MOUSEBUTTONDOWN); | m_mouse->SetKey(event.button.button - 1, event.type == SDL_MOUSEBUTTONDOWN); | ||||
| else | 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 | // TODO: mouse wheel as axis | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -242,6 +242,9 @@ void SdlInputData::Tick(float seconds) | |||||
| m_mouse->SetAxis(0, (mouse.x - vprevmouse.x) * MOUSE_SPEED_MOD / max_screen_size); | 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) | // 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); | 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 | //Mouse is focused, Validate the InScreen Key | ||||
| @@ -27,6 +27,8 @@ | |||||
| # include <dirent.h> | # include <dirent.h> | ||||
| #endif | #endif | ||||
| #include <sys/stat.h> | |||||
| #include "core.h" | #include "core.h" | ||||
| namespace lol | namespace lol | ||||
| @@ -45,7 +47,8 @@ class FileData | |||||
| void Open(StreamType stream) | void Open(StreamType stream) | ||||
| { | { | ||||
| if (m_type == StreamType::File) | |||||
| if (m_type == StreamType::File || | |||||
| m_type == StreamType::FileBinary) | |||||
| return; | return; | ||||
| m_type = stream; | m_type = stream; | ||||
| switch((int)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__ | #if __CELLOS_LV2__ | ||||
| String realfile = String(SYS_APP_HOME) + '/' + file; | String realfile = String(SYS_APP_HOME) + '/' + file; | ||||
| CellFsErrno err = cellFsOpen(realfile.C(), CELL_FS_O_RDONLY, | 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); | m_asset = AAssetManager_open(g_assets, file.C(), AASSET_MODE_UNKNOWN); | ||||
| #elif HAVE_STDIO_H | #elif HAVE_STDIO_H | ||||
| /* FIXME: no modes, no error checking, no nothing */ | /* 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 | #endif | ||||
| } | } | ||||
| @@ -93,6 +97,26 @@ class FileData | |||||
| #endif | #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) | int Read(uint8_t *buf, int count) | ||||
| { | { | ||||
| #if __CELLOS_LV2__ | #if __CELLOS_LV2__ | ||||
| @@ -169,25 +193,46 @@ class FileData | |||||
| return Write((uint8_t const *)buf.C(), buf.Count()); | return Write((uint8_t const *)buf.C(), buf.Count()); | ||||
| } | } | ||||
| void Close() | |||||
| long int GetPosFromStart() | |||||
| { | { | ||||
| if (m_type != StreamType::File) | |||||
| return; | |||||
| #if __CELLOS_LV2__ | #if __CELLOS_LV2__ | ||||
| if (m_fd >= 0) | |||||
| cellFsClose(m_fd); | |||||
| m_fd = -1; | |||||
| return 0; | |||||
| #elif __ANDROID__ | #elif __ANDROID__ | ||||
| if (m_asset) | |||||
| AAsset_close(m_asset); | |||||
| m_asset = nullptr; | |||||
| return 0; | |||||
| #elif HAVE_STDIO_H | #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 | #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__ | #if __CELLOS_LV2__ | ||||
| int m_fd; | int m_fd; | ||||
| #elif __ANDROID__ | #elif __ANDROID__ | ||||
| @@ -195,8 +240,9 @@ class FileData | |||||
| #elif HAVE_STDIO_H | #elif HAVE_STDIO_H | ||||
| FILE *m_fd; | FILE *m_fd; | ||||
| #endif | #endif | ||||
| Atomic<int> m_refcount; | |||||
| StreamType m_type; | |||||
| Atomic<int> m_refcount; | |||||
| StreamType m_type; | |||||
| struct stat m_stat; | |||||
| }; | }; | ||||
| //-- FILE -- | //-- 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(); | return m_data->IsValid(); | ||||
| } | } | ||||
| //-- | |||||
| void File::Close() | |||||
| { | |||||
| m_data->Close(); | |||||
| } | |||||
| //-- | //-- | ||||
| int File::Read(uint8_t *buf, int count) | 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(); | |||||
| } | } | ||||
| //--------------- | //--------------- | ||||
| @@ -76,6 +76,42 @@ TileSet *Tiler::Register(char const *path) | |||||
| return tileset; | 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) | void Tiler::Deregister(TileSet *tileset) | ||||
| { | { | ||||
| data->tilesets.RemoveSlot(tileset); | data->tilesets.RemoveSlot(tileset); | ||||
| @@ -31,6 +31,10 @@ public: | |||||
| static TileSet *Register(char const *path, ivec2 size, ivec2 count); | static TileSet *Register(char const *path, ivec2 size, ivec2 count); | ||||
| static TileSet *Register(String const &path); | static TileSet *Register(String const &path); | ||||
| static TileSet *Register(char 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 *); | static void Deregister(TileSet *); | ||||
| private: | private: | ||||
| @@ -60,6 +60,22 @@ TileSet::TileSet(char const *path) | |||||
| : m_data(new TileSetData()) | : m_data(new TileSetData()) | ||||
| { | { | ||||
| Init(path); | Init(path); | ||||
| Array<ivec2, ivec2> 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<ivec2, ivec2> 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) | 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), | AddTile(ibox2(size * ivec2(i, j), | ||||
| size * ivec2(i + 1, j + 1))); | size * ivec2(i + 1, j + 1))); | ||||
| } | } | ||||
| Array<ivec2, ivec2> 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<ivec2, ivec2> 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) | void TileSet::Init(char const *path) | ||||
| { | |||||
| Init(path, Image::Create(path)); | |||||
| } | |||||
| void TileSet::Init(char const *path, Image* image) | |||||
| { | { | ||||
| m_data->m_name = String("<tileset> ") + path; | m_data->m_name = String("<tileset> ") + path; | ||||
| m_data->m_texture = 0; | 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_image_size = m_data->m_image->GetSize(); | ||||
| m_data->m_texture_size = ivec2(PotUp(m_data->m_image_size.x), | m_data->m_texture_size = ivec2(PotUp(m_data->m_image_size.x), | ||||
| PotUp(m_data->m_image_size.y)); | PotUp(m_data->m_image_size.y)); | ||||
| @@ -108,6 +164,18 @@ int TileSet::AddTile(ibox2 rect) | |||||
| return m_data->m_tiles.Count() - 1; | 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() | TileSet::~TileSet() | ||||
| { | { | ||||
| delete m_data; | delete m_data; | ||||
| @@ -32,10 +32,12 @@ class TileSet : public Entity | |||||
| { | { | ||||
| public: | public: | ||||
| TileSet(char const *path); | TileSet(char const *path); | ||||
| TileSet(char const *path, Image* image); | |||||
| virtual ~TileSet(); | virtual ~TileSet(); | ||||
| /* Old style: path to PNG file */ | /* Old style: path to PNG file */ | ||||
| TileSet(char const *path, ivec2 size, ivec2 count); | TileSet(char const *path, ivec2 size, ivec2 count); | ||||
| TileSet(char const *path, Image* image, ivec2 size, ivec2 count); | |||||
| protected: | protected: | ||||
| /* Inherited from Entity */ | /* Inherited from Entity */ | ||||
| @@ -45,6 +47,7 @@ protected: | |||||
| public: | public: | ||||
| /* New methods */ | /* New methods */ | ||||
| int AddTile(ibox2 rect); | int AddTile(ibox2 rect); | ||||
| void AddTile(ivec2 count); | |||||
| int GetTileCount() const; | int GetTileCount() const; | ||||
| ivec2 GetTileSize(int tileid) const; | ivec2 GetTileSize(int tileid) const; | ||||
| @@ -58,6 +61,7 @@ public: | |||||
| private: | private: | ||||
| void Init(char const *path); | void Init(char const *path); | ||||
| void Init(char const *path, Image* image); | |||||
| TileSetData *m_data; | TileSetData *m_data; | ||||
| }; | }; | ||||