506 lines
15 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. #elif defined _XBOX
  20. # include <xtl.h>
  21. # undef near /* Fuck Microsoft */
  22. # undef far /* Fuck Microsoft again */
  23. #endif
  24. using namespace std;
  25. namespace lol
  26. {
  27. //
  28. // The FramebufferData class
  29. // -------------------------
  30. //
  31. class FramebufferData
  32. {
  33. friend class Framebuffer;
  34. ibox2 m_saved_viewport;
  35. ivec2 m_size;
  36. bool m_bound;
  37. #if defined USE_D3D9
  38. IDirect3DDevice9 *m_dev;
  39. IDirect3DTexture9 *m_texture;
  40. IDirect3DSurface9 *m_surface, *m_back_surface;
  41. #elif defined _XBOX
  42. D3DDevice *m_dev;
  43. D3DTexture *m_texture;
  44. D3DSurface *m_surface, *m_back_surface;
  45. #else
  46. GLuint m_fbo, m_texture, m_depth;
  47. #endif
  48. };
  49. //
  50. // The FramebufferFormat struct
  51. // ----------------------
  52. //
  53. uint32_t FramebufferFormat::GetFormat()
  54. {
  55. switch (m_format)
  56. {
  57. #if defined USE_D3D9
  58. case R_16_F: return D3DFMT_R16F;
  59. case R_32_F: return D3DFMT_R32F;
  60. case RG_16:
  61. case RG_16_I:
  62. case RG_16_UI: return D3DFMT_G16R16;
  63. case RG_16_F: return D3DFMT_G16R16F;
  64. case RG_32_F: return D3DFMT_G32R32F;
  65. case RGB_8:
  66. case RGB_8_I:
  67. case RGB_8_UI: return D3DFMT_R8G8B8;
  68. case RGBA_8:
  69. case RGBA_8_I:
  70. case RGBA_8_UI: return D3DFMT_A8R8G8B8;
  71. case RGBA_16:
  72. case RGBA_16_I:
  73. case RGBA_16_UI: return D3DFMT_A16B16G16R16;
  74. case RGBA_16_F: return D3DFMT_A16B16G16R16F;
  75. case RGBA_32_F: return D3DFMT_A32B32G32R32F;
  76. #elif defined _XBOX
  77. case R_16_F: return D3DFMT_R16F;
  78. case R_32_F: return D3DFMT_R32F;
  79. case RG_16:
  80. case RG_16_I:
  81. case RG_16_UI: return D3DFMT_G16R16;
  82. case RG_16_F: return D3DFMT_G16R16F;
  83. case RG_32_F: return D3DFMT_G32R32F;
  84. case RGB_8:
  85. case RGB_8_I:
  86. case RGB_8_UI: return D3DFMT_X8R8G8B8;
  87. case RGBA_8:
  88. case RGBA_8_I:
  89. case RGBA_8_UI: return D3DFMT_A8R8G8B8;
  90. case RGBA_16:
  91. case RGBA_16_I:
  92. case RGBA_16_UI: return D3DFMT_A16B16G16R16;
  93. case RGBA_16_F: return D3DFMT_A16B16G16R16F;
  94. case RGBA_32_F: return D3DFMT_A32B32G32R32F;
  95. #elif defined __CELLOS_LV2__
  96. /* Supported drawable formats on the PS3: GL_ARGB_SCE, GL_RGB16F_ARB,
  97. * GL_RGBA16F_ARB, GL_RGB32F_ARB, GL_RGBA32F_ARB, GL_LUMINANCE32F_ARB. */
  98. case RGB_16_F: return GL_RGB16F_ARB;
  99. case RGB_32_F: return GL_RGB32F_ARB;
  100. case RGBA_8: return GL_ARGB_SCE;
  101. case RGBA_16_F: return GL_RGBA16F_ARB;
  102. case RGBA_32_F: return GL_RGBA32F_ARB;
  103. #elif defined HAVE_GLES_2X
  104. /* FIXME: incomplete */
  105. case RGBA_8:
  106. case RGBA_8_I:
  107. case RGBA_8_UI: return GL_RGBA;
  108. #elif defined __APPLE__ && defined __MACH__
  109. case R_8:
  110. case R_8_I:
  111. case R_8_UI:
  112. case R_8_F:
  113. case R_16:
  114. case R_16_I:
  115. case R_16_UI:
  116. case R_16_F:
  117. case R_32_I:
  118. case R_32:
  119. case R_32_UI:
  120. case R_32_F: return GL_RED;
  121. case RG_8:
  122. case RG_8_I:
  123. case RG_8_UI:
  124. case RG_8_F:
  125. case RG_16:
  126. case RG_16_I:
  127. case RG_16_UI:
  128. case RG_16_F:
  129. case RG_32:
  130. case RG_32_I:
  131. case RG_32_UI:
  132. case RG_32_F: return GL_RG;
  133. case RGB_8:
  134. case RGB_8_I:
  135. case RGB_8_UI:
  136. case RGB_8_F:
  137. case RGB_16:
  138. case RGB_16_I:
  139. case RGB_16_UI:
  140. case RGB_16_F:
  141. case RGB_32:
  142. case RGB_32_I:
  143. case RGB_32_UI:
  144. case RGB_32_F: return (m_invert_rgb)?(GL_BGR):(GL_RGB);
  145. case RGBA_8:
  146. case RGBA_8_I:
  147. case RGBA_8_UI:
  148. case RGBA_8_F:
  149. case RGBA_16:
  150. case RGBA_16_I:
  151. case RGBA_16_UI:
  152. case RGBA_16_F:
  153. case RGBA_32:
  154. case RGBA_32_I:
  155. case RGBA_32_UI:
  156. case RGBA_32_F: return (m_invert_rgb)?(GL_BGRA):(GL_RGBA);
  157. #else
  158. case R_8: return GL_R8;
  159. case R_8_I: return GL_R8I;
  160. case R_8_UI: return GL_R8UI;
  161. case R_16: return GL_R16;
  162. case R_16_I: return GL_R16I;
  163. case R_16_UI: return GL_R16UI;
  164. case R_16_F: return GL_R16F;
  165. case R_32_I: return GL_R32I;
  166. case R_32_UI: return GL_R32UI;
  167. case R_32_F: return GL_R32F;
  168. case RG_8: return GL_RG8;
  169. case RG_8_I: return GL_RG8I;
  170. case RG_8_UI: return GL_RG8UI;
  171. case RG_16: return GL_RG16;
  172. case RG_16_I: return GL_RG16I;
  173. case RG_16_UI: return GL_RG16UI;
  174. case RG_16_F: return GL_RG16F;
  175. case RG_32_I: return GL_RG32I;
  176. case RG_32_UI: return GL_RG32UI;
  177. case RG_32_F: return GL_RG32F;
  178. case RGB_8: return GL_RGB8;
  179. case RGB_8_I: return GL_RGB8I;
  180. case RGB_8_UI: return GL_RGB8UI;
  181. case RGB_16: return GL_RGB16;
  182. case RGB_16_I: return GL_RGB16I;
  183. case RGB_16_UI: return GL_RGB16UI;
  184. case RGB_16_F: return GL_RGB16F;
  185. case RGB_32_I: return GL_RGB32I;
  186. case RGB_32_UI: return GL_RGB32UI;
  187. case RGB_32_F: return GL_RGB32F;
  188. case RGBA_8: return GL_RGBA8;
  189. case RGBA_8_I: return GL_RGBA8I;
  190. case RGBA_8_UI: return GL_RGBA8UI;
  191. case RGBA_16: return GL_RGBA16;
  192. case RGBA_16_I: return GL_RGBA16I;
  193. case RGBA_16_UI: return GL_RGBA16UI;
  194. case RGBA_16_F: return GL_RGBA16F;
  195. case RGBA_32_I: return GL_RGBA32I;
  196. case RGBA_32_UI: return GL_RGBA32UI;
  197. case RGBA_32_F: return GL_RGBA32F;
  198. #endif
  199. default:
  200. ASSERT(false, "unknown framebuffer format %d", m_format);
  201. return 0;
  202. }
  203. }
  204. uint32_t FramebufferFormat::GetFormatOrder()
  205. {
  206. switch (m_format)
  207. {
  208. #if defined USE_D3D9 || defined _XBOX
  209. /* FIXME: not implemented at all */
  210. #elif defined __CELLOS_LV2__
  211. /* FIXME: not implemented at all */
  212. #elif defined HAVE_GLES_2X
  213. /* FIXME: incomplete */
  214. case R_8: case RG_8: case RGB_8: case RGBA_8:
  215. case R_8_I: case RG_8_I: case RGB_8_I: case RGBA_8_I:
  216. return GL_BYTE;
  217. case R_8_UI: case RG_8_UI: case RGB_8_UI: case RGBA_8_UI:
  218. return GL_UNSIGNED_BYTE;
  219. #elif defined __APPLE__ && defined __MACH__
  220. case R_8: case RG_8: case RGB_8: case RGBA_8:
  221. case R_8_I: case RG_8_I: case RGB_8_I: case RGBA_8_I:
  222. return GL_BYTE;
  223. case R_8_UI: case RG_8_UI: case RGB_8_UI: case RGBA_8_UI:
  224. return GL_UNSIGNED_BYTE;
  225. case R_16: case RG_16: case RGB_16: case RGBA_16:
  226. case R_16_I: case RG_16_I: case RGB_16_I: case RGBA_16_I:
  227. return GL_SHORT;
  228. case R_16_UI: case RG_16_UI: case RGB_16_UI: case RGBA_16_UI:
  229. return GL_UNSIGNED_SHORT;
  230. case R_16_F: case RG_16_F: case RGB_16_F: case RGBA_16_F:
  231. ASSERT(false, "unsupported framebuffer format order %d", m_format);
  232. return 0;
  233. case R_32_I: case RG_32_I: case RGB_32_I: case RGBA_32_I:
  234. return GL_INT;
  235. case R_32_UI: case RG_32_UI: case RGB_32_UI: case RGBA_32_UI:
  236. return GL_UNSIGNED_INT;
  237. case R_32_F: case RG_32_F: case RGB_32_F: case RGBA_32_F:
  238. return GL_FLOAT;
  239. #else
  240. case R_8: case R_8_I: case R_8_UI: case R_8_F:
  241. case R_16: case R_16_I: case R_16_UI: case R_16_F:
  242. case R_32: case R_32_I: case R_32_UI: case R_32_F:
  243. return GL_RED;
  244. case RG_8: case RG_8_I: case RG_8_UI: case RG_8_F:
  245. case RG_16: case RG_16_I: case RG_16_UI: case RG_16_F:
  246. case RG_32: case RG_32_I: case RG_32_UI: case RG_32_F:
  247. return GL_RG;
  248. case RGB_8: case RGB_8_I: case RGB_8_UI: case RGB_8_F:
  249. case RGB_16: case RGB_16_I: case RGB_16_UI: case RGB_16_F:
  250. case RGB_32: case RGB_32_I: case RGB_32_UI: case RGB_32_F:
  251. return m_invert_rgb ? GL_BGR : GL_RGB;
  252. case RGBA_8: case RGBA_8_I: case RGBA_8_UI: case RGBA_8_F:
  253. case RGBA_16: case RGBA_16_I: case RGBA_16_UI: case RGBA_16_F:
  254. case RGBA_32: case RGBA_32_I: case RGBA_32_UI: case RGBA_32_F:
  255. return (m_invert_rgb)?(GL_BGRA):(GL_RGBA);
  256. #endif
  257. default:
  258. ASSERT(false, "unknown framebuffer format order %d", m_format);
  259. return 0;
  260. }
  261. }
  262. //
  263. // The Framebuffer class
  264. // ----------------------
  265. //
  266. Framebuffer::Framebuffer(ivec2 size, FramebufferFormat fbo_format)
  267. : m_data(new FramebufferData)
  268. {
  269. m_data->m_size = size;
  270. m_data->m_bound = false;
  271. #if defined USE_D3D9
  272. m_data->m_dev = (IDirect3DDevice9 *)g_renderer->GetDevice();
  273. if (FAILED(m_data->m_dev->CreateTexture(size.x, size.y, 1,
  274. D3DUSAGE_RENDERTARGET,
  275. (D3DFORMAT)fbo_format.GetFormat(),
  276. D3DPOOL_DEFAULT,
  277. &m_data->m_texture, nullptr)))
  278. Abort();
  279. if (FAILED(m_data->m_texture->GetSurfaceLevel(0, &m_data->m_surface)))
  280. Abort();
  281. #elif defined _XBOX
  282. m_data->m_dev = (D3DDevice *)g_renderer->GetDevice();
  283. if (FAILED(m_data->m_dev->CreateTexture(size.x, size.y, 1, 0,
  284. (D3DFORMAT)fbo_format.GetFormat(),
  285. D3DPOOL_DEFAULT,
  286. &m_data->m_texture, nullptr)))
  287. Abort();
  288. if (FAILED(m_data->m_dev->CreateRenderTarget(size.x, size.y,
  289. (D3DFORMAT)fbo_format.GetFormat(),
  290. D3DMULTISAMPLE_NONE, 0, 0,
  291. &m_data->m_surface, nullptr)))
  292. Abort();
  293. #else
  294. # if GL_VERSION_1_1
  295. GLenum internal_format = fbo_format.GetFormat();
  296. GLenum format = fbo_format.GetFormatOrder();
  297. GLenum depth = GL_DEPTH_COMPONENT;
  298. # elif defined __CELLOS_LV2__
  299. /* Supported drawable formats on the PS3: GL_ARGB_SCE, GL_RGB16F_ARB,
  300. * GL_RGBA16F_ARB, GL_RGB32F_ARB, GL_RGBA32F_ARB, GL_LUMINANCE32F_ARB. */
  301. GLenum internal_format = fbo_format.GetFormat();
  302. GLenum format = fbo_format.GetFormatOrder();
  303. # elif GL_ES_VERSION_2_0
  304. /* In OpenGL ES, internal format and format must match. */
  305. GLenum internal_format = fbo_format.GetFormat();
  306. GLenum format = fbo_format.GetFormat();
  307. GLenum depth = GL_DEPTH_COMPONENT16; /* for WebGL */
  308. # else
  309. /* In OpenGL ES, internal format and format must match. */
  310. GLenum internal_format = fbo_format.GetFormat();
  311. GLenum format = fbo_format.GetFormat();
  312. # endif
  313. GLenum wrapmode = GL_CLAMP_TO_EDGE;
  314. GLenum filtering = GL_NEAREST;
  315. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  316. glGenFramebuffers(1, &m_data->m_fbo);
  317. glBindFramebuffer(GL_FRAMEBUFFER, m_data->m_fbo);
  318. # else
  319. glGenFramebuffersOES(1, &m_data->m_fbo);
  320. glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_data->m_fbo);
  321. # endif
  322. glGenTextures(1, &m_data->m_texture);
  323. glActiveTexture(GL_TEXTURE0);
  324. glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
  325. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapmode);
  326. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapmode);
  327. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
  328. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
  329. glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size.x, size.y, 0,
  330. format, GL_UNSIGNED_BYTE, nullptr);
  331. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  332. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
  333. GL_TEXTURE_2D, m_data->m_texture, 0);
  334. # else
  335. glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_EXT,
  336. GL_TEXTURE_2D, m_data->m_texture, 0);
  337. # endif
  338. m_data->m_depth = GL_INVALID_ENUM;
  339. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  340. if (depth != GL_INVALID_ENUM)
  341. {
  342. /* XXX: might not work on GL ES, see
  343. * http://stackoverflow.com/q/4041682/111461
  344. * See also http://qt-project.org/forums/viewthread/11734 */
  345. glGenRenderbuffers(1, &m_data->m_depth);
  346. glBindRenderbuffer(GL_RENDERBUFFER, m_data->m_depth);
  347. glRenderbufferStorage(GL_RENDERBUFFER, depth, size.x, size.y);
  348. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
  349. GL_RENDERBUFFER, m_data->m_depth);
  350. }
  351. # endif
  352. glBindTexture(GL_TEXTURE_2D, 0);
  353. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  354. GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  355. ASSERT(status == GL_FRAMEBUFFER_COMPLETE,
  356. "invalid framebuffer status 0x%x", status);
  357. # endif
  358. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  359. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  360. # else
  361. glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
  362. # endif
  363. #endif
  364. }
  365. Framebuffer::~Framebuffer()
  366. {
  367. #if defined USE_D3D9 || defined _XBOX
  368. m_data->m_surface->Release();
  369. m_data->m_texture->Release();
  370. #else
  371. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  372. glDeleteFramebuffers(1, &m_data->m_fbo);
  373. # else
  374. glDeleteFramebuffersOES(1, &m_data->m_fbo);
  375. # endif
  376. glDeleteTextures(1, &m_data->m_texture);
  377. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  378. if (m_data->m_depth != GL_INVALID_ENUM)
  379. glDeleteRenderbuffers(1, &m_data->m_depth);
  380. # endif
  381. #endif
  382. delete m_data;
  383. }
  384. ShaderTexture Framebuffer::GetTexture() const
  385. {
  386. ShaderTexture ret;
  387. #if defined USE_D3D9 || defined _XBOX
  388. ret.m_flags = (uint64_t)(uintptr_t)m_data->m_texture;
  389. #else
  390. ret.m_flags = m_data->m_texture;
  391. #endif
  392. return ret;
  393. }
  394. ivec2 Framebuffer::GetSize() const
  395. {
  396. return m_data->m_size;
  397. }
  398. void Framebuffer::Bind()
  399. {
  400. ASSERT(!m_data->m_bound, "trying to bind an already bound framebuffer");
  401. #if defined USE_D3D9 || defined _XBOX
  402. if (FAILED(m_data->m_dev->GetRenderTarget(0, &m_data->m_back_surface)))
  403. Abort();
  404. if (FAILED(m_data->m_dev->SetRenderTarget(0, m_data->m_surface)))
  405. Abort();
  406. #else
  407. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  408. glBindFramebuffer(GL_FRAMEBUFFER, m_data->m_fbo);
  409. # else
  410. glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_data->m_fbo);
  411. # endif
  412. #endif
  413. /* FIXME: this should be done in the RenderContext object
  414. * instead, maybe by getting rid of Framebuffer::Bind() and
  415. * creating RenderContext::SetFramebuffer() instead. */
  416. m_data->m_saved_viewport = g_renderer->GetViewport();
  417. g_renderer->SetViewport(ibox2(ivec2(0), m_data->m_size));
  418. m_data->m_bound = true;
  419. }
  420. void Framebuffer::Unbind()
  421. {
  422. ASSERT(m_data->m_bound, "trying to unbind an unbound framebuffer");
  423. #if defined USE_D3D9 || defined _XBOX
  424. # if defined _XBOX
  425. if (FAILED(m_data->m_dev->Resolve(D3DRESOLVE_RENDERTARGET0, nullptr,
  426. m_data->m_texture, nullptr, 0, 0, nullptr,
  427. 0, 0, nullptr)))
  428. Abort();
  429. # endif
  430. if (FAILED(m_data->m_dev->SetRenderTarget(0, m_data->m_back_surface)))
  431. Abort();
  432. m_data->m_back_surface->Release();
  433. #else
  434. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  435. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  436. # else
  437. glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
  438. # endif
  439. #endif
  440. g_renderer->SetViewport(m_data->m_saved_viewport);
  441. m_data->m_bound = false;
  442. }
  443. } /* namespace lol */