307 行
9.3 KiB

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