@@ -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; | ||||
}; | }; | ||||