COpenGLTexture.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998
  1. // Copyright (C) 2002-2012 Nikolaus Gebhardt
  2. // This file is part of the "Irrlicht Engine".
  3. // For conditions of distribution and use, see copyright notice in irrlicht.h
  4. #include "IrrCompileConfig.h"
  5. #ifdef _IRR_COMPILE_WITH_OPENGL_
  6. #include "irrTypes.h"
  7. #include "COpenGLTexture.h"
  8. #include "COpenGLDriver.h"
  9. #include "os.h"
  10. #include "CColorConverter.h"
  11. #include "IAttributes.h"
  12. #include "IrrlichtDevice.h"
  13. #include "irrString.h"
  14. namespace irr
  15. {
  16. namespace video
  17. {
  18. extern bool useCoreContext;
  19. //! constructor for usual textures
  20. COpenGLTexture::COpenGLTexture(IImage* origImage, const io::path& name, void* mipmapData, COpenGLDriver* driver)
  21. : ITexture(name), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0), MipImage(0),
  22. TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT),
  23. PixelType(GL_UNSIGNED_BYTE), MipLevelStored(0), MipmapLegacyMode(true),
  24. IsRenderTarget(false), AutomaticMipmapUpdate(false),
  25. ReadOnlyLock(false), KeepImage(true)
  26. {
  27. #ifdef _DEBUG
  28. setDebugName("COpenGLTexture");
  29. #endif
  30. HasMipMaps = Driver->getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);
  31. getImageValues(origImage);
  32. glGenTextures(1, &TextureName);
  33. if (ImageSize==TextureSize)
  34. {
  35. Image = Driver->createImage(ColorFormat, ImageSize);
  36. origImage->copyTo(Image);
  37. }
  38. else
  39. {
  40. Image = Driver->createImage(ColorFormat, TextureSize);
  41. // scale texture
  42. origImage->copyToScaling(Image);
  43. }
  44. uploadTexture(true, mipmapData);
  45. if (!KeepImage)
  46. {
  47. Image->drop();
  48. Image=0;
  49. }
  50. }
  51. //! constructor for basic setup (only for derived classes)
  52. COpenGLTexture::COpenGLTexture(const io::path& name, COpenGLDriver* driver)
  53. : ITexture(name), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0), MipImage(0),
  54. TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT),
  55. PixelType(GL_UNSIGNED_BYTE), MipLevelStored(0), HasMipMaps(true),
  56. MipmapLegacyMode(true), IsRenderTarget(false), AutomaticMipmapUpdate(false),
  57. ReadOnlyLock(false), KeepImage(true)
  58. {
  59. #ifdef _DEBUG
  60. setDebugName("COpenGLTexture");
  61. #endif
  62. }
  63. //! destructor
  64. COpenGLTexture::~COpenGLTexture()
  65. {
  66. if (TextureName)
  67. glDeleteTextures(1, &TextureName);
  68. if (Image)
  69. Image->drop();
  70. }
  71. //! Choose best matching color format, based on texture creation flags
  72. ECOLOR_FORMAT COpenGLTexture::getBestColorFormat(ECOLOR_FORMAT format)
  73. {
  74. ECOLOR_FORMAT destFormat = ECF_A8R8G8B8;
  75. switch (format)
  76. {
  77. case ECF_A1R5G5B5:
  78. if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT))
  79. destFormat = ECF_A1R5G5B5;
  80. break;
  81. case ECF_R5G6B5:
  82. if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT))
  83. destFormat = ECF_A1R5G5B5;
  84. break;
  85. case ECF_A8R8G8B8:
  86. if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) ||
  87. Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))
  88. destFormat = ECF_A1R5G5B5;
  89. break;
  90. case ECF_R8G8B8:
  91. if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) ||
  92. Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))
  93. destFormat = ECF_A1R5G5B5;
  94. default:
  95. break;
  96. }
  97. if (Driver->getTextureCreationFlag(ETCF_NO_ALPHA_CHANNEL))
  98. {
  99. switch (destFormat)
  100. {
  101. case ECF_A1R5G5B5:
  102. destFormat = ECF_R5G6B5;
  103. break;
  104. case ECF_A8R8G8B8:
  105. destFormat = ECF_R8G8B8;
  106. break;
  107. default:
  108. break;
  109. }
  110. }
  111. return destFormat;
  112. }
  113. //! Get opengl values for the GPU texture storage
  114. GLint COpenGLTexture::getOpenGLFormatAndParametersFromColorFormat(ECOLOR_FORMAT format,
  115. GLint& filtering,
  116. GLenum& colorformat,
  117. GLenum& type)
  118. {
  119. // default
  120. filtering = GL_LINEAR;
  121. colorformat = GL_RGBA;
  122. type = GL_UNSIGNED_BYTE;
  123. GLenum internalformat = GL_RGBA;
  124. switch(format)
  125. {
  126. case ECF_A1R5G5B5:
  127. colorformat=GL_BGRA_EXT;
  128. type=GL_UNSIGNED_SHORT_1_5_5_5_REV;
  129. internalformat = GL_RGBA;
  130. break;
  131. case ECF_R5G6B5:
  132. colorformat=GL_RGB;
  133. type=GL_UNSIGNED_SHORT_5_6_5;
  134. internalformat = GL_RGB;
  135. break;
  136. case ECF_R8G8B8:
  137. colorformat=GL_BGR;
  138. type=GL_UNSIGNED_BYTE;
  139. internalformat = GL_RGB;
  140. break;
  141. case ECF_A8R8G8B8:
  142. colorformat=GL_BGRA_EXT;
  143. if (Driver->Version > 101)
  144. type=GL_UNSIGNED_INT_8_8_8_8_REV;
  145. internalformat = GL_RGBA;
  146. break;
  147. // _rg formats.
  148. case ECF_R8:
  149. colorformat = GL_RED;
  150. type = GL_UNSIGNED_BYTE;
  151. internalformat = GL_R8;
  152. break;
  153. case ECF_R16:
  154. colorformat = GL_RED;
  155. type = GL_UNSIGNED_SHORT;
  156. internalformat = GL_R16;
  157. break;
  158. case ECF_R8G8:
  159. colorformat = GL_RG;
  160. type = GL_UNSIGNED_BYTE;
  161. internalformat = GL_RG8;
  162. break;
  163. case ECF_R16G16:
  164. colorformat = GL_RG;
  165. type = GL_UNSIGNED_SHORT;
  166. internalformat = GL_RG16;
  167. break;
  168. // Floating Point texture formats. Thanks to Patryk "Nadro" Nadrowski.
  169. case ECF_R16F:
  170. {
  171. #ifdef GL_ARB_texture_rg
  172. filtering = GL_NEAREST;
  173. colorformat = GL_RED;
  174. type = GL_FLOAT;
  175. internalformat = GL_R16F;
  176. #else
  177. ColorFormat = ECF_A8R8G8B8;
  178. internalformat = GL_RGB8;
  179. #endif
  180. }
  181. break;
  182. case ECF_G16R16F:
  183. {
  184. #ifdef GL_ARB_texture_rg
  185. filtering = GL_NEAREST;
  186. colorformat = GL_RG;
  187. type = GL_FLOAT;
  188. internalformat = GL_RG16F;
  189. #else
  190. ColorFormat = ECF_A8R8G8B8;
  191. internalformat = GL_RGB8;
  192. #endif
  193. }
  194. break;
  195. case ECF_A16B16G16R16F:
  196. {
  197. #ifdef GL_ARB_texture_rg
  198. filtering = GL_NEAREST;
  199. colorformat = GL_RGBA;
  200. type = GL_FLOAT;
  201. internalformat = GL_RGBA16F_ARB;
  202. #else
  203. ColorFormat = ECF_A8R8G8B8;
  204. internalformat = GL_RGBA8;
  205. #endif
  206. }
  207. break;
  208. case ECF_R32F:
  209. {
  210. #ifdef GL_ARB_texture_rg
  211. filtering = GL_NEAREST;
  212. colorformat = GL_RED;
  213. type = GL_FLOAT;
  214. internalformat = GL_R32F;
  215. #else
  216. ColorFormat = ECF_A8R8G8B8;
  217. internalformat = GL_RGB8;
  218. #endif
  219. }
  220. break;
  221. case ECF_G32R32F:
  222. {
  223. #ifdef GL_ARB_texture_rg
  224. filtering = GL_NEAREST;
  225. colorformat = GL_RG;
  226. type = GL_FLOAT;
  227. internalformat = GL_RG32F;
  228. #else
  229. ColorFormat = ECF_A8R8G8B8;
  230. internalformat = GL_RGB8;
  231. #endif
  232. }
  233. break;
  234. case ECF_A32B32G32R32F:
  235. {
  236. #ifdef GL_ARB_texture_float
  237. filtering = GL_NEAREST;
  238. colorformat = GL_RGBA;
  239. type = GL_FLOAT;
  240. internalformat = GL_RGBA32F_ARB;
  241. #else
  242. ColorFormat = ECF_A8R8G8B8;
  243. internalformat = GL_RGBA8;
  244. #endif
  245. }
  246. break;
  247. default:
  248. {
  249. os::Printer::log("Unsupported texture format", ELL_ERROR);
  250. internalformat = GL_RGBA8;
  251. }
  252. }
  253. //#if defined(GL_ARB_framebuffer_sRGB) || defined(GL_EXT_framebuffer_sRGB)
  254. // if (Driver->Params.HandleSRGB)
  255. // {
  256. // if (internalformat==GL_RGBA)
  257. // internalformat=GL_SRGB_ALPHA_EXT;
  258. // else if (internalformat==GL_RGB)
  259. // internalformat=GL_SRGB_EXT;
  260. // }
  261. //#endif
  262. return internalformat;
  263. }
  264. // prepare values ImageSize, TextureSize, and ColorFormat based on image
  265. void COpenGLTexture::getImageValues(IImage* image)
  266. {
  267. if (!image)
  268. {
  269. os::Printer::log("No image for OpenGL texture.", ELL_ERROR);
  270. return;
  271. }
  272. ImageSize = image->getDimension();
  273. if ( !ImageSize.Width || !ImageSize.Height)
  274. {
  275. os::Printer::log("Invalid size of image for OpenGL Texture.", ELL_ERROR);
  276. return;
  277. }
  278. const f32 ratio = (f32)ImageSize.Width/(f32)ImageSize.Height;
  279. if ((ImageSize.Width>Driver->MaxTextureSize) && (ratio >= 1.0f))
  280. {
  281. ImageSize.Width = Driver->MaxTextureSize;
  282. ImageSize.Height = (u32)(Driver->MaxTextureSize/ratio);
  283. }
  284. else if (ImageSize.Height>Driver->MaxTextureSize)
  285. {
  286. ImageSize.Height = Driver->MaxTextureSize;
  287. ImageSize.Width = (u32)(Driver->MaxTextureSize*ratio);
  288. }
  289. TextureSize=ImageSize.getOptimalSize(!Driver->queryFeature(EVDF_TEXTURE_NPOT));
  290. const core::dimension2du max_size = Driver->getDriverAttributes()
  291. .getAttributeAsDimension2d("MAX_TEXTURE_SIZE");
  292. if (max_size.Width> 0 && TextureSize.Width > max_size.Width)
  293. {
  294. TextureSize.Width = max_size.Width;
  295. }
  296. if (max_size.Height> 0 && TextureSize.Height > max_size.Height)
  297. {
  298. TextureSize.Height = max_size.Height;
  299. }
  300. ColorFormat = getBestColorFormat(image->getColorFormat());
  301. }
  302. //! copies the the texture into an open gl texture.
  303. void COpenGLTexture::uploadTexture(bool newTexture, void* mipmapData, u32 level)
  304. {
  305. // check which image needs to be uploaded
  306. IImage* image = level?MipImage:Image;
  307. if (!image)
  308. {
  309. os::Printer::log("No image for OpenGL texture to upload", ELL_ERROR);
  310. return;
  311. }
  312. // get correct opengl color data values
  313. GLenum oldInternalFormat = InternalFormat;
  314. GLint filtering;
  315. InternalFormat = getOpenGLFormatAndParametersFromColorFormat(ColorFormat, filtering, PixelFormat, PixelType);
  316. // make sure we don't change the internal format of existing images
  317. if (!newTexture)
  318. InternalFormat=oldInternalFormat;
  319. Driver->setActiveTexture(0, this);
  320. if (Driver->testGLError())
  321. os::Printer::log("Could not bind Texture", ELL_ERROR);
  322. // mipmap handling for main texture
  323. if (!level && newTexture)
  324. {
  325. #ifndef DISABLE_MIPMAPPING
  326. #ifdef GL_SGIS_generate_mipmap
  327. // auto generate if possible and no mipmap data is given
  328. if (HasMipMaps && !mipmapData && Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE))
  329. {
  330. if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED) && !useCoreContext)
  331. glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST);
  332. else if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY) && !useCoreContext)
  333. glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
  334. else if (!useCoreContext)
  335. glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_DONT_CARE);
  336. AutomaticMipmapUpdate=true;
  337. if (!Driver->queryFeature(EVDF_FRAMEBUFFER_OBJECT))
  338. {
  339. glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
  340. MipmapLegacyMode=true;
  341. }
  342. else
  343. MipmapLegacyMode=false;
  344. }
  345. else
  346. #endif
  347. {
  348. // Either generate manually due to missing capability
  349. // or use predefined mipmap data
  350. AutomaticMipmapUpdate=false;
  351. regenerateMipMapLevels(mipmapData);
  352. }
  353. if (HasMipMaps) // might have changed in regenerateMipMapLevels
  354. {
  355. // enable bilinear mipmap filter
  356. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
  357. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  358. }
  359. else
  360. #else
  361. HasMipMaps=false;
  362. os::Printer::log("Did not create OpenGL texture mip maps.", ELL_INFORMATION);
  363. #endif
  364. {
  365. // enable bilinear filter without mipmaps
  366. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  367. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  368. }
  369. }
  370. // now get image data and upload to GPU
  371. void* source = image->lock();
  372. if (newTexture)
  373. glTexImage2D(GL_TEXTURE_2D, level, InternalFormat, image->getDimension().Width,
  374. image->getDimension().Height, 0, PixelFormat, PixelType, source);
  375. else
  376. glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, image->getDimension().Width,
  377. image->getDimension().Height, PixelFormat, PixelType, source);
  378. image->unlock();
  379. if (!MipmapLegacyMode && AutomaticMipmapUpdate)
  380. {
  381. if (!useCoreContext)
  382. glEnable(GL_TEXTURE_2D);
  383. Driver->extGlGenerateMipmap(GL_TEXTURE_2D);
  384. }
  385. if (Driver->testGLError())
  386. os::Printer::log("Could not glTexImage2D", ELL_ERROR);
  387. }
  388. //! lock function
  389. void* COpenGLTexture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel)
  390. {
  391. // store info about which image is locked
  392. IImage* image = (mipmapLevel==0)?Image:MipImage;
  393. ReadOnlyLock |= (mode==ETLM_READ_ONLY);
  394. MipLevelStored = mipmapLevel;
  395. if (!ReadOnlyLock && mipmapLevel)
  396. {
  397. #ifdef GL_SGIS_generate_mipmap
  398. if (Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE))
  399. {
  400. // do not automatically generate and update mipmaps
  401. glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
  402. }
  403. #endif
  404. AutomaticMipmapUpdate=false;
  405. }
  406. // if data not available or might have changed on GPU download it
  407. if (!image || IsRenderTarget)
  408. {
  409. // prepare the data storage if necessary
  410. if (!image)
  411. {
  412. if (mipmapLevel)
  413. {
  414. u32 i=0;
  415. u32 width = TextureSize.Width;
  416. u32 height = TextureSize.Height;
  417. do
  418. {
  419. if (width>1)
  420. width>>=1;
  421. if (height>1)
  422. height>>=1;
  423. ++i;
  424. }
  425. while (i != mipmapLevel);
  426. MipImage = image = Driver->createImage(ECF_A8R8G8B8, core::dimension2du(width,height));
  427. }
  428. else
  429. Image = image = Driver->createImage(ECF_A8R8G8B8, ImageSize);
  430. ColorFormat = ECF_A8R8G8B8;
  431. }
  432. if (!image)
  433. return 0;
  434. if (mode != ETLM_WRITE_ONLY)
  435. {
  436. u8* pixels = static_cast<u8*>(image->lock());
  437. if (!pixels)
  438. return 0;
  439. // we need to keep the correct texture bound later on
  440. GLint tmpTexture;
  441. glGetIntegerv(GL_TEXTURE_BINDING_2D, &tmpTexture);
  442. glBindTexture(GL_TEXTURE_2D, TextureName);
  443. // we need to flip textures vertical
  444. // however, it seems that this does not hold for mipmap
  445. // textures, for unknown reasons.
  446. // allows to read pixels in top-to-bottom order
  447. #ifdef GL_MESA_pack_invert
  448. if (!mipmapLevel && Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_MESA_pack_invert))
  449. glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
  450. #endif
  451. // download GPU data as ARGB8 to pixels;
  452. glGetTexImage(GL_TEXTURE_2D, mipmapLevel, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
  453. if (!mipmapLevel)
  454. {
  455. #ifdef GL_MESA_pack_invert
  456. if (Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_MESA_pack_invert))
  457. glPixelStorei(GL_PACK_INVERT_MESA, GL_FALSE);
  458. else
  459. #endif
  460. {
  461. // opengl images are horizontally flipped, so we have to fix that here.
  462. const s32 pitch=image->getPitch();
  463. u8* p2 = pixels + (image->getDimension().Height - 1) * pitch;
  464. u8* tmpBuffer = new u8[pitch];
  465. for (u32 i=0; i < image->getDimension().Height; i += 2)
  466. {
  467. memcpy(tmpBuffer, pixels, pitch);
  468. memcpy(pixels, p2, pitch);
  469. memcpy(p2, tmpBuffer, pitch);
  470. pixels += pitch;
  471. p2 -= pitch;
  472. }
  473. delete [] tmpBuffer;
  474. }
  475. }
  476. image->unlock();
  477. //reset old bound texture
  478. glBindTexture(GL_TEXTURE_2D, tmpTexture);
  479. }
  480. }
  481. return image->lock();
  482. }
  483. //! unlock function
  484. void COpenGLTexture::unlock()
  485. {
  486. // test if miplevel or main texture was locked
  487. IImage* image = MipImage?MipImage:Image;
  488. if (!image)
  489. return;
  490. // unlock image to see changes
  491. image->unlock();
  492. // copy texture data to GPU
  493. if (!ReadOnlyLock)
  494. uploadTexture(false, 0, MipLevelStored);
  495. ReadOnlyLock = false;
  496. // cleanup local image
  497. if (MipImage)
  498. {
  499. MipImage->drop();
  500. MipImage=0;
  501. }
  502. else if (!KeepImage)
  503. {
  504. Image->drop();
  505. Image=0;
  506. }
  507. // update information
  508. if (Image)
  509. ColorFormat=Image->getColorFormat();
  510. else
  511. ColorFormat=ECF_A8R8G8B8;
  512. }
  513. //! Returns size of the original image.
  514. const core::dimension2d<u32>& COpenGLTexture::getOriginalSize() const
  515. {
  516. return ImageSize;
  517. }
  518. //! Returns size of the texture.
  519. const core::dimension2d<u32>& COpenGLTexture::getSize() const
  520. {
  521. return TextureSize;
  522. }
  523. //! returns driver type of texture, i.e. the driver, which created the texture
  524. E_DRIVER_TYPE COpenGLTexture::getDriverType() const
  525. {
  526. return EDT_OPENGL;
  527. }
  528. //! returns color format of texture
  529. ECOLOR_FORMAT COpenGLTexture::getColorFormat() const
  530. {
  531. return ColorFormat;
  532. }
  533. //! returns pitch of texture (in bytes)
  534. u32 COpenGLTexture::getPitch() const
  535. {
  536. if (Image)
  537. return Image->getPitch();
  538. else
  539. return 0;
  540. }
  541. //! return open gl texture name
  542. GLuint COpenGLTexture::getOpenGLTextureName() const
  543. {
  544. return TextureName;
  545. }
  546. //! Returns whether this texture has mipmaps
  547. bool COpenGLTexture::hasMipMaps() const
  548. {
  549. return HasMipMaps;
  550. }
  551. //! Regenerates the mip map levels of the texture. Useful after locking and
  552. //! modifying the texture
  553. void COpenGLTexture::regenerateMipMapLevels(void* mipmapData)
  554. {
  555. if (AutomaticMipmapUpdate || !HasMipMaps || !Image)
  556. return;
  557. if ((Image->getDimension().Width==1) && (Image->getDimension().Height==1))
  558. return;
  559. // Manually create mipmaps or use prepared version
  560. u32 width=Image->getDimension().Width;
  561. u32 height=Image->getDimension().Height;
  562. u32 i=0;
  563. u8* target = static_cast<u8*>(mipmapData);
  564. do
  565. {
  566. if (width>1)
  567. width>>=1;
  568. if (height>1)
  569. height>>=1;
  570. ++i;
  571. if (!target)
  572. target = new u8[width*height*Image->getBytesPerPixel()];
  573. // create scaled version if no mipdata available
  574. if (!mipmapData)
  575. Image->copyToScaling(target, width, height, Image->getColorFormat());
  576. glTexImage2D(GL_TEXTURE_2D, i, InternalFormat, width, height,
  577. 0, PixelFormat, PixelType, target);
  578. // get next prepared mipmap data if available
  579. if (mipmapData)
  580. {
  581. mipmapData = static_cast<u8*>(mipmapData)+width*height*Image->getBytesPerPixel();
  582. target = static_cast<u8*>(mipmapData);
  583. }
  584. }
  585. while (width!=1 || height!=1);
  586. // cleanup
  587. if (!mipmapData)
  588. delete [] target;
  589. }
  590. bool COpenGLTexture::isRenderTarget() const
  591. {
  592. return IsRenderTarget;
  593. }
  594. void COpenGLTexture::setIsRenderTarget(bool isTarget)
  595. {
  596. IsRenderTarget = isTarget;
  597. }
  598. bool COpenGLTexture::isFrameBufferObject() const
  599. {
  600. return false;
  601. }
  602. //! Bind Render Target Texture
  603. void COpenGLTexture::bindRTT()
  604. {
  605. }
  606. //! Unbind Render Target Texture
  607. void COpenGLTexture::unbindRTT()
  608. {
  609. Driver->setActiveTexture(0, this);
  610. // Copy Our ViewPort To The Texture
  611. glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, getSize().Width, getSize().Height);
  612. }
  613. /* FBO Textures */
  614. // helper function for render to texture
  615. static bool checkFBOStatus(COpenGLDriver* Driver);
  616. //! RTT ColorFrameBuffer constructor
  617. COpenGLFBOTexture::COpenGLFBOTexture(const core::dimension2d<u32>& size,
  618. const io::path& name, COpenGLDriver* driver,
  619. ECOLOR_FORMAT format)
  620. : COpenGLTexture(name, driver), DepthTexture(0), ColorFrameBuffer(0)
  621. {
  622. #ifdef _DEBUG
  623. setDebugName("COpenGLTexture_FBO");
  624. #endif
  625. ImageSize = size;
  626. TextureSize = size;
  627. if (ECF_UNKNOWN == format)
  628. format = getBestColorFormat(driver->getColorFormat());
  629. ColorFormat = format;
  630. GLint FilteringType;
  631. InternalFormat = getOpenGLFormatAndParametersFromColorFormat(format, FilteringType, PixelFormat, PixelType);
  632. HasMipMaps = false;
  633. IsRenderTarget = true;
  634. #ifdef GL_EXT_framebuffer_object
  635. // generate frame buffer
  636. Driver->extGlGenFramebuffers(1, &ColorFrameBuffer);
  637. bindRTT();
  638. // generate color texture
  639. glGenTextures(1, &TextureName);
  640. Driver->setActiveTexture(0, this);
  641. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, FilteringType);
  642. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  643. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  644. glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, ImageSize.Width,
  645. ImageSize.Height, 0, PixelFormat, PixelType, 0);
  646. #ifdef _DEBUG
  647. driver->testGLError();
  648. #endif
  649. // attach color texture to frame buffer
  650. Driver->extGlFramebufferTexture2D(GL_FRAMEBUFFER_EXT,
  651. GL_COLOR_ATTACHMENT0_EXT,
  652. GL_TEXTURE_2D,
  653. TextureName,
  654. 0);
  655. #ifdef _DEBUG
  656. checkFBOStatus(Driver);
  657. #endif
  658. #endif
  659. unbindRTT();
  660. }
  661. //! destructor
  662. COpenGLFBOTexture::~COpenGLFBOTexture()
  663. {
  664. if (DepthTexture)
  665. if (DepthTexture->drop())
  666. Driver->removeDepthTexture(DepthTexture);
  667. if (ColorFrameBuffer)
  668. Driver->extGlDeleteFramebuffers(1, &ColorFrameBuffer);
  669. }
  670. bool COpenGLFBOTexture::isFrameBufferObject() const
  671. {
  672. return true;
  673. }
  674. //! Bind Render Target Texture
  675. void COpenGLFBOTexture::bindRTT()
  676. {
  677. #ifdef GL_EXT_framebuffer_object
  678. if (ColorFrameBuffer != 0)
  679. Driver->extGlBindFramebuffer(GL_FRAMEBUFFER_EXT, ColorFrameBuffer);
  680. glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
  681. #endif
  682. }
  683. //! Unbind Render Target Texture
  684. void COpenGLFBOTexture::unbindRTT()
  685. {
  686. #ifdef GL_EXT_framebuffer_object
  687. if (ColorFrameBuffer != 0)
  688. Driver->extGlBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
  689. #endif
  690. }
  691. /* FBO Depth Textures */
  692. //! RTT DepthBuffer constructor
  693. COpenGLFBODepthTexture::COpenGLFBODepthTexture(
  694. const core::dimension2d<u32>& size,
  695. const io::path& name,
  696. COpenGLDriver* driver,
  697. bool useStencil)
  698. : COpenGLTexture(name, driver), DepthRenderBuffer(0),
  699. StencilRenderBuffer(0), UseStencil(useStencil)
  700. {
  701. #ifdef _DEBUG
  702. setDebugName("COpenGLTextureFBO_Depth");
  703. #endif
  704. ImageSize = size;
  705. TextureSize = size;
  706. InternalFormat = GL_RGBA;
  707. PixelFormat = GL_RGBA;
  708. PixelType = GL_UNSIGNED_BYTE;
  709. HasMipMaps = false;
  710. if (useStencil)
  711. {
  712. glGenTextures(1, &DepthRenderBuffer);
  713. glBindTexture(GL_TEXTURE_2D, DepthRenderBuffer);
  714. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  715. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  716. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  717. #ifdef GL_EXT_packed_depth_stencil
  718. if (Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_EXT_packed_depth_stencil))
  719. {
  720. // generate packed depth stencil texture
  721. glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_STENCIL_EXT, ImageSize.Width,
  722. ImageSize.Height, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 0);
  723. StencilRenderBuffer = DepthRenderBuffer; // stencil is packed with depth
  724. }
  725. else // generate separate stencil and depth textures
  726. #endif
  727. {
  728. // generate depth texture
  729. glTexImage2D(GL_TEXTURE_2D, 0, Driver->getZBufferBits(), ImageSize.Width,
  730. ImageSize.Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
  731. // generate stencil texture
  732. glGenTextures(1, &StencilRenderBuffer);
  733. glBindTexture(GL_TEXTURE_2D, StencilRenderBuffer);
  734. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  735. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  736. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  737. glTexImage2D(GL_TEXTURE_2D, 0, GL_STENCIL_INDEX, ImageSize.Width,
  738. ImageSize.Height, 0, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, 0);
  739. }
  740. }
  741. #ifdef GL_EXT_framebuffer_object
  742. else
  743. {
  744. // generate depth buffer
  745. Driver->extGlGenRenderbuffers(1, &DepthRenderBuffer);
  746. Driver->extGlBindRenderbuffer(GL_RENDERBUFFER_EXT, DepthRenderBuffer);
  747. Driver->extGlRenderbufferStorage(GL_RENDERBUFFER_EXT,
  748. Driver->getZBufferBits(), ImageSize.Width,
  749. ImageSize.Height);
  750. }
  751. #endif
  752. }
  753. //! destructor
  754. COpenGLFBODepthTexture::~COpenGLFBODepthTexture()
  755. {
  756. if (DepthRenderBuffer && UseStencil)
  757. glDeleteTextures(1, &DepthRenderBuffer);
  758. else
  759. Driver->extGlDeleteRenderbuffers(1, &DepthRenderBuffer);
  760. if (StencilRenderBuffer && StencilRenderBuffer != DepthRenderBuffer)
  761. glDeleteTextures(1, &StencilRenderBuffer);
  762. }
  763. //combine depth texture and rtt
  764. bool COpenGLFBODepthTexture::attach(ITexture* renderTex)
  765. {
  766. if (!renderTex)
  767. return false;
  768. video::COpenGLFBOTexture* rtt = static_cast<video::COpenGLFBOTexture*>(renderTex);
  769. rtt->bindRTT();
  770. #ifdef GL_EXT_framebuffer_object
  771. if (UseStencil)
  772. {
  773. // attach depth stencil texture to depth buffer
  774. Driver->extGlFramebufferTexture2D(GL_FRAMEBUFFER_EXT,
  775. GL_DEPTH_STENCIL_ATTACHMENT,
  776. GL_TEXTURE_2D,
  777. DepthRenderBuffer,
  778. 0);
  779. }
  780. else
  781. {
  782. // attach depth renderbuffer to depth buffer
  783. Driver->extGlFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT,
  784. GL_DEPTH_ATTACHMENT_EXT,
  785. GL_RENDERBUFFER_EXT,
  786. DepthRenderBuffer);
  787. }
  788. #endif
  789. // check the status
  790. if (!checkFBOStatus(Driver))
  791. {
  792. os::Printer::log("FBO incomplete");
  793. return false;
  794. }
  795. rtt->DepthTexture=this;
  796. rtt->DepthBufferTexture = DepthRenderBuffer;
  797. grab(); // grab the depth buffer, not the RTT
  798. rtt->unbindRTT();
  799. return true;
  800. }
  801. //! Bind Render Target Texture
  802. void COpenGLFBODepthTexture::bindRTT()
  803. {
  804. }
  805. //! Unbind Render Target Texture
  806. void COpenGLFBODepthTexture::unbindRTT()
  807. {
  808. }
  809. bool COpenGLFBODepthTexture::hasStencil()
  810. {
  811. return UseStencil;
  812. }
  813. bool checkFBOStatus(COpenGLDriver* Driver)
  814. {
  815. #ifdef GL_EXT_framebuffer_object
  816. GLenum status = Driver->extGlCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
  817. switch (status)
  818. {
  819. //Our FBO is perfect, return true
  820. case GL_FRAMEBUFFER_COMPLETE_EXT:
  821. return true;
  822. case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
  823. os::Printer::log("FBO has invalid read buffer", ELL_ERROR);
  824. break;
  825. case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
  826. os::Printer::log("FBO has invalid draw buffer", ELL_ERROR);
  827. break;
  828. case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
  829. os::Printer::log("FBO has one or several incomplete image attachments", ELL_ERROR);
  830. break;
  831. case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
  832. os::Printer::log("FBO has one or several image attachments with different internal formats", ELL_ERROR);
  833. break;
  834. case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
  835. os::Printer::log("FBO has one or several image attachments with different dimensions", ELL_ERROR);
  836. break;
  837. // not part of fbo_object anymore, but won't harm as it is just a return value
  838. #ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
  839. case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
  840. os::Printer::log("FBO has a duplicate image attachment", ELL_ERROR);
  841. break;
  842. #endif
  843. case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
  844. os::Printer::log("FBO missing an image attachment", ELL_ERROR);
  845. break;
  846. #ifdef GL_EXT_framebuffer_multisample
  847. case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
  848. os::Printer::log("FBO wrong multisample setup", ELL_ERROR);
  849. break;
  850. #endif
  851. case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
  852. os::Printer::log("FBO format unsupported", ELL_ERROR);
  853. break;
  854. default:
  855. break;
  856. }
  857. #endif
  858. os::Printer::log("FBO error", ELL_ERROR);
  859. // _IRR_DEBUG_BREAK_IF(true);
  860. return false;
  861. }
  862. } // end namespace video
  863. } // end namespace irr
  864. #endif // _IRR_COMPILE_WITH_OPENGL_