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.

296 lines
8.3 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. #if defined HAVE_CONFIG_H
  12. # include "config.h"
  13. #endif
  14. #include "core.h"
  15. #include "../../image/image-private.h"
  16. using namespace std;
  17. namespace lol
  18. {
  19. /*
  20. * Image implementation class
  21. */
  22. DECLARE_IMAGE_LOADER(ZedImageData, 0)
  23. {
  24. public:
  25. virtual bool Open(char const *);
  26. virtual bool Close();
  27. virtual uint8_t *GetData() const;
  28. virtual bool RetrieveTiles(Array<ivec2, ivec2>& tiles)
  29. {
  30. tiles += m_tiles;
  31. m_tiles.Empty();
  32. return true;
  33. }
  34. private:
  35. uint8_t *m_pixels;
  36. //<Pos, Size>
  37. Array<ivec2, ivec2> m_tiles;
  38. };
  39. /*
  40. * Public Image class
  41. */
  42. bool ZedImageData::Open(char const *path)
  43. {
  44. if (!lol::String(path).EndsWith(".RSC"))
  45. return false;
  46. File file;
  47. file.Open(path, FileAccess::Read, true);
  48. //Put file in memory
  49. long file_size = file.GetSize();
  50. Array<uint8_t> file_buffer;
  51. file_buffer.Resize(file_size);
  52. file.Read((uint8_t*)&file_buffer[0], file_size);
  53. file.Close();
  54. //Get FileCount
  55. uint32_t file_pos = 0;
  56. uint16_t file_count = 0;
  57. file_count = *((uint16_t*)(&file_buffer[file_pos]));
  58. file_pos += sizeof(uint16_t);
  59. Array<long int> file_offset;
  60. file_offset.Resize(file_count);
  61. //Get all the file offsets
  62. for (int i = 0; i < file_count; i++)
  63. {
  64. file_offset[i] = *((long int*)(&file_buffer[file_pos]));
  65. file_pos += sizeof(long int);
  66. }
  67. file_offset << file_size;
  68. m_tiles.Reserve(file_count);
  69. struct CompactSecondary
  70. {
  71. CompactSecondary(int32_t size) { m_size = size; }
  72. int32_t m_size;
  73. Array<int32_t> m_tiles;
  74. };
  75. struct CompactMain
  76. {
  77. CompactMain(int32_t size) { m_size = size; m_count = 0; }
  78. int32_t m_size;
  79. int32_t m_count;
  80. Array<CompactSecondary> m_secondary;
  81. };
  82. struct Compacter2d
  83. {
  84. void PowSetup(int32_t start, int32_t count)
  85. {
  86. for (int i = 0; i < count; i++)
  87. {
  88. m_primary << CompactMain(start << i);
  89. for (int j = 0; j < count; j++)
  90. m_primary.Last().m_secondary << CompactSecondary(start << j);
  91. }
  92. }
  93. void StepSetup(int32_t start, int32_t interval, int32_t count)
  94. {
  95. for (int i = 0; i < count; i++)
  96. {
  97. m_primary << CompactMain(start + interval * i);
  98. for (int j = 0; j < count; j++)
  99. m_primary.Last().m_secondary << CompactSecondary(start + interval * j);
  100. }
  101. }
  102. void CustomSetup(Array<int32_t> custom_list)
  103. {
  104. for (int i = 0; i < custom_list.Count(); i++)
  105. {
  106. m_primary << CompactMain(custom_list[i]);
  107. for (int j = 0; j < custom_list.Count(); j++)
  108. m_primary.Last().m_secondary << CompactSecondary(custom_list[j]);
  109. }
  110. }
  111. void Store(int32_t tile, ivec2 size)
  112. {
  113. for (int i = 0; i < m_primary.Count(); i++)
  114. {
  115. if (size.y <= m_primary[i].m_size || i == m_primary.Count() - 1)
  116. {
  117. for (int j = 0; j < m_primary[i].m_secondary.Count(); j++)
  118. {
  119. if (size.x <= m_primary[i].m_secondary[j].m_size || j == m_primary[i].m_secondary.Count() - 1)
  120. {
  121. m_primary[i].m_secondary[j].m_tiles << tile;
  122. m_primary[i].m_count++;
  123. break;
  124. }
  125. }
  126. break;
  127. }
  128. }
  129. }
  130. Array<CompactMain> m_primary;
  131. };
  132. Compacter2d compacter;
  133. compacter.StepSetup(8, 8, 10);
  134. uint32_t total_size = 0;
  135. Array<uint8_t> file_convert;
  136. file_convert.Reserve(file_size);
  137. Array<ivec2> available_sizes;
  138. for (int i = 0; i < file_count; i++)
  139. {
  140. file_pos = file_offset[i];
  141. //Get image size
  142. uint8_t size_x = 0;
  143. uint8_t size_y = 0;
  144. size_y = file_buffer[file_pos++];
  145. size_x = file_buffer[file_pos++];
  146. //special tweak
  147. size_x *= 8;
  148. total_size += (size_x * size_y);
  149. //Prepare read
  150. uint32_t header_length = (size_y + 5) & 0xFC;
  151. uint32_t data_length = (file_offset[i+1] - file_offset[i]) - header_length;
  152. uint32_t data_pos = file_offset[i] + header_length;
  153. //Prepare buffer and tiles infos
  154. int32_t convert_pos = file_convert.Count();
  155. ivec2 size = ivec2(size_x, size_y);
  156. compacter.Store(m_tiles.Count(), ivec2(size_x, size_y));
  157. m_tiles.Push(ivec2(file_convert.Count(), data_length), ivec2(size_x, size_y));
  158. file_convert.Resize(convert_pos + data_length);
  159. ivec2 size_16 = size;
  160. int32_t s_16 = 8;
  161. while (1)
  162. {
  163. if (size_16.x <= s_16)
  164. {
  165. size_16.x = s_16;
  166. break;
  167. }
  168. s_16 <<= 1;
  169. }
  170. s_16 = 8;
  171. while (1)
  172. {
  173. if (size_16.y <= s_16)
  174. {
  175. size_16.y = s_16;
  176. break;
  177. }
  178. s_16 <<= 1;
  179. }
  180. int j = 0;
  181. for (; j < available_sizes.Count(); j++)
  182. if (available_sizes[j] == size_16)
  183. break;
  184. if (j >= available_sizes.Count())
  185. available_sizes << size_16;
  186. //Retrieve actual datas
  187. file_pos = data_pos;
  188. memcpy(&file_convert[convert_pos], &file_buffer[file_pos], data_length);
  189. file_pos += data_length;
  190. }
  191. int32_t tex_sqrt = (int32_t)lol::sqrt((float)total_size);
  192. int32_t tex_size = 2;
  193. while (tex_size < tex_sqrt)
  194. tex_size <<= 1;
  195. //Prepare final imqge
  196. m_size = ivec2(tex_size);
  197. m_format = PixelFormat::Y_8;
  198. m_pixels = new uint8_t[tex_size * tex_size * 1 * sizeof(*m_pixels)];
  199. uint8_t *image = m_pixels;
  200. //Data refactor stage
  201. ivec2 pos = ivec2(0);
  202. for (int j = compacter.m_primary.Count() - 1; j >= 0; j--)
  203. {
  204. for (int k = compacter.m_primary[j].m_secondary.Count() - 1; k >= 0; k--)
  205. {
  206. //Try something smaller
  207. if (pos.x + compacter.m_primary[j].m_secondary[k].m_size >= tex_size)
  208. continue;
  209. while (compacter.m_primary[j].m_secondary[k].m_tiles.Count() > 0)
  210. {
  211. //Try something smaller
  212. if (pos.x + compacter.m_primary[j].m_secondary[k].m_size >= tex_size)
  213. break;
  214. compacter.m_primary[j].m_count--;
  215. int i = compacter.m_primary[j].m_secondary[k].m_tiles.Pop();
  216. int32_t file_off = m_tiles[i].m1[0];
  217. ivec2 t_size = m_tiles[i].m2;
  218. ASSERT(pos.y + t_size.y < tex_size);
  219. //Move image to texture
  220. int32_t img_off = pos.x + pos.y * tex_size;
  221. //At this stage image data consists of 4 vertical interlaced blocks
  222. for (int pass = 0; pass < 4; pass++)
  223. {
  224. for (int y_cur = 0; y_cur < t_size.y; y_cur++)
  225. {
  226. for (int x_cur = 0; x_cur < t_size.x / 4; x_cur++)
  227. {
  228. int32_t img_pos = img_off + pass + 4 * x_cur + y_cur * (int32_t)tex_size;
  229. image[img_pos] = file_convert[file_off++];
  230. }
  231. }
  232. }
  233. //Register new pos and move to next
  234. m_tiles[i].m1 = pos;
  235. pos.x += t_size.x;
  236. }
  237. }
  238. //Do another loop
  239. if (compacter.m_primary[j].m_count > 0)
  240. {
  241. pos.x = 0;
  242. pos.y += compacter.m_primary[j].m_size;
  243. j++;
  244. }
  245. }
  246. return true;
  247. }
  248. bool ZedImageData::Close()
  249. {
  250. delete[] m_pixels;
  251. return true;
  252. }
  253. uint8_t * ZedImageData::GetData() const
  254. {
  255. return m_pixels;
  256. }
  257. } /* namespace lol */