GLS.FileDDS.pas 20 KB

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