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.
 
 
 

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