365 rivejä
10 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2013 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://www.wtfpl.net/ for more details.
  9. //
  10. #if defined HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #include "core.h"
  14. #include "lolgl.h"
  15. #if defined _WIN32 && defined USE_D3D9
  16. # define FAR
  17. # define NEAR
  18. # include <d3d9.h>
  19. #endif
  20. using namespace std;
  21. namespace lol
  22. {
  23. //
  24. // The TextureData class
  25. // ---------------------
  26. //
  27. class TextureData
  28. {
  29. friend class Texture;
  30. ivec2 m_size;
  31. PixelFormat m_format;
  32. #if defined USE_D3D9
  33. IDirect3DDevice9 *m_dev;
  34. IDirect3DTexture9 *m_texture;
  35. D3DTEXTUREFILTERTYPE m_mag_filter;
  36. D3DTEXTUREFILTERTYPE m_min_filter;
  37. D3DTEXTUREFILTERTYPE m_mip_filter;
  38. #elif defined _XBOX
  39. D3DDevice *m_dev;
  40. D3DTexture *m_texture;
  41. D3DTEXTUREFILTERTYPE m_mag_filter;
  42. D3DTEXTUREFILTERTYPE m_min_filter;
  43. D3DTEXTUREFILTERTYPE m_mip_filter;
  44. #else
  45. GLuint m_texture;
  46. GLint m_internal_format;
  47. GLenum m_gl_format, m_gl_type;
  48. #endif
  49. int m_bytes_per_elem;
  50. };
  51. //
  52. // The Texture class
  53. // -----------------
  54. //
  55. #define GET_CLAMPED(array, index) \
  56. array[std::max(0, std::min((int)(index), \
  57. (int)sizeof(array) / (int)sizeof(*array)))]
  58. Texture::Texture(ivec2 size, PixelFormat format)
  59. : m_data(new TextureData)
  60. {
  61. m_data->m_size = size;
  62. m_data->m_format = format;
  63. #if defined USE_D3D9 || defined _XBOX
  64. # if defined USE_D3D9
  65. m_data->m_dev = (IDirect3DDevice9 *)g_renderer->GetDevice();
  66. # elif defined _XBOX
  67. m_data->m_dev = (D3DDevice *)g_renderer->GetDevice();
  68. # endif
  69. static struct
  70. {
  71. D3DFORMAT format;
  72. int bytes;
  73. }
  74. const d3d_formats[] =
  75. {
  76. /* Unknown */
  77. { D3DFMT_UNKNOWN, 0 },
  78. /* FIXME: this is all mixed up for the RGBA/ARGB combinations */
  79. # if defined USE_D3D9
  80. { D3DFMT_R8G8B8, 3 }, /* RGB_8 */
  81. { D3DFMT_A8R8G8B8, 4 }, /* RGBA_8 */
  82. { D3DFMT_A8R8G8B8, 4 }, /* ARGB_8 */
  83. { D3DFMT_UNKNOWN, 0 }, /* ABGR_8 */
  84. { D3DFMT_L8, 1 }, /* Y8 */
  85. # else
  86. { D3DFMT_UNKNOWN, 0 },
  87. { D3DFMT_UNKNOWN, 0 },
  88. /* By default the X360 will swizzle the texture. Ask for linear. */
  89. { D3DFMT_LIN_A8R8G8B8, 4 },
  90. { D3DFMT_UNKNOWN, 0 },
  91. { D3DFMT_LIN_L8, 1 },
  92. # endif
  93. };
  94. D3DFORMAT d3d_format = GET_CLAMPED(d3d_formats, format).format;
  95. ASSERT(d3d_format != D3DFMT_UNKNOWN,
  96. "unsupported texture format %d\n", format);
  97. # if defined USE_D3D9
  98. int d3d_usage = D3DUSAGE_DYNAMIC;
  99. # else
  100. int d3d_usage = D3DUSAGE_WRITEONLY;
  101. # endif
  102. m_data->m_dev->CreateTexture(m_data->m_size.x, m_data->m_size.y, 1,
  103. d3d_usage, d3d_format,
  104. D3DPOOL_DEFAULT, &m_data->m_texture, nullptr);
  105. m_data->m_bytes_per_elem = GET_CLAMPED(d3d_formats, format).bytes;
  106. #else
  107. static struct
  108. {
  109. GLint internal_format;
  110. GLenum format, type;
  111. int bytes;
  112. }
  113. const gl_formats[] =
  114. {
  115. { 0, 0, 0, 0 }, /* Unknown */
  116. /* FIXME: this is all mixed up for the RGBA/ARGB combinations */
  117. #if __CELLOS_LV2__
  118. { GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, 3 },
  119. { GL_ARGB_SCE, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, 4 },
  120. { GL_ARGB_SCE, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, 4 },
  121. { GL_ARGB_SCE, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, 4 },
  122. { GL_LUMINANCE8, GL_LUMINANCE, GL_UNSIGNED_BYTE, 1 },
  123. #elif defined __native_client__ || defined HAVE_GLES_2X
  124. { GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, 3 },
  125. { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 4 },
  126. { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 4 },
  127. /* FIXME: if GL_RGBA is not available, we should advertise
  128. * this format as "not available" on this platform. */
  129. { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 4 },
  130. { GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 1 },
  131. #else
  132. { GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, 3 }, /* RGB_8 */
  133. /* Seems efficient for little endian textures */
  134. { GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 4 }, /* ARGB_8 */
  135. { GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 4 }, /* ARGB_8 */
  136. { GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 4 }, /* ABGR_8 */
  137. { GL_R8, GL_RED, GL_UNSIGNED_BYTE, 1 }, /* A8 */
  138. #endif
  139. };
  140. m_data->m_internal_format = GET_CLAMPED(gl_formats, format).internal_format;
  141. m_data->m_gl_format = GET_CLAMPED(gl_formats, format).format;
  142. m_data->m_gl_type = GET_CLAMPED(gl_formats, format).type;
  143. m_data->m_bytes_per_elem = GET_CLAMPED(gl_formats, format).bytes;
  144. glGenTextures(1, &m_data->m_texture);
  145. glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
  146. # if defined __CELLOS_LV2__
  147. /* We need this hint because by default the storage type is
  148. * GL_TEXTURE_SWIZZLED_GPU_SCE. */
  149. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_ALLOCATION_HINT_SCE,
  150. GL_TEXTURE_TILED_GPU_SCE);
  151. # endif
  152. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  153. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  154. #endif
  155. }
  156. TextureUniform Texture::GetTextureUniform() const
  157. {
  158. TextureUniform ret;
  159. #if defined USE_D3D9 || defined _XBOX
  160. ret.m_flags = (uint64_t)(uintptr_t)m_data->m_texture;
  161. ret.m_attrib = m_data->m_mag_filter;
  162. ret.m_attrib |= m_data->m_min_filter << 8;
  163. ret.m_attrib |= m_data->m_mip_filter << 16;
  164. #else
  165. ret.m_flags = m_data->m_texture;
  166. #endif
  167. return ret;
  168. }
  169. void Texture::Bind()
  170. {
  171. #if defined _XBOX || defined USE_D3D9
  172. m_data->m_dev->SetTexture(0, m_data->m_texture);
  173. #else
  174. # if !defined HAVE_GLES_2X
  175. glEnable(GL_TEXTURE_2D);
  176. # endif
  177. glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
  178. #endif
  179. }
  180. void Texture::SetData(void *data)
  181. {
  182. #if defined _XBOX || defined USE_D3D9
  183. D3DLOCKED_RECT rect;
  184. # if defined USE_D3D9
  185. m_data->m_texture->LockRect(0, &rect, nullptr, D3DLOCK_DISCARD);
  186. # else
  187. m_data->m_texture->LockRect(0, &rect, nullptr, 0);
  188. # endif
  189. memcpy(rect.pBits, data, rect.Pitch * m_data->m_size.y);
  190. m_data->m_texture->UnlockRect(0);
  191. #else
  192. glTexImage2D(GL_TEXTURE_2D, 0, m_data->m_internal_format,
  193. m_data->m_size.x, m_data->m_size.y, 0,
  194. m_data->m_gl_format, m_data->m_gl_type, data);
  195. #endif
  196. }
  197. void Texture::SetSubData(ivec2 origin, ivec2 size, void *data)
  198. {
  199. #if defined _XBOX || defined USE_D3D9
  200. D3DLOCKED_RECT rect;
  201. m_data->m_texture->LockRect(0, &rect, nullptr, 0);
  202. int stride = size.x * m_data->m_bytes_per_elem;
  203. for (int j = 0; j < size.y; j++)
  204. {
  205. uint8_t *dst = (uint8_t *)rect.pBits + (origin.y + j) * rect.Pitch;
  206. uint8_t *src = (uint8_t *)data + j * stride;
  207. memcpy(dst, src, stride);
  208. }
  209. m_data->m_texture->UnlockRect(0);
  210. #else
  211. glTexSubImage2D(GL_TEXTURE_2D, 0, origin.x, origin.y, size.x, size.y,
  212. m_data->m_gl_format, m_data->m_gl_type, data);
  213. #endif
  214. }
  215. void Texture::SetMagFiltering(TextureMagFilter filter)
  216. {
  217. #if defined _XBOX || defined USE_D3D9
  218. // In DirectX, texture filtering is a per-texture-unit state
  219. switch (filter)
  220. {
  221. case TextureMagFilter::LINEAR_TEXEL:
  222. m_data->m_mag_filter = D3DTEXF_LINEAR;
  223. break;
  224. case TextureMagFilter::NEAREST_TEXEL:
  225. default:
  226. m_data->m_mag_filter = D3DTEXF_POINT;
  227. break;
  228. }
  229. #else
  230. glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
  231. GLenum gl_filter;
  232. switch (filter)
  233. {
  234. case TextureMagFilter::LINEAR_TEXEL:
  235. gl_filter = GL_LINEAR;
  236. break;
  237. case TextureMagFilter::NEAREST_TEXEL:
  238. default:
  239. gl_filter = GL_NEAREST;
  240. break;
  241. }
  242. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter);
  243. #endif
  244. }
  245. void Texture::SetMinFiltering(TextureMinFilter filter)
  246. {
  247. #if defined _XBOX || defined USE_D3D9
  248. // In DirectX, texture filtering is a per-texture-unit state
  249. #define F(x, y) \
  250. m_data->m_min_filter = x; m_data->m_mip_filter = y;
  251. switch (filter)
  252. {
  253. case TextureMinFilter::LINEAR_TEXEL_NO_MIPMAP:
  254. F(D3DTEXF_POINT, D3DTEXF_NONE);
  255. break;
  256. case TextureMinFilter::NEAREST_TEXEL_NEAREST_MIPMAP:
  257. F(D3DTEXF_POINT, D3DTEXF_POINT);
  258. break;
  259. case TextureMinFilter::LINEAR_TEXEL_NEAREST_MIPMAP:
  260. F(D3DTEXF_LINEAR, D3DTEXF_POINT);
  261. break;
  262. case TextureMinFilter::NEAREST_TEXEL_LINEAR_MIPMAP:
  263. F(D3DTEXF_POINT, D3DTEXF_LINEAR);
  264. break;
  265. case TextureMinFilter::LINEAR_TEXEL_LINEAR_MIPMAP:
  266. F(D3DTEXF_LINEAR, D3DTEXF_LINEAR);
  267. break;
  268. case TextureMinFilter::NEAREST_TEXEL_NO_MIPMAP:
  269. default:
  270. F(D3DTEXF_POINT, D3DTEXF_NONE);
  271. break;
  272. }
  273. #undef F
  274. #else
  275. glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
  276. GLenum gl_filter;
  277. switch (filter)
  278. {
  279. case TextureMinFilter::LINEAR_TEXEL_NO_MIPMAP:
  280. gl_filter = GL_LINEAR;
  281. break;
  282. case TextureMinFilter::NEAREST_TEXEL_NEAREST_MIPMAP:
  283. gl_filter = GL_NEAREST_MIPMAP_NEAREST;
  284. break;
  285. case TextureMinFilter::NEAREST_TEXEL_LINEAR_MIPMAP:
  286. gl_filter = GL_NEAREST_MIPMAP_LINEAR;
  287. break;
  288. case TextureMinFilter::LINEAR_TEXEL_NEAREST_MIPMAP:
  289. gl_filter = GL_LINEAR_MIPMAP_NEAREST;
  290. break;
  291. case TextureMinFilter::LINEAR_TEXEL_LINEAR_MIPMAP:
  292. gl_filter = GL_LINEAR_MIPMAP_LINEAR;
  293. break;
  294. case TextureMinFilter::NEAREST_TEXEL_NO_MIPMAP:
  295. default:
  296. gl_filter = GL_NEAREST;
  297. break;
  298. }
  299. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter);
  300. #endif
  301. }
  302. void Texture::GenerateMipmaps()
  303. {
  304. #if defined USE_D3D9
  305. m_data->m_texture->->GenerateMipSubLevels();
  306. #elif defined _XBOX
  307. /* FIXME: No direct mipmap generation support on X360 */
  308. #elif defined __CELLOS_LV2__
  309. glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
  310. glGenerateMipmapOES(GL_TEXTURE_2D);
  311. #else
  312. glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
  313. glGenerateMipmap(GL_TEXTURE_2D);
  314. #endif
  315. }
  316. Texture::~Texture()
  317. {
  318. #if defined USE_D3D9 || defined _XBOX
  319. m_data->m_texture->Release();
  320. #else
  321. glDeleteTextures(1, &m_data->m_texture);
  322. #endif
  323. delete m_data;
  324. }
  325. } /* namespace lol */