GLS.FileDDS.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. //
  2. // The graphics engine GLScene https://github.com/glscene
  3. //
  4. unit GLS.FileDDS;
  5. (* DDS File support - Direct Draw Surface *)
  6. interface
  7. {$I GLScene.Defines.inc}
  8. uses
  9. Winapi.OpenGL,
  10. Winapi.OpenGLext,
  11. System.Classes,
  12. System.SysUtils,
  13. System.Math,
  14. GLS.Context,
  15. GLS.Graphics,
  16. GLS.Texture,
  17. GLScene.VectorGeometry,
  18. GLS.TextureFormat,
  19. GLS.CompositeImage,
  20. GLS.MultiSampleImage,
  21. // GLScene.RGBE,
  22. GLS.ApplicationFileIO,
  23. GLS.Material,
  24. GLScene.Strings;
  25. type
  26. TGLDDSDetailLevels = (ddsHighDet, ddsMediumDet, ddsLowDet);
  27. TGLDDSImage = class(TGLBaseImage)
  28. private
  29. procedure FlipSurface(ChangeData: PGLubyte; W, H, D: integer);
  30. public
  31. class function Capabilities: TGLDataFileCapabilities; override;
  32. procedure LoadFromFile(const Filename: string); override;
  33. procedure SaveToFile(const Filename: string); override;
  34. procedure LoadFromStream(Stream: TStream); override;
  35. procedure SaveToStream(Stream: TStream); override;
  36. // Assigns from any Texture.
  37. procedure AssignFromTexture(TextureContext: TGLContext;
  38. const TextureHandle: Cardinal; TextureTarget: TGLTextureTarget;
  39. const CurrentFormat: Boolean;
  40. const IntFormat: TGLInternalFormat); reintroduce;
  41. end;
  42. // get or create material in material library
  43. function GetOrCreateLibMaterial(aMaterialLibrary: TGLMaterialLibrary;
  44. aMaterialName: string): TGLLibMaterial;
  45. function LibMat(aMatLib: TGLMaterialLibrary; aMatName: string): TGLLibMaterial;
  46. // load DDS to texture
  47. {
  48. function DDStex(aMatLib: TGLMaterialLibrary; aTexName, aDDSFileName: string;
  49. aSecondTexName: string = ''; aDDSLevel: integer = 0): TGLLibMaterial; overload;
  50. }
  51. function DDStex(aMatLib: TGLMaterialLibrary; aTexName, aDDSFileName: string;
  52. aSecondTexName: string = ''; aDDSLevel: integer = 0): TGLLibMaterial; overload;
  53. function DDStex(aTexture: TGLTexture; aDDSFileName: string;
  54. aDDSLevel: integer = 0): TGLTexture; overload;
  55. function DDStex(aTextureEx: TGLTextureExItem; aDDSFileName: string;
  56. aDDSLevel: integer = 0): TGLTextureExItem; overload;
  57. var
  58. (* Variable determines which resolution to use textures,
  59. high - it loads all levels,
  60. midle - skipped the first level,
  61. low - skipped the first two levels. *)
  62. vDDSDetailLevel: TGLDDSDetailLevels = ddsHighDet;
  63. //----------------------------------------------------------------------
  64. implementation
  65. //----------------------------------------------------------------------
  66. uses
  67. Formats.DXTC;
  68. // --------------------------------------------------------------------
  69. function GetOrCreateLibMaterial(aMaterialLibrary: TGLMaterialLibrary;
  70. aMaterialName: string): TGLLibMaterial;
  71. begin
  72. result := nil;
  73. if aMaterialLibrary = nil then
  74. exit;
  75. result := aMaterialLibrary.LibMaterialByName(aMaterialName);
  76. if result = nil then
  77. begin
  78. result := aMaterialLibrary.Materials.Add;
  79. result.Name := aMaterialName;
  80. end;
  81. end;
  82. // ---------------------------------------------------------------------
  83. function LibMat(aMatLib: TGLMaterialLibrary; aMatName: string): TGLLibMaterial;
  84. begin
  85. if aMatLib = nil then
  86. exit;
  87. result := aMatLib.LibMaterialByName(aMatName);
  88. if result = nil then
  89. begin
  90. result := aMatLib.Materials.Add;
  91. result.Name := aMatName;
  92. end;
  93. end;
  94. // DDStex
  95. // --------------------------------------------------------------------
  96. function DDStex(aMatLib: TGLMaterialLibrary; aTexName, aDDSFileName: string;
  97. aSecondTexName: string = ''; aDDSLevel: integer = 0): TGLLibMaterial;
  98. begin
  99. result := GetOrCreateLibMaterial(aMatLib, aTexName);
  100. result.Texture2Name := aSecondTexName;
  101. DDStex(result.Material.Texture, aDDSFileName, aDDSLevel);
  102. end;
  103. // ---------------------------------------------------------------------
  104. {
  105. function DDStex(aMatLib: TGLMaterialLibrary; aTexName, aDDSFileName: string;
  106. aSecondTexName: string = ''; aDDSLevel: integer = 0): TGLLibMaterial;
  107. var
  108. Level: TGLDDSDetailLevels;
  109. begin
  110. Level := vDDSDetailLevel;
  111. case aDDSLevel of
  112. 1: vDDSDetailLevel := ddsMediumDet;
  113. 2: vDDSDetailLevel := ddsLowDet;
  114. else
  115. vDDSDetailLevel := ddsHighDet;
  116. end;
  117. Result := LibMat(aMatLib, aTexName);
  118. Result.Texture2Name := aSecondTexName;
  119. with Result.Material.Texture do
  120. begin
  121. ImageClassName := 'TGLCompositeImage';
  122. Image.LoadFromFile(aDDSFileName);
  123. Disabled := false;
  124. end;
  125. vDDSDetailLevel := Level;
  126. end;
  127. }
  128. // DDStex
  129. // --------------------------------------------------------------------
  130. function DDStex(aTextureEx: TGLTextureExItem; aDDSFileName: string;
  131. aDDSLevel: integer = 0): TGLTextureExItem;
  132. begin
  133. DDStex(aTextureEx.Texture, aDDSFileName, aDDSLevel);
  134. result := aTextureEx;
  135. end;
  136. // DDStex
  137. // --------------------------------------------------------------------
  138. function DDStex(aTexture: TGLTexture; aDDSFileName: string;
  139. aDDSLevel: integer = 0): TGLTexture;
  140. var
  141. def: TGLDDSDetailLevels;
  142. begin
  143. def := vDDSDetailLevel;
  144. case aDDSLevel of
  145. 1: vDDSDetailLevel := ddsMediumDet;
  146. 2: vDDSDetailLevel := ddsLowDet;
  147. else
  148. vDDSDetailLevel := ddsHighDet;
  149. end;
  150. with aTexture do
  151. begin
  152. ImageClassName := 'TGLCompositeImage';
  153. if FileExists(aDDSFileName) then
  154. Image.LoadFromFile(aDDSFileName);
  155. Disabled := false;
  156. end;
  157. result := aTexture;
  158. vDDSDetailLevel := def;
  159. end;
  160. // ------------------
  161. // ------------------ TGLDDSImage ------------------
  162. // ------------------
  163. procedure TGLDDSImage.LoadFromFile(const Filename: string);
  164. var
  165. fs: TStream;
  166. begin
  167. if FileStreamExists(fileName) then
  168. begin
  169. fs := TFileStream.Create(fileName, fmOpenRead);
  170. try
  171. LoadFromStream(fs);
  172. finally
  173. fs.Free;
  174. ResourceName := filename;
  175. end;
  176. end
  177. else
  178. raise EInvalidRasterFile.CreateFmt(strFileNotFound, [filename]);
  179. end;
  180. procedure TGLDDSImage.SaveToFile(const Filename: string);
  181. var
  182. fs: TStream;
  183. begin
  184. fs := TFileStream.Create(FileName, fmOpenWrite or fmCreate);
  185. try
  186. SaveToStream(fs);
  187. finally
  188. fs.Free;
  189. end;
  190. ResourceName := filename;
  191. end;
  192. procedure TGLDDSImage.LoadFromStream(Stream: TStream);
  193. var
  194. header: TDDSHeader;
  195. DX10header: TDDS_HEADER_DXT10;
  196. btcCompressed: Boolean;
  197. face, faceCount, level: Integer;
  198. w, h, d, bw, bh, size, offset: Integer;
  199. bDXT10Header: Boolean;
  200. procedure CalcSize;
  201. begin
  202. if btcCompressed then
  203. begin
  204. bw := (w + 3) div 4;
  205. bh := (h + 3) div 4;
  206. end
  207. else
  208. begin
  209. bw := w;
  210. bh := h;
  211. end;
  212. if d = 0 then
  213. d := 1;
  214. size := bw * bh * d * fElementSize;
  215. end;
  216. begin
  217. stream.Read(header, Sizeof(TDDSHeader));
  218. // DDS files always start with the same magic number ("DDS ")
  219. if TFOURCC(header.Magic) <> 'DDS ' then
  220. raise EInvalidRasterFile.Create('Invalid DDS file');
  221. // Verify header to validate DDS file
  222. if (header.SurfaceFormat.dwSize <> sizeof(TDDSURFACEDESC2))
  223. or (header.SurfaceFormat.ddpf.dwSize <> sizeof(TDDPIXELFORMAT)) then
  224. raise EInvalidRasterFile.Create('Invalid DDS file');
  225. // Check for DX10 extension
  226. bDXT10Header := (header.SurfaceFormat.ddpf.dwFlags and DDPF_FOURCC <> 0)
  227. and (header.SurfaceFormat.ddpf.dwFourCC = FOURCC_DX10);
  228. if bDXT10Header then
  229. stream.Read(DX10header, Sizeof(TDDS_HEADER_DXT10));
  230. with header.SurfaceFormat do
  231. begin
  232. (* There are flags that are supposed to mark these fields as valid,
  233. but some dds files don't set them properly *)
  234. UnMipmap;
  235. FLOD[0].Width := dwWidth;
  236. FLOD[0].Height := dwHeight;
  237. // check if image is a volume texture
  238. if ((dwCaps2 and DDSCAPS2_VOLUME) <> 0) and (dwDepth > 0) then
  239. FLOD[0].Depth := dwDepth
  240. else
  241. FLOD[0].Depth := 0;
  242. if (dwFlags and DDSD_MIPMAPCOUNT) <> 0 then
  243. fLevelCount := MaxInteger(dwMipMapCount, 1)
  244. else
  245. fLevelCount := 1;
  246. //check cube-map faces
  247. fCubeMap := false;
  248. faceCount := 0;
  249. if (dwCaps2 and DDSCAPS2_CUBEMAP) <> 0 then
  250. begin
  251. //this is a cubemap, count the faces
  252. if (dwCaps2 and DDSCAPS2_CUBEMAP_POSITIVEX) <> 0 then
  253. Inc(faceCount);
  254. if (dwCaps2 and DDSCAPS2_CUBEMAP_NEGATIVEX) <> 0 then
  255. Inc(faceCount);
  256. if (dwCaps2 and DDSCAPS2_CUBEMAP_POSITIVEY) <> 0 then
  257. Inc(faceCount);
  258. if (dwCaps2 and DDSCAPS2_CUBEMAP_NEGATIVEY) <> 0 then
  259. Inc(faceCount);
  260. if (dwCaps2 and DDSCAPS2_CUBEMAP_POSITIVEZ) <> 0 then
  261. Inc(faceCount);
  262. if (dwCaps2 and DDSCAPS2_CUBEMAP_NEGATIVEZ) <> 0 then
  263. Inc(faceCount);
  264. //check for a complete cubemap
  265. if (faceCount <> 6) or (GetWidth <> GetHeight) then
  266. raise EInvalidRasterFile.Create('Invalid cubemap');
  267. fCubeMap := true;
  268. end;
  269. fTextureArray := false;
  270. if not DDSHeaderToGLEnum(header,
  271. DX10header,
  272. bDXT10Header,
  273. fInternalFormat,
  274. fColorFormat,
  275. fDataType,
  276. fElementSize) then
  277. raise EInvalidRasterFile.Create('DDS errorneus format');
  278. btcCompressed := IsCompressedFormat(fInternalFormat);
  279. end; // of with
  280. offset := 0;
  281. case vDDSDetailLevel of
  282. ddsHighDet: ; // Do nothing..
  283. ddsMediumDet:
  284. if fLevelCount > 1 then
  285. begin
  286. w := FLOD[0].Width;
  287. h := FLOD[0].Height;
  288. d := FLOD[0].Depth;
  289. CalcSize;
  290. offset := size;
  291. FLOD[0].Width := FLOD[0].Width div 2;
  292. FLOD[0].Height := FLOD[0].Height div 2;
  293. FLOD[0].Depth := FLOD[0].Depth div 2;
  294. Dec(fLevelCount);
  295. end;
  296. ddsLowDet:
  297. if fLevelCount > 2 then
  298. begin
  299. w := FLOD[0].Width;
  300. h := FLOD[0].Height;
  301. d := FLOD[0].Depth;
  302. CalcSize;
  303. offset := size;
  304. Div2(w);
  305. Div2(h);
  306. Div2(d);
  307. CalcSize;
  308. offset := offset + size;
  309. FLOD[0].Width := FLOD[0].Width div 4;
  310. FLOD[0].Height := FLOD[0].Height div 4;
  311. FLOD[0].Depth := FLOD[0].Depth div 4;
  312. Dec(fLevelCount, 2);
  313. end;
  314. else
  315. Assert(False, strErrorEx + strUnknownType);
  316. end;
  317. ReallocMem(fData, DataSize);
  318. if not fCubeMap then
  319. faceCount := 1;
  320. for face := 0 to faceCount - 1 do
  321. begin
  322. if offset > 0 then
  323. stream.Seek(offset, soCurrent);
  324. for level := 0 to fLevelCount - 1 do
  325. begin
  326. stream.Read(GetLevelAddress(level, face)^, GetLevelSizeInByte(level) div faceCount);
  327. if not fCubeMap and vVerticalFlipDDS then
  328. flipSurface(GetLevelAddress(level, face), FLOD[level].Width, FLOD[level].Height, FLOD[level].Depth);
  329. end;
  330. end; // for level
  331. end;
  332. procedure TGLDDSImage.SaveToStream(Stream: TStream);
  333. const
  334. Magic: array[0..3] of AnsiChar = 'DDS ';
  335. var
  336. header: TDDSHeader;
  337. DX10header: TDDS_HEADER_DXT10;
  338. buffer: PGLubyte;
  339. level, size: Integer;
  340. begin
  341. FillChar(header, SizeOf(TDDSHeader), 0);
  342. header.Magic := Cardinal(Magic);
  343. header.SurfaceFormat.dwSize := sizeof(TDDSURFACEDESC2);
  344. header.SurfaceFormat.ddpf.dwSize := sizeof(TDDPIXELFORMAT);
  345. header.SurfaceFormat.dwWidth := GetWidth;
  346. header.SurfaceFormat.dwHeight := GetHeight;
  347. header.SurfaceFormat.dwDepth := GetDepth;
  348. header.SurfaceFormat.dwPitchOrLinearSize := fElementSize * GetWidth;
  349. header.SurfaceFormat.dwFlags := DDSD_CAPS or
  350. DDSD_HEIGHT or
  351. DDSD_WIDTH or
  352. DDSD_PIXELFORMAT;
  353. if IsCompressed then
  354. begin
  355. header.SurfaceFormat.dwPitchOrLinearSize :=
  356. header.SurfaceFormat.dwPitchOrLinearSize * Cardinal(GetHeight) *
  357. Cardinal(GetDepth);
  358. header.SurfaceFormat.dwFlags := header.SurfaceFormat.dwFlags or DDSD_PITCH;
  359. end
  360. else
  361. header.SurfaceFormat.dwFlags := header.SurfaceFormat.dwFlags or
  362. DDSD_LINEARSIZE;
  363. header.SurfaceFormat.dwCaps := DDSCAPS_TEXTURE;
  364. header.SurfaceFormat.dwCaps2 := 0;
  365. if IsVolume then
  366. begin
  367. header.SurfaceFormat.dwFlags := header.SurfaceFormat.dwFlags or DDSD_DEPTH;
  368. header.SurfaceFormat.dwCaps := header.SurfaceFormat.dwCaps or
  369. DDSCAPS_COMPLEX;
  370. header.SurfaceFormat.dwCaps2 := header.SurfaceFormat.dwCaps2 or
  371. DDSCAPS2_VOLUME;
  372. end;
  373. if fLevelCount > 1 then
  374. begin
  375. header.SurfaceFormat.dwCaps := header.SurfaceFormat.dwCaps or DDSCAPS_COMPLEX
  376. or DDSCAPS_MIPMAP;
  377. header.SurfaceFormat.dwFlags := header.SurfaceFormat.dwFlags or
  378. DDSD_MIPMAPCOUNT;
  379. header.SurfaceFormat.dwMipMapCount := fLevelCount;
  380. end
  381. else
  382. header.SurfaceFormat.dwMipMapCount := 0;
  383. if fCubeMap then
  384. begin
  385. header.SurfaceFormat.dwCaps := header.SurfaceFormat.dwCaps or
  386. DDSCAPS_COMPLEX;
  387. header.SurfaceFormat.dwCaps2 := header.SurfaceFormat.dwCaps2 or
  388. DDSCAPS2_CUBEMAP or
  389. DDSCAPS2_CUBEMAP_POSITIVEX or
  390. DDSCAPS2_CUBEMAP_NEGATIVEX or
  391. DDSCAPS2_CUBEMAP_POSITIVEY or
  392. DDSCAPS2_CUBEMAP_NEGATIVEY or
  393. DDSCAPS2_CUBEMAP_POSITIVEZ or
  394. DDSCAPS2_CUBEMAP_NEGATIVEZ;
  395. end;
  396. if not GLEnumToDDSHeader(header,
  397. DX10header,
  398. false,
  399. fInternalFormat,
  400. fColorFormat,
  401. fDataType,
  402. fElementSize) then
  403. raise
  404. EInvalidRasterFile.Create('These image format do not match the DDS format specification.');
  405. stream.Write(header, Sizeof(TDDSHeader));
  406. // stream.Write(DX10header, Sizeof(TDDS_HEADER_DXT10));
  407. if fCubeMap or not vVerticalFlipDDS then
  408. begin
  409. stream.Write(fData[0], DataSize);
  410. Exit;
  411. end
  412. else
  413. begin
  414. GetMem(buffer, GetLevelSizeInByte(0));
  415. try
  416. for level := 0 to fLevelCount - 1 do
  417. begin
  418. size := GetLevelSizeInByte(level);
  419. Move(GetLevelAddress(level)^, buffer^, size);
  420. flipSurface(buffer, LevelWidth[level], LevelHeight[level], LevelDepth[level]);
  421. stream.Write(buffer^, size);
  422. end;
  423. finally
  424. FreeMem(buffer);
  425. end;
  426. end;
  427. end;
  428. procedure TGLDDSImage.AssignFromTexture(TextureContext: TGLContext;
  429. const textureHandle: Cardinal;
  430. textureTarget: TGLTextureTarget;
  431. const CurrentFormat: Boolean;
  432. const intFormat: TGLInternalFormat);
  433. var
  434. oldContext: TGLContext;
  435. contextActivate: Boolean;
  436. texFormat, texLod, optLod: Cardinal;
  437. level, faceCount, face: Integer;
  438. residentFormat: TGLInternalFormat;
  439. bCompressed: Boolean;
  440. vtcBuffer, top, bottom: PGLubyte;
  441. i, j, k: Integer;
  442. cw, ch: Integer;
  443. glTarget: Cardinal;
  444. function blockOffset(x, y, z: Integer): Integer;
  445. begin
  446. if z >= (FLOD[level].Depth and -4) then
  447. Result := fElementSize * (cw * ch * (FLOD[level].Depth and -4) + x +
  448. cw * (y + ch * (z - 4 * ch)))
  449. else
  450. Result := fElementSize * (4 * (x + cw * (y + ch * Floor(z / 4))) + (z and
  451. 3));
  452. if Result < 0 then
  453. Result := 0;
  454. end;
  455. begin
  456. oldContext := CurrentGLContext;
  457. contextActivate := (oldContext <> textureContext);
  458. if contextActivate then
  459. begin
  460. if Assigned(oldContext) then
  461. oldContext.Deactivate;
  462. textureContext.Activate;
  463. end;
  464. glTarget := DecodeTextureTarget(textureTarget);
  465. try
  466. textureContext.GLStates.TextureBinding[0, textureTarget] := textureHandle;
  467. fLevelCount := 0;
  468. gl.GetTexParameteriv(glTarget, GL_TEXTURE_MAX_LEVEL, @texLod);
  469. if glTarget = GL_TEXTURE_CUBE_MAP then
  470. begin
  471. fCubeMap := true;
  472. faceCount := 6;
  473. glTarget := GL_TEXTURE_CUBE_MAP_POSITIVE_X;
  474. end
  475. else
  476. begin
  477. fCubeMap := false;
  478. faceCount := 1;
  479. end;
  480. fTextureArray := (glTarget = GL_TEXTURE_1D_ARRAY)
  481. or (glTarget = GL_TEXTURE_2D_ARRAY)
  482. or (glTarget = GL_TEXTURE_CUBE_MAP_ARRAY);
  483. repeat
  484. // Check level existence
  485. gl.GetTexLevelParameteriv(glTarget, fLevelCount,
  486. GL_TEXTURE_INTERNAL_FORMAT,
  487. @texFormat);
  488. if texFormat = 1 then
  489. Break;
  490. Inc(fLevelCount);
  491. if fLevelCount = 1 then
  492. begin
  493. gl.GetTexLevelParameteriv(glTarget, 0, GL_TEXTURE_WIDTH, @FLOD[0].Width);
  494. gl.GetTexLevelParameteriv(glTarget, 0, GL_TEXTURE_HEIGHT, @FLOD[0].Height);
  495. FLOD[0].Depth := 0;
  496. if (glTarget = GL_TEXTURE_3D)
  497. or (glTarget = GL_TEXTURE_2D_ARRAY)
  498. or (glTarget = GL_TEXTURE_CUBE_MAP_ARRAY) then
  499. gl.GetTexLevelParameteriv(glTarget, 0, GL_TEXTURE_DEPTH, @FLOD[0].Depth);
  500. residentFormat := OpenGLFormatToInternalFormat(texFormat);
  501. if CurrentFormat then
  502. fInternalFormat := residentFormat
  503. else
  504. fInternalFormat := intFormat;
  505. if not FindDDSCompatibleDataFormat(fInternalFormat,
  506. fColorFormat,
  507. fDataType) then
  508. FindCompatibleDataFormat(fInternalFormat,
  509. fColorFormat,
  510. fDataType);
  511. // Get optimal number or MipMap levels
  512. optLod := GetImageLodNumber(FLOD[0].Width, FLOD[0].Height, FLOD[0].Depth, glTarget = GL_TEXTURE_3D);
  513. if texLod > optLod then
  514. texLod := optLod;
  515. // Check for MipMap posibility
  516. if ((fInternalFormat >= tfFLOAT_R16)
  517. and (fInternalFormat <= tfFLOAT_RGBA32)) then
  518. texLod := 1;
  519. end;
  520. until fLevelCount = Integer(texLod);
  521. if fLevelCount > 0 then
  522. begin
  523. fElementSize := GetTextureElementSize(fColorFormat, fDataType);
  524. ReallocMem(FData, DataSize);
  525. bCompressed := IsCompressed;
  526. vtcBuffer := nil;
  527. for face := 0 to faceCount - 1 do
  528. begin
  529. if fCubeMap then
  530. glTarget := face + GL_TEXTURE_CUBE_MAP_POSITIVE_X;
  531. for level := 0 to fLevelCount - 1 do
  532. begin
  533. if bCompressed then
  534. begin
  535. if gl.NV_texture_compression_vtc and (FLOD[level].Depth > 0)
  536. and not fTextureArray then
  537. begin
  538. if level = 0 then
  539. GetMem(vtcBuffer, GetLevelSizeInByte(0));
  540. gl.GetCompressedTexImage(glTarget, level, vtcBuffer);
  541. // Shufle blocks from VTC to S3TC
  542. cw := (FLOD[level].Width + 3) div 4;
  543. ch := (FLOD[level].Height + 3) div 4;
  544. top := GetLevelAddress(level);
  545. for k := 0 to FLOD[level].Depth - 1 do
  546. for i := 0 to ch - 1 do
  547. for j := 0 to cw - 1 do
  548. begin
  549. bottom := vtcBuffer;
  550. Inc(bottom, blockOffset(j, i, k));
  551. Move(bottom^, top^, fElementSize);
  552. Inc(top, fElementSize);
  553. end;
  554. end
  555. else
  556. gl.GetCompressedTexImage(glTarget, level, GetLevelAddress(level));
  557. end
  558. else
  559. gl.GetTexImage(glTarget, level, fColorFormat, fDataType, GetLevelAddress(level));
  560. end; // for level
  561. end; // for face
  562. if Assigned(vtcBuffer) then
  563. FreeMem(vtcBuffer);
  564. // Check memory corruption
  565. ReallocMem(FData, DataSize);
  566. end;
  567. if fLevelCount < 1 then
  568. fLevelCount := 1;
  569. gl.CheckError;
  570. finally
  571. if contextActivate then
  572. begin
  573. textureContext.Deactivate;
  574. if Assigned(oldContext) then
  575. oldContext.Activate;
  576. end;
  577. end;
  578. end;
  579. procedure TGLDDSImage.FlipSurface(ChangeData: PGLubyte; W, H, D: integer);
  580. var
  581. LineSize: integer;
  582. SliceSize: integer;
  583. TempBuf: PGLubyte;
  584. i, j: integer;
  585. Top, Bottom: PGLubyte;
  586. FlipBlocks: procedure(data: PGLubyte; size: integer);
  587. begin
  588. if d = 0 then
  589. d := 1;
  590. if not isCompressed then
  591. begin
  592. lineSize := fElementSize * w;
  593. sliceSize := lineSize * h;
  594. GetMem(tempBuf, lineSize);
  595. for i := 0 to d - 1 do
  596. begin
  597. top := ChangeData;
  598. Inc(top, i * sliceSize);
  599. bottom := top;
  600. Inc(bottom, sliceSize - lineSize);
  601. for j := 0 to (h div 2) - 1 do
  602. begin
  603. Move(top^, tempBuf^, lineSize);
  604. Move(bottom^, top^, lineSize);
  605. Move(tempBuf^, bottom^, lineSize);
  606. Inc(top, lineSize);
  607. Dec(bottom, lineSize);
  608. end;
  609. end;
  610. FreeMem(tempBuf);
  611. end
  612. else
  613. begin
  614. w := (w + 3) div 4;
  615. h := (h + 3) div 4;
  616. case fColorFormat of
  617. GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: flipblocks := flip_blocks_dxtc1;
  618. GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: flipblocks := flip_blocks_dxtc3;
  619. GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: flipblocks := flip_blocks_dxtc5;
  620. else
  621. exit;
  622. end;
  623. lineSize := fElementSize * w;
  624. sliceSize := lineSize * h;
  625. GetMem(tempBuf, lineSize);
  626. for i := 0 to d - 1 do
  627. begin
  628. top := ChangeData;
  629. Inc(top, i * sliceSize);
  630. bottom := top;
  631. Inc(bottom, sliceSize - lineSize);
  632. for j := 0 to (h div 2) - 1 do
  633. begin
  634. if top = bottom then
  635. begin
  636. flipblocks(top, w);
  637. break;
  638. end;
  639. flipblocks(top, w);
  640. flipblocks(bottom, w);
  641. Move(top^, tempBuf^, lineSize);
  642. Move(bottom^, top^, lineSize);
  643. Move(tempBuf^, bottom^, lineSize);
  644. Inc(top, lineSize);
  645. Dec(bottom, lineSize);
  646. end;
  647. end;
  648. FreeMem(tempBuf);
  649. end;
  650. end;
  651. class function TGLDDSImage.Capabilities: TGLDataFileCapabilities;
  652. begin
  653. Result := [dfcRead, dfcWrite];
  654. end;
  655. //----------------------------------------------
  656. initialization
  657. //----------------------------------------------
  658. RegisterRasterFormat('dds', 'Direct Draw Surface', TGLDDSImage);
  659. end.