BsGLPixelBuffer.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. #include "BsGLPixelBuffer.h"
  2. #include "BsGLTexture.h"
  3. #include "BsGLSupport.h"
  4. #include "BsGLPixelFormat.h"
  5. #include "BsException.h"
  6. #include "BsBitwise.h"
  7. #include "BsGLRenderTexture.h"
  8. namespace BansheeEngine
  9. {
  10. GLPixelBuffer::GLPixelBuffer(UINT32 inWidth, UINT32 inHeight, UINT32 inDepth,
  11. PixelFormat inFormat, GpuBufferUsage usage):
  12. PixelBuffer(inWidth, inHeight, inDepth, inFormat, usage, false),
  13. mBuffer(inWidth, inHeight, inDepth, inFormat),
  14. mGLInternalFormat(GL_NONE)
  15. {
  16. mCurrentLockOptions = (GpuLockOptions)0;
  17. }
  18. GLPixelBuffer::~GLPixelBuffer()
  19. {
  20. // Force free buffer
  21. mBuffer.freeInternalBuffer();
  22. }
  23. void GLPixelBuffer::allocateBuffer()
  24. {
  25. if(mBuffer.getData())
  26. // Already allocated
  27. return;
  28. mBuffer.allocateInternalBuffer();
  29. // TODO: use PBO if we're HBU_DYNAMIC
  30. }
  31. void GLPixelBuffer::freeBuffer()
  32. {
  33. // Free buffer if we're STATIC to save memory
  34. if(mUsage & GBU_STATIC)
  35. {
  36. mBuffer.freeInternalBuffer();
  37. }
  38. }
  39. PixelData GLPixelBuffer::lockImpl(PixelVolume lockBox, GpuLockOptions options)
  40. {
  41. allocateBuffer();
  42. if(options != GBL_WRITE_ONLY_DISCARD)
  43. {
  44. // Download the old contents of the texture
  45. download(mBuffer);
  46. }
  47. mCurrentLockOptions = options;
  48. mLockedBox = lockBox;
  49. return mBuffer.getSubVolume(lockBox);
  50. }
  51. void GLPixelBuffer::unlockImpl(void)
  52. {
  53. if (mCurrentLockOptions != GBL_READ_ONLY)
  54. {
  55. // From buffer to card, only upload if was locked for writing
  56. upload(mCurrentLock, mLockedBox);
  57. }
  58. freeBuffer();
  59. }
  60. void GLPixelBuffer::upload(const PixelData &data, const PixelVolume &dest)
  61. {
  62. BS_EXCEPT(RenderingAPIException,
  63. "Upload not possible for this pixelbuffer type");
  64. }
  65. void GLPixelBuffer::download(const PixelData &data)
  66. {
  67. BS_EXCEPT(RenderingAPIException, "Download not possible for this pixelbuffer type");
  68. }
  69. void GLPixelBuffer::blitFromTexture(GLTextureBuffer *src)
  70. {
  71. blitFromTexture(src,
  72. PixelVolume(0,0,0,src->getWidth(),src->getHeight(),src->getDepth()),
  73. PixelVolume(0,0,0,mWidth,mHeight,mDepth)
  74. );
  75. }
  76. void GLPixelBuffer::blitFromTexture(GLTextureBuffer *src, const PixelVolume &srcBox, const PixelVolume &dstBox)
  77. {
  78. BS_EXCEPT(RenderingAPIException, "BlitFromTexture not possible for this pixelbuffer type");
  79. }
  80. void GLPixelBuffer::bindToFramebuffer(GLenum attachment, UINT32 zoffset)
  81. {
  82. BS_EXCEPT(RenderingAPIException, "Framebuffer bind not possible for this pixelbuffer type");
  83. }
  84. GLTextureBuffer::GLTextureBuffer(const String &baseName, GLenum target, GLuint id,
  85. GLint face, GLint level, GpuBufferUsage usage, bool crappyCard,
  86. bool writeGamma, UINT32 multisampleCount):
  87. GLPixelBuffer(0, 0, 0, PF_UNKNOWN, usage),
  88. mTarget(target), mFaceTarget(0), mTextureID(id), mFace(face), mLevel(level),
  89. mSoftwareMipmap(crappyCard)
  90. {
  91. // devise mWidth, mHeight and mDepth and mFormat
  92. GLint value = 0;
  93. glBindTexture( mTarget, mTextureID );
  94. // Get face identifier
  95. mFaceTarget = mTarget;
  96. if(mTarget == GL_TEXTURE_CUBE_MAP)
  97. mFaceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
  98. // Get width
  99. glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_WIDTH, &value);
  100. mWidth = value;
  101. // Get height
  102. if(target == GL_TEXTURE_1D)
  103. value = 1; // Height always 1 for 1D textures
  104. else
  105. glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_HEIGHT, &value);
  106. mHeight = value;
  107. // Get depth
  108. if(target != GL_TEXTURE_3D)
  109. value = 1; // Depth always 1 for non-3D textures
  110. else
  111. glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_DEPTH, &value);
  112. mDepth = value;
  113. // Get format
  114. glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_INTERNAL_FORMAT, &value);
  115. mGLInternalFormat = value;
  116. mFormat = GLPixelUtil::getClosestEngineFormat(value);
  117. // Default
  118. mRowPitch = mWidth;
  119. mSlicePitch = mHeight*mWidth;
  120. mSizeInBytes = PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat);
  121. // Set up pixel box
  122. mBuffer = PixelData(mWidth, mHeight, mDepth, mFormat);
  123. if(mWidth==0 || mHeight==0 || mDepth==0)
  124. /// We are invalid, do not allocate a buffer
  125. return;
  126. }
  127. GLTextureBuffer::~GLTextureBuffer()
  128. { }
  129. void GLTextureBuffer::upload(const PixelData &data, const PixelVolume &dest)
  130. {
  131. if((mUsage & TU_RENDERTARGET) != 0)
  132. BS_EXCEPT(NotImplementedException, "Writing to render texture from CPU not supported.");
  133. glBindTexture( mTarget, mTextureID );
  134. if(PixelUtil::isCompressed(data.getFormat()))
  135. {
  136. if(data.getFormat() != mFormat || !data.isConsecutive())
  137. BS_EXCEPT(InvalidParametersException,
  138. "Compressed images must be consecutive, in the source format");
  139. GLenum format = GLPixelUtil::getClosestGLInternalFormat(mFormat);
  140. // Data must be consecutive and at beginning of buffer as PixelStorei not allowed
  141. // for compressed formats
  142. switch(mTarget) {
  143. case GL_TEXTURE_1D:
  144. // some systems (e.g. old Apple) don't like compressed subimage calls
  145. // so prefer non-sub versions
  146. if (dest.left == 0)
  147. {
  148. glCompressedTexImage1D(GL_TEXTURE_1D, mLevel,
  149. format,
  150. dest.getWidth(),
  151. 0,
  152. data.getConsecutiveSize(),
  153. data.getData());
  154. }
  155. else
  156. {
  157. glCompressedTexSubImage1D(GL_TEXTURE_1D, mLevel,
  158. dest.left,
  159. dest.getWidth(),
  160. format, data.getConsecutiveSize(),
  161. data.getData());
  162. }
  163. break;
  164. case GL_TEXTURE_2D:
  165. case GL_TEXTURE_CUBE_MAP:
  166. // some systems (e.g. old Apple) don't like compressed subimage calls
  167. // so prefer non-sub versions
  168. if (dest.left == 0 && dest.top == 0)
  169. {
  170. glCompressedTexImage2D(mFaceTarget, mLevel,
  171. format,
  172. dest.getWidth(),
  173. dest.getHeight(),
  174. 0,
  175. data.getConsecutiveSize(),
  176. data.getData());
  177. }
  178. else
  179. {
  180. glCompressedTexSubImage2D(mFaceTarget, mLevel,
  181. dest.left, dest.top,
  182. dest.getWidth(), dest.getHeight(),
  183. format, data.getConsecutiveSize(),
  184. data.getData());
  185. }
  186. break;
  187. case GL_TEXTURE_3D:
  188. // some systems (e.g. old Apple) don't like compressed subimage calls
  189. // so prefer non-sub versions
  190. if (dest.left == 0 && dest.top == 0 && dest.front == 0)
  191. {
  192. glCompressedTexImage3D(GL_TEXTURE_3D, mLevel,
  193. format,
  194. dest.getWidth(),
  195. dest.getHeight(),
  196. dest.getDepth(),
  197. 0,
  198. data.getConsecutiveSize(),
  199. data.getData());
  200. }
  201. else
  202. {
  203. glCompressedTexSubImage3D(GL_TEXTURE_3D, mLevel,
  204. dest.left, dest.top, dest.front,
  205. dest.getWidth(), dest.getHeight(), dest.getDepth(),
  206. format, data.getConsecutiveSize(),
  207. data.getData());
  208. }
  209. break;
  210. }
  211. }
  212. else
  213. {
  214. if(data.getWidth() != data.getRowPitch())
  215. glPixelStorei(GL_UNPACK_ROW_LENGTH, data.getRowPitch());
  216. if(data.getHeight()*data.getWidth() != data.getSlicePitch())
  217. glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, (data.getSlicePitch()/data.getWidth()));
  218. if(data.getLeft() > 0 || data.getTop() > 0 || data.getFront() > 0)
  219. glPixelStorei(GL_UNPACK_SKIP_PIXELS, data.getLeft() + data.getRowPitch() * data.getTop() + data.getSlicePitch() * data.getFront());
  220. if((data.getWidth()*PixelUtil::getNumElemBytes(data.getFormat())) & 3) {
  221. // Standard alignment of 4 is not right
  222. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  223. }
  224. switch(mTarget) {
  225. case GL_TEXTURE_1D:
  226. glTexSubImage1D(GL_TEXTURE_1D, mLevel,
  227. dest.left,
  228. dest.getWidth(),
  229. GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()),
  230. data.getData());
  231. break;
  232. case GL_TEXTURE_2D:
  233. case GL_TEXTURE_CUBE_MAP:
  234. glTexSubImage2D(mFaceTarget, mLevel,
  235. dest.left, dest.top,
  236. dest.getWidth(), dest.getHeight(),
  237. GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()),
  238. data.getData());
  239. break;
  240. case GL_TEXTURE_3D:
  241. glTexSubImage3D(
  242. GL_TEXTURE_3D, mLevel,
  243. dest.left, dest.top, dest.front,
  244. dest.getWidth(), dest.getHeight(), dest.getDepth(),
  245. GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()),
  246. data.getData());
  247. break;
  248. }
  249. }
  250. // Restore defaults
  251. glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  252. if (GLEW_VERSION_1_2)
  253. glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
  254. glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
  255. glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
  256. }
  257. void GLTextureBuffer::download(const PixelData &data)
  258. {
  259. if((mUsage & TU_RENDERTARGET) != 0)
  260. BS_EXCEPT(NotImplementedException, "Reading from render texture to CPU not supported."); // TODO: This needs to be implemented
  261. if((mUsage & TU_DEPTHSTENCIL) != 0)
  262. BS_EXCEPT(NotImplementedException, "Reading from depth stencil texture to CPU not supported."); // TODO: This needs to be implemented
  263. if(data.getWidth() != getWidth() ||
  264. data.getHeight() != getHeight() ||
  265. data.getDepth() != getDepth())
  266. BS_EXCEPT(InvalidParametersException, "only download of entire buffer is supported by GL");
  267. glBindTexture( mTarget, mTextureID );
  268. if(PixelUtil::isCompressed(data.getFormat()))
  269. {
  270. if(data.getFormat() != mFormat || !data.isConsecutive())
  271. BS_EXCEPT(InvalidParametersException,
  272. "Compressed images must be consecutive, in the source format");
  273. // Data must be consecutive and at beginning of buffer as PixelStorei not allowed
  274. // for compressed formate
  275. glGetCompressedTexImage(mFaceTarget, mLevel, data.getData());
  276. }
  277. else
  278. {
  279. if(data.getWidth() != data.getRowPitch())
  280. glPixelStorei(GL_PACK_ROW_LENGTH, data.getRowPitch());
  281. if(data.getHeight()*data.getWidth() != data.getSlicePitch())
  282. glPixelStorei(GL_PACK_IMAGE_HEIGHT, (data.getSlicePitch()/data.getWidth()));
  283. if(data.getLeft() > 0 || data.getTop() > 0 || data.getFront() > 0)
  284. glPixelStorei(GL_PACK_SKIP_PIXELS, data.getLeft() + data.getRowPitch() * data.getTop() + data.getSlicePitch() * data.getFront());
  285. if((data.getWidth()*PixelUtil::getNumElemBytes(data.getFormat())) & 3) {
  286. // Standard alignment of 4 is not right
  287. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  288. }
  289. // We can only get the entire texture
  290. glGetTexImage(mFaceTarget, mLevel,
  291. GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()),
  292. data.getData());
  293. // Restore defaults
  294. glPixelStorei(GL_PACK_ROW_LENGTH, 0);
  295. glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
  296. glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
  297. glPixelStorei(GL_PACK_ALIGNMENT, 4);
  298. }
  299. }
  300. void GLTextureBuffer::bindToFramebuffer(GLenum attachment, UINT32 zoffset)
  301. {
  302. assert(zoffset < mDepth);
  303. switch(mTarget)
  304. {
  305. case GL_TEXTURE_1D:
  306. glFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, attachment,
  307. mFaceTarget, mTextureID, mLevel);
  308. break;
  309. case GL_TEXTURE_2D:
  310. case GL_TEXTURE_CUBE_MAP:
  311. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
  312. mFaceTarget, mTextureID, mLevel);
  313. break;
  314. case GL_TEXTURE_2D_MULTISAMPLE:
  315. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
  316. mFaceTarget, mTextureID, 0);
  317. break;
  318. case GL_TEXTURE_3D:
  319. glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, attachment,
  320. mFaceTarget, mTextureID, mLevel, zoffset);
  321. break;
  322. }
  323. }
  324. void GLTextureBuffer::copyFromFramebuffer(UINT32 zoffset)
  325. {
  326. glBindTexture(mTarget, mTextureID);
  327. switch(mTarget)
  328. {
  329. case GL_TEXTURE_1D:
  330. glCopyTexSubImage1D(mFaceTarget, mLevel, 0, 0, 0, mWidth);
  331. break;
  332. case GL_TEXTURE_2D:
  333. case GL_TEXTURE_CUBE_MAP:
  334. glCopyTexSubImage2D(mFaceTarget, mLevel, 0, 0, 0, 0, mWidth, mHeight);
  335. break;
  336. case GL_TEXTURE_3D:
  337. glCopyTexSubImage3D(mFaceTarget, mLevel, 0, 0, zoffset, 0, 0, mWidth, mHeight);
  338. break;
  339. }
  340. }
  341. /// Very fast texture-to-texture blitter and hardware bi/trilinear scaling implementation using FBO
  342. /// Destination texture must be 1D, 2D, 3D, or Cube
  343. /// Source texture must be 1D, 2D or 3D
  344. /// Supports compressed formats as both source and destination format, it will use the hardware DXT compressor
  345. /// if available.
  346. /// @author W.J. van der Laan
  347. void GLTextureBuffer::blitFromTexture(GLTextureBuffer *src, const PixelVolume &srcBox, const PixelVolume &dstBox)
  348. {
  349. //std::cerr << "GLTextureBuffer::blitFromTexture " <<
  350. //src->mTextureID << ":" << srcBox.left << "," << srcBox.top << "," << srcBox.right << "," << srcBox.bottom << " " <<
  351. //mTextureID << ":" << dstBox.left << "," << dstBox.top << "," << dstBox.right << "," << dstBox.bottom << std::endl;
  352. /// Store reference to FBO manager
  353. GLRTTManager *fboMan = static_cast<GLRTTManager *>(GLRTTManager::instancePtr());
  354. /// Save and clear GL state for rendering
  355. glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT |
  356. GL_FOG_BIT | GL_LIGHTING_BIT | GL_POLYGON_BIT | GL_SCISSOR_BIT | GL_STENCIL_BUFFER_BIT |
  357. GL_TEXTURE_BIT | GL_VIEWPORT_BIT);
  358. // Important to disable all other texture units
  359. if (GLEW_VERSION_1_2)
  360. {
  361. glActiveTextureARB(GL_TEXTURE0);
  362. }
  363. /// Disable alpha, depth and scissor testing, disable blending,
  364. /// disable culling, disble lighting, disable fog and reset foreground
  365. /// colour.
  366. glDisable(GL_ALPHA_TEST);
  367. glDisable(GL_DEPTH_TEST);
  368. glDisable(GL_SCISSOR_TEST);
  369. glDisable(GL_BLEND);
  370. glDisable(GL_CULL_FACE);
  371. glDisable(GL_LIGHTING);
  372. glDisable(GL_FOG);
  373. glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  374. /// Save and reset matrices
  375. glMatrixMode(GL_MODELVIEW);
  376. glPushMatrix();
  377. glLoadIdentity();
  378. glMatrixMode(GL_PROJECTION);
  379. glPushMatrix();
  380. glLoadIdentity();
  381. glMatrixMode(GL_TEXTURE);
  382. glPushMatrix();
  383. glLoadIdentity();
  384. /// Set up source texture
  385. glBindTexture(src->mTarget, src->mTextureID);
  386. /// Set filtering modes depending on the dimensions and source
  387. if(srcBox.getWidth()==dstBox.getWidth() &&
  388. srcBox.getHeight()==dstBox.getHeight() &&
  389. srcBox.getDepth()==dstBox.getDepth())
  390. {
  391. /// Dimensions match -- use nearest filtering (fastest and pixel correct)
  392. glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  393. glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  394. }
  395. else
  396. {
  397. /// Manual mipmaps, stay safe with bilinear filtering so that no
  398. /// intermipmap leakage occurs.
  399. glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  400. glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  401. }
  402. /// Clamp to edge (fastest)
  403. glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  404. glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  405. glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
  406. /// Set origin base level mipmap to make sure we source from the right mip
  407. /// level.
  408. glTexParameteri(src->mTarget, GL_TEXTURE_BASE_LEVEL, src->mLevel);
  409. /// Store old binding so it can be restored later
  410. GLint oldfb;
  411. glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &oldfb);
  412. /// Set up temporary FBO
  413. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboMan->getTemporaryFBO());
  414. GLuint tempTex = 0;
  415. if(!fboMan->checkFormat(mFormat))
  416. {
  417. /// If target format not directly supported, create intermediate texture
  418. GLenum tempFormat = GLPixelUtil::getClosestGLInternalFormat(fboMan->getSupportedAlternative(mFormat));
  419. glGenTextures(1, &tempTex);
  420. glBindTexture(GL_TEXTURE_2D, tempTex);
  421. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
  422. /// Allocate temporary texture of the size of the destination area
  423. glTexImage2D(GL_TEXTURE_2D, 0, tempFormat,
  424. GLPixelUtil::optionalPO2(dstBox.getWidth()), GLPixelUtil::optionalPO2(dstBox.getHeight()),
  425. 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
  426. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
  427. GL_TEXTURE_2D, tempTex, 0);
  428. /// Set viewport to size of destination slice
  429. glViewport(0, 0, dstBox.getWidth(), dstBox.getHeight());
  430. }
  431. else
  432. {
  433. /// We are going to bind directly, so set viewport to size and position of destination slice
  434. glViewport(dstBox.left, dstBox.top, dstBox.getWidth(), dstBox.getHeight());
  435. }
  436. /// Process each destination slice
  437. for(UINT32 slice=dstBox.front; slice<dstBox.back; ++slice)
  438. {
  439. if(!tempTex)
  440. {
  441. /// Bind directly
  442. bindToFramebuffer(GL_COLOR_ATTACHMENT0_EXT, slice);
  443. }
  444. /// Calculate source texture coordinates
  445. float u1 = (float)srcBox.left / (float)src->mWidth;
  446. float v1 = (float)srcBox.top / (float)src->mHeight;
  447. float u2 = (float)srcBox.right / (float)src->mWidth;
  448. float v2 = (float)srcBox.bottom / (float)src->mHeight;
  449. /// Calculate source slice for this destination slice
  450. float w = (float)(slice - dstBox.front) / (float)dstBox.getDepth();
  451. /// Get slice # in source
  452. w = w * (float)(srcBox.getDepth() + srcBox.front);
  453. /// Normalise to texture coordinate in 0.0 .. 1.0
  454. w = (w+0.5f) / (float)src->mDepth;
  455. /// Finally we're ready to rumble
  456. glBindTexture(src->mTarget, src->mTextureID);
  457. glEnable(src->mTarget);
  458. glBegin(GL_QUADS);
  459. glTexCoord3f(u1, v1, w);
  460. glVertex2f(-1.0f, -1.0f);
  461. glTexCoord3f(u2, v1, w);
  462. glVertex2f(1.0f, -1.0f);
  463. glTexCoord3f(u2, v2, w);
  464. glVertex2f(1.0f, 1.0f);
  465. glTexCoord3f(u1, v2, w);
  466. glVertex2f(-1.0f, 1.0f);
  467. glEnd();
  468. glDisable(src->mTarget);
  469. if(tempTex)
  470. {
  471. /// Copy temporary texture
  472. glBindTexture(mTarget, mTextureID);
  473. switch(mTarget)
  474. {
  475. case GL_TEXTURE_1D:
  476. glCopyTexSubImage1D(mFaceTarget, mLevel,
  477. dstBox.left,
  478. 0, 0, dstBox.getWidth());
  479. break;
  480. case GL_TEXTURE_2D:
  481. case GL_TEXTURE_CUBE_MAP:
  482. glCopyTexSubImage2D(mFaceTarget, mLevel,
  483. dstBox.left, dstBox.top,
  484. 0, 0, dstBox.getWidth(), dstBox.getHeight());
  485. break;
  486. case GL_TEXTURE_3D:
  487. glCopyTexSubImage3D(mFaceTarget, mLevel,
  488. dstBox.left, dstBox.top, slice,
  489. 0, 0, dstBox.getWidth(), dstBox.getHeight());
  490. break;
  491. }
  492. }
  493. }
  494. /// Reset source texture to sane state
  495. glBindTexture(src->mTarget, src->mTextureID);
  496. glTexParameteri(src->mTarget, GL_TEXTURE_BASE_LEVEL, 0);
  497. /// Detach texture from temporary framebuffer
  498. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
  499. GL_RENDERBUFFER_EXT, 0);
  500. /// Restore old framebuffer
  501. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, oldfb);
  502. /// Restore matrix stacks and render state
  503. glMatrixMode(GL_TEXTURE);
  504. glPopMatrix();
  505. glMatrixMode(GL_PROJECTION);
  506. glPopMatrix();
  507. glMatrixMode(GL_MODELVIEW);
  508. glPopMatrix();
  509. glPopAttrib();
  510. glDeleteTextures(1, &tempTex);
  511. }
  512. GLRenderBuffer::GLRenderBuffer(GLenum format, UINT32 width, UINT32 height, GLsizei numSamples):
  513. GLPixelBuffer(width, height, 1, GLPixelUtil::getClosestEngineFormat(format), GBU_DYNAMIC),
  514. mRenderbufferID(0)
  515. {
  516. mGLInternalFormat = format;
  517. /// Generate renderbuffer
  518. glGenRenderbuffersEXT(1, &mRenderbufferID);
  519. /// Bind it to FBO
  520. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mRenderbufferID);
  521. /// Allocate storage for depth buffer
  522. if (numSamples > 0)
  523. {
  524. glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT,
  525. numSamples, format, width, height);
  526. }
  527. else
  528. {
  529. glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format,
  530. width, height);
  531. }
  532. }
  533. GLRenderBuffer::~GLRenderBuffer()
  534. {
  535. /// Generate renderbuffer
  536. glDeleteRenderbuffersEXT(1, &mRenderbufferID);
  537. }
  538. void GLRenderBuffer::bindToFramebuffer(GLenum attachment, UINT32 zoffset)
  539. {
  540. assert(zoffset < mDepth);
  541. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment,
  542. GL_RENDERBUFFER_EXT, mRenderbufferID);
  543. }
  544. };