Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 

329 wiersze
9.8 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. ShaderTexture Texture::GetTexture() const
  157. {
  158. ShaderTexture 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::NEAREST_TEXEL: m_data->m_mag_filter = D3DTEXF_POINT; break;
  222. case TextureMagFilter::LINEAR_TEXEL: m_data->m_mag_filter = D3DTEXF_LINEAR; break;
  223. }
  224. #else
  225. glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
  226. GLenum gl_filter;
  227. switch (filter)
  228. {
  229. case TextureMagFilter::NEAREST_TEXEL: gl_filter = GL_NEAREST; break;
  230. case TextureMagFilter::LINEAR_TEXEL: gl_filter = GL_LINEAR; break;
  231. }
  232. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter);
  233. #endif
  234. }
  235. void Texture::SetMinFiltering(TextureMinFilter filter)
  236. {
  237. #if defined _XBOX || defined USE_D3D9
  238. // In DirectX, texture filtering is a per-texture-unit state
  239. #define F(x, y) \
  240. m_data->m_min_filter = x; m_data->m_mip_filter = y;
  241. switch (filter)
  242. {
  243. case TextureMinFilter::NEAREST_TEXEL_NO_MIPMAP: F(D3DTEXF_POINT, D3DTEXF_NONE); break;
  244. case TextureMinFilter::LINEAR_TEXEL_NO_MIPMAP: F(D3DTEXF_POINT, D3DTEXF_NONE); break;
  245. case TextureMinFilter::NEAREST_TEXEL_NEAREST_MIPMAP: F(D3DTEXF_POINT, D3DTEXF_POINT); break;
  246. case TextureMinFilter::LINEAR_TEXEL_NEAREST_MIPMAP: F(D3DTEXF_LINEAR, D3DTEXF_POINT); break;
  247. case TextureMinFilter::NEAREST_TEXEL_LINEAR_MIPMAP: F(D3DTEXF_POINT, D3DTEXF_LINEAR); break;
  248. case TextureMinFilter::LINEAR_TEXEL_LINEAR_MIPMAP: F(D3DTEXF_LINEAR, D3DTEXF_LINEAR); break;
  249. }
  250. #undef F
  251. #else
  252. glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
  253. GLenum gl_filter;
  254. switch (filter)
  255. {
  256. case TextureMinFilter::NEAREST_TEXEL_NO_MIPMAP: gl_filter = GL_NEAREST; break;
  257. case TextureMinFilter::LINEAR_TEXEL_NO_MIPMAP: gl_filter = GL_LINEAR; break;
  258. case TextureMinFilter::NEAREST_TEXEL_NEAREST_MIPMAP: gl_filter = GL_NEAREST_MIPMAP_NEAREST; break;
  259. case TextureMinFilter::NEAREST_TEXEL_LINEAR_MIPMAP: gl_filter = GL_NEAREST_MIPMAP_LINEAR; break;
  260. case TextureMinFilter::LINEAR_TEXEL_NEAREST_MIPMAP: gl_filter = GL_LINEAR_MIPMAP_NEAREST; break;
  261. case TextureMinFilter::LINEAR_TEXEL_LINEAR_MIPMAP: gl_filter = GL_LINEAR_MIPMAP_LINEAR; break;
  262. }
  263. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter);
  264. #endif
  265. }
  266. void Texture::GenerateMipmaps()
  267. {
  268. #if defined USE_D3D9
  269. m_data->m_texture->->GenerateMipSubLevels();
  270. #elif defined _XBOX
  271. /* FIXME: No direct mipmap generation support on X360 */
  272. #elif defined __CELLOS_LV2__
  273. glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
  274. glGenerateMipmapOES(GL_TEXTURE_2D);
  275. #else
  276. glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
  277. glGenerateMipmap(GL_TEXTURE_2D);
  278. #endif
  279. }
  280. Texture::~Texture()
  281. {
  282. #if defined USE_D3D9 || defined _XBOX
  283. m_data->m_texture->Release();
  284. #else
  285. glDeleteTextures(1, &m_data->m_texture);
  286. #endif
  287. delete m_data;
  288. }
  289. } /* namespace lol */