@@ -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 uint8_t *GetData() const = 0; | |||
virtual bool RetrieveTiles(Array<ivec2, ivec2>& tiles) { return false; } | |||
protected: | |||
ivec2 m_size; | |||
@@ -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<ivec2, ivec2>& tiles) const | |||
{ | |||
return m_data->RetrieveTiles(tiles); | |||
} | |||
Image::~Image() | |||
{ | |||
m_data->Close(); | |||
@@ -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"); | |||
@@ -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<ivec2, ivec2>& tiles) const; | |||
private: | |||
Image(); | |||
@@ -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; | |||
@@ -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<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 | |||
} /* namespace lol */ | |||
@@ -144,6 +144,8 @@ | |||
<ClCompile Include="image\codec\ios-image.cpp" /> | |||
<ClCompile Include="image\codec\ps3-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\color.cpp" /> | |||
<ClCompile Include="image\image.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 | |||
@@ -27,6 +27,8 @@ | |||
# include <dirent.h> | |||
#endif | |||
#include <sys/stat.h> | |||
#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<int> m_refcount; | |||
StreamType m_type; | |||
Atomic<int> 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(); | |||
} | |||
//--------------- | |||
@@ -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); | |||
@@ -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: | |||
@@ -60,6 +60,22 @@ TileSet::TileSet(char const *path) | |||
: m_data(new TileSetData()) | |||
{ | |||
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) | |||
@@ -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<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) | |||
{ | |||
Init(path, Image::Create(path)); | |||
} | |||
void TileSet::Init(char const *path, Image* image) | |||
{ | |||
m_data->m_name = String("<tileset> ") + 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; | |||
@@ -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; | |||
}; | |||