You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

307 lines
9.1 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2014 Benjamin Huet <huet.benjamin@gmail.com>
  5. // 2014 Sam Hocevar <sam@hocevar.net>
  6. // This program is free software; you can redistribute it and/or
  7. // modify it under the terms of the Do What The Fuck You Want To
  8. // Public License, Version 2, as published by Sam Hocevar. See
  9. // http://www.wtfpl.net/ for more details.
  10. //
  11. #include <lol/engine-internal.h>
  12. #include "../../image/image-private.h"
  13. namespace lol
  14. {
  15. /*
  16. * Image implementation class
  17. */
  18. class ZedImageCodec : public ImageCodec
  19. {
  20. public:
  21. virtual char const *GetName() { return "<ZedImageCodec>"; }
  22. virtual bool Load(Image *image, char const *path);
  23. virtual bool Save(Image *image, char const *path);
  24. virtual bool RetrieveTiles(array<ivec2, ivec2>& tiles)
  25. {
  26. bool result = m_tiles.Count() > 0;
  27. tiles += m_tiles;
  28. m_tiles.Empty();
  29. return result;
  30. }
  31. private:
  32. //<Pos, Size>
  33. array<ivec2, ivec2> m_tiles;
  34. };
  35. DECLARE_IMAGE_CODEC(ZedImageCodec, 10)
  36. /*
  37. * Public Image class
  38. */
  39. bool ZedImageCodec::Load(Image *image, char const *path)
  40. {
  41. if (!lol::String(path).EndsWith(".RSC"))
  42. return false;
  43. // Compacter definition
  44. struct CompactSecondary
  45. {
  46. CompactSecondary(int32_t size) { m_size = size; }
  47. int32_t m_size;
  48. array<int32_t> m_tiles;
  49. };
  50. struct CompactMain
  51. {
  52. CompactMain(int32_t size) { m_size = size; m_count = 0; }
  53. int32_t m_size;
  54. int32_t m_count;
  55. array<CompactSecondary> m_secondary;
  56. };
  57. struct Compacter2d
  58. {
  59. void PowSetup(int32_t start, int32_t count)
  60. {
  61. for (int i = 0; i < count; i++)
  62. {
  63. m_primary << CompactMain(start << i);
  64. for (int j = 0; j < count; j++)
  65. m_primary.Last().m_secondary << CompactSecondary(start << j);
  66. }
  67. }
  68. void StepSetup(int32_t start, int32_t interval, int32_t count)
  69. {
  70. for (int i = 0; i < count; i++)
  71. {
  72. m_primary << CompactMain(start + interval * i);
  73. for (int j = 0; j < count; j++)
  74. m_primary.Last().m_secondary << CompactSecondary(start + interval * j);
  75. }
  76. }
  77. void CustomSetup(array<int32_t> custom_list)
  78. {
  79. for (int i = 0; i < custom_list.Count(); i++)
  80. {
  81. m_primary << CompactMain(custom_list[i]);
  82. for (int j = 0; j < custom_list.Count(); j++)
  83. m_primary.Last().m_secondary << CompactSecondary(custom_list[j]);
  84. }
  85. }
  86. void Store(int32_t tile, ivec2 size)
  87. {
  88. for (int i = 0; i < m_primary.Count(); i++)
  89. {
  90. if (size.y <= m_primary[i].m_size || i == m_primary.Count() - 1)
  91. {
  92. for (int j = 0; j < m_primary[i].m_secondary.Count(); j++)
  93. {
  94. if (size.x <= m_primary[i].m_secondary[j].m_size || j == m_primary[i].m_secondary.Count() - 1)
  95. {
  96. m_primary[i].m_secondary[j].m_tiles << tile;
  97. m_primary[i].m_count++;
  98. break;
  99. }
  100. }
  101. break;
  102. }
  103. }
  104. }
  105. array<CompactMain> m_primary;
  106. };
  107. File file;
  108. file.Open(path, FileAccess::Read, true);
  109. //Put file in memory
  110. long file_size = file.GetSize();
  111. array<uint8_t> file_buffer;
  112. file_buffer.Resize(file_size);
  113. file.Read((uint8_t*)&file_buffer[0], file_size);
  114. file.Close();
  115. //Get FileCount
  116. uint32_t file_pos = 0;
  117. uint16_t file_count = 0;
  118. file_count = *((uint16_t*)(&file_buffer[file_pos]));
  119. file_pos += sizeof(uint16_t);
  120. array<long int> file_offset;
  121. file_offset.Resize(file_count);
  122. //Get all the file offsets
  123. for (int i = 0; i < file_count; i++)
  124. {
  125. file_offset[i] = *((long int*)(&file_buffer[file_pos]));
  126. file_pos += sizeof(long int);
  127. }
  128. file_offset << file_size;
  129. m_tiles.Reserve(file_count);
  130. Compacter2d compacter;
  131. compacter.StepSetup(8, 8, 10);
  132. uint32_t total_size = 0;
  133. array<uint8_t> file_convert;
  134. file_convert.Reserve(file_size);
  135. array<ivec2> available_sizes;
  136. for (int i = 0; i < file_count; i++)
  137. {
  138. file_pos = file_offset[i];
  139. //Get image size
  140. uint8_t size_x = 0;
  141. uint8_t size_y = 0;
  142. size_y = file_buffer[file_pos++];
  143. size_x = file_buffer[file_pos++];
  144. //special tweak
  145. size_x *= 8;
  146. total_size += (size_x * size_y);
  147. //Prepare read
  148. uint32_t header_length = (size_y + 5) & 0xFC;
  149. uint32_t data_length = (file_offset[i+1] - file_offset[i]) - header_length;
  150. uint32_t data_pos = file_offset[i] + header_length;
  151. /* Seems useless in the end
  152. //Retrieve Header & footer
  153. array<uint8_t> header_data;
  154. header_data.Resize(header_length);
  155. memcpy(&header_data[0], &file_buffer[file_offset[i]], header_length);
  156. array<uint8_t> footer_data;
  157. uint32_t footer_length = lol::min((uint32_t)file_buffer.Count(), data_pos + data_length + header_length) - (data_pos + data_length);
  158. if (footer_length > 0)
  159. {
  160. footer_data.Resize(footer_length);
  161. memcpy(&footer_data[0], &file_buffer[data_pos + data_length], footer_length);
  162. }
  163. */
  164. //Prepare buffer and tiles infos
  165. int32_t convert_pos = file_convert.Count();
  166. ivec2 size = ivec2(size_x, size_y);
  167. compacter.Store(m_tiles.Count(), ivec2(size_x, size_y));
  168. m_tiles.Push(ivec2(file_convert.Count(), data_length), ivec2(size_x, size_y));
  169. file_convert.Resize(convert_pos + data_length);
  170. //Retrieve actual datas
  171. file_pos = data_pos;
  172. memcpy(&file_convert[convert_pos], &file_buffer[file_pos], data_length);
  173. file_pos += data_length;
  174. //Store size type
  175. {
  176. ivec2 size_16 = size;
  177. int32_t s_16 = 8;
  178. while (1)
  179. {
  180. if (size_16.x < s_16)
  181. {
  182. size_16.x = s_16;
  183. break;
  184. }
  185. s_16 <<= 1;
  186. }
  187. s_16 = 8;
  188. while (1)
  189. {
  190. if (size_16.y < s_16)
  191. {
  192. size_16.y = s_16;
  193. break;
  194. }
  195. s_16 <<= 1;
  196. }
  197. int j = 0;
  198. for (; j < available_sizes.Count(); j++)
  199. if (available_sizes[j] == size_16)
  200. break;
  201. if (j >= available_sizes.Count())
  202. available_sizes << size_16;
  203. }
  204. }
  205. int32_t tex_sqrt = (int32_t)lol::sqrt((float)total_size);
  206. int32_t tex_size = 2;
  207. while (tex_size < tex_sqrt)
  208. tex_size <<= 1;
  209. //Prepare final imqge
  210. image->SetSize(ivec2(tex_size));
  211. uint8_t *pixels = image->Lock<PixelFormat::Y_8>();
  212. //Data refactor stage
  213. ivec2 pos = ivec2(0);
  214. for (int j = compacter.m_primary.Count() - 1; j >= 0; j--)
  215. {
  216. for (int k = compacter.m_primary[j].m_secondary.Count() - 1; k >= 0; k--)
  217. {
  218. //Try something smaller
  219. if (pos.x + compacter.m_primary[j].m_secondary[k].m_size >= tex_size)
  220. continue;
  221. while (compacter.m_primary[j].m_secondary[k].m_tiles.Count() > 0)
  222. {
  223. //Try something smaller
  224. if (pos.x + compacter.m_primary[j].m_secondary[k].m_size >= tex_size)
  225. break;
  226. compacter.m_primary[j].m_count--;
  227. int i = compacter.m_primary[j].m_secondary[k].m_tiles.Pop();
  228. int32_t file_off = m_tiles[i].m1[0];
  229. ivec2 t_size = m_tiles[i].m2;
  230. ASSERT(pos.y + t_size.y < tex_size);
  231. //Move image to texture
  232. int32_t img_off = pos.x + pos.y * tex_size;
  233. //At this stage image data consists of 4 vertical interlaced blocks
  234. for (int pass = 0; pass < 4; pass++)
  235. {
  236. for (int y_cur = 0; y_cur < t_size.y; y_cur++)
  237. {
  238. for (int x_cur = 0; x_cur < t_size.x / 4; x_cur++)
  239. {
  240. int32_t img_pos = img_off + pass + 4 * x_cur + y_cur * (int32_t)tex_size;
  241. pixels[img_pos] = file_convert[file_off++];
  242. }
  243. }
  244. }
  245. //Register new pos and move to next
  246. m_tiles[i].m1 = pos;
  247. pos.x += t_size.x;
  248. }
  249. }
  250. //Do another loop
  251. if (compacter.m_primary[j].m_count > 0)
  252. {
  253. pos.x = 0;
  254. pos.y += compacter.m_primary[j].m_size;
  255. j++;
  256. }
  257. }
  258. image->Unlock(pixels);
  259. return true;
  260. }
  261. bool ZedImageCodec::Save(Image *image, char const *path)
  262. {
  263. UNUSED(path);
  264. /* FIXME: do we need to implement this? */
  265. return true;
  266. }
  267. } /* namespace lol */