326 lines
7.6 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://sam.zoy.org/projects/COPYING.WTFPL for more details.
  9. //
  10. #if defined HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #include <cstdlib>
  14. #include <cstdio>
  15. #include <cmath>
  16. #include <cstring>
  17. #if defined WIN32 && !defined _XBOX
  18. # define WIN32_LEAN_AND_MEAN
  19. # include <windows.h>
  20. # if defined USE_D3D9
  21. # define FAR
  22. # define NEAR
  23. # include <d3d9.h>
  24. # endif
  25. #endif
  26. #include "core.h"
  27. #include "lolgl.h"
  28. using namespace std;
  29. #if defined USE_D3D9
  30. extern IDirect3DDevice9 *g_d3ddevice;
  31. #elif defined _XBOX
  32. extern D3DDevice *g_d3ddevice;
  33. #endif
  34. namespace lol
  35. {
  36. /*
  37. * TileSet implementation class
  38. */
  39. class TileSetData
  40. {
  41. friend class TileSet;
  42. private:
  43. char *name, *path;
  44. int *tiles, ntiles;
  45. ivec2 size, isize, count;
  46. vec2 scale;
  47. float tx, ty;
  48. Image *img;
  49. #if defined USE_D3D9
  50. IDirect3DTexture9 *m_tex;
  51. #elif defined _XBOX
  52. D3DTexture *m_tex;
  53. #else
  54. GLuint m_tex;
  55. #endif
  56. };
  57. /*
  58. * Public TileSet class
  59. */
  60. TileSet::TileSet(char const *path, ivec2 size, ivec2 count)
  61. : data(new TileSetData())
  62. {
  63. data->name = (char *)malloc(10 + strlen(path) + 1);
  64. data->path = data->name + 10;
  65. sprintf(data->name, "<tileset> %s", path);
  66. data->tiles = NULL;
  67. data->m_tex = 0;
  68. data->img = new Image(path);
  69. data->isize = data->img->GetSize();
  70. if (count.x > 0 && count.y > 0)
  71. {
  72. data->count = count;
  73. data->size = data->isize / count;
  74. }
  75. else
  76. {
  77. if (size.x <= 0 || size.y <= 0)
  78. size = ivec2(32, 32);
  79. data->count.x = data->isize.x > size.x ? data->isize.x / size.x : 1;
  80. data->count.y = data->isize.y > size.y ? data->isize.y / size.y : 1;
  81. data->size = size;
  82. }
  83. data->tx = (float)data->size.x / PotUp(data->isize.x);
  84. data->ty = (float)data->size.y / PotUp(data->isize.y);
  85. data->ntiles = data->count.x * data->count.y;
  86. m_drawgroup = DRAWGROUP_BEFORE;
  87. }
  88. TileSet::~TileSet()
  89. {
  90. free(data->tiles);
  91. free(data->name);
  92. delete data;
  93. }
  94. void TileSet::TickDraw(float deltams)
  95. {
  96. Entity::TickDraw(deltams);
  97. if (IsDestroying())
  98. {
  99. if (data->img)
  100. delete data->img;
  101. else
  102. #if defined USE_D3D9 || defined _XBOX
  103. /* FIXME: is it really the correct call? */
  104. data->m_tex->Release();
  105. #else
  106. glDeleteTextures(1, &data->m_tex);
  107. #endif
  108. }
  109. else if (data->img)
  110. {
  111. #if defined USE_D3D9 || defined _XBOX
  112. D3DFORMAT format;
  113. #else
  114. GLuint format;
  115. #endif
  116. int planes;
  117. switch (data->img->GetFormat())
  118. {
  119. case Image::FORMAT_RGB:
  120. #if defined USE_D3D9
  121. format = D3DFMT_R8G8B8;
  122. #elif defined _XBOX
  123. format = D3DFMT_LIN_A8R8G8B8; /* FIXME */
  124. #else
  125. format = GL_RGB;
  126. #endif
  127. planes = 3;
  128. break;
  129. case Image::FORMAT_RGBA:
  130. default:
  131. #if defined USE_D3D9
  132. format = D3DFMT_A8R8G8B8;
  133. #elif defined _XBOX
  134. /* By default the X360 will swizzle the texture. Ask for linear. */
  135. format = D3DFMT_LIN_A8R8G8B8;
  136. #else
  137. format = GL_RGBA;
  138. #endif
  139. planes = 4;
  140. break;
  141. }
  142. int w = PotUp(data->isize.x);
  143. int h = PotUp(data->isize.y);
  144. uint8_t *pixels = (uint8_t *)data->img->GetData();
  145. if (w != data->isize.x || h != data->isize.y)
  146. {
  147. uint8_t *tmp = (uint8_t *)malloc(planes * w * h);
  148. for (int line = 0; line < data->isize.y; line++)
  149. memcpy(tmp + planes * w * line,
  150. pixels + planes * data->isize.x * line,
  151. planes * data->isize.x);
  152. pixels = tmp;
  153. }
  154. #if defined USE_D3D9 || defined _XBOX
  155. D3DLOCKED_RECT rect;
  156. HRESULT hr;
  157. # if defined USE_D3D9
  158. hr = g_d3ddevice->CreateTexture(w, h, 1, D3DUSAGE_DYNAMIC, format,
  159. D3DPOOL_DEFAULT, &data->m_tex, NULL);
  160. # elif defined _XBOX
  161. hr = g_d3ddevice->CreateTexture(w, h, 1, D3DUSAGE_WRITEONLY, format,
  162. D3DPOOL_DEFAULT, &data->m_tex, NULL);
  163. # endif
  164. if (FAILED(hr))
  165. Abort();
  166. # if defined USE_D3D9
  167. hr = data->m_tex->LockRect(0, &rect, NULL, D3DLOCK_DISCARD);
  168. # else
  169. hr = data->m_tex->LockRect(0, &rect, NULL, 0);
  170. # endif
  171. if (FAILED(hr))
  172. Abort();
  173. for (int j = 0; j < h; j++)
  174. memcpy((uint8_t *)rect.pBits + j * rect.Pitch, pixels + w * j * 4, w * 4);
  175. hr = data->m_tex->UnlockRect(0);
  176. if (FAILED(hr))
  177. Abort();
  178. #else
  179. glGenTextures(1, &data->m_tex);
  180. glEnable(GL_TEXTURE_2D);
  181. glBindTexture(GL_TEXTURE_2D, data->m_tex);
  182. glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0,
  183. format, GL_UNSIGNED_BYTE, pixels);
  184. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  185. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  186. #endif
  187. if (pixels != data->img->GetData())
  188. free(pixels);
  189. delete data->img;
  190. data->img = NULL;
  191. }
  192. }
  193. char const *TileSet::GetName()
  194. {
  195. return data->name;
  196. }
  197. ivec2 TileSet::GetCount() const
  198. {
  199. return data->count;
  200. }
  201. ivec2 TileSet::GetSize(int tileid) const
  202. {
  203. return data->size;
  204. }
  205. void TileSet::Bind()
  206. {
  207. if (!data->img && data->m_tex)
  208. {
  209. #if defined USE_D3D9 || defined _XBOX
  210. HRESULT hr = g_d3ddevice->SetTexture(0, data->m_tex);
  211. if (FAILED(hr))
  212. Abort();
  213. #else
  214. glActiveTexture(GL_TEXTURE0);
  215. glBindTexture(GL_TEXTURE_2D, data->m_tex);
  216. #endif
  217. }
  218. }
  219. void TileSet::Unbind()
  220. {
  221. if (!data->img && data->m_tex)
  222. {
  223. #if defined USE_D3D9 || defined _XBOX
  224. HRESULT hr = g_d3ddevice->SetTexture(0, NULL);
  225. if (FAILED(hr))
  226. Abort();
  227. #else
  228. glActiveTexture(GL_TEXTURE0);
  229. glBindTexture(GL_TEXTURE_2D, 0);
  230. #endif
  231. }
  232. }
  233. void TileSet::BlitTile(uint32_t id, vec3 pos, int o, vec2 scale,
  234. float *vertex, float *texture)
  235. {
  236. float tx = data->tx * ((id & 0xffff) % data->count.x);
  237. float ty = data->ty * ((id & 0xffff) / data->count.x);
  238. int dx = data->size.x * scale.x;
  239. int dy = o ? 0 : data->size.y * scale.y;
  240. int dz = o ? data->size.y * scale.y : 0;
  241. if (!data->img && data->m_tex)
  242. {
  243. float tmp[10];
  244. *vertex++ = tmp[0] = pos.x;
  245. *vertex++ = tmp[1] = pos.y + dy;
  246. *vertex++ = tmp[2] = pos.z + dz;
  247. *texture++ = tmp[3] = tx;
  248. *texture++ = tmp[4] = ty;
  249. *vertex++ = pos.x + dx;
  250. *vertex++ = pos.y + dy;
  251. *vertex++ = pos.z + dz;
  252. *texture++ = tx + data->tx;
  253. *texture++ = ty;
  254. *vertex++ = tmp[5] = pos.x + dx;
  255. *vertex++ = tmp[6] = pos.y;
  256. *vertex++ = tmp[7] = pos.z;
  257. *texture++ = tmp[8] = tx + data->tx;
  258. *texture++ = tmp[9] = ty + data->ty;
  259. *vertex++ = tmp[0];
  260. *vertex++ = tmp[1];
  261. *vertex++ = tmp[2];
  262. *texture++ = tmp[3];
  263. *texture++ = tmp[4];
  264. *vertex++ = tmp[5];
  265. *vertex++ = tmp[6];
  266. *vertex++ = tmp[7];
  267. *texture++ = tmp[8];
  268. *texture++ = tmp[9];
  269. *vertex++ = pos.x;
  270. *vertex++ = pos.y;
  271. *vertex++ = pos.z;
  272. *texture++ = tx;
  273. *texture++ = ty + data->ty;
  274. }
  275. else
  276. {
  277. memset(vertex, 0, 3 * sizeof(float));
  278. memset(texture, 0, 2 * sizeof(float));
  279. }
  280. }
  281. } /* namespace lol */