2
0

ImagingOpenGL.pas 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  1. {
  2. Vampyre Imaging Library
  3. by Marek Mauder
  4. http://imaginglib.sourceforge.net
  5. The contents of this file are used with permission, subject to the Mozilla
  6. Public License Version 1.1 (the "License"); you may not use this file except
  7. in compliance with the License. You may obtain a copy of the License at
  8. http://www.mozilla.org/MPL/MPL-1.1.html
  9. Software distributed under the License is distributed on an "AS IS" basis,
  10. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
  11. the specific language governing rights and limitations under the License.
  12. Alternatively, the contents of this file may be used under the terms of the
  13. GNU Lesser General Public License (the "LGPL License"), in which case the
  14. provisions of the LGPL License are applicable instead of those above.
  15. If you wish to allow use of your version of this file only under the terms
  16. of the LGPL License and not to allow others to use your version of this file
  17. under the MPL, indicate your decision by deleting the provisions above and
  18. replace them with the notice and other provisions required by the LGPL
  19. License. If you do not delete the provisions above, a recipient may use
  20. your version of this file under either the MPL or the LGPL License.
  21. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
  22. }
  23. { This unit contains functions for loading and saving OpenGL textures
  24. using Imaging and for converting images to textures and vice versa.}
  25. unit ImagingOpenGL;
  26. {$I ImagingOptions.inc}
  27. { Define this symbol if you want to use dglOpenGL header.}
  28. {$DEFINE OPENGL_USE_DGL_HEADERS}
  29. {$IFDEF OPENGL_NO_EXT_HEADERS}
  30. {$UNDEF OPENGL_USE_DGL_HEADERS}
  31. {$ENDIF}
  32. interface
  33. uses
  34. SysUtils, Classes, ImagingTypes, Imaging, ImagingFormats,
  35. {$IF Defined(OPENGL_USE_DGL_HEADERS)}
  36. dglOpenGL,
  37. {$ELSE}
  38. gl, glext,
  39. {$IFEND}
  40. ImagingUtility;
  41. type
  42. { Various texture capabilities of installed OpenGL driver.}
  43. TGLTextureCaps = record
  44. MaxTextureSize: LongInt; // Max size of texture in pixels supported by HW
  45. NonPowerOfTwo: Boolean; // HW has full support for NPOT textures
  46. DXTCompression: Boolean; // HW supports S3TC/DXTC compressed textures
  47. ATI3DcCompression: Boolean; // HW supports ATI 3Dc compressed textures (ATI2N)
  48. LATCCompression: Boolean; // HW supports LATC/RGTC compressed textures (ATI1N+ATI2N)
  49. FloatTextures: Boolean; // HW supports floating point textures
  50. MaxAnisotropy: LongInt; // Max anisotropy for aniso texture filtering
  51. MaxSimultaneousTextures: LongInt; // Number of texture units
  52. ClampToEdge: Boolean; // GL_EXT_texture_edge_clamp
  53. TextureLOD: Boolean; // GL_SGIS_texture_lod
  54. VertexTextureUnits: Integer; // Texture units accessible in vertex programs
  55. end;
  56. { Returns texture capabilities of installed OpenGL driver.}
  57. function GetGLTextureCaps(var Caps: TGLTextureCaps): Boolean;
  58. { Function which can be used to retrieve GL extension functions.}
  59. function GetGLProcAddress(const ProcName: string): Pointer;
  60. { Returns True if the given GL extension is supported.}
  61. function IsGLExtensionSupported(const Extension: string): Boolean;
  62. { Returns True if the given image format can be represented as GL texture
  63. format. GLFormat, GLType, and GLInternal are parameters for functions like
  64. glTexImage. Note that GLU functions like gluBuildMipmaps cannot handle some
  65. formats returned by this function (i.e. GL_UNSIGNED_SHORT_5_5_5_1 as GLType).
  66. If you are using compressed or floating-point images make sure that they are
  67. supported by hardware using GetGLTextureCaps, ImageFormatToGL does not
  68. check this.}
  69. function ImageFormatToGL(Format: TImageFormat; var GLFormat: GLenum;
  70. var GLType: GLenum; var GLInternal: GLint; const Caps: TGLTextureCaps): Boolean;
  71. { All GL textures created by Imaging functions have default parameters set -
  72. that means that no glTexParameter calls are made so default filtering,
  73. wrapping, and other parameters are used. Created textures
  74. are left bound by glBindTexture when function is exited.}
  75. { Creates GL texture from image in file in format supported by Imaging.
  76. You can use CreatedWidth and Height parameters to query dimensions of created textures
  77. (it could differ from dimensions of source image).}
  78. function LoadGLTextureFromFile(const FileName: string; CreatedWidth: PLongInt = nil;
  79. CreatedHeight: PLongInt = nil): GLuint;
  80. { Creates GL texture from image in stream in format supported by Imaging.
  81. You can use CreatedWidth and Height parameters to query dimensions of created textures
  82. (it could differ from dimensions of source image).}
  83. function LoadGLTextureFromStream(Stream: TStream; CreatedWidth: PLongInt = nil;
  84. CreatedHeight: PLongInt = nil): GLuint;
  85. { Creates GL texture from image in memory in format supported by Imaging.
  86. You can use CreatedWidth and Height parameters to query dimensions of created textures
  87. (it could differ from dimensions of source image).}
  88. function LoadGLTextureFromMemory(Data: Pointer; Size: LongInt;
  89. CreatedWidth: PLongInt = nil; CreatedHeight: PLongInt = nil): GLuint;
  90. { Converts TImageData structure to OpenGL texture.
  91. Input images is used as main mipmap level and additional requested
  92. levels are generated from this one. For the details on parameters
  93. look at CreateGLTextureFromMultiImage function.}
  94. function CreateGLTextureFromImage(const Image: TImageData;
  95. Width: LongInt = 0; Height: LongInt = 0; MipMaps: Boolean = True;
  96. OverrideFormat: TImageFormat = ifUnknown; CreatedWidth: PLongInt = nil;
  97. CreatedHeight: PLongInt = nil): GLuint;
  98. { Converts images in TDymImageDataArray to one OpenGL texture.
  99. Image at index MainLevelIndex in the array is used as main mipmap level and
  100. additional images are used as subsequent levels. If there is not enough images
  101. in array missing levels are automatically generated (and if there is enough images
  102. but they have wrong dimensions or format then they are resized/converted).
  103. If driver supports only power of two sized textures images are resized.
  104. OverrideFormat can be used to convert image into specific format before
  105. it is passed to OpenGL, ifUnknown means no conversion.
  106. If desired texture format is not supported by hardware default
  107. A8R8G8B8 format is used instead for color images and ifGray8 is used
  108. for luminance images. DXTC (S3TC) compressed and floating point textures
  109. are created if supported by hardware.
  110. Width and Height can be used to set size of main mipmap level according
  111. to your needs, Width and Height of 0 mean use width and height of input
  112. image that will become main level mipmap.
  113. MipMaps set to True mean build all possible levels, False means use only level 0.
  114. You can use CreatedWidth and CreatedHeight parameters to query dimensions of
  115. created texture's largest mipmap level (it could differ from dimensions
  116. of source image).}
  117. function CreateGLTextureFromMultiImage(const Images: TDynImageDataArray;
  118. Width: LongInt = 0; Height: LongInt = 0; MipMaps: Boolean = True;
  119. MainLevelIndex: LongInt = 0; OverrideFormat: TImageFormat = ifUnknown;
  120. CreatedWidth: PLongInt = nil; CreatedHeight: PLongInt = nil): GLuint;
  121. { Saves GL texture to file in one of formats supported by Imaging.
  122. Saves all present mipmap levels.}
  123. function SaveGLTextureToFile(const FileName: string; const Texture: GLuint): Boolean;
  124. { Saves GL texture to stream in one of formats supported by Imaging.
  125. Saves all present mipmap levels.}
  126. function SaveGLTextureToStream(const Ext: string; Stream: TStream; const Texture: GLuint): Boolean;
  127. { Saves GL texture to memory in one of formats supported by Imaging.
  128. Saves all present mipmap levels.}
  129. function SaveGLTextureToMemory(const Ext: string; Data: Pointer; var Size: LongInt; const Texture: GLuint): Boolean;
  130. { Converts main level of the GL texture to TImageData strucrue. OverrideFormat
  131. can be used to convert output image to the specified format rather
  132. than use the format taken from GL texture, ifUnknown means no conversion.}
  133. function CreateImageFromGLTexture(const Texture: GLuint;
  134. var Image: TImageData; OverrideFormat: TImageFormat = ifUnknown): Boolean;
  135. { Converts GL texture to TDynImageDataArray array of images. You can specify
  136. how many mipmap levels of the input texture you want to be converted
  137. (default is all levels). OverrideFormat can be used to convert output images to
  138. the specified format rather than use the format taken from GL texture,
  139. ifUnknown means no conversion.}
  140. function CreateMultiImageFromGLTexture(const Texture: GLuint;
  141. var Images: TDynImageDataArray; MipLevels: LongInt = 0;
  142. OverrideFormat: TImageFormat = ifUnknown): Boolean;
  143. var
  144. { Standard behaviour of image->texture functions like CreateGLTextureFrom(Multi)Image is:
  145. If graphic card supports non power of 2 textures and image is nonpow2 then
  146. texture is created directly from image.
  147. If graphic card does not support them input image is rescaled (bilinear)
  148. to power of 2 size.
  149. If you set PasteNonPow2ImagesIntoPow2 to True then instead of rescaling, a new
  150. pow2 texture is created and nonpow2 input image is pasted into it
  151. keeping its original size. This could be useful for some 2D stuff
  152. (and its faster than rescaling of course). Note that this is applied
  153. to all rescaling smaller->bigger operations that might ocurr during
  154. image->texture process (usually only pow2/nonpow2 stuff and when you
  155. set custom Width & Height in CreateGLTextureFrom(Multi)Image).}
  156. PasteNonPow2ImagesIntoPow2: Boolean = False;
  157. { Standard behaviur if GL_ARB_texture_non_power_of_two extension is not supported
  158. is to rescale image to power of 2 dimensions. NPOT extension is exposed only
  159. when HW has full support for NPOT textures but some cards
  160. (pre-DX10 ATI Radeons, some other maybe) have partial NPOT support.
  161. Namely Radeons can use NPOT textures but not mipmapped. If you know what you are doing
  162. you can disable NPOT support check so the image won't be rescaled to POT
  163. by seting DisableNPOTSupportCheck to True.}
  164. DisableNPOTSupportCheck: Boolean = False;
  165. implementation
  166. const
  167. // Cube map consts
  168. GL_TEXTURE_BINDING_CUBE_MAP = $8514;
  169. GL_TEXTURE_CUBE_MAP_POSITIVE_X = $8515;
  170. GL_TEXTURE_CUBE_MAP_NEGATIVE_X = $8516;
  171. GL_TEXTURE_CUBE_MAP_POSITIVE_Y = $8517;
  172. GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = $8518;
  173. GL_TEXTURE_CUBE_MAP_POSITIVE_Z = $8519;
  174. GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = $851A;
  175. // Texture formats
  176. GL_COLOR_INDEX = $1900;
  177. GL_STENCIL_INDEX = $1901;
  178. GL_DEPTH_COMPONENT = $1902;
  179. GL_RED = $1903;
  180. GL_GREEN = $1904;
  181. GL_BLUE = $1905;
  182. GL_ALPHA = $1906;
  183. GL_RGB = $1907;
  184. GL_RGBA = $1908;
  185. GL_LUMINANCE = $1909;
  186. GL_LUMINANCE_ALPHA = $190A;
  187. GL_BGR_EXT = $80E0;
  188. GL_BGRA_EXT = $80E1;
  189. // Texture internal formats
  190. GL_ALPHA4 = $803B;
  191. GL_ALPHA8 = $803C;
  192. GL_ALPHA12 = $803D;
  193. GL_ALPHA16 = $803E;
  194. GL_LUMINANCE4 = $803F;
  195. GL_LUMINANCE8 = $8040;
  196. GL_LUMINANCE12 = $8041;
  197. GL_LUMINANCE16 = $8042;
  198. GL_LUMINANCE4_ALPHA4 = $8043;
  199. GL_LUMINANCE6_ALPHA2 = $8044;
  200. GL_LUMINANCE8_ALPHA8 = $8045;
  201. GL_LUMINANCE12_ALPHA4 = $8046;
  202. GL_LUMINANCE12_ALPHA12 = $8047;
  203. GL_LUMINANCE16_ALPHA16 = $8048;
  204. GL_INTENSITY = $8049;
  205. GL_INTENSITY4 = $804A;
  206. GL_INTENSITY8 = $804B;
  207. GL_INTENSITY12 = $804C;
  208. GL_INTENSITY16 = $804D;
  209. GL_R3_G3_B2 = $2A10;
  210. GL_RGB4 = $804F;
  211. GL_RGB5 = $8050;
  212. GL_RGB8 = $8051;
  213. GL_RGB10 = $8052;
  214. GL_RGB12 = $8053;
  215. GL_RGB16 = $8054;
  216. GL_RGBA2 = $8055;
  217. GL_RGBA4 = $8056;
  218. GL_RGB5_A1 = $8057;
  219. GL_RGBA8 = $8058;
  220. GL_RGB10_A2 = $8059;
  221. GL_RGBA12 = $805A;
  222. GL_RGBA16 = $805B;
  223. GL_RGB565 = $8D62;
  224. // Floating point texture formats
  225. GL_RGBA32F_ARB = $8814;
  226. GL_INTENSITY32F_ARB = $8817;
  227. GL_LUMINANCE32F_ARB = $8818;
  228. GL_RGBA16F_ARB = $881A;
  229. GL_INTENSITY16F_ARB = $881D;
  230. GL_LUMINANCE16F_ARB = $881E;
  231. // Compressed texture formats
  232. // S3TC/DXTC
  233. GL_COMPRESSED_RGB_S3TC_DXT1_EXT = $83F0;
  234. GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = $83F1;
  235. GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = $83F2;
  236. GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = $83F3;
  237. // 3Dc LATC
  238. GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI = $8837;
  239. GL_COMPRESSED_LUMINANCE_LATC1_EXT = $8C70;
  240. GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT = $8C71;
  241. GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT = $8C72;
  242. GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT = $8C73;
  243. // ETC1 GL_OES_compressed_ETC1_RGB8_texture
  244. GL_ETC1_RGB_OES = $8D64;
  245. // PVRTC GL_IMG_texture_compression_pvrtc
  246. GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = $8C00;
  247. GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = $8C01;
  248. GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = $8C02;
  249. GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = $8C03;
  250. // AMD ATC
  251. GL_ATC_RGBA_EXPLICIT_ALPHA_AMD = $8C93;
  252. GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD = $87EE;
  253. // ETC2/EAC
  254. GL_COMPRESSED_R11_EAC = $9270;
  255. GL_COMPRESSED_SIGNED_R11_EAC = $9271;
  256. GL_COMPRESSED_RG11_EAC = $9272;
  257. GL_COMPRESSED_SIGNED_RG11_EAC = $9273;
  258. GL_COMPRESSED_RGB8_ETC2 = $9274;
  259. GL_COMPRESSED_SRGB8_ETC2 = $9275;
  260. GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = $9276;
  261. GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = $9277;
  262. GL_COMPRESSED_RGBA8_ETC2_EAC = $9278;
  263. GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = $9279;
  264. // Various GL extension constants
  265. GL_MAX_TEXTURE_UNITS = $84E2;
  266. GL_TEXTURE_MAX_ANISOTROPY_EXT = $84FE;
  267. GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = $84FF;
  268. // Texture source data formats
  269. GL_UNSIGNED_BYTE_3_3_2 = $8032;
  270. GL_UNSIGNED_SHORT_4_4_4_4 = $8033;
  271. GL_UNSIGNED_SHORT_5_5_5_1 = $8034;
  272. GL_UNSIGNED_INT_8_8_8_8 = $8035;
  273. GL_UNSIGNED_INT_10_10_10_2 = $8036;
  274. GL_UNSIGNED_BYTE_2_3_3_REV = $8362;
  275. GL_UNSIGNED_SHORT_5_6_5 = $8363;
  276. GL_UNSIGNED_SHORT_5_6_5_REV = $8364;
  277. GL_UNSIGNED_SHORT_4_4_4_4_REV = $8365;
  278. GL_UNSIGNED_SHORT_1_5_5_5_REV = $8366;
  279. GL_UNSIGNED_INT_8_8_8_8_REV = $8367;
  280. GL_UNSIGNED_INT_2_10_10_10_REV = $8368;
  281. GL_HALF_FLOAT_ARB = $140B;
  282. // Other GL constants
  283. GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = $8B4C;
  284. {$IFDEF MSWINDOWS}
  285. GLLibName = 'opengl32.dll';
  286. {$ENDIF}
  287. {$IFDEF UNIX}
  288. GLLibName = 'libGL.so';
  289. {$ENDIF}
  290. type
  291. TglCompressedTexImage2D = procedure (Target: GLenum; Level: GLint;
  292. InternalFormat: GLenum; Width: GLsizei; Height: GLsizei; Border: GLint;
  293. ImageSize: GLsizei; const Data: PGLvoid);
  294. {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF}
  295. var
  296. glCompressedTexImage2D: TglCompressedTexImage2D = nil;
  297. ExtensionBuffer: string = '';
  298. {$IFDEF MSWINDOWS}
  299. function wglGetProcAddress(ProcName: PAnsiChar): Pointer; stdcall; external GLLibName;
  300. {$ENDIF}
  301. {$IFDEF UNIX}
  302. function glXGetProcAddress(ProcName: PAnsiChar): Pointer; cdecl; external GLLibName;
  303. {$ENDIF}
  304. function IsGLExtensionSupported(const Extension: string): Boolean;
  305. var
  306. ExtPos: LongInt;
  307. begin
  308. if ExtensionBuffer = '' then
  309. ExtensionBuffer := glGetString(GL_EXTENSIONS);
  310. ExtPos := Pos(Extension, ExtensionBuffer);
  311. Result := ExtPos > 0;
  312. if Result then
  313. begin
  314. Result := ((ExtPos + Length(Extension) - 1) = Length(ExtensionBuffer)) or
  315. not (ExtensionBuffer[ExtPos + Length(Extension)] in ['_', 'A'..'Z', 'a'..'z']);
  316. end;
  317. end;
  318. function GetGLProcAddress(const ProcName: string): Pointer;
  319. begin
  320. {$IFDEF MSWINDOWS}
  321. Result := wglGetProcAddress(PAnsiChar(AnsiString(ProcName)));
  322. {$ENDIF}
  323. {$IFDEF UNIX}
  324. Result := glXGetProcAddress(PAnsiChar(AnsiString(ProcName)));
  325. {$ENDIF}
  326. end;
  327. function GetGLTextureCaps(var Caps: TGLTextureCaps): Boolean;
  328. begin
  329. // Check DXTC support and load extension functions if necesary
  330. Caps.DXTCompression := IsGLExtensionSupported('GL_ARB_texture_compression') and
  331. IsGLExtensionSupported('GL_EXT_texture_compression_s3tc');
  332. if Caps.DXTCompression then
  333. glCompressedTexImage2D := GetGLProcAddress('glCompressedTexImage2D');
  334. Caps.DXTCompression := Caps.DXTCompression and (@glCompressedTexImage2D <> nil);
  335. Caps.ATI3DcCompression := Caps.DXTCompression and
  336. IsGLExtensionSupported('GL_ATI_texture_compression_3dc');
  337. Caps.LATCCompression := Caps.DXTCompression and
  338. IsGLExtensionSupported('GL_EXT_texture_compression_latc');
  339. // Check non power of 2 textures
  340. Caps.NonPowerOfTwo := IsGLExtensionSupported('GL_ARB_texture_non_power_of_two');
  341. // Check for floating point textures support
  342. Caps.FloatTextures := IsGLExtensionSupported('GL_ARB_texture_float');
  343. // Get max texture size
  344. glGetIntegerv(GL_MAX_TEXTURE_SIZE, @Caps.MaxTextureSize);
  345. // Get max anisotropy
  346. if IsGLExtensionSupported('GL_EXT_texture_filter_anisotropic') then
  347. glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, @Caps.MaxAnisotropy)
  348. else
  349. Caps.MaxAnisotropy := 0;
  350. // Get number of texture units
  351. if IsGLExtensionSupported('GL_ARB_multitexture') then
  352. glGetIntegerv(GL_MAX_TEXTURE_UNITS, @Caps.MaxSimultaneousTextures)
  353. else
  354. Caps.MaxSimultaneousTextures := 1;
  355. // Get number of vertex texture units
  356. if IsGLExtensionSupported('GL_ARB_vertex_shader') then
  357. glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, @Caps.VertexTextureUnits)
  358. else
  359. Caps.VertexTextureUnits := 1;
  360. // Get max texture size
  361. glGetIntegerv(GL_MAX_TEXTURE_SIZE, @Caps.MaxTextureSize);
  362. // Clamp texture to edge?
  363. Caps.ClampToEdge := IsGLExtensionSupported('GL_EXT_texture_edge_clamp');
  364. // Texture LOD extension?
  365. Caps.TextureLOD := IsGLExtensionSupported('GL_SGIS_texture_lod');
  366. Result := True;
  367. end;
  368. function ImageFormatToGL(Format: TImageFormat; var GLFormat: GLenum;
  369. var GLType: GLenum; var GLInternal: GLint; const Caps: TGLTextureCaps): Boolean;
  370. begin
  371. GLFormat := 0;
  372. GLType := 0;
  373. GLInternal := 0;
  374. case Format of
  375. // Gray formats
  376. ifGray8, ifGray16:
  377. begin
  378. GLFormat := GL_LUMINANCE;
  379. GLType := Iff(Format = ifGray8, GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT);
  380. GLInternal := Iff(Format = ifGray8, GL_LUMINANCE8, GL_LUMINANCE16);
  381. end;
  382. ifA8Gray8, ifA16Gray16:
  383. begin
  384. GLFormat := GL_LUMINANCE_ALPHA;
  385. GLType := Iff(Format = ifA8Gray8, GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT);
  386. GLInternal := Iff(Format = ifA8Gray8, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE16_ALPHA16);
  387. end;
  388. // RGBA formats
  389. ifR3G3B2:
  390. begin
  391. GLFormat := GL_RGB;
  392. GLType := GL_UNSIGNED_BYTE_3_3_2;
  393. GLInternal := GL_R3_G3_B2;
  394. end;
  395. ifR5G6B5:
  396. begin
  397. GLFormat := GL_RGB;
  398. GLType := GL_UNSIGNED_SHORT_5_6_5;
  399. GLInternal := GL_RGB5; //GL_RGB565 ot working on Radeons
  400. end;
  401. ifA1R5G5B5, ifX1R5G5B5:
  402. begin
  403. GLFormat := GL_BGRA_EXT;
  404. GLType := GL_UNSIGNED_SHORT_1_5_5_5_REV;
  405. GLInternal := Iff(Format = ifA1R5G5B5, GL_RGB5_A1, GL_RGB5);
  406. end;
  407. ifA4R4G4B4, ifX4R4G4B4:
  408. begin
  409. GLFormat := GL_BGRA_EXT;
  410. GLType := GL_UNSIGNED_SHORT_4_4_4_4_REV;
  411. GLInternal := Iff(Format = ifA4R4G4B4, GL_RGBA4, GL_RGB4);
  412. end;
  413. ifR8G8B8:
  414. begin
  415. GLFormat := GL_BGR_EXT;
  416. GLType := GL_UNSIGNED_BYTE;
  417. GLInternal := GL_RGB8;
  418. end;
  419. ifA8R8G8B8, ifX8R8G8B8:
  420. begin
  421. GLFormat := GL_BGRA_EXT;
  422. GLType := GL_UNSIGNED_BYTE;
  423. GLInternal := Iff(Format = ifA8R8G8B8, GL_RGBA8, GL_RGB8);
  424. end;
  425. ifR16G16B16, ifB16G16R16:
  426. begin
  427. GLFormat := Iff(Format = ifR16G16B16, GL_BGR_EXT, GL_RGB);
  428. GLType := GL_UNSIGNED_SHORT;
  429. GLInternal := GL_RGB16;
  430. end;
  431. ifA16R16G16B16, ifA16B16G16R16:
  432. begin
  433. GLFormat := Iff(Format = ifA16R16G16B16, GL_BGRA_EXT, GL_RGBA);
  434. GLType := GL_UNSIGNED_SHORT;
  435. GLInternal := GL_RGBA16;
  436. end;
  437. // Floating-Point formats
  438. ifR32F:
  439. begin
  440. GLFormat := GL_RED;
  441. GLType := GL_FLOAT;
  442. GLInternal := GL_LUMINANCE32F_ARB;
  443. end;
  444. ifA32R32G32B32F, ifA32B32G32R32F:
  445. begin
  446. GLFormat := Iff(Format = ifA32R32G32B32F, GL_BGRA_EXT, GL_RGBA);
  447. GLType := GL_FLOAT;
  448. GLInternal := GL_RGBA32F_ARB;
  449. end;
  450. ifR16F:
  451. begin
  452. GLFormat := GL_RED;
  453. GLType := GL_HALF_FLOAT_ARB;
  454. GLInternal := GL_LUMINANCE16F_ARB;
  455. end;
  456. ifA16R16G16B16F, ifA16B16G16R16F:
  457. begin
  458. GLFormat := Iff(Format = ifA16R16G16B16F, GL_BGRA_EXT, GL_RGBA);
  459. GLType := GL_HALF_FLOAT_ARB;
  460. GLInternal := GL_RGBA16F_ARB;
  461. end;
  462. // Special formats
  463. ifDXT1: GLInternal := GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
  464. ifDXT3: GLInternal := GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
  465. ifDXT5: GLInternal := GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
  466. ifATI1N: GLInternal := GL_COMPRESSED_LUMINANCE_LATC1_EXT;
  467. ifATI2N:
  468. begin
  469. GLInternal := GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
  470. if not Caps.LATCCompression and Caps.ATI3DcCompression then
  471. GLInternal := GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI;
  472. end;
  473. end;
  474. Result := GLInternal <> 0;
  475. end;
  476. function LoadGLTextureFromFile(const FileName: string; CreatedWidth, CreatedHeight: PLongInt): GLuint;
  477. var
  478. Images: TDynImageDataArray;
  479. begin
  480. if LoadMultiImageFromFile(FileName, Images) and (Length(Images) > 0) then
  481. begin
  482. Result := CreateGLTextureFromMultiImage(Images, Images[0].Width,
  483. Images[0].Height, True, 0, ifUnknown, CreatedWidth, CreatedHeight);
  484. end
  485. else
  486. Result := 0;
  487. FreeImagesInArray(Images);
  488. end;
  489. function LoadGLTextureFromStream(Stream: TStream; CreatedWidth, CreatedHeight: PLongInt): GLuint;
  490. var
  491. Images: TDynImageDataArray;
  492. begin
  493. if LoadMultiImageFromStream(Stream, Images) and (Length(Images) > 0) then
  494. begin
  495. Result := CreateGLTextureFromMultiImage(Images, Images[0].Width,
  496. Images[0].Height, True, 0, ifUnknown, CreatedWidth, CreatedHeight);
  497. end
  498. else
  499. Result := 0;
  500. FreeImagesInArray(Images);
  501. end;
  502. function LoadGLTextureFromMemory(Data: Pointer; Size: LongInt; CreatedWidth, CreatedHeight: PLongInt): GLuint;
  503. var
  504. Images: TDynImageDataArray;
  505. begin
  506. if LoadMultiImageFromMemory(Data, Size, Images) and (Length(Images) > 0) then
  507. begin
  508. Result := CreateGLTextureFromMultiImage(Images, Images[0].Width,
  509. Images[0].Height, True, 0, ifUnknown, CreatedWidth, CreatedHeight);
  510. end
  511. else
  512. Result := 0;
  513. FreeImagesInArray(Images);
  514. end;
  515. function CreateGLTextureFromImage(const Image: TImageData;
  516. Width, Height: LongInt; MipMaps: Boolean; OverrideFormat: TImageFormat;
  517. CreatedWidth, CreatedHeight: PLongInt): GLuint;
  518. var
  519. Arr: TDynImageDataArray;
  520. begin
  521. // Just calls function operating on image arrays
  522. SetLength(Arr, 1);
  523. Arr[0] := Image;
  524. Result := CreateGLTextureFromMultiImage(Arr, Width, Height, MipMaps, 0,
  525. OverrideFormat, CreatedWidth, CreatedHeight);
  526. end;
  527. function CreateGLTextureFromMultiImage(const Images: TDynImageDataArray;
  528. Width, Height: LongInt; MipMaps: Boolean; MainLevelIndex: LongInt; OverrideFormat: TImageFormat;
  529. CreatedWidth, CreatedHeight: PLongInt): GLuint;
  530. const
  531. BlockCompressedFormats: TImageFormats = [ifDXT1, ifDXT3, ifDXT5, ifATI1N, ifATI2N];
  532. var
  533. I, MipLevels, PossibleLevels, ExistingLevels, CurrentWidth, CurrentHeight: LongInt;
  534. Caps: TGLTextureCaps;
  535. GLFormat: GLenum;
  536. GLType: GLenum;
  537. GLInternal: GLint;
  538. Desired, ConvTo: TImageFormat;
  539. Info: TImageFormatInfo;
  540. LevelsArray: TDynImageDataArray;
  541. NeedsResize, NeedsConvert: Boolean;
  542. UnpackAlignment, UnpackSkipRows, UnpackSkipPixels, UnpackRowLength: LongInt;
  543. procedure PasteImage(var Image: TImageData; Width, Height: LongInt);
  544. var
  545. Clone: TImageData;
  546. begin
  547. CloneImage(Image, Clone);
  548. NewImage(Width, Height, Clone.Format, Image);
  549. FillRect(Image, 0, 0, Width, Height, Clone.Bits);
  550. CopyRect(Clone, 0, 0, Clone.Width, Clone.Height, Image, 0, 0);
  551. FreeImage(Clone);
  552. end;
  553. begin
  554. Result := 0;
  555. ExistingLevels := Length(Images);
  556. if GetGLTextureCaps(Caps) and (ExistingLevels > 0) then
  557. try
  558. // Check if requested main level is at valid index
  559. if (MainLevelIndex < 0) or (MainLevelIndex > High(Images)) then
  560. MainLevelIndex := 0;
  561. // First check desired size and modify it if necessary
  562. if Width <= 0 then Width := Images[MainLevelIndex].Width;
  563. if Height <= 0 then Height := Images[MainLevelIndex].Height;
  564. if not Caps.NonPowerOfTwo and not DisableNPOTSupportCheck then
  565. begin
  566. // If device supports only power of 2 texture sizes
  567. Width := NextPow2(Width);
  568. Height := NextPow2(Height);
  569. end;
  570. Width := ClampInt(Width, 1, Caps.MaxTextureSize);
  571. Height := ClampInt(Height, 1, Caps.MaxTextureSize);
  572. // Get various mipmap level counts and modify
  573. // desired MipLevels if its value is invalid
  574. PossibleLevels := GetNumMipMapLevels(Width, Height);
  575. if MipMaps then
  576. MipLevels := PossibleLevels
  577. else
  578. MipLevels := 1;
  579. // Prepare array for mipmap levels. Make it larger than necessary - that
  580. // way we can use the same index for input images and levels in the large loop below
  581. SetLength(LevelsArray, MipLevels + MainLevelIndex);
  582. // Now determine which image format will be used
  583. if OverrideFormat = ifUnknown then
  584. Desired := Images[MainLevelIndex].Format
  585. else
  586. Desired := OverrideFormat;
  587. // Check if the hardware supports floating point and compressed textures
  588. GetImageFormatInfo(Desired, Info);
  589. if Info.IsFloatingPoint and not Caps.FloatTextures then
  590. Desired := ifA8R8G8B8;
  591. if (Desired in [ifDXT1, ifDXT3, ifDXT5]) and not Caps.DXTCompression then
  592. Desired := ifA8R8G8B8;
  593. if (Desired = ifATI1N) and not Caps.LATCCompression then
  594. Desired := ifGray8;
  595. if (Desired = ifATI2N) and not (Caps.ATI3DcCompression or Caps.LATCCompression) then
  596. Desired := ifA8Gray8;
  597. // Try to find GL format equivalent to image format and if it is not
  598. // found use one of default formats
  599. if not ImageFormatToGL(Desired, GLFormat, GLType, GLInternal, Caps) then
  600. begin
  601. GetImageFormatInfo(Desired, Info);
  602. if Info.HasGrayChannel then
  603. ConvTo := ifGray8
  604. else
  605. ConvTo := ifA8R8G8B8;
  606. if not ImageFormatToGL(ConvTo, GLFormat, GLType, GLInternal, Caps) then
  607. Exit;
  608. end
  609. else
  610. ConvTo := Desired;
  611. CurrentWidth := Width;
  612. CurrentHeight := Height;
  613. // If user is interested in width and height of created texture lets
  614. // give him that
  615. if CreatedWidth <> nil then CreatedWidth^ := CurrentWidth;
  616. if CreatedHeight <> nil then CreatedHeight^ := CurrentHeight;
  617. // Store old pixel unpacking settings
  618. glGetIntegerv(GL_UNPACK_ALIGNMENT, @UnpackAlignment);
  619. glGetIntegerv(GL_UNPACK_SKIP_ROWS, @UnpackSkipRows);
  620. glGetIntegerv(GL_UNPACK_SKIP_PIXELS, @UnpackSkipPixels);
  621. glGetIntegerv(GL_UNPACK_ROW_LENGTH, @UnpackRowLength);
  622. // Set new pixel unpacking settings
  623. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  624. glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
  625. glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
  626. glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  627. // Generate new texture, bind it and set
  628. glGenTextures(1, @Result);
  629. glBindTexture(GL_TEXTURE_2D, Result);
  630. if glIsTexture(Result) <> GL_TRUE then
  631. Exit;
  632. for I := MainLevelIndex to MipLevels - 1 + MainLevelIndex do
  633. begin
  634. // Check if we can use input image array as a source for this mipmap level
  635. if I < ExistingLevels then
  636. begin
  637. // Check if input image for this mipmap level has the right
  638. // size and format
  639. NeedsConvert := not (Images[I].Format = ConvTo);
  640. if ConvTo in BlockCompressedFormats then
  641. begin
  642. // Input images in DXTC will have min dimensions of 4, but we need
  643. // current Width and Height to be lesser (for glCompressedTexImage2D)
  644. NeedsResize := not ((Images[I].Width = Max(4, CurrentWidth)) and
  645. (Images[I].Height = Max(4, CurrentHeight)));
  646. end
  647. else
  648. NeedsResize := not ((Images[I].Width = CurrentWidth) and (Images[I].Height = CurrentHeight));
  649. if NeedsResize or NeedsConvert then
  650. begin
  651. // Input image must be resized or converted to different format
  652. // to become valid mipmap level
  653. CloneImage(Images[I], LevelsArray[I]);
  654. if NeedsConvert then
  655. ConvertImage(LevelsArray[I], ConvTo);
  656. if NeedsResize then
  657. begin
  658. if (not PasteNonPow2ImagesIntoPow2) or (LevelsArray[I].Width > CurrentWidth) or
  659. (LevelsArray[I].Height > CurrentHeight)then
  660. begin
  661. // If pasteNP2toP2 is disabled or if source is bigger than target
  662. // we rescale image, otherwise we paste it with the same size
  663. ResizeImage(LevelsArray[I], CurrentWidth, CurrentHeight, rfBilinear)
  664. end
  665. else
  666. PasteImage(LevelsArray[I], CurrentWidth, CurrentHeight);
  667. end;
  668. end
  669. else
  670. // Input image can be used without any changes
  671. LevelsArray[I] := Images[I];
  672. end
  673. else
  674. begin
  675. // This mipmap level is not present in the input image array
  676. // so we create a new level
  677. FillMipMapLevel(LevelsArray[I - 1], CurrentWidth, CurrentHeight, LevelsArray[I]);
  678. end;
  679. if ConvTo in BlockCompressedFormats then
  680. begin
  681. // Note: GL DXTC texture snaller than 4x4 must have width and height
  682. // as expected for non-DXTC texture (like 1x1 - we cannot
  683. // use LevelsArray[I].Width and LevelsArray[I].Height - they are
  684. // at least 4 for DXTC images). But Bits and Size passed to
  685. // glCompressedTexImage2D must contain regular 4x4 DXTC block.
  686. glCompressedTexImage2D(GL_TEXTURE_2D, I - MainLevelIndex, GLInternal, CurrentWidth,
  687. CurrentHeight, 0, LevelsArray[I].Size, LevelsArray[I].Bits)
  688. end
  689. else
  690. begin
  691. glTexImage2D(GL_TEXTURE_2D, I - MainLevelIndex, GLInternal, CurrentWidth,
  692. CurrentHeight, 0, GLFormat, GLType, LevelsArray[I].Bits);
  693. end;
  694. // Calculate width and height of the next mipmap level
  695. CurrentWidth := ClampInt(CurrentWidth div 2, 1, CurrentWidth);
  696. CurrentHeight := ClampInt(CurrentHeight div 2, 1, CurrentHeight);
  697. end;
  698. // Restore old pixel unpacking settings
  699. glPixelStorei(GL_UNPACK_ALIGNMENT, UnpackAlignment);
  700. glPixelStorei(GL_UNPACK_SKIP_ROWS, UnpackSkipRows);
  701. glPixelStorei(GL_UNPACK_SKIP_PIXELS, UnpackSkipPixels);
  702. glPixelStorei(GL_UNPACK_ROW_LENGTH, UnpackRowLength);
  703. finally
  704. // Free local image copies
  705. for I := 0 to Length(LevelsArray) - 1 do
  706. begin
  707. if ((I < ExistingLevels) and (LevelsArray[I].Bits <> Images[I].Bits)) or
  708. (I >= ExistingLevels) then
  709. FreeImage(LevelsArray[I]);
  710. end;
  711. end;
  712. end;
  713. function SaveGLTextureToFile(const FileName: string; const Texture: GLuint): Boolean;
  714. var
  715. Arr: TDynImageDataArray;
  716. Fmt: TImageFileFormat;
  717. IsDDS: Boolean;
  718. begin
  719. Result := CreateMultiImageFromGLTexture(Texture, Arr);
  720. if Result then
  721. begin
  722. Fmt := FindImageFileFormatByName(FileName);
  723. if Fmt <> nil then
  724. begin
  725. IsDDS := SameText(Fmt.Extensions[0], 'dds');
  726. if IsDDS then
  727. begin
  728. PushOptions;
  729. SetOption(ImagingDDSSaveMipMapCount, Length(Arr));
  730. end;
  731. Result := SaveMultiImageToFile(FileName, Arr);
  732. if IsDDS then
  733. PopOptions;
  734. end;
  735. FreeImagesInArray(Arr);
  736. end;
  737. end;
  738. function SaveGLTextureToStream(const Ext: string; Stream: TStream; const Texture: GLuint): Boolean;
  739. var
  740. Arr: TDynImageDataArray;
  741. Fmt: TImageFileFormat;
  742. IsDDS: Boolean;
  743. begin
  744. Result := CreateMultiImageFromGLTexture(Texture, Arr);
  745. if Result then
  746. begin
  747. Fmt := FindImageFileFormatByExt(Ext);
  748. if Fmt <> nil then
  749. begin
  750. IsDDS := SameText(Fmt.Extensions[0], 'dds');
  751. if IsDDS then
  752. begin
  753. PushOptions;
  754. SetOption(ImagingDDSSaveMipMapCount, Length(Arr));
  755. end;
  756. Result := SaveMultiImageToStream(Ext, Stream, Arr);
  757. if IsDDS then
  758. PopOptions;
  759. end;
  760. FreeImagesInArray(Arr);
  761. end;
  762. end;
  763. function SaveGLTextureToMemory(const Ext: string; Data: Pointer; var Size: LongInt; const Texture: GLuint): Boolean;
  764. var
  765. Arr: TDynImageDataArray;
  766. Fmt: TImageFileFormat;
  767. IsDDS: Boolean;
  768. begin
  769. Result := CreateMultiImageFromGLTexture(Texture, Arr);
  770. if Result then
  771. begin
  772. Fmt := FindImageFileFormatByExt(Ext);
  773. if Fmt <> nil then
  774. begin
  775. IsDDS := SameText(Fmt.Extensions[0], 'dds');
  776. if IsDDS then
  777. begin
  778. PushOptions;
  779. SetOption(ImagingDDSSaveMipMapCount, Length(Arr));
  780. end;
  781. Result := SaveMultiImageToMemory(Ext, Data, Size, Arr);
  782. if IsDDS then
  783. PopOptions;
  784. end;
  785. FreeImagesInArray(Arr);
  786. end;
  787. end;
  788. function CreateImageFromGLTexture(const Texture: GLuint;
  789. var Image: TImageData; OverrideFormat: TImageFormat): Boolean;
  790. var
  791. Arr: TDynImageDataArray;
  792. begin
  793. // Just calls function operating on image arrays
  794. FreeImage(Image);
  795. SetLength(Arr, 1);
  796. Result := CreateMultiImageFromGLTexture(Texture, Arr, 1, OverrideFormat);
  797. Image := Arr[0];
  798. end;
  799. function CreateMultiImageFromGLTexture(const Texture: GLuint;
  800. var Images: TDynImageDataArray; MipLevels: LongInt; OverrideFormat: TImageFormat): Boolean;
  801. var
  802. I, Width, Height, ExistingLevels: LongInt;
  803. begin
  804. FreeImagesInArray(Images);
  805. SetLength(Images, 0);
  806. Result := False;
  807. if glIsTexture(Texture) = GL_TRUE then
  808. begin
  809. // Check if desired mipmap level count is valid
  810. glBindTexture(GL_TEXTURE_2D, Texture);
  811. if MipLevels <= 0 then
  812. begin
  813. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, @Width);
  814. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, @Height);
  815. MipLevels := GetNumMipMapLevels(Width, Height);
  816. end;
  817. SetLength(Images, MipLevels);
  818. ExistingLevels := 0;
  819. for I := 0 to MipLevels - 1 do
  820. begin
  821. // Get the current level size
  822. glGetTexLevelParameteriv(GL_TEXTURE_2D, I, GL_TEXTURE_WIDTH, @Width);
  823. glGetTexLevelParameteriv(GL_TEXTURE_2D, I, GL_TEXTURE_HEIGHT, @Height);
  824. // Break when the mipmap chain is broken
  825. if (Width = 0) or (Height = 0) then
  826. Break;
  827. // Create new image and copy texture data
  828. NewImage(Width, Height, ifA8R8G8B8, Images[I]);
  829. glGetTexImage(GL_TEXTURE_2D, I, GL_BGRA_EXT, GL_UNSIGNED_BYTE, Images[I].Bits);
  830. Inc(ExistingLevels);
  831. end;
  832. // Resize mipmap array if necessary
  833. if MipLevels <> ExistingLevels then
  834. SetLength(Images, ExistingLevels);
  835. // Convert images to desired format if set
  836. if OverrideFormat <> ifUnknown then
  837. for I := 0 to Length(Images) - 1 do
  838. ConvertImage(Images[I], OverrideFormat);
  839. Result := True;
  840. end;
  841. end;
  842. initialization
  843. {
  844. File Notes:
  845. -- TODOS ----------------------------------------------------
  846. -- 0.77.1 ---------------------------------------------------
  847. - Added some new compressed formats IDs
  848. -- 0.26.5 Changes/Bug Fixes ---------------------------------
  849. - Fixed GetGLProcAddress in Unicode Delphi. Compressed
  850. textures didn't work because of this.
  851. -- 0.26.1 Changes/Bug Fixes ---------------------------------
  852. - Added support for GLScene's OpenGL header.
  853. -- 0.25.0 Changes/Bug Fixes ---------------------------------
  854. - Added 3Dc compressed texture formats support.
  855. - Added detection of 3Dc formats to texture caps.
  856. -- 0.24.3 Changes/Bug Fixes ---------------------------------
  857. - Added DisableNPOTSupportCheck option and related functionality.
  858. - Added some new texture caps detection.
  859. -- 0.24.1 Changes/Bug Fixes ---------------------------------
  860. - Added PasteNonPow2ImagesIntoPow2 option and related functionality.
  861. - Better NeedsResize determination for small DXTC textures -
  862. avoids needless resizing.
  863. - Added MainLevelIndex to CreateMultiImageFromGLTexture.
  864. -- 0.21 Changes/Bug Fixes -----------------------------------
  865. - Added CreatedWidth and CreatedHeight parameters to most
  866. LoadGLTextureFromXXX/CreateGLTextureFromXXX functions.
  867. -- 0.19 Changes/Bug Fixes -----------------------------------
  868. - fixed bug in CreateGLTextureFromMultiImage which caused assert failure
  869. when creating mipmaps (using FillMipMapLevel) for DXTC formats
  870. - changed single channel floating point texture formats from
  871. GL_INTENSITY..._ARB to GL_LUMINANCE..._ARB
  872. - added support for half float texture formats (GL_RGBA16F_ARB etc.)
  873. -- 0.17 Changes/Bug Fixes -----------------------------------
  874. - filtered mipmap creation
  875. - more texture caps added
  876. - fixed memory leaks in SaveGLTextureTo... functions
  877. -- 0.15 Changes/Bug Fixes -----------------------------------
  878. - unit created and initial stuff added
  879. }
  880. end.