25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 

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