525 lines
16 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. #elif defined _XBOX
  17. # include <xtl.h>
  18. # undef near /* Fuck Microsoft */
  19. # undef far /* Fuck Microsoft again */
  20. #endif
  21. namespace lol
  22. {
  23. //
  24. // The FramebufferData class
  25. // -------------------------
  26. //
  27. class FramebufferData
  28. {
  29. friend class Framebuffer;
  30. ibox2 m_saved_viewport;
  31. ivec2 m_size;
  32. bool m_bound;
  33. #if defined USE_D3D9
  34. IDirect3DDevice9 *m_dev;
  35. IDirect3DTexture9 *m_texture;
  36. IDirect3DSurface9 *m_surface, *m_back_surface;
  37. #elif defined _XBOX
  38. D3DDevice *m_dev;
  39. D3DTexture *m_texture;
  40. D3DSurface *m_surface, *m_back_surface;
  41. #else
  42. GLuint m_fbo, m_texture, m_depth;
  43. #endif
  44. };
  45. //
  46. // The FramebufferFormat struct
  47. // ----------------------
  48. //
  49. uint32_t FramebufferFormat::GetFormat()
  50. {
  51. switch (m_format)
  52. {
  53. #if defined USE_D3D9
  54. case R_16_F: return D3DFMT_R16F;
  55. case R_32_F: return D3DFMT_R32F;
  56. case RG_16:
  57. case RG_16_I:
  58. case RG_16_UI: return D3DFMT_G16R16;
  59. case RG_16_F: return D3DFMT_G16R16F;
  60. case RG_32_F: return D3DFMT_G32R32F;
  61. case RGB_8:
  62. case RGB_8_I:
  63. case RGB_8_UI: return D3DFMT_R8G8B8;
  64. case RGBA_8:
  65. case RGBA_8_I:
  66. case RGBA_8_UI: return D3DFMT_A8R8G8B8;
  67. case RGBA_16:
  68. case RGBA_16_I:
  69. case RGBA_16_UI: return D3DFMT_A16B16G16R16;
  70. case RGBA_16_F: return D3DFMT_A16B16G16R16F;
  71. case RGBA_32_F: return D3DFMT_A32B32G32R32F;
  72. #elif defined _XBOX
  73. case R_16_F: return D3DFMT_R16F;
  74. case R_32_F: return D3DFMT_R32F;
  75. case RG_16:
  76. case RG_16_I:
  77. case RG_16_UI: return D3DFMT_G16R16;
  78. case RG_16_F: return D3DFMT_G16R16F;
  79. case RG_32_F: return D3DFMT_G32R32F;
  80. case RGB_8:
  81. case RGB_8_I:
  82. case RGB_8_UI: return D3DFMT_X8R8G8B8;
  83. case RGBA_8:
  84. case RGBA_8_I:
  85. case RGBA_8_UI: return D3DFMT_A8R8G8B8;
  86. case RGBA_16:
  87. case RGBA_16_I:
  88. case RGBA_16_UI: return D3DFMT_A16B16G16R16;
  89. case RGBA_16_F: return D3DFMT_A16B16G16R16F;
  90. case RGBA_32_F: return D3DFMT_A32B32G32R32F;
  91. #elif defined __CELLOS_LV2__
  92. /* Supported drawable formats on the PS3: GL_ARGB_SCE, GL_RGB16F_ARB,
  93. * GL_RGBA16F_ARB, GL_RGB32F_ARB, GL_RGBA32F_ARB, GL_LUMINANCE32F_ARB. */
  94. case RGB_16_F: return GL_RGB16F_ARB;
  95. case RGB_32_F: return GL_RGB32F_ARB;
  96. case RGBA_8: return GL_ARGB_SCE;
  97. case RGBA_16_F: return GL_RGBA16F_ARB;
  98. case RGBA_32_F: return GL_RGBA32F_ARB;
  99. #elif defined HAVE_GLES_2X
  100. /* FIXME: incomplete */
  101. case RGBA_8:
  102. case RGBA_8_I:
  103. case RGBA_8_UI: return GL_RGBA;
  104. #elif defined __APPLE__ && defined __MACH__
  105. case R_8:
  106. case R_8_I:
  107. case R_8_UI:
  108. case R_8_F:
  109. case R_16:
  110. case R_16_I:
  111. case R_16_UI:
  112. case R_16_F:
  113. case R_32_I:
  114. case R_32:
  115. case R_32_UI:
  116. case R_32_F: return GL_RED;
  117. case RG_8:
  118. case RG_8_I:
  119. case RG_8_UI:
  120. case RG_8_F:
  121. case RG_16:
  122. case RG_16_I:
  123. case RG_16_UI:
  124. case RG_16_F:
  125. case RG_32:
  126. case RG_32_I:
  127. case RG_32_UI:
  128. case RG_32_F: return GL_RG;
  129. case RGB_8:
  130. case RGB_8_I:
  131. case RGB_8_UI:
  132. case RGB_8_F:
  133. case RGB_16:
  134. case RGB_16_I:
  135. case RGB_16_UI:
  136. case RGB_16_F:
  137. case RGB_32:
  138. case RGB_32_I:
  139. case RGB_32_UI:
  140. case RGB_32_F: return (m_invert_rgb)?(GL_BGR):(GL_RGB);
  141. case RGBA_8:
  142. case RGBA_8_I:
  143. case RGBA_8_UI:
  144. case RGBA_8_F:
  145. case RGBA_16:
  146. case RGBA_16_I:
  147. case RGBA_16_UI:
  148. case RGBA_16_F:
  149. case RGBA_32:
  150. case RGBA_32_I:
  151. case RGBA_32_UI:
  152. # if defined GL_BGRA
  153. case RGBA_32_F: return (m_invert_rgb)?(GL_BGRA):(GL_RGBA);
  154. # else
  155. case RGBA_32_F: return GL_RGBA;
  156. # endif
  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. # if defined GL_BGRA
  256. return (m_invert_rgb)?(GL_BGRA):(GL_RGBA);
  257. # else
  258. return GL_RGBA;
  259. # endif
  260. #endif
  261. default:
  262. ASSERT(false, "unknown framebuffer format order %d", m_format);
  263. return 0;
  264. }
  265. }
  266. //
  267. // The Framebuffer class
  268. // ----------------------
  269. //
  270. Framebuffer::Framebuffer(ivec2 size, FramebufferFormat fbo_format)
  271. : m_data(new FramebufferData)
  272. {
  273. m_data->m_size = size;
  274. m_data->m_bound = false;
  275. #if defined USE_D3D9
  276. m_data->m_dev = (IDirect3DDevice9 *)g_renderer->GetDevice();
  277. if (FAILED(m_data->m_dev->CreateTexture(size.x, size.y, 1,
  278. D3DUSAGE_RENDERTARGET,
  279. (D3DFORMAT)fbo_format.GetFormat(),
  280. D3DPOOL_DEFAULT,
  281. &m_data->m_texture, nullptr)))
  282. Abort();
  283. if (FAILED(m_data->m_texture->GetSurfaceLevel(0, &m_data->m_surface)))
  284. Abort();
  285. #elif defined _XBOX
  286. m_data->m_dev = (D3DDevice *)g_renderer->GetDevice();
  287. if (FAILED(m_data->m_dev->CreateTexture(size.x, size.y, 1, 0,
  288. (D3DFORMAT)fbo_format.GetFormat(),
  289. D3DPOOL_DEFAULT,
  290. &m_data->m_texture, nullptr)))
  291. Abort();
  292. if (FAILED(m_data->m_dev->CreateRenderTarget(size.x, size.y,
  293. (D3DFORMAT)fbo_format.GetFormat(),
  294. D3DMULTISAMPLE_NONE, 0, 0,
  295. &m_data->m_surface, nullptr)))
  296. Abort();
  297. #else
  298. # if GL_VERSION_1_1
  299. GLenum internal_format = fbo_format.GetFormat();
  300. GLenum format = fbo_format.GetFormatOrder();
  301. GLenum depth = GL_DEPTH_COMPONENT;
  302. # elif defined __CELLOS_LV2__
  303. /* Supported drawable formats on the PS3: GL_ARGB_SCE, GL_RGB16F_ARB,
  304. * GL_RGBA16F_ARB, GL_RGB32F_ARB, GL_RGBA32F_ARB, GL_LUMINANCE32F_ARB. */
  305. GLenum internal_format = fbo_format.GetFormat();
  306. GLenum format = fbo_format.GetFormatOrder();
  307. # elif GL_ES_VERSION_2_0
  308. /* In OpenGL ES, internal format and format must match. */
  309. GLenum internal_format = fbo_format.GetFormat();
  310. GLenum format = fbo_format.GetFormat();
  311. GLenum depth = GL_DEPTH_COMPONENT16; /* for WebGL */
  312. # else
  313. /* In OpenGL ES, internal format and format must match. */
  314. GLenum internal_format = fbo_format.GetFormat();
  315. GLenum format = fbo_format.GetFormat();
  316. # endif
  317. GLenum wrapmode = GL_CLAMP_TO_EDGE;
  318. GLenum filtering = GL_NEAREST;
  319. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  320. glGenFramebuffers(1, &m_data->m_fbo);
  321. glBindFramebuffer(GL_FRAMEBUFFER, m_data->m_fbo);
  322. # else
  323. glGenFramebuffersOES(1, &m_data->m_fbo);
  324. glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_data->m_fbo);
  325. # endif
  326. glGenTextures(1, &m_data->m_texture);
  327. glActiveTexture(GL_TEXTURE0);
  328. glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
  329. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapmode);
  330. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapmode);
  331. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
  332. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
  333. glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size.x, size.y, 0,
  334. format, GL_UNSIGNED_BYTE, nullptr);
  335. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  336. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
  337. GL_TEXTURE_2D, m_data->m_texture, 0);
  338. # else
  339. glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_EXT,
  340. GL_TEXTURE_2D, m_data->m_texture, 0);
  341. # endif
  342. m_data->m_depth = GL_INVALID_ENUM;
  343. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  344. if (depth != GL_INVALID_ENUM)
  345. {
  346. /* XXX: might not work on GL ES, see
  347. * http://stackoverflow.com/q/4041682/111461
  348. * See also http://qt-project.org/forums/viewthread/11734 */
  349. glGenRenderbuffers(1, &m_data->m_depth);
  350. glBindRenderbuffer(GL_RENDERBUFFER, m_data->m_depth);
  351. glRenderbufferStorage(GL_RENDERBUFFER, depth, size.x, size.y);
  352. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
  353. GL_RENDERBUFFER, m_data->m_depth);
  354. }
  355. # endif
  356. glBindTexture(GL_TEXTURE_2D, 0);
  357. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  358. GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  359. ASSERT(status == GL_FRAMEBUFFER_COMPLETE,
  360. "invalid framebuffer status 0x%x", status);
  361. # endif
  362. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  363. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  364. # else
  365. glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
  366. # endif
  367. #endif
  368. }
  369. Framebuffer::~Framebuffer()
  370. {
  371. #if defined USE_D3D9 || defined _XBOX
  372. m_data->m_surface->Release();
  373. m_data->m_texture->Release();
  374. #else
  375. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  376. glDeleteFramebuffers(1, &m_data->m_fbo);
  377. # else
  378. glDeleteFramebuffersOES(1, &m_data->m_fbo);
  379. # endif
  380. glDeleteTextures(1, &m_data->m_texture);
  381. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  382. if (m_data->m_depth != GL_INVALID_ENUM)
  383. glDeleteRenderbuffers(1, &m_data->m_depth);
  384. # endif
  385. #endif
  386. delete m_data;
  387. }
  388. TextureUniform Framebuffer::GetTextureUniform() const
  389. {
  390. TextureUniform ret;
  391. #if defined USE_D3D9 || defined _XBOX
  392. ret.m_flags = (uint64_t)(uintptr_t)m_data->m_texture;
  393. #else
  394. ret.m_flags = m_data->m_texture;
  395. #endif
  396. return ret;
  397. }
  398. ivec2 Framebuffer::GetSize() const
  399. {
  400. return m_data->m_size;
  401. }
  402. Image Framebuffer::GetImage() const
  403. {
  404. Image ret(m_data->m_size);
  405. #if defined USE_D3D9 || defined _XBOX
  406. /* TODO: implement D3D Framebuffer::GetImage() */
  407. #else
  408. u8vec4 *buffer = ret.Lock<PixelFormat::RGBA_8>();
  409. glReadPixels(0, 0, m_data->m_size.x, m_data->m_size.y,
  410. GL_RGBA, GL_UNSIGNED_BYTE, buffer);
  411. ret.Unlock(buffer);
  412. #endif
  413. return ret;
  414. }
  415. void Framebuffer::Bind()
  416. {
  417. ASSERT(!m_data->m_bound, "trying to bind an already bound framebuffer");
  418. #if defined USE_D3D9 || defined _XBOX
  419. if (FAILED(m_data->m_dev->GetRenderTarget(0, &m_data->m_back_surface)))
  420. Abort();
  421. if (FAILED(m_data->m_dev->SetRenderTarget(0, m_data->m_surface)))
  422. Abort();
  423. #else
  424. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  425. glBindFramebuffer(GL_FRAMEBUFFER, m_data->m_fbo);
  426. # else
  427. glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_data->m_fbo);
  428. # endif
  429. #endif
  430. /* FIXME: this should be done in the RenderContext object
  431. * instead, maybe by getting rid of Framebuffer::Bind() and
  432. * creating RenderContext::SetFramebuffer() instead. */
  433. m_data->m_saved_viewport = g_renderer->GetViewport();
  434. g_renderer->SetViewport(ibox2(ivec2::zero, m_data->m_size));
  435. m_data->m_bound = true;
  436. }
  437. void Framebuffer::Unbind()
  438. {
  439. ASSERT(m_data->m_bound, "trying to unbind an unbound framebuffer");
  440. #if defined USE_D3D9 || defined _XBOX
  441. # if defined _XBOX
  442. if (FAILED(m_data->m_dev->Resolve(D3DRESOLVE_RENDERTARGET0, nullptr,
  443. m_data->m_texture, nullptr, 0, 0, nullptr,
  444. 0, 0, nullptr)))
  445. Abort();
  446. # endif
  447. if (FAILED(m_data->m_dev->SetRenderTarget(0, m_data->m_back_surface)))
  448. Abort();
  449. m_data->m_back_surface->Release();
  450. #else
  451. # if GL_VERSION_1_1 || GL_ES_VERSION_2_0
  452. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  453. # else
  454. glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
  455. # endif
  456. #endif
  457. g_renderer->SetViewport(m_data->m_saved_viewport);
  458. m_data->m_bound = false;
  459. }
  460. } /* namespace lol */