GLS.FileDDS.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. //
  2. // The graphics platform GLScene https://github.com/glscene
  3. //
  4. unit GLS.FileDDS;
  5. (* DDS File support - Direct Draw Surface *)
  6. interface
  7. {$I Scenario.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. Scenario.TextureFormat,
  18. GLS.CompositeImage,
  19. GLS.MultiSampleImage,
  20. GLS.RGBE,
  21. GLS.ApplicationFileIO,
  22. GLS.VectorGeometry,
  23. GLS.Material,
  24. Scenario.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.