GLS.Graphics.pas 129 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070
  1. //
  2. // The multimedia graphics platform GLScene https://github.com/glscene
  3. //
  4. unit GLS.Graphics;
  5. (*
  6. Utility class and functions to manipulate a bitmap in OpenGL's default
  7. byte order (GL_RGBA vs TBitmap's GL_BGRA)
  8. Note: TGLBitmap32 = TGLImage has support for Alex Denissov's Graphics32 library
  9. (http://www.g32.org), just make sure the USE_GRAPHICS32 conditionnal
  10. is active in GLScene.inc and recompile.
  11. *)
  12. interface
  13. {$I GLScene.inc}
  14. uses
  15. Winapi.OpenGL,
  16. Winapi.OpenGLext,
  17. Winapi.Windows,
  18. System.Classes,
  19. System.SysUtils,
  20. System.SyncObjs,
  21. System.Math,
  22. VCL.Graphics,
  23. VCL.Imaging.Pngimage,
  24. VCL.Consts,
  25. {$IFDEF USE_GRAPHICS32} GR32, {$ENDIF}
  26. GLS.VectorTypes,
  27. GLS.State,
  28. GLS.ApplicationFileIO,
  29. GLS.PersistentClasses,
  30. GLS.Context,
  31. GLS.ImageUtils,
  32. GLS.Color,
  33. GLS.TextureFormat,
  34. GLS.VectorGeometry,
  35. GLS.Utils,
  36. GLS.Strings,
  37. GLS.Logger;
  38. {$DEFINE PRF_HACK_PASSES}
  39. type
  40. TGLPixel24 = packed record
  41. r, g, b: Byte;
  42. end;
  43. PGLPixel24 = ^TGLPixel24;
  44. TGLPixel32 = packed record
  45. r, g, b, a: Byte;
  46. end;
  47. PGLPixel32 = ^TGLPixel32;
  48. TGLPixel32Array = array[0..MaxInt shr 3] of TGLPixel32;
  49. PGLPixel32Array = ^TGLPixel32Array;
  50. TGLLODStreamingState = (ssKeeping, ssLoading, ssLoaded, ssTransfered);
  51. TGLImageLevelDesc = record
  52. Width: Integer;
  53. Height: Integer;
  54. Depth: Integer;
  55. PBO: TGLUnpackPBOHandle;
  56. MapAddress: Pointer;
  57. Offset: LongWord;
  58. StreamOffset: LongWord;
  59. Size: LongWord;
  60. State: TGLLODStreamingState;
  61. end;
  62. TGLImageLODRange = 0..15;
  63. TGLImagePiramid = array[TGLImageLODRange] of TGLImageLevelDesc;
  64. TGLBaseImage = class(TGLDataFile)
  65. private
  66. FSourceStream: TStream;
  67. FStreamLevel: TGLImageLODRange;
  68. FFinishEvent: TFinishTaskEvent;
  69. {$IFDEF USE_SERVICE_CONTEXT}
  70. procedure ImageStreamingTask; stdcall;
  71. {$ENDIF}
  72. protected
  73. fData: PGLPixel32Array;
  74. FLOD: TGLImagePiramid;
  75. fLevelCount: TGLImageLODRange;
  76. fColorFormat: Cardinal;
  77. fInternalFormat: TGLInternalFormat;
  78. fDataType: Cardinal;
  79. fElementSize: Integer;
  80. fCubeMap: Boolean;
  81. fTextureArray: Boolean;
  82. function GetData: PGLPixel32Array; virtual;
  83. function GetWidth: Integer;
  84. function GetHeight: Integer;
  85. function GetDepth: Integer;
  86. function GetLevelAddress(ALevel: Byte): Pointer; overload;
  87. function GetLevelAddress(ALevel, AFace: Byte): Pointer; overload;
  88. function GetLevelWidth(ALOD: TGLImageLODRange): Integer;
  89. function GetLevelHeight(ALOD: TGLImageLODRange): Integer;
  90. function GetLevelDepth(ALOD: TGLImageLODRange): Integer;
  91. function GetLevelPBO(ALOD: TGLImageLODRange): TGLUnpackPBOHandle;
  92. function GetLevelOffset(ALOD: TGLImageLODRange): Integer;
  93. function GetLevelSizeInByte(ALOD: TGLImageLODRange): Integer;
  94. function GetLevelStreamingState(ALOD: TGLImageLODRange): TGLLODStreamingState;
  95. procedure SetLevelStreamingState(ALOD: TGLImageLODRange; AState: TGLLODStreamingState);
  96. procedure SaveHeader;
  97. procedure LoadHeader;
  98. procedure StartStreaming;
  99. procedure DoStreaming;
  100. public
  101. constructor Create; reintroduce; virtual;
  102. destructor Destroy; override;
  103. procedure Assign(Source: TPersistent); override;
  104. function GetTextureTarget: TGLTextureTarget;
  105. // Registers the bitmap's content as an OpenGL texture map.
  106. procedure RegisterAsOpenGLTexture(
  107. AHandle: TGLTextureHandle;
  108. aMipmapGen: Boolean;
  109. aTexFormat: Cardinal;
  110. out texWidth: integer;
  111. out texHeight: integer;
  112. out texDepth: integer); virtual;
  113. // Assigns from any Texture.
  114. function AssignFromTexture(
  115. AHandle: TGLTextureHandle;
  116. const CastToFormat: Boolean;
  117. const intFormat: TGLInternalFormat = tfRGBA8;
  118. const colorFormat: Cardinal = 0;
  119. const dataType: Cardinal = 0): Boolean; virtual;
  120. (* Convert vertical cross format of non compressed, non mipmaped image
  121. to six face of cube map *)
  122. function ConvertCrossToCubeMap: Boolean;
  123. // Convert flat image to volume by dividing it into slice.
  124. function ConvertToVolume(const col, row: Integer; const MakeArray: Boolean): Boolean;
  125. // Return size in byte of all image
  126. function DataSize: Cardinal;
  127. //True if the bitmap is empty (ie. width or height is zero).
  128. function IsEmpty: Boolean;
  129. function IsCompressed: Boolean;
  130. function IsVolume: Boolean;
  131. //Narrow image data to simple RGBA8 ubyte
  132. procedure Narrow;
  133. //Generate LOD pyramid
  134. procedure GenerateMipmap(AFilter: TImageFilterFunction); virtual;
  135. // Leave top level and remove other
  136. procedure UnMipmap; virtual;
  137. // Direct Access to image data
  138. property Data: PGLPixel32Array read GetData;
  139. // Set image of error.
  140. procedure SetErrorImage;
  141. // Recalculate levels information based on first level.
  142. procedure UpdateLevelsInfo;
  143. property LevelWidth[ALOD: TGLImageLODRange]: Integer read GetLevelWidth;
  144. property LevelHeight[ALOD: TGLImageLODRange]: Integer read GetLevelHeight;
  145. property LevelDepth[ALOD: TGLImageLODRange]: Integer read GetLevelDepth;
  146. property LevelPixelBuffer[ALOD: TGLImageLODRange]: TGLUnpackPBOHandle
  147. read GetLevelPBO;
  148. // LOD offset in byte
  149. property LevelOffset[ALOD: TGLImageLODRange]: Integer read GetLevelOffset;
  150. // LOD size in byte
  151. property LevelSizeInByte[ALOD: TGLImageLODRange]: Integer
  152. read GetLevelSizeInByte;
  153. property LevelStreamingState[ALOD: TGLImageLODRange]: TGLLODStreamingState
  154. read GetLevelStreamingState write SetLevelStreamingState;
  155. // Number of levels.
  156. property LevelCount: TGLImageLODRange read fLevelCount;
  157. property InternalFormat: TGLInternalFormat read FInternalFormat;
  158. property ColorFormat: Cardinal read fColorFormat;
  159. property DataType: Cardinal read fDataType;
  160. property ElementSize: Integer read fElementSize;
  161. property CubeMap: Boolean read fCubeMap;
  162. property TextureArray: Boolean read fTextureArray;
  163. end;
  164. TGLBaseImageClass = class of TGLBaseImage;
  165. (* Contains and manipulates a 32 bits (24+8) bitmap.
  166. This is the base class for preparing and manipulating textures in GLS.Scene,
  167. this function does not rely on a windows handle and should be used for
  168. in-memory manipulations only.
  169. 16 bits textures are automatically converted to 24 bits and an opaque (255)
  170. alpha channel is assumed for all planes, the byte order is as specified
  171. in GL_RGBA. If 32 bits is used in this class, it can however output 16 bits texture
  172. data for use in OpenGL.
  173. The class has support for registering its content as a texture, as well
  174. as for directly drawing/reading from the current OpenGL buffer. *)
  175. TGLImage = class(TGLBaseImage)
  176. private
  177. FVerticalReverseOnAssignFromBitmap: Boolean;
  178. FBlank: Boolean;
  179. fOldColorFormat: Cardinal;
  180. fOldDataType: Cardinal;
  181. procedure DataConvertTask;
  182. protected
  183. procedure SetWidth(val: Integer);
  184. procedure SetHeight(const val: Integer);
  185. procedure SetDepth(const val: Integer);
  186. procedure SetBlank(const Value: Boolean);
  187. procedure SetCubeMap(const val: Boolean);
  188. procedure SetArray(const val: Boolean);
  189. function GetScanLine(index: Integer): PGLPixel32Array;
  190. procedure AssignFrom24BitsBitmap(aBitmap: TBitmap);
  191. procedure AssignFrom32BitsBitmap(aBitmap: TBitmap);
  192. {$IFDEF USE_GRAPHICS32}
  193. procedure AssignFromBitmap32(aBitmap32: TBitmap32);
  194. {$ENDIF}
  195. procedure AssignFromPngImage(aPngImage: TPngImage);
  196. public
  197. constructor Create; override;
  198. destructor Destroy; override;
  199. // Accepts TGLImage and TGraphic subclasses.
  200. procedure Assign(Source: TPersistent); override;
  201. (* Assigns from a 24 bits bitmap without swapping RGB.
  202. This is faster than a regular assignment, but R and B channels
  203. will be reversed (from what you would view in a TImage). Suitable
  204. if you do your own drawing and reverse RGB on the drawing side.
  205. If you're after speed, don't forget to set the bitmap's dimensions
  206. to a power of two! *)
  207. procedure AssignFromBitmap24WithoutRGBSwap(aBitmap: TBitmap);
  208. (* Assigns from a 2D Texture.
  209. The context which holds the texture must be active and the texture
  210. handle valid. *)
  211. procedure AssignFromTexture2D(textureHandle: Cardinal); overload;
  212. (*Assigns from a Texture handle.
  213. If the handle is invalid, the bitmap32 will be empty. *)
  214. procedure AssignFromTexture2D(textureHandle: TGLTextureHandle); overload;
  215. // Create a 32 bits TBitmap from self content.
  216. function Create32BitsBitmap: TBitmap;
  217. // Width of the bitmap.
  218. property Width: Integer read GetWidth write SetWidth;
  219. // Height of the bitmap.
  220. property Height: Integer read GetHeight write SetHeight;
  221. // Depth of the bitmap.
  222. property Depth: Integer read GetDepth write SetDepth;
  223. // OpenGL color format
  224. property ColorFormat: Cardinal read fColorFormat;
  225. // Recommended texture internal format
  226. property InternalFormat: TGLInternalFormat read FInternalFormat write
  227. FInternalFormat;
  228. // OpenGL data type
  229. property DataType: Cardinal read fDataType;
  230. // Size in bytes of pixel or block
  231. property ElementSize: Integer read fElementSize;
  232. property CubeMap: Boolean read fCubeMap write SetCubeMap;
  233. property TextureArray: Boolean read fTextureArray write SetArray;
  234. (* Access to a specific Bitmap ScanLine. index should be in the [0; Height[ range.
  235. Warning : this function is NOT protected against invalid indexes,
  236. and invoking it is invalid if the bitmap is Empty. *)
  237. property ScanLine[index: Integer]: PGLPixel32Array read GetScanLine;
  238. property VerticalReverseOnAssignFromBitmap: Boolean read
  239. FVerticalReverseOnAssignFromBitmap write
  240. FVerticalReverseOnAssignFromBitmap;
  241. (* Set Blank to true if you actually don't need to allocate data in main menory.
  242. Useful for textures that are generated by the GPU on the fly. *)
  243. property Blank: boolean read FBlank write SetBlank;
  244. // Recast image OpenGL data type and color format.
  245. procedure SetColorFormatDataType(const AColorFormat, ADataType: Cardinal);
  246. (* Set Alpha channel values to the pixel intensity.
  247. The intensity is calculated as the mean of RGB components. *)
  248. procedure SetAlphaFromIntensity;
  249. (* Set Alpha channel to 0 for pixels of given color, 255 for others).
  250. This makes pixels of given color totally transparent while the others
  251. are completely opaque. *)
  252. procedure SetAlphaTransparentForColor(const aColor: TColor); overload;
  253. procedure SetAlphaTransparentForColor(const aColor: TGLPixel32); overload;
  254. procedure SetAlphaTransparentForColor(const aColor: TGLPixel24); overload;
  255. // Set Alpha channel values to given byte value.
  256. procedure SetAlphaToValue(const aValue: Byte);
  257. // Set Alpha channel values to given float [0..1] value.
  258. procedure SetAlphaToFloatValue(const aValue: Single);
  259. (* Inverts the AlphaChannel component.
  260. What was transparent becomes opaque and vice-versa. *)
  261. procedure InvertAlpha;
  262. // AlphaChannel components are replaced by their sqrt.
  263. procedure SqrtAlpha;
  264. // Apply a brightness (scaled saturating) correction to the RGB components.
  265. procedure BrightnessCorrection(const factor: Single);
  266. // Apply a gamma correction to the RGB components.
  267. procedure GammaCorrection(const gamma: Single);
  268. (* Downsample the bitmap by a factor of 2 in both dimensions.
  269. If one of the dimensions is 1 or less, does nothing. *)
  270. procedure DownSampleByFactor2;
  271. (* Reads the given area from the current active OpenGL rendering context.
  272. The best spot for reading pixels is within a SceneViewer's PostRender
  273. event : the scene has been fully rendered and the OpenGL context
  274. is still active. *)
  275. procedure ReadPixels(const area: TRect);
  276. (* Draws the whole bitmap at given position in the current OpenGL context.
  277. This function must be called with a rendering context active.
  278. Blending and Alpha channel functions are not altered by this function
  279. and must be adjusted separately. *)
  280. procedure DrawPixels(const x, y: Single);
  281. (* Converts a grayscale 'elevation' bitmap to normal map.
  282. Actually, only the Green component in the original bitmap is used. *)
  283. procedure GrayScaleToNormalMap(const scale: Single;
  284. wrapX: Boolean = True; wrapY: Boolean = True);
  285. // Assumes the bitmap content is a normal map and normalizes all pixels.
  286. procedure NormalizeNormalMap;
  287. // Converts a TImage back into a TBitmap
  288. procedure AssignToBitmap(aBitmap: TBitmap);
  289. // Generate level of detail.
  290. procedure GenerateMipmap(AFilter: TImageFilterFunction); override;
  291. // Clear all levels except first.
  292. procedure UnMipmap; override;
  293. end;
  294. TGLBitmap32 = TGLImage;
  295. TGLRasterFileFormat = class
  296. public
  297. BaseImageClass: TGLBaseImageClass;
  298. Extension: string;
  299. Description: string;
  300. DescResID: Integer;
  301. end;
  302. // Stores registered raster file formats.
  303. TGLRasterFileFormatsList = class(TGLPersistentObjectList)
  304. public
  305. destructor Destroy; override;
  306. procedure Add(const Ext, Desc: string; DescID: Integer; AClass:
  307. TGLBaseImageClass);
  308. function FindExt(ext: string): TGLBaseImageClass;
  309. function FindFromFileName(const fileName: string): TGLBaseImageClass;
  310. function FindFromStream(const AStream: TStream): TGLBaseImageClass;
  311. procedure Remove(AClass: TGLBaseImageClass);
  312. procedure BuildFilterStrings(imageFileClass: TGLBaseImageClass;
  313. var descriptions, filters: string;
  314. formatsThatCanBeOpened: Boolean = True;
  315. formatsThatCanBeSaved: Boolean = False);
  316. function FindExtByIndex(index: Integer;
  317. formatsThatCanBeOpened: Boolean = True;
  318. formatsThatCanBeSaved: Boolean = False): string;
  319. end;
  320. EInvalidRasterFile = class(Exception);
  321. procedure Div2(var Value: Integer);
  322. procedure BGR24ToRGB24(src, dest: Pointer; pixelCount: Integer);
  323. procedure BGR24ToRGBA32(src, dest: Pointer; pixelCount: Integer);
  324. procedure RGB24ToRGBA32(src, dest: Pointer; pixelCount: Integer);
  325. procedure BGRA32ToRGBA32(src, dest: Pointer; pixelCount: Integer);
  326. procedure GammaCorrectRGBArray(base: Pointer; pixelCount: Integer; gamma: Single);
  327. procedure BrightenRGBArray(base: Pointer; pixelCount: Integer; factor: Single);
  328. // Read access to the list of registered vector file formats
  329. function GetRasterFileFormats: TGLRasterFileFormatsList;
  330. (* Returns an extension by its index
  331. in the internal image files dialogs filter.
  332. Use InternalImageFileFormatsFilter to obtain the filter. *)
  333. function RasterFileFormatExtensionByIndex(index: Integer): string;
  334. procedure RegisterRasterFormat(const AExtension, ADescription: string;
  335. AClass: TGLBaseImageClass);
  336. procedure UnregisterRasterFormat(AClass: TGLBaseImageClass);
  337. // Return an optimal number of texture pyramid
  338. function GetImageLodNumber(w, h, d: Integer; IsVolume: Boolean): Integer;
  339. (* Returns the TGraphicClass associated to the extension, if any.
  340. Accepts anExtension with or without the '.' *)
  341. function GraphicClassForExtension(const anExtension: string): TGraphicClass;
  342. (* Adds to the passed TStrings the list of registered formats.
  343. Convention is "extension=description" for the string, the Objects hold
  344. the corresponding TGraphicClass (extensions do not include the '.'). *)
  345. procedure HackTPictureRegisteredFormats(destList: TStrings);
  346. var
  347. vVerticalFlipDDS: Boolean = True;
  348. // ------------------------------------------------------------------
  349. implementation
  350. // ------------------------------------------------------------------
  351. var
  352. vRasterFileFormats: TGLRasterFileFormatsList;
  353. // ------------------------------ Raster File Registries
  354. function GetRasterFileFormats: TGLRasterFileFormatsList;
  355. begin
  356. if not Assigned(vRasterFileFormats) then
  357. vRasterFileFormats := TGLRasterFileFormatsList.Create;
  358. Result := vRasterFileFormats;
  359. end;
  360. procedure RegisterRasterFormat(const AExtension, ADescription: string;
  361. AClass: TGLBaseImageClass);
  362. begin
  363. RegisterClass(AClass);
  364. GetRasterFileFormats.Add(AExtension, ADescription, 0, AClass);
  365. end;
  366. procedure UnregisterRasterFormat(AClass: TGLBaseImageClass);
  367. begin
  368. if Assigned(vRasterFileFormats) then
  369. vRasterFileFormats.Remove(AClass);
  370. end;
  371. function RasterFileFormatExtensionByIndex(index: Integer): string;
  372. begin
  373. Result := GetRasterFileFormats.FindExtByIndex(index);
  374. end;
  375. destructor TGLRasterFileFormatsList.Destroy;
  376. begin
  377. Clean;
  378. inherited;
  379. end;
  380. procedure TGLRasterFileFormatsList.Add(const Ext, Desc: string; DescID: Integer;
  381. AClass: TGLBaseImageClass);
  382. var
  383. newRec: TGLRasterFileFormat;
  384. begin
  385. newRec := TGLRasterFileFormat.Create;
  386. with newRec do
  387. begin
  388. Extension := AnsiLowerCase(Ext);
  389. BaseImageClass := AClass;
  390. Description := Desc;
  391. DescResID := DescID;
  392. end;
  393. inherited Add(newRec);
  394. end;
  395. function TGLRasterFileFormatsList.FindExt(Ext: string): TGLBaseImageClass;
  396. var
  397. i: Integer;
  398. begin
  399. Ext := AnsiLowerCase(Ext);
  400. for i := Count - 1 downto 0 do
  401. with TGLRasterFileFormat(Items[i]) do
  402. begin
  403. if Extension = Ext then
  404. begin
  405. Result := BaseImageClass;
  406. Exit;
  407. end;
  408. end;
  409. Result := nil;
  410. end;
  411. function TGLRasterFileFormatsList.FindFromFileName(const fileName: string):
  412. TGLBaseImageClass;
  413. var
  414. Ext: string;
  415. begin
  416. Ext := ExtractFileExt(FileName);
  417. System.Delete(Ext, 1, 1);
  418. Result := FindExt(Ext);
  419. if not Assigned(Result) then
  420. raise EInvalidRasterFile.CreateFmt(strUnknownExtension,
  421. [Ext, 'GLFile' + UpperCase(Ext)]);
  422. end;
  423. function TGLRasterFileFormatsList.FindFromStream(const AStream: TStream): TGLBaseImageClass;
  424. var
  425. Ext: string;
  426. magic: array [0 .. 1] of LongWord;
  427. begin
  428. magic[0] := 0;
  429. magic[1] := 1;
  430. AStream.ReadBuffer(magic, 2 * SizeOf(LongWord));
  431. AStream.Seek(-2 * SizeOf(LongWord), 1);
  432. if magic[0] = $20534444 then
  433. Ext := 'DDS'
  434. else if magic[1] = $4354334F then
  435. Ext := 'O3TC'
  436. else if (magic[0] and $0000FFFF) = $00003F23 then
  437. Ext := 'HDR'
  438. else if (magic[0] = $474E5089) and (magic[1] = $0A1A0A0D) then
  439. Ext := 'PNG'
  440. else if (magic[0] = $E0FFD8FF) and (magic[1] = $464A1000) then
  441. Ext := 'JPG';
  442. Result := FindExt(Ext);
  443. if not Assigned(Result) then
  444. raise EInvalidRasterFile.CreateFmt(strUnknownExtension,
  445. [Ext, 'GLFile' + UpperCase(Ext)]);
  446. end;
  447. procedure TGLRasterFileFormatsList.Remove(AClass: TGLBaseImageClass);
  448. var
  449. i: Integer;
  450. begin
  451. for i := Count - 1 downto 0 do
  452. begin
  453. if TGLRasterFileFormat(Items[i]).BaseImageClass.InheritsFrom(AClass) then
  454. DeleteAndFree(i);
  455. end;
  456. end;
  457. procedure TGLRasterFileFormatsList.BuildFilterStrings(
  458. imageFileClass: TGLBaseImageClass;
  459. var descriptions, filters: string;
  460. formatsThatCanBeOpened: Boolean = True;
  461. formatsThatCanBeSaved: Boolean = False);
  462. var
  463. k, i: Integer;
  464. p: TGLRasterFileFormat;
  465. begin
  466. descriptions := '';
  467. filters := '';
  468. k := 0;
  469. for i := 0 to Count - 1 do
  470. begin
  471. p := TGLRasterFileFormat(Items[i]);
  472. if p.BaseImageClass.InheritsFrom(imageFileClass) and (p.Extension <> '')
  473. and ((formatsThatCanBeOpened and (dfcRead in
  474. p.BaseImageClass.Capabilities))
  475. or (formatsThatCanBeSaved and (dfcWrite in p.BaseImageClass.Capabilities))) then
  476. begin
  477. with p do
  478. begin
  479. if k <> 0 then
  480. begin
  481. descriptions := descriptions + '|';
  482. filters := filters + ';';
  483. end;
  484. if (Description = '') and (DescResID <> 0) then
  485. Description := LoadStr(DescResID);
  486. FmtStr(descriptions, '%s%s (*.%s)|*.%2:s', [descriptions, Description,
  487. Extension]);
  488. filters := filters + '*.' + Extension;
  489. Inc(k);
  490. end;
  491. end;
  492. end;
  493. if (k > 1) and (not formatsThatCanBeSaved) then
  494. FmtStr(descriptions, '%s (%s)|%1:s|%s',
  495. [sAllFilter, filters, descriptions]);
  496. end;
  497. function TGLRasterFileFormatsList.FindExtByIndex(index: Integer;
  498. formatsThatCanBeOpened: Boolean = True;
  499. formatsThatCanBeSaved: Boolean = False): string;
  500. var
  501. i: Integer;
  502. p: TGLRasterFileFormat;
  503. begin
  504. Result := '';
  505. if index > 0 then
  506. begin
  507. for i := 0 to Count - 1 do
  508. begin
  509. p := TGLRasterFileFormat(Items[i]);
  510. if (formatsThatCanBeOpened and (dfcRead in p.BaseImageClass.Capabilities))
  511. or (formatsThatCanBeSaved and (dfcWrite in
  512. p.BaseImageClass.Capabilities)) then
  513. begin
  514. if index = 1 then
  515. begin
  516. Result := p.Extension;
  517. Break;
  518. end
  519. else
  520. Dec(index);
  521. end;
  522. end;
  523. end;
  524. end;
  525. procedure Div2(var Value: Integer);
  526. begin
  527. Value := Value div 2;
  528. if Value = 0 then
  529. Inc(Value);
  530. end;
  531. function GetImageLodNumber(w, h, d: integer; IsVolume: Boolean): Integer;
  532. var
  533. L: Integer;
  534. begin
  535. L := 1;
  536. d := MaxInteger(d, 1);
  537. while ((w > 1) or (h > 1) or (d > 1)) do
  538. begin
  539. Div2(w);
  540. Div2(h);
  541. if IsVolume then
  542. Div2(d);
  543. Inc(L);
  544. end;
  545. Result := L;
  546. end;
  547. procedure CalcImagePiramid(var APiramid: TGLImagePiramid);
  548. begin
  549. //
  550. end;
  551. // -------------------- RGBA Utils
  552. procedure GammaCorrectRGBArray(base: Pointer; pixelCount: Integer;
  553. gamma: Single);
  554. var
  555. vGammaLUT: array[0..255] of Byte;
  556. invGamma: Single;
  557. i: Integer;
  558. ptr: PByte;
  559. begin
  560. if pixelCount < 1 then
  561. Exit;
  562. Assert(gamma > 0);
  563. // build LUT
  564. if gamma < 0.1 then
  565. invGamma := 10
  566. else
  567. invGamma := 1 / gamma;
  568. for i := 0 to 255 do
  569. vGammaLUT[i] := Round(255 * Power(i * (1 / 255), InvGamma));
  570. // perform correction
  571. ptr := base;
  572. for i := 0 to pixelCount * 3 - 1 do
  573. begin
  574. ptr^ := vGammaLUT[ptr^];
  575. Inc(ptr);
  576. end;
  577. end;
  578. procedure GammaCorrectRGBAArray(base: Pointer; pixelCount: Integer;
  579. gamma: Single);
  580. var
  581. vGammaLUT: array [0 .. 255] of Byte;
  582. pLUT: PByteArray;
  583. invGamma: Single;
  584. i: Integer;
  585. ptr: PByte;
  586. begin
  587. if pixelCount < 1 then
  588. Exit;
  589. Assert(gamma > 0);
  590. // build LUT
  591. if gamma < 0.1 then
  592. invGamma := 10
  593. else
  594. invGamma := 1 / gamma;
  595. for i := 0 to 255 do
  596. vGammaLUT[i] := Round(255 * Power(i * (1 / 255), invGamma));
  597. // perform correction
  598. ptr := base;
  599. pLUT := @vGammaLUT[0];
  600. for i := 0 to pixelCount - 1 do
  601. begin
  602. ptr^ := pLUT^[ptr^];
  603. Inc(ptr);
  604. ptr^ := pLUT^[ptr^];
  605. Inc(ptr);
  606. ptr^ := pLUT^[ptr^];
  607. Inc(ptr, 2);
  608. end;
  609. end;
  610. procedure BrightenRGBArray(base: Pointer; pixelCount: Integer; factor: Single);
  611. var
  612. vBrightnessLUT: array[0..255] of Byte;
  613. i, k: Integer;
  614. ptr: PByte;
  615. begin
  616. if pixelCount < 1 then
  617. Exit;
  618. Assert(factor >= 0);
  619. // build LUT
  620. for i := 0 to 255 do
  621. begin
  622. k := Round(factor * i);
  623. if k > 255 then
  624. k := 255;
  625. vBrightnessLUT[i] := Byte(k);
  626. end;
  627. // perform correction
  628. ptr := base;
  629. for i := 0 to pixelCount * 3 - 1 do
  630. begin
  631. ptr^ := vBrightnessLUT[ptr^];
  632. Inc(ptr);
  633. end;
  634. end;
  635. procedure BrightenRGBAArray(base: Pointer; pixelCount: Integer; factor: Single);
  636. var
  637. vBrightnessLUT: array[0..255] of Byte;
  638. pLUT: PByteArray;
  639. i: Integer;
  640. ptr: PByte;
  641. k: Integer;
  642. begin
  643. if pixelCount < 1 then
  644. Exit;
  645. Assert(factor >= 0);
  646. // build LUT
  647. for i := 0 to 255 do
  648. begin
  649. k := Round(factor * i);
  650. if k > 255 then
  651. k := 255;
  652. vBrightnessLUT[i] := k;
  653. end;
  654. // perform correction
  655. ptr := base;
  656. pLUT := @vBrightnessLUT[0];
  657. for i := 0 to pixelCount - 1 do
  658. begin
  659. ptr^ := pLUT^[ptr^];
  660. Inc(ptr);
  661. ptr^ := pLUT^[ptr^];
  662. Inc(ptr);
  663. ptr^ := pLUT^[ptr^];
  664. Inc(ptr, 2);
  665. end;
  666. end;
  667. procedure BGR24ToRGB24(src, dest: Pointer; pixelCount: Integer); register;
  668. begin
  669. while pixelCount > 0 do
  670. begin
  671. PAnsiChar(dest)[0] := PAnsiChar(src)[2];
  672. PAnsiChar(dest)[1] := PAnsiChar(src)[1];
  673. PAnsiChar(dest)[2] := PAnsiChar(src)[0];
  674. Inc(PAnsiChar(dest), 3);
  675. Inc(PAnsiChar(src), 3);
  676. Dec(pixelCount);
  677. end;
  678. end;
  679. procedure BGR24ToRGBA32(src, dest: Pointer; pixelCount: Integer);
  680. begin
  681. while pixelCount > 0 do
  682. begin
  683. PAnsiChar(dest)[0] := PAnsiChar(src)[2];
  684. PAnsiChar(dest)[1] := PAnsiChar(src)[1];
  685. PAnsiChar(dest)[2] := PAnsiChar(src)[0];
  686. PAnsiChar(dest)[3] := #255;
  687. Inc(PAnsiChar(dest), 4);
  688. Inc(PAnsiChar(src), 3);
  689. Dec(pixelCount);
  690. end;
  691. end;
  692. procedure RGB24ToRGBA32(src, dest: Pointer; pixelCount: Integer);
  693. begin
  694. while pixelCount > 0 do
  695. begin
  696. PAnsiChar(dest)[0] := PAnsiChar(src)[0];
  697. PAnsiChar(dest)[1] := PAnsiChar(src)[1];
  698. PAnsiChar(dest)[2] := PAnsiChar(src)[2];
  699. PAnsiChar(dest)[3] := #255;
  700. Inc(PAnsiChar(dest), 4);
  701. Inc(PAnsiChar(src), 3);
  702. Dec(pixelCount);
  703. end;
  704. end;
  705. procedure BGRA32ToRGBA32(src, dest: Pointer; pixelCount: Integer);
  706. begin
  707. while pixelCount > 0 do
  708. begin
  709. PAnsiChar(dest)[0] := PAnsiChar(src)[2];
  710. PAnsiChar(dest)[1] := PAnsiChar(src)[1];
  711. PAnsiChar(dest)[2] := PAnsiChar(src)[0];
  712. PAnsiChar(dest)[3] := PAnsiChar(src)[3];
  713. Inc(PAnsiChar(dest), 4);
  714. Inc(PAnsiChar(src), 4);
  715. Dec(pixelCount);
  716. end;
  717. end;
  718. // ------------------
  719. // ------------------ TGLBaseImage ------------------
  720. // ------------------
  721. constructor TGLBaseImage.Create;
  722. begin
  723. inherited Create(Self);
  724. FillChar(FLOD, SizeOf(TGLImagePiramid), $00);
  725. fLevelCount := 1; // first level always is present
  726. fColorFormat := GL_RGBA;
  727. fInternalFormat := tfRGBA8;
  728. fDataType := GL_UNSIGNED_BYTE;
  729. fElementSize := 4;
  730. fCubeMap := False;
  731. fTextureArray := False;
  732. end;
  733. destructor TGLBaseImage.Destroy;
  734. var
  735. level: TGLImageLODRange;
  736. begin
  737. if Assigned(fData) then
  738. begin
  739. FreeMem(fData);
  740. fData := nil;
  741. end;
  742. FreeAndNil(FFinishEvent);
  743. for level := 0 to High(TGLImageLODRange) do
  744. begin
  745. FLOD[level].PBO.Free;
  746. end;
  747. FSourceStream.Free;
  748. inherited Destroy;
  749. end;
  750. procedure TGLBaseImage.Assign(Source: TPersistent);
  751. var
  752. img: TGLBaseImage;
  753. Size: Integer;
  754. begin
  755. if Source is TGLBaseImage then
  756. begin
  757. img := Source as TGLBaseImage;
  758. FLOD := img.FLOD;
  759. fLevelCount := img.fLevelCount;
  760. fColorFormat := img.fColorFormat;
  761. fInternalFormat := img.fInternalFormat;
  762. fDataType := img.fDataType;
  763. fElementSize := img.fElementSize;
  764. fCubeMap := img.fCubeMap;
  765. fTextureArray := img.fTextureArray;
  766. Size := img.DataSize;
  767. ReallocMem(fData, Size);
  768. Move(img.fData^, fData^, Size);
  769. end
  770. else if Source <> nil then
  771. inherited; // raise AssingError
  772. end;
  773. function TGLBaseImage.GetTextureTarget: TGLTextureTarget;
  774. begin
  775. Result := ttTexture2D;
  776. // Choose a texture target
  777. if GetHeight = 1 then
  778. Result := ttTexture1D;
  779. if fCubeMap then
  780. Result := ttTextureCube;
  781. if IsVolume then
  782. Result := ttTexture3D;
  783. if fTextureArray then
  784. begin
  785. if (GetDepth < 2) then
  786. Result := ttTexture1Darray
  787. else
  788. Result := ttTexture2DArray;
  789. if fCubeMap then
  790. Result := ttTextureCubeArray;
  791. end;
  792. if ((FInternalFormat >= tfFLOAT_R16)
  793. and (FInternalFormat <= tfFLOAT_RGBA32)) then
  794. Result := ttTextureRect;
  795. end;
  796. function TGLBaseImage.DataSize: Cardinal;
  797. var
  798. L: TGLImageLODRange;
  799. s: Cardinal;
  800. begin
  801. s := 0;
  802. if not IsEmpty then
  803. begin
  804. UpdateLevelsInfo;
  805. for l := 0 to FLevelCount - 1 do
  806. s := s + FLOD[l].Size;
  807. end;
  808. Result := s;
  809. end;
  810. function TGLBaseImage.GetWidth: Integer;
  811. begin
  812. Result := FLOD[0].Width;
  813. end;
  814. function TGLBaseImage.GetDepth: Integer;
  815. begin
  816. Result := FLOD[0].Depth;
  817. end;
  818. function TGLBaseImage.GetHeight: Integer;
  819. begin
  820. Result := FLOD[0].Height;
  821. end;
  822. function TGLBaseImage.GetLevelAddress(ALevel: Byte): Pointer;
  823. begin
  824. Result := fData;
  825. Inc(PByte(Result), FLOD[ALevel].Offset);
  826. end;
  827. function TGLBaseImage.GetLevelAddress(ALevel, AFace: Byte): Pointer;
  828. begin
  829. Result := fData;
  830. Inc(PByte(Result), FLOD[ALevel].Offset);
  831. Inc(PByte(Result), AFace * (FLOD[ALevel].Size div 6));
  832. end;
  833. function TGLBaseImage.GetLevelDepth(ALOD: TGLImageLODRange): Integer;
  834. begin
  835. Result := FLOD[ALOD].Depth;
  836. end;
  837. function TGLBaseImage.GetLevelHeight(ALOD: TGLImageLODRange): Integer;
  838. begin
  839. Result := FLOD[ALOD].Height;
  840. end;
  841. function TGLBaseImage.GetLevelOffset(ALOD: TGLImageLODRange): Integer;
  842. begin
  843. Result := FLOD[ALOD].Offset;
  844. end;
  845. function TGLBaseImage.GetLevelPBO(ALOD: TGLImageLODRange): TGLUnpackPBOHandle;
  846. begin
  847. Result := FLOD[ALOD].PBO;
  848. end;
  849. function TGLBaseImage.GetLevelSizeInByte(ALOD: TGLImageLODRange): Integer;
  850. begin
  851. Result := FLOD[ALOD].Size;
  852. end;
  853. function TGLBaseImage.GetLevelStreamingState(ALOD: TGLImageLODRange): TGLLODStreamingState;
  854. begin
  855. Result := FLOD[ALOD].State;
  856. end;
  857. function TGLBaseImage.GetLevelWidth(ALOD: TGLImageLODRange): Integer;
  858. begin
  859. Result := FLOD[ALOD].Width;
  860. end;
  861. function TGLBaseImage.IsEmpty: Boolean;
  862. begin
  863. Result := (GetWidth = 0) or (GetHeight = 0);
  864. end;
  865. function TGLBaseImage.IsCompressed: Boolean;
  866. begin
  867. Result := IsCompressedFormat(fInternalFormat);
  868. end;
  869. function TGLBaseImage.IsVolume: Boolean;
  870. begin
  871. Result := (GetDepth > 0) and not fTextureArray and not fCubeMap;
  872. end;
  873. function TGLBaseImage.ConvertCrossToCubeMap: Boolean;
  874. var
  875. fW, fH, cubeSize, realCubeSize, e: Integer;
  876. lData: PByteArray;
  877. ptr: PGLubyte;
  878. i, j: Integer;
  879. bGenMipmap: Boolean;
  880. begin
  881. Result := False;
  882. // Can't already be a cubemap
  883. if fCubeMap or fTextureArray then
  884. Exit;
  885. //this function only supports vertical cross format for now (3 wide by 4 high)
  886. if (GetWidth div 3 <> GetHeight div 4)
  887. or (GetWidth mod 3 <> 0)
  888. or (GetHeight mod 4 <> 0)
  889. or (GetDepth > 0) then
  890. Exit;
  891. bGenMipmap := FLevelCount > 1;
  892. UnMipmap;
  893. // Get the source data
  894. lData := PByteArray(fData);
  895. if IsCompressed then
  896. begin
  897. fW := (GetWidth + 3) div 4;
  898. fH := (GetHeight + 3) div 4;
  899. realCubeSize := (fH div 4) * 4;
  900. end
  901. else
  902. begin
  903. fW := GetWidth;
  904. fH := GetHeight;
  905. realCubeSize := fH div 4;
  906. end;
  907. cubeSize := fH;
  908. GetMem(fData, fW * fH * fElementSize);
  909. FLOD[0].Width := realCubeSize;
  910. FLOD[0].Height := realCubeSize;
  911. FLOD[0].Depth := 6;
  912. // Extract the faces
  913. ptr := PGLubyte(fData);
  914. // positive X
  915. for j := 0 to cubeSize - 1 do
  916. begin
  917. e := ((fH - (cubeSize + j + 1)) * fW + 2 * cubeSize) * fElementSize;
  918. Move(lData[e], ptr^, cubeSize * fElementSize);
  919. Inc(ptr, cubeSize * fElementSize);
  920. end;
  921. // negative X
  922. for j := 0 to cubeSize - 1 do
  923. begin
  924. Move(lData[(fH - (cubeSize + j + 1)) * fW * fElementSize],
  925. ptr^, cubeSize * fElementSize);
  926. Inc(ptr, cubeSize * fElementSize);
  927. end;
  928. // positive Y
  929. for j := 0 to cubeSize - 1 do
  930. begin
  931. e := ((4 * cubeSize - j - 1) * fW + cubeSize) * fElementSize;
  932. Move(lData[e], ptr^, cubeSize * fElementSize);
  933. Inc(ptr, cubeSize * fElementSize);
  934. end;
  935. // negative Y
  936. for j := 0 to cubeSize - 1 do
  937. begin
  938. e := ((2 * cubeSize - j - 1) * fW + cubeSize) * fElementSize;
  939. Move(lData[e], ptr^, cubeSize * fElementSize);
  940. Inc(ptr, cubeSize * fElementSize);
  941. end;
  942. // positive Z
  943. for j := 0 to cubeSize - 1 do
  944. begin
  945. e := ((fH - (cubeSize + j + 1)) * fW + cubeSize) * fElementSize;
  946. Move(lData[e], ptr^, cubeSize * fElementSize);
  947. Inc(ptr, cubeSize * fElementSize);
  948. end;
  949. // negative Z
  950. for j := 0 to cubeSize - 1 do
  951. for i := 0 to cubeSize - 1 do
  952. begin
  953. e := (j * fW + 2 * cubeSize - (i + 1)) * fElementSize;
  954. Move(lData[e], ptr^, fElementSize);
  955. Inc(ptr, fElementSize);
  956. end;
  957. // Set the new # of faces, width and height
  958. fCubeMap := true;
  959. FreeMem(lData);
  960. if bGenMipmap then
  961. GenerateMipmap(ImageTriangleFilter);
  962. Result := true;
  963. end;
  964. function TGLBaseImage.ConvertToVolume(const col, row: Integer; const MakeArray:
  965. Boolean): Boolean;
  966. var
  967. fW, fH, sW, sH, sD: Integer;
  968. lData: PByteArray;
  969. ptr: PGLubyte;
  970. i, j, k: Integer;
  971. begin
  972. Result := false;
  973. if fCubeMap then
  974. Exit;
  975. if (GetDepth > 0) and not fTextureArray and MakeArray then
  976. begin
  977. // Let volume be array
  978. fTextureArray := True;
  979. Result := True;
  980. Exit;
  981. end;
  982. if fTextureArray and not MakeArray then
  983. begin
  984. // Let array be volume
  985. fTextureArray := False;
  986. Result := True;
  987. Exit;
  988. end;
  989. Result := MakeArray;
  990. // Check sizes
  991. sD := col * row;
  992. if sD < 1 then
  993. Exit;
  994. if IsCompressed then
  995. begin
  996. fW := (GetWidth + 3) div 4;
  997. fH := (GetHeight + 3) div 4;
  998. end
  999. else
  1000. begin
  1001. fW := GetWidth;
  1002. fH := GetHeight;
  1003. end;
  1004. sW := fW div col;
  1005. sH := fH div row;
  1006. if (sW = 0) or (sH = 0) then
  1007. begin
  1008. Result := False;
  1009. Exit;
  1010. end;
  1011. // Mipmaps are not supported
  1012. UnMipmap;
  1013. // Get the source data
  1014. lData := PByteArray(fData);
  1015. GetMem(fData, sW * sH * sD * fElementSize);
  1016. ptr := PGLubyte(fData);
  1017. for i := 0 to row - 1 do
  1018. for j := 0 to col - 1 do
  1019. for k := 0 to sH - 1 do
  1020. begin
  1021. Move(lData[(i * fW * sH + j * sW + k * fW) * fElementSize],
  1022. ptr^, sW * fElementSize);
  1023. Inc(ptr, sW * fElementSize);
  1024. end;
  1025. if IsCompressed then
  1026. begin
  1027. FLOD[0].Width := sW * 4;
  1028. FLOD[0].Height := sH * 4;
  1029. end
  1030. else
  1031. begin
  1032. FLOD[0].Width := sW;
  1033. FLOD[0].Height := sH;
  1034. end;
  1035. FLOD[0].Depth := sD;
  1036. fTextureArray := Result;
  1037. FreeMem(lData);
  1038. Result := True;
  1039. end;
  1040. procedure TGLBaseImage.SetErrorImage;
  1041. const
  1042. cTextureError: array[0..12287] of Byte = (
  1043. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1044. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1045. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1046. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1047. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$00,$00,$FF,$FF,$B6,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$DB,$90,$3A,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$3A,$00,$00,$FF,$DB,$90,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$90,$DB,$FF,$FF,$B6,$90,$90,$DB,$FF,$00,$00,$3A,$00,$00,$00,$00,$00,$00,$90,$3A,$00,$FF,$FF,$DB,$00,$66,$B6,$66,$00,$00,$FF,$FF,$B6,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$3A,$00,$00,$FF,$DB,$90,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$90,$DB,$FF,$00,$00,$00,
  1048. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$DB,$90,$3A,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$00,$00,$FF,$FF,$B6,$00,$66,$B6,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$90,$DB,$FF,$00,$00,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1049. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$DB,$90,$3A,$B6,$FF,$FF,$00,$00,$66,$B6,$66,$00,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1050. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$90,$90,$DB,$FF,$FF,$B6,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1051. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$FF,$FF,$FF,$B6,$FF,$FF,$00,$00,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1052. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$00,$00,$FF,$FF,$B6,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$FF,$FF,$FF,$B6,$FF,$FF,$00,$00,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1053. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$90,$DB,$FF,$00,$00,$3A,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$00,$00,$FF,$FF,$B6,$3A,$90,$DB,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1054. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$DB,$90,$3A,$90,$DB,$FF,$00,$00,$3A,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$90,$DB,$FF,$00,$00,$3A,$90,$3A,$00,$FF,$FF,$DB,$00,$66,$B6,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1055. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$90,$3A,$00,$FF,$FF,$DB,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$DB,$90,$3A,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$90,$3A,$00,$FF,$FF,$DB,$00,$66,$B6,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$90,$DB,$FF,$00,$00,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1056. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$00,$00,$FF,$FF,$B6,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$90,$3A,$00,$FF,$FF,$DB,$00,$66,$B6,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$00,$00,$FF,$FF,$B6,$FF,$FF,$FF,$FF,$FF,$FF,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$90,$DB,$FF,$00,$00,$3A,$00,$00,$00,$00,$00,$00,$66,$00,$00,$FF,$FF,$B6,$3A,$90,$DB,$66,$00,$00,$FF,$FF,$B6,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1057. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1058. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1059. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1060. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1061. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1062. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1063. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$DB,$90,$3A,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$90,$3A,$00,$FF,$FF,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$DB,$90,$3A,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$DB,$90,$3A,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$66,$00,$00,$FF,$FF,$B6,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1064. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$DB,$90,$3A,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$B6,$FF,$FF,$00,$00,$66,$00,$00,$00,$00,$00,$00,$DB,$90,$3A,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$DB,$90,$3A,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1065. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1066. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$90,$3A,$00,$FF,$FF,$DB,$00,$66,$B6,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$B6,$FF,$FF,$00,$00,$66,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1067. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$90,$3A,$00,$DB,$FF,$DB,$00,$3A,$90,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$B6,$66,$00,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1068. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$00,$00,$FF,$FF,$B6,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$90,$3A,$00,$DB,$FF,$DB,$00,$3A,$90,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$00,$00,$00,$66,$00,$00,$FF,$FF,$B6,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$00,$00,$FF,$FF,$B6,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1069. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$90,$DB,$FF,$00,$00,$3A,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$66,$00,$00,$FF,$FF,$B6,$00,$66,$B6,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$B6,$FF,$FF,$00,$00,$66,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$90,$DB,$FF,$00,$00,$3A,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$90,$DB,$FF,$00,$00,$3A,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1070. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$B6,$66,$00,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1071. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$90,$3A,$00,$FF,$FF,$DB,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$DB,$FF,$FF,$00,$3A,$90,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$FF,$B6,$66,$66,$B6,$FF,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1072. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$90,$3A,$00,$FF,$FF,$DB,$00,$66,$B6,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$FF,$FF,$00,$00,$66,$00,$00,$00,$00,$00,$00,$90,$3A,$00,$FF,$FF,$DB,$00,$66,$B6,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$90,$3A,$00,$FF,$FF,$DB,$00,$66,$B6,$00,$00,$00,$00,$00,$00,$3A,$00,$00,$FF,$DB,$90,$3A,$90,$DB,$00,$00,$00,$66,$00,$00,$FF,$FF,$B6,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$3A,$90,$DB,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1073. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1074. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1075. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1076. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1077. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1078. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1079. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1080. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1081. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1082. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1083. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1084. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1085. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1086. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1087. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1088. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1089. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1090. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1091. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1092. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1093. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1094. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1095. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1096. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1097. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1098. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1099. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1100. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$90,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1101. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$66,$00,$00,$00,$66,$B6,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1102. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1103. $00,$00,$00,$00,$00,$00,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$DB,$90,$3A,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$66,$B6,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$B6,$90,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$DB,$90,$3A,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$66,$B6,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$DB,$90,$3A,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3A,$90,$DB,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B6,$66,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1104. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1105. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  1106. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
  1107. );
  1108. begin
  1109. UnMipmap;
  1110. FLOD[0].Width := 64;
  1111. FLOD[0].Height := 64;
  1112. FLOD[0].Depth := 0;
  1113. fColorFormat := GL_RGBA;
  1114. fInternalFormat := tfRGB8;
  1115. fDataType := GL_UNSIGNED_BYTE;
  1116. fElementSize := 4;
  1117. fCubeMap := false;
  1118. fTextureArray := false;
  1119. FColorFormat := GL_RGB;
  1120. ReallocMem(FData, DataSize);
  1121. Move(cTextureError[0], FData[0], DataSize);
  1122. end;
  1123. procedure TGLBaseImage.SetLevelStreamingState(ALOD: TGLImageLODRange;
  1124. AState: TGLLODStreamingState);
  1125. begin
  1126. FLOD[ALOD].State := AState;
  1127. end;
  1128. procedure TGLBaseImage.Narrow;
  1129. var
  1130. Size: Integer;
  1131. newData: Pointer;
  1132. begin
  1133. // Check for already norrow
  1134. if (fColorFormat = GL_RGBA)
  1135. and (GetDepth = 0)
  1136. and (fDataType = GL_UNSIGNED_BYTE)
  1137. and (FLevelCount = 1)
  1138. and not (fTextureArray or fCubeMap) then
  1139. Exit;
  1140. UnMipmap;
  1141. // Use image utils
  1142. Size := GetWidth * GetHeight * 4;
  1143. GetMem(newData, Size);
  1144. try
  1145. ConvertImage(
  1146. fData, newData,
  1147. fColorFormat, GL_RGBA,
  1148. fDataType, GL_UNSIGNED_BYTE,
  1149. GetWidth, GetHeight);
  1150. except
  1151. GLSLogger.LogError(Format(strCantConvertImg, [ClassName]));
  1152. SetErrorImage;
  1153. FreeMem(newData);
  1154. Exit;
  1155. end;
  1156. fInternalFormat := tfRGBA8;
  1157. fColorFormat := GL_RGBA;
  1158. fDataType := GL_UNSIGNED_BYTE;
  1159. fElementSize := 4;
  1160. fTextureArray := False;
  1161. fCubeMap := False;
  1162. FreeMem(fData);
  1163. fData := newData;
  1164. end;
  1165. procedure TGLBaseImage.GenerateMipmap(AFilter: TImageFilterFunction);
  1166. var
  1167. LAddresses: TPointerArray;
  1168. level, slice, d: Integer;
  1169. begin
  1170. UnMipmap;
  1171. if IsVolume then
  1172. begin
  1173. fLevelCount := GetImageLodNumber(GetWidth, GetHeight, GetDepth, True);
  1174. UpdateLevelsInfo;
  1175. ReallocMem(FData, DataSize);
  1176. // Message Hint 'TGLBaseImage.GenerateMipmap not yet implemented for volume images'
  1177. end
  1178. else
  1179. begin
  1180. fLevelCount := GetImageLodNumber(GetWidth, GetHeight, GetDepth, False);
  1181. ReallocMem(FData, DataSize);
  1182. SetLength(LAddresses, fLevelCount-1);
  1183. for level := 1 to fLevelCount-1 do
  1184. LAddresses[level-1] := GetLevelAddress(level);
  1185. d := MaxInteger(GetDepth, 1);
  1186. for slice := 0 to d - 1 do
  1187. begin
  1188. Build2DMipmap(GetLevelAddress(0), LAddresses, fColorFormat, fDataType,
  1189. AFilter, GetWidth, GetHeight);
  1190. for level := 1 to fLevelCount - 1 do
  1191. Inc(PByte(LAddresses[level - 1]), GetLevelSizeInByte(level) div d);
  1192. end;
  1193. end;
  1194. end;
  1195. procedure TGLBaseImage.UnMipmap;
  1196. var
  1197. level: TGLImageLODRange;
  1198. begin
  1199. for level := 1 to High(TGLImageLODRange) do
  1200. begin
  1201. FLOD[level].Width := 0;
  1202. FLOD[level].Height := 0;
  1203. FLOD[level].Depth := 0;
  1204. end;
  1205. FLevelCount := 1;
  1206. end;
  1207. procedure TGLBaseImage.UpdateLevelsInfo;
  1208. var
  1209. level: TGLImageLODRange;
  1210. w, h, d: Integer;
  1211. function GetSize(const level: Integer): Integer;
  1212. var
  1213. ld, bw, bh, lsize: Integer;
  1214. begin
  1215. if fTextureArray then
  1216. ld := FLOD[0].Depth
  1217. else
  1218. ld := d;
  1219. if ld = 0 then
  1220. ld := 1;
  1221. if IsCompressed then
  1222. begin
  1223. bw := (w + 3) div 4;
  1224. bh := (h + 3) div 4;
  1225. end
  1226. else
  1227. begin
  1228. bw := w;
  1229. bh := h;
  1230. end;
  1231. if bh = 0 then
  1232. bh := 1;
  1233. lsize := bw * bh * ld * fElementSize;
  1234. if fCubeMap and not fTextureArray then
  1235. lsize := lsize * 6;
  1236. // Align to Double Word
  1237. if (lsize and 3) <> 0 then
  1238. lsize := 4 * (1 + lsize div 4);
  1239. Result := lsize;
  1240. end;
  1241. begin
  1242. w := FLOD[0].Width;
  1243. h := FLOD[0].Height;
  1244. d := FLOD[0].Depth;
  1245. FLOD[0].Size := GetSize(0);
  1246. FLOD[0].Offset := 0;
  1247. for level := 1 to High(TGLImageLODRange) do
  1248. begin
  1249. Div2(w);
  1250. Div2(h);
  1251. if not fTextureArray then
  1252. d := d div 2;
  1253. FLOD[level].Width := w;
  1254. FLOD[level].Height := h;
  1255. FLOD[level].Depth := d;
  1256. FLOD[level].Offset := FLOD[level - 1].Offset + FLOD[level - 1].Size;
  1257. FLOD[level].Size := GetSize(level);
  1258. end;
  1259. end;
  1260. function TGLBaseImage.GetData: PGLPixel32Array;
  1261. begin
  1262. Result := fData;
  1263. end;
  1264. procedure TGLBaseImage.RegisterAsOpenGLTexture(
  1265. AHandle: TGLTextureHandle;
  1266. aMipmapGen: Boolean;
  1267. aTexFormat: Cardinal;
  1268. out texWidth: integer;
  1269. out texHeight: integer;
  1270. out texDepth: integer);
  1271. var
  1272. glTarget: Cardinal;
  1273. glHandle: Cardinal;
  1274. Level: integer;
  1275. LLevelCount, face: integer;
  1276. bCompress, bBlank: boolean;
  1277. w, h, d, cw, ch, maxSize: TGLsizei;
  1278. p, buffer: Pointer;
  1279. vtcBuffer, top, bottom: PGLubyte;
  1280. i, j, k: Integer;
  1281. transferMethod: 0..3;
  1282. function blockOffset(x, y, z: Integer): Integer;
  1283. begin
  1284. if z >= (d and -4) then
  1285. Result := fElementSize * (cw * ch * (d and -4) + x +
  1286. cw * (y + ch * (z - 4 * ch)))
  1287. else
  1288. Result := fElementSize * (4 * (x + cw * (y + ch * floor(z / 4))) + (z and
  1289. 3));
  1290. if Result < 0 then
  1291. Result := 0;
  1292. end;
  1293. begin
  1294. if AHandle.Target = ttNoShape then
  1295. Exit;
  1296. UpdateLevelsInfo;
  1297. if Self is TGLImage then
  1298. bBlank := TGLImage(Self).Blank
  1299. else
  1300. bBlank := False;
  1301. // Check for Non-power-of-two
  1302. if not gl.ARB_texture_non_power_of_two then
  1303. begin
  1304. w := RoundUpToPowerOf2(GetWidth);
  1305. h := RoundUpToPowerOf2(GetHeight);
  1306. d := RoundUpToPowerOf2(GetDepth);
  1307. if GetDepth = 0 then
  1308. d := 0;
  1309. end
  1310. else
  1311. begin
  1312. w := GetWidth;
  1313. h := GetHeight;
  1314. d := GetDepth;
  1315. end;
  1316. // Check maximum dimension
  1317. maxSize := CurrentGLContext.GLStates.MaxTextureSize;
  1318. if w > maxSize then
  1319. w := maxSize;
  1320. if h > maxSize then
  1321. h := maxSize;
  1322. texWidth := w;
  1323. texHeight := h;
  1324. texDepth := d;
  1325. LLevelCount := fLevelCount;
  1326. bCompress := IsCompressed;
  1327. // Rescale if need and can
  1328. buffer := nil;
  1329. if (w <> GetWidth) or (h <> GetHeight) then
  1330. begin
  1331. if not((d > 0) // not volume
  1332. or bCompress // not compressed
  1333. or bBlank) then // not blank
  1334. begin
  1335. GetMem(buffer, w * h * fElementSize);
  1336. try
  1337. RescaleImage(fData, buffer, fColorFormat, fDataType,
  1338. ImageLanczos3Filter, GetWidth, GetHeight, w, h);
  1339. LLevelCount := 1;
  1340. except
  1341. bBlank := True;
  1342. end;
  1343. end
  1344. else
  1345. bBlank := True;
  1346. end;
  1347. if Self is TGLImage then
  1348. TGLImage(Self).FBlank := bBlank;
  1349. glHandle := AHandle.Handle;
  1350. glTarget := DecodeTextureTarget(AHandle.Target);
  1351. // Hardware mipmap autogeneration
  1352. aMipmapGen := aMipmapGen and IsTargetSupportMipmap(glTarget);
  1353. aMipmapGen := aMipmapGen and (LLevelCount = 1);
  1354. if aMipmapGen then
  1355. begin
  1356. if gl.SGIS_generate_mipmap then
  1357. begin
  1358. if gl.EXT_direct_state_access then
  1359. gl.TexParameterf(
  1360. glTarget,
  1361. GL_GENERATE_MIPMAP_SGIS,
  1362. GL_TRUE)
  1363. else
  1364. gl.TexParameteri(glTarget, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
  1365. end
  1366. else
  1367. begin
  1368. // Software LODs generation
  1369. Self.GenerateMipmap(ImageTriangleFilter);
  1370. LLevelCount := LevelCount;
  1371. end;
  1372. end;
  1373. // Setup top limitation of LODs
  1374. if gl.SGIS_texture_lod and (LLevelCount > 1) then
  1375. if gl.EXT_direct_state_access then
  1376. gl.TexParameterf(
  1377. glTarget,
  1378. GL_TEXTURE_MAX_LEVEL_SGIS,
  1379. LLevelCount - 1)
  1380. else
  1381. gl.TexParameteri(glTarget, GL_TEXTURE_MAX_LEVEL_SGIS, LLevelCount - 1);
  1382. // Select transfer method
  1383. if bCompress then
  1384. transferMethod := 1
  1385. else
  1386. transferMethod := 0;
  1387. if gl.EXT_direct_state_access then
  1388. transferMethod := transferMethod + 2;
  1389. // if image is blank then doing only allocatation texture in videomemory
  1390. vtcBuffer := nil;
  1391. case AHandle.Target of
  1392. ttTexture1D:
  1393. for level := 0 to LLevelCount - 1 do
  1394. begin
  1395. if Assigned(buffer) then
  1396. p := buffer
  1397. else if not bBlank then
  1398. p := GetLevelAddress(level)
  1399. else
  1400. p := nil;
  1401. case transferMethod of
  1402. 0: gl.TexImage1D(glTarget, level, aTexFormat, w, 0, fColorFormat,
  1403. fDataType, p);
  1404. 1: gl.CompressedTexImage1D(glTarget, level, aTexFormat, w, 0,
  1405. GetLevelSizeInByte(level), p);
  1406. 2: gl.TextureImage1D(glHandle, glTarget, level, aTexFormat, w, 0,
  1407. fColorFormat, fDataType, p);
  1408. 3: gl.CompressedTextureImage1D(glHandle, glTarget, level, aTexFormat, w,
  1409. 0, GetLevelSizeInByte(level), p)
  1410. end;
  1411. Div2(w);
  1412. end;
  1413. ttTexture2D:
  1414. for Level := 0 to LLevelCount - 1 do
  1415. begin
  1416. if Assigned(buffer) then
  1417. p := buffer
  1418. else if not bBlank then
  1419. p := GetLevelAddress(Level)
  1420. else
  1421. p := nil;
  1422. case transferMethod of
  1423. 0: gl.TexImage2D(glTarget, level, aTexFormat, w, h, 0, fColorFormat,
  1424. fDataType, p);
  1425. 1: gl.CompressedTexImage2D(glTarget, level, aTexFormat, w, h, 0,
  1426. GetLevelSizeInByte(level), p);
  1427. 2: gl.TextureImage2D(glHandle, glTarget, level, aTexFormat, w, h, 0,
  1428. fColorFormat, fDataType, p);
  1429. 3: gl.CompressedTextureImage2D(glHandle, glTarget, level, aTexFormat, w,
  1430. h, 0, GetLevelSizeInByte(level), p);
  1431. end;
  1432. Div2(w);
  1433. Div2(h);
  1434. end;
  1435. ttTextureRect:
  1436. begin
  1437. if Assigned(buffer) then
  1438. p := buffer
  1439. else if not bBlank then
  1440. p := GetLevelAddress(0)
  1441. else
  1442. p := nil;
  1443. case transferMethod of
  1444. 0: gl.TexImage2D(glTarget, 0, aTexFormat, w, h, 0, fColorFormat,
  1445. fDataType, p);
  1446. 1: gl.CompressedTexImage2D(glTarget, 0, aTexFormat, w, h, 0,
  1447. GetLevelSizeInByte(0), p);
  1448. 2: gl.TextureImage2D(glHandle, glTarget, 0, aTexFormat, w, h, 0,
  1449. fColorFormat, fDataType, p);
  1450. 3: gl.CompressedTextureImage2D(glHandle, glTarget, 0, aTexFormat, w, h,
  1451. 0, GetLevelSizeInByte(0), p);
  1452. end;
  1453. end;
  1454. ttTexture3D:
  1455. for Level := 0 to LLevelCount - 1 do
  1456. begin
  1457. if Assigned(buffer) then
  1458. p := buffer
  1459. else if not bBlank then
  1460. p := GetLevelAddress(Level)
  1461. else
  1462. p := nil;
  1463. if gl.NV_texture_compression_vtc and bCompress then
  1464. begin
  1465. // Shufle blocks for Volume Texture Compression
  1466. if Assigned(p) then
  1467. begin
  1468. cw := (w + 3) div 4;
  1469. ch := (h + 3) div 4;
  1470. if Level = 0 then
  1471. GetMem(vtcBuffer, GetLevelSizeInByte(0));
  1472. top := p;
  1473. for k := 0 to d - 1 do
  1474. for i := 0 to ch - 1 do
  1475. for j := 0 to cw - 1 do
  1476. begin
  1477. bottom := vtcBuffer;
  1478. Inc(bottom, blockOffset(j, i, k));
  1479. Move(top^, bottom^, fElementSize);
  1480. Inc(top, fElementSize);
  1481. end;
  1482. end;
  1483. if gl.EXT_direct_state_access then
  1484. gl.CompressedTextureImage3D(glHandle, glTarget, level, aTexFormat, w,
  1485. h, d, 0, GetLevelSizeInByte(level), vtcBuffer)
  1486. else
  1487. gl.CompressedTexImage3D(glTarget, level, aTexFormat, w, h, d, 0,
  1488. GetLevelSizeInByte(level), vtcBuffer);
  1489. end
  1490. else
  1491. begin
  1492. // Normal compression
  1493. case transferMethod of
  1494. 0: gl.TexImage3D(glTarget, level, aTexFormat, w, h, d, 0,
  1495. fColorFormat, fDataType, p);
  1496. 1: gl.CompressedTexImage3D(glTarget, level, aTexFormat, w, h, d, 0,
  1497. GetLevelSizeInByte(level), p);
  1498. 2: gl.TextureImage3D(glHandle, glTarget, level, aTexFormat, w, h, d,
  1499. 0, fColorFormat, fDataType, p);
  1500. 3: gl.CompressedTextureImage3D(glHandle, glTarget, level, aTexFormat,
  1501. w, h, d, 0, GetLevelSizeInByte(level), p);
  1502. end;
  1503. end;
  1504. Div2(w);
  1505. Div2(h);
  1506. Div2(d);
  1507. end;
  1508. ttTextureCube:
  1509. for Level := 0 to LLevelCount - 1 do
  1510. begin
  1511. for face := GL_TEXTURE_CUBE_MAP_POSITIVE_X to
  1512. GL_TEXTURE_CUBE_MAP_NEGATIVE_Z do
  1513. begin
  1514. if Assigned(buffer) then
  1515. p := buffer
  1516. else if not bBlank then
  1517. p := GetLevelAddress(level, face - GL_TEXTURE_CUBE_MAP_POSITIVE_X)
  1518. else
  1519. p := nil;
  1520. case transferMethod of
  1521. 0: gl.TexImage2D(face, level, aTexFormat, w, h, 0, fColorFormat,
  1522. fDataType, p);
  1523. 1: gl.CompressedTexImage2D(face, level, aTexFormat, w, h, 0,
  1524. GetLevelSizeInByte(level) div 6, p);
  1525. 2: gl.TextureImage2D(glHandle, face, level, aTexFormat, w, h, 0,
  1526. fColorFormat, fDataType, p);
  1527. 3: gl.CompressedTextureImage2D(glHandle, face, level, aTexFormat, w,
  1528. h, 0, GetLevelSizeInByte(level) div 6, p);
  1529. end;
  1530. end;
  1531. Div2(w);
  1532. Div2(h);
  1533. end;
  1534. ttTexture1DArray:
  1535. for Level := 0 to LLevelCount - 1 do
  1536. begin
  1537. if Assigned(buffer) then
  1538. p := buffer
  1539. else if not bBlank then
  1540. p := GetLevelAddress(Level)
  1541. else
  1542. p := nil;
  1543. case transferMethod of
  1544. 0: gl.TexImage2D(glTarget, level, aTexFormat, w, h, 0, fColorFormat,
  1545. fDataType, p);
  1546. 1: gl.CompressedTexImage2D(glTarget, level, aTexFormat, w, h, 0,
  1547. GetLevelSizeInByte(level), p);
  1548. 2: gl.TextureImage2D(glHandle, glTarget, level, aTexFormat, w, h, 0,
  1549. fColorFormat, fDataType, p);
  1550. 3: gl.CompressedTextureImage2D(glHandle, glTarget, level, aTexFormat, w,
  1551. h, 0, GetLevelSizeInByte(level), p);
  1552. end;
  1553. Div2(w);
  1554. end;
  1555. ttTexture2DArray, ttTextureCubeArray:
  1556. for Level := 0 to LLevelCount - 1 do
  1557. begin
  1558. if Assigned(buffer) then
  1559. p := buffer
  1560. else if not bBlank then
  1561. p := GetLevelAddress(Level)
  1562. else
  1563. p := nil;
  1564. case transferMethod of
  1565. 0: gl.TexImage3D(glTarget, level, aTexFormat, w, h, d, 0, fColorFormat,
  1566. fDataType, p);
  1567. 1: gl.CompressedTexImage3D(glTarget, level, aTexFormat, w, h, d, 0,
  1568. GetLevelSizeInByte(level), p);
  1569. 2: gl.TextureImage3D(glHandle, glTarget, level, aTexFormat, w, h, d, 0,
  1570. fColorFormat, fDataType, p);
  1571. 3: gl.CompressedTextureImage3D(glHandle, glTarget, level, aTexFormat, w,
  1572. h, d, 0, GetLevelSizeInByte(level), p);
  1573. end;
  1574. Div2(w);
  1575. Div2(h);
  1576. end;
  1577. end; // of case
  1578. if Assigned(buffer) then
  1579. FreeMem(buffer);
  1580. if Assigned(vtcBuffer) then
  1581. FreeMem(vtcBuffer);
  1582. end;
  1583. function TGLBaseImage.AssignFromTexture(AHandle: TGLTextureHandle;
  1584. const CastToFormat: Boolean; const intFormat: TGLInternalFormat = tfRGBA8;
  1585. const colorFormat: Cardinal = 0; const dataType: Cardinal = 0): Boolean;
  1586. var
  1587. LContext: TGLContext;
  1588. texFormat, texLod, optLod: Cardinal;
  1589. glTarget: Cardinal;
  1590. level, maxFace, face: Integer;
  1591. lData: PGLubyte;
  1592. residentFormat: TGLInternalFormat;
  1593. bCompressed: Boolean;
  1594. vtcBuffer, top, bottom: PGLubyte;
  1595. i, j, k: Integer;
  1596. w, d, h, cw, ch: Integer;
  1597. function blockOffset(x, y, z: Integer): Integer;
  1598. begin
  1599. if z >= (d and -4) then
  1600. Result := fElementSize * (cw * ch * (d and -4) + x + cw *
  1601. (y + ch * (z - 4 * ch)))
  1602. else
  1603. Result := fElementSize * (4 * (x + cw * (y + ch * floor(z / 4))) +
  1604. (z and 3));
  1605. end;
  1606. begin
  1607. Result := False;
  1608. LContext := CurrentGLContext;
  1609. if LContext = nil then
  1610. begin
  1611. LContext := AHandle.RenderingContext;
  1612. if LContext = nil then
  1613. Exit;
  1614. end;
  1615. LContext.Activate;
  1616. if AHandle.IsDataNeedUpdate then
  1617. begin
  1618. LContext.Deactivate;
  1619. Exit;
  1620. end;
  1621. glTarget := DecodeTextureTarget(AHandle.Target);
  1622. try
  1623. LContext.GLStates.TextureBinding[0, AHandle.Target] := AHandle.Handle;
  1624. FLevelCount := 0;
  1625. gl.GetTexParameteriv(glTarget, GL_TEXTURE_MAX_LEVEL, @texLod);
  1626. if glTarget = GL_TEXTURE_CUBE_MAP then
  1627. begin
  1628. fCubeMap := True;
  1629. maxFace := 5;
  1630. glTarget := GL_TEXTURE_CUBE_MAP_POSITIVE_X;
  1631. end
  1632. else
  1633. begin
  1634. fCubeMap := False;
  1635. maxFace := 0;
  1636. end;
  1637. fTextureArray := (glTarget = GL_TEXTURE_1D_ARRAY) or
  1638. (glTarget = GL_TEXTURE_2D_ARRAY) or
  1639. (glTarget = GL_TEXTURE_CUBE_MAP_ARRAY);
  1640. repeat
  1641. // Check level existence
  1642. gl.GetTexLevelParameteriv(glTarget, FLevelCount,
  1643. GL_TEXTURE_INTERNAL_FORMAT,
  1644. @texFormat);
  1645. if texFormat = 1 then
  1646. Break;
  1647. Inc(FLevelCount);
  1648. if FLevelCount = 1 then
  1649. begin
  1650. gl.GetTexLevelParameteriv(glTarget, 0, GL_TEXTURE_WIDTH, @FLOD[0].Width);
  1651. gl.GetTexLevelParameteriv(glTarget, 0, GL_TEXTURE_HEIGHT,@FLOD[0].Height);
  1652. FLOD[0].Depth := 0;
  1653. if (glTarget = GL_TEXTURE_3D)
  1654. or (glTarget = GL_TEXTURE_2D_ARRAY)
  1655. or (glTarget = GL_TEXTURE_CUBE_MAP_ARRAY) then
  1656. gl.GetTexLevelParameteriv(glTarget, 0, GL_TEXTURE_DEPTH, @FLOD[0].Depth);
  1657. residentFormat := OpenGLFormatToInternalFormat(texFormat);
  1658. if CastToFormat then
  1659. fInternalFormat := residentFormat
  1660. else
  1661. fInternalFormat := intFormat;
  1662. FindCompatibleDataFormat(fInternalFormat, fColorFormat, fDataType);
  1663. // Substitute properties if need
  1664. if colorFormat > 0 then
  1665. fColorFormat := colorFormat;
  1666. if dataType > 0 then
  1667. fDataType := dataType;
  1668. // Get optimal number or MipMap levels
  1669. optLod := GetImageLodNumber(GetWidth, GetHeight, GetDepth, glTarget = GL_TEXTURE_3D);
  1670. if texLod > optLod then
  1671. texLod := optLod;
  1672. // Check for MipMap posibility
  1673. if ((fInternalFormat >= tfFLOAT_R16)
  1674. and (fInternalFormat <= tfFLOAT_RGBA32)) then
  1675. texLod := 1;
  1676. end;
  1677. until FLevelCount = Integer(texLod);
  1678. if FLevelCount > 0 then
  1679. begin
  1680. fElementSize := GetTextureElementSize(fColorFormat, fDataType);
  1681. UpdateLevelsInfo;
  1682. ReallocMem(FData, DataSize);
  1683. lData := PGLubyte(fData);
  1684. bCompressed := IsCompressed;
  1685. vtcBuffer := nil;
  1686. w := GetWidth;
  1687. h := GetHeight;
  1688. d := GetDepth;
  1689. for face := 0 to maxFace do
  1690. begin
  1691. if fCubeMap then
  1692. glTarget := face + GL_TEXTURE_CUBE_MAP_POSITIVE_X;
  1693. for level := 0 to FLevelCount - 1 do
  1694. begin
  1695. if bCompressed then
  1696. begin
  1697. if GL.NV_texture_compression_vtc and (d > 1) and not fTextureArray then
  1698. begin
  1699. if level = 0 then
  1700. GetMem(vtcBuffer, GetLevelSizeInByte(0));
  1701. gl.GetCompressedTexImage(glTarget, level, vtcBuffer);
  1702. // Shufle blocks from VTC to S3TC
  1703. cw := (w + 3) div 4;
  1704. ch := (h + 3) div 4;
  1705. top := lData;
  1706. for k := 0 to d - 1 do
  1707. for i := 0 to ch - 1 do
  1708. for j := 0 to cw - 1 do
  1709. begin
  1710. bottom := vtcBuffer;
  1711. Inc(bottom, blockOffset(j, i, k));
  1712. Move(bottom^, top^, fElementSize);
  1713. Inc(top, fElementSize);
  1714. end;
  1715. Div2(w);
  1716. Div2(h);
  1717. Div2(d);
  1718. end
  1719. else
  1720. gl.GetCompressedTexImage(glTarget, level, lData);
  1721. end
  1722. else
  1723. gl.GetTexImage(glTarget, level, fColorFormat, fDataType, lData);
  1724. Inc(lData, GetLevelSizeInByte(level));
  1725. end; // for level
  1726. end; // for face
  1727. if Assigned(vtcBuffer) then
  1728. FreeMem(vtcBuffer);
  1729. // Check memory corruption
  1730. ReallocMem(FData, DataSize);
  1731. end;
  1732. if Self is TGLImage then
  1733. begin
  1734. TGLImage(Self).FBlank := FLevelCount = 0;
  1735. if FLevelCount = 0 then
  1736. begin
  1737. UnMipmap;
  1738. FreeMem(fData);
  1739. fData := nil;
  1740. end;
  1741. end;
  1742. gl.CheckError;
  1743. Result := True;
  1744. finally
  1745. LContext.Deactivate;
  1746. end;
  1747. end;
  1748. procedure TGLBaseImage.SaveHeader;
  1749. var
  1750. Temp: Integer;
  1751. LStream: TStream;
  1752. begin
  1753. Temp := 0;
  1754. LStream := nil;
  1755. try
  1756. LStream := TFileStream.Create(ResourceName, fmOpenWrite or fmCreate);
  1757. with LStream do
  1758. begin
  1759. Write(Temp, SizeOf(Integer)); // Version
  1760. Write(FLOD[0].Width, SizeOf(Integer));
  1761. Write(FLOD[0].Height, SizeOf(Integer));
  1762. Write(FLOD[0].Depth, SizeOf(Integer));
  1763. Write(fColorFormat, SizeOf(Cardinal));
  1764. Temp := Integer(fInternalFormat);
  1765. Write(Temp, SizeOf(Integer));
  1766. Write(fDataType, SizeOf(Cardinal));
  1767. Write(fElementSize, SizeOf(Integer));
  1768. Write(fLevelCount, SizeOf(TGLImageLODRange));
  1769. Temp := Integer(fCubeMap);
  1770. Write(Temp, SizeOf(Integer));
  1771. Temp := Integer(fTextureArray);
  1772. Write(Temp, SizeOf(Integer));
  1773. end;
  1774. finally
  1775. LStream.Free;
  1776. end;
  1777. end;
  1778. procedure TGLBaseImage.LoadHeader;
  1779. var
  1780. Temp: Integer;
  1781. LStream: TStream;
  1782. begin
  1783. LStream := nil;
  1784. try
  1785. LStream := TFileStream.Create(ResourceName, fmOpenRead);
  1786. with LStream do
  1787. begin
  1788. Read(Temp, SizeOf(Integer)); // Version
  1789. if Temp > 0 then
  1790. begin
  1791. GLSLogger.LogError(Format(strUnknownArchive, [Self.ClassType, Temp]));
  1792. Abort;
  1793. end;
  1794. Read(FLOD[0].Width, SizeOf(Integer));
  1795. Read(FLOD[0].Height, SizeOf(Integer));
  1796. Read(FLOD[0].Depth, SizeOf(Integer));
  1797. Read(fColorFormat, SizeOf(Cardinal));
  1798. Read(Temp, SizeOf(Integer));
  1799. fInternalFormat := TGLInternalFormat(Temp);
  1800. Read(fDataType, SizeOf(Cardinal));
  1801. Read(fElementSize, SizeOf(Integer));
  1802. Read(fLevelCount, SizeOf(TGLImageLODRange));
  1803. Read(Temp, SizeOf(Integer));
  1804. fCubeMap := Boolean(Temp);
  1805. Read(Temp, SizeOf(Integer));
  1806. fTextureArray := Boolean(Temp);
  1807. UpdateLevelsInfo;
  1808. end;
  1809. finally
  1810. LStream.Free;
  1811. end;
  1812. end;
  1813. var
  1814. vGlobalStreamingTaskCounter: Integer = 0;
  1815. procedure TGLBaseImage.StartStreaming;
  1816. var
  1817. level: TGLImageLODRange;
  1818. begin
  1819. FStreamLevel := fLevelCount - 1;
  1820. for level := 0 to High(TGLImageLODRange) do
  1821. FLOD[level].State := ssKeeping;
  1822. end;
  1823. procedure TGLBaseImage.DoStreaming;
  1824. begin
  1825. {$IFDEF USE_SERVICE_CONTEXT}
  1826. if Assigned(FFinishEvent) then
  1827. begin
  1828. if FFinishEvent.WaitFor(0) <> wrSignaled then
  1829. Exit;
  1830. end
  1831. else
  1832. FFinishEvent := TFinishTaskEvent.Create;
  1833. Inc(vGlobalStreamingTaskCounter);
  1834. AddTaskForServiceContext(ImageStreamingTask, FFinishEvent);
  1835. {$ENDIF}
  1836. end;
  1837. {$IFDEF USE_SERVICE_CONTEXT}
  1838. procedure TGLBaseImage.ImageStreamingTask;
  1839. var
  1840. readSize: Integer;
  1841. ptr: PByte;
  1842. begin
  1843. with FLOD[FStreamLevel] do
  1844. begin
  1845. if PBO = nil then
  1846. PBO := TGLUnpackPBOHandle.Create;
  1847. PBO.AllocateHandle;
  1848. if PBO.IsDataNeedUpdate then
  1849. begin
  1850. (* This may work with multiple unshared context, but never tested
  1851. because unlikely. *)
  1852. PBO.BindBufferData(nil, MaxInteger(Size, 1024), GL_STREAM_DRAW);
  1853. if Assigned(MapAddress) then
  1854. if not PBO.UnmapBuffer then
  1855. Exit;
  1856. MapAddress := PBO.MapBuffer(GL_WRITE_ONLY);
  1857. StreamOffset := 0;
  1858. PBO.UnBind;
  1859. PBO.NotifyDataUpdated;
  1860. end;
  1861. if FSourceStream = nil then
  1862. begin
  1863. FSourceStream := TFileStream.Create(ResourceName +
  1864. IntToHex(FStreamLevel,2), fmOpenRead + fmShareDenyNone);
  1865. end;
  1866. // Move to position of next piece and read it
  1867. readSize := MinInteger(Cardinal(8192 div vGlobalStreamingTaskCounter),
  1868. Cardinal(Size - StreamOffset));
  1869. if readSize > 0 then
  1870. begin
  1871. ptr := PByte(MapAddress);
  1872. Inc(ptr, StreamOffset);
  1873. FSourceStream.Read(ptr^, readSize);
  1874. Inc(StreamOffset, readSize);
  1875. end;
  1876. Dec(vGlobalStreamingTaskCounter);
  1877. if StreamOffset >= Size then
  1878. begin
  1879. PBO.Bind;
  1880. if PBO.UnmapBuffer then
  1881. State := ssLoaded;
  1882. PBO.UnBind;
  1883. if State <> ssLoaded then
  1884. Exit; // Can't unmap
  1885. MapAddress := nil;
  1886. StreamOffset := 0;
  1887. if FStreamLevel > 0 then
  1888. Dec(FStreamLevel);
  1889. FSourceStream.Destroy;
  1890. FSourceStream := nil;
  1891. end;
  1892. end;
  1893. end;
  1894. {$ENDIF}
  1895. // ------------------
  1896. // ------------------ TGLImage ------------------
  1897. // ------------------
  1898. constructor TGLImage.Create;
  1899. begin
  1900. inherited Create;
  1901. SetBlank(False);
  1902. end;
  1903. destructor TGLImage.Destroy;
  1904. begin
  1905. inherited Destroy;
  1906. end;
  1907. procedure TGLImage.Assign(Source: TPersistent);
  1908. var
  1909. bmp: TBitmap;
  1910. graphic: TGraphic;
  1911. begin
  1912. if (Source is TGLImage) or (Source is TGLBaseImage) then
  1913. begin
  1914. if Source is TGLImage then
  1915. FBlank := TGLImage(Source).FBlank
  1916. else
  1917. FBlank := False;
  1918. if not FBlank then
  1919. inherited
  1920. else
  1921. begin
  1922. FLOD := TGLImage(Source).FLOD;
  1923. FLevelCount := TGLImage(Source).FLevelCount;
  1924. fCubeMap := TGLImage(Source).fCubeMap;
  1925. fColorFormat := TGLImage(Source).fColorFormat;
  1926. fInternalFormat := TGLImage(Source).fInternalFormat;
  1927. fDataType := TGLImage(Source).fDataType;
  1928. fElementSize := TGLImage(Source).fElementSize;
  1929. fTextureArray := TGLImage(Source).fTextureArray;
  1930. end;
  1931. end
  1932. else if Source is TGraphic then
  1933. begin
  1934. if (Source is TBitmap)
  1935. and (TBitmap(Source).PixelFormat in [pf24bit, pf32bit])
  1936. and (((TBitmap(Source).Width and 3) = 0) or gl.EXT_bgra) then
  1937. begin
  1938. if TBitmap(Source).PixelFormat = pf24bit then
  1939. AssignFrom24BitsBitmap(TBitmap(Source))
  1940. else
  1941. AssignFrom32BitsBitmap(TBitmap(Source))
  1942. end
  1943. else if Source is TPngImage then
  1944. AssignFromPngImage(TPngImage(Source))
  1945. else
  1946. begin
  1947. graphic := TGraphic(Source);
  1948. bmp := TBitmap.Create;
  1949. try
  1950. // crossbuilder: useless to set pixelformat before setting the size ?
  1951. // or maybe just useless at all on gtk .. as soon as
  1952. // bmp.canvas is touched, it's the pixelformat of the device
  1953. // no matter what was adjusted before ??
  1954. // bmp.PixelFormat:=glpf24bit;
  1955. // bmp.Height:=graphic.Height;
  1956. // crossbuilder: using setsize because setting width or height while
  1957. // the other one is zero results in not setting with/hight
  1958. bmp.PixelFormat := pf24bit;
  1959. bmp.Height := graphic.Height;
  1960. if (graphic.Width and 3) = 0 then
  1961. begin
  1962. bmp.Width := graphic.Width;
  1963. bmp.Canvas.Draw(0, 0, graphic);
  1964. end
  1965. else
  1966. begin
  1967. bmp.Width := (graphic.Width and $FFFC) + 4;
  1968. bmp.Canvas.StretchDraw(Rect(0, 0, bmp.Width, bmp.Height), graphic);
  1969. end;
  1970. AssignFrom24BitsBitmap(bmp);
  1971. finally
  1972. bmp.Free;
  1973. end;
  1974. end;
  1975. {$IFDEF USE_GRAPHICS32}
  1976. end
  1977. else if Source is TBitmap32 then
  1978. begin
  1979. Narrow;
  1980. AssignFromBitmap32(TBitmap32(Source));
  1981. {$ENDIF}
  1982. end
  1983. else
  1984. inherited;
  1985. end;
  1986. procedure TGLImage.AssignFrom24BitsBitmap(aBitmap: TBitmap);
  1987. var
  1988. y, lineSize: Integer;
  1989. rowOffset: Int64;
  1990. pSrc, pDest: PAnsiChar;
  1991. begin
  1992. Assert(aBitmap.PixelFormat = pf24bit);
  1993. UnMipmap;
  1994. FLOD[0].Width := aBitmap.Width;
  1995. FLOD[0].Height := aBitmap.Height;
  1996. FLOD[0].Depth := 0;
  1997. if gl.EXT_bgra then
  1998. begin
  1999. fColorFormat := GL_BGR;
  2000. fElementSize := 3;
  2001. end
  2002. else
  2003. begin
  2004. Assert((aBitmap.Width and 3) = 0);
  2005. fColorFormat := GL_RGBA;
  2006. fElementSize := 4;
  2007. end;
  2008. fInternalFormat := tfRGBA8;
  2009. fDataType := GL_UNSIGNED_BYTE;
  2010. fCubeMap := False;
  2011. fTextureArray := False;
  2012. ReallocMem(fData, DataSize);
  2013. FBlank := False;
  2014. lineSize := GetWidth * fElementSize;
  2015. if Height > 0 then
  2016. begin
  2017. pDest := @PAnsiChar(FData)[GetWidth * fElementSize * (GetHeight - 1)];
  2018. if Height = 1 then
  2019. begin
  2020. if gl.EXT_bgra then
  2021. begin
  2022. pSrc := aBitmap.ScanLine[0]; //BitmapScanLine(aBitmap, 0);
  2023. Move(pSrc^, pDest^, lineSize);
  2024. end
  2025. else
  2026. BGR24ToRGBA32(aBitmap.ScanLine[0], pDest, GetWidth);
  2027. end
  2028. else
  2029. begin
  2030. if VerticalReverseOnAssignFromBitmap then
  2031. begin
  2032. pSrc := aBitmap.ScanLine[GetHeight - 1];
  2033. rowOffset := Integer(aBitmap.ScanLine[GetHeight - 2]) - Integer(pSrc);
  2034. end
  2035. else
  2036. begin
  2037. pSrc := aBitmap.ScanLine[0];
  2038. rowOffset := Int64(aBitmap.ScanLine[1]) - Int64(pSrc);
  2039. end;
  2040. if gl.EXT_bgra then
  2041. begin
  2042. for y := 0 to Height - 1 do
  2043. begin
  2044. Move(pSrc^, pDest^, lineSize);
  2045. Dec(pDest, lineSize);
  2046. Inc(pSrc, rowOffset);
  2047. end;
  2048. end
  2049. else
  2050. begin
  2051. for y := 0 to Height - 1 do
  2052. begin
  2053. BGR24ToRGBA32(pSrc, pDest, Width);
  2054. Dec(pDest, lineSize);
  2055. Inc(pSrc, rowOffset);
  2056. end;
  2057. end;
  2058. end;
  2059. end;
  2060. end;
  2061. procedure TGLImage.AssignFromBitmap24WithoutRGBSwap(aBitmap: TBitmap);
  2062. var
  2063. y: Integer;
  2064. rowOffset: Int64;
  2065. pSrc, pDest: PAnsiChar;
  2066. begin
  2067. Assert(aBitmap.PixelFormat = pf24bit);
  2068. Assert((aBitmap.Width and 3) = 0);
  2069. UnMipmap;
  2070. FLOD[0].Width := aBitmap.Width;
  2071. FLOD[0].Height := aBitmap.Height;
  2072. FLOD[0].Depth := 0;
  2073. fColorFormat := GL_RGBA;
  2074. fInternalFormat := tfRGBA8;
  2075. fDataType := GL_UNSIGNED_BYTE;
  2076. fElementSize := 4;
  2077. fCubeMap := False;
  2078. fTextureArray := False;
  2079. ReallocMem(fData, DataSize);
  2080. FBlank := False;
  2081. if Height > 0 then
  2082. begin
  2083. pDest := @PAnsiChar(fData)[Width * 4 * (Height - 1)];
  2084. if Height = 1 then
  2085. begin
  2086. RGB24ToRGBA32(aBitmap.ScanLine[0], pDest, GetWidth);
  2087. end
  2088. else
  2089. begin
  2090. if VerticalReverseOnAssignFromBitmap then
  2091. begin
  2092. pSrc := aBitmap.ScanLine[GetHeight - 1];
  2093. rowOffset := Cardinal(aBitmap.ScanLine[GetHeight - 2]);
  2094. Dec(rowOffset, Cardinal(pSrc));
  2095. end
  2096. else
  2097. begin
  2098. pSrc := aBitmap.ScanLine[0];
  2099. rowOffset := Cardinal(aBitmap.ScanLine[1]);
  2100. Dec(rowOffset, Cardinal(pSrc));
  2101. end;
  2102. for y := 0 to Height - 1 do
  2103. begin
  2104. RGB24ToRGBA32(pSrc, pDest, GetWidth);
  2105. Dec(pDest, GetWidth * 4);
  2106. Inc(pSrc, rowOffset);
  2107. end;
  2108. end;
  2109. end;
  2110. end;
  2111. procedure TGLImage.AssignFrom32BitsBitmap(aBitmap: TBitmap);
  2112. var
  2113. y: Integer;
  2114. rowOffset: Int64;
  2115. pSrc, pDest: PAnsiChar;
  2116. begin
  2117. Assert(aBitmap.PixelFormat = pf32bit);
  2118. UnMipmap;
  2119. FLOD[0].Width := aBitmap.Width;
  2120. FLOD[0].Height := aBitmap.Height;
  2121. FLOD[0].Depth := 0;
  2122. if gl.EXT_bgra then
  2123. fColorFormat := GL_BGRA
  2124. else
  2125. begin
  2126. Assert((aBitmap.Width and 3) = 0);
  2127. fColorFormat := GL_RGBA;
  2128. end;
  2129. fInternalFormat := tfRGBA8;
  2130. fDataType := GL_UNSIGNED_BYTE;
  2131. fElementSize := 4;
  2132. fCubeMap := False;
  2133. fTextureArray := False;
  2134. ReallocMem(fData, DataSize);
  2135. FBlank := False;
  2136. if Height > 0 then
  2137. begin
  2138. pDest := @PAnsiChar(FData)[Width * 4 * (Height - 1)];
  2139. if VerticalReverseOnAssignFromBitmap then
  2140. begin
  2141. pSrc := aBitmap.ScanLine[Height - 1];
  2142. if Height > 1 then
  2143. begin
  2144. rowOffset := Cardinal(aBitmap.ScanLine[Height - 2]);
  2145. Dec(rowOffset, Cardinal(pSrc));
  2146. end
  2147. else
  2148. rowOffset := 0;
  2149. end
  2150. else
  2151. begin
  2152. pSrc := aBitmap.ScanLine[0];
  2153. if Height > 1 then
  2154. begin
  2155. rowOffset := Cardinal(aBitmap.ScanLine[1]);
  2156. Dec(rowOffset, Cardinal(pSrc));
  2157. end
  2158. else
  2159. rowOffset := 0;
  2160. end;
  2161. if gl.EXT_bgra then
  2162. begin
  2163. for y := 0 to Height - 1 do
  2164. begin
  2165. Move(pSrc^, pDest^, Width * 4);
  2166. Dec(pDest, Width * 4);
  2167. Inc(pSrc, rowOffset);
  2168. end;
  2169. end
  2170. else
  2171. begin
  2172. for y := 0 to Height - 1 do
  2173. begin
  2174. BGRA32ToRGBA32(pSrc, pDest, Width);
  2175. Dec(pDest, Width * 4);
  2176. Inc(pSrc, rowOffset);
  2177. end;
  2178. end;
  2179. end;
  2180. end;
  2181. {$IFDEF USE_GRAPHICS32}
  2182. procedure TGLImage.AssignFromBitmap32(aBitmap32: TBitmap32);
  2183. var
  2184. y: Integer;
  2185. pSrc, pDest: PAnsiChar;
  2186. begin
  2187. UnMipmap;
  2188. FLOD[0].Width := aBitmap32.Width;
  2189. FLOD[0].Height := aBitmap32.Height;
  2190. FLOD[0].Depth := 0;
  2191. fColorFormat := GL_RGBA;
  2192. fInternalFormat := tfRGBA8;
  2193. fDataType := GL_UNSIGNED_BYTE;
  2194. fElementSize := 4;
  2195. fCubeMap := False;
  2196. fTextureArray := False;
  2197. ReallocMem(fData, DataSize);
  2198. FBlank := False;
  2199. if Height > 0 then
  2200. begin
  2201. pDest := @PAnsiChar(FData)[Width * 4 * (Height - 1)];
  2202. for y := 0 to Height - 1 do
  2203. begin
  2204. if VerticalReverseOnAssignFromBitmap then
  2205. pSrc := PAnsiChar(aBitmap32.ScanLine[Height - 1 - y])
  2206. else
  2207. pSrc := PAnsiChar(aBitmap32.ScanLine[y]);
  2208. BGRA32ToRGBA32(pSrc, pDest, Width);
  2209. Dec(pDest, Width * 4);
  2210. end;
  2211. end;
  2212. end;
  2213. {$ENDIF}
  2214. procedure TGLImage.AssignFromPngImage(aPngImage: TPngImage);
  2215. var
  2216. i, j: Integer;
  2217. SourceScan: PRGBLine;
  2218. DestScan: PGLPixel32Array;
  2219. AlphaScan: VCL.Imaging.Pngimage.PByteArray;
  2220. Pixel: Integer;
  2221. begin
  2222. if (aPngImage.Width and 3) > 0 then
  2223. aPngImage.Resize((aPngImage.Width and $FFFC) + 4, aPngImage.Height);
  2224. UnMipmap;
  2225. FLOD[0].Width := aPngImage.Width;
  2226. FLOD[0].Height := aPngImage.Height;
  2227. FLOD[0].Depth := 0;
  2228. fColorFormat := GL_RGBA;
  2229. fInternalFormat := tfRGBA8;
  2230. fDataType := GL_UNSIGNED_BYTE;
  2231. fElementSize := 4;
  2232. fCubeMap := False;
  2233. fTextureArray := False;
  2234. ReallocMem(fData, DataSize);
  2235. FBlank := False;
  2236. case aPngImage.Header.ColorType of
  2237. { Direct ScanLine (24 Bits) }
  2238. COLOR_RGB, COLOR_RGBALPHA: for j := 1 to aPngImage.Height do
  2239. begin
  2240. SourceScan := aPngImage.Scanline[aPngImage.Height - j];
  2241. AlphaScan := aPngImage.AlphaScanline[aPngImage.Height - j];
  2242. DestScan := ScanLine[Pred(j)];
  2243. for i := 0 to Pred(aPngImage.Width) do
  2244. begin
  2245. DestScan^[i].r := SourceScan^[i].rgbtRed;
  2246. DestScan^[i].g := SourceScan^[i].rgbtGreen;
  2247. DestScan^[i].b := SourceScan^[i].rgbtBlue;
  2248. if Assigned(AlphaScan) then
  2249. DestScan^[i].a := AlphaScan^[i]
  2250. else
  2251. DestScan^[i].a := $FF;
  2252. end;
  2253. end;
  2254. else
  2255. // Internal Decode TColor - Palette
  2256. for j := 1 to aPngImage.Height do
  2257. begin
  2258. AlphaScan := aPngImage.AlphaScanline[aPngImage.Height - j];
  2259. DestScan := ScanLine[Pred(j)];
  2260. for i := 0 to Pred(aPngImage.Width) do
  2261. begin
  2262. Pixel := aPngImage.Pixels[i, aPngImage.Height - j];
  2263. DestScan^[i].r := Pixel and $FF;
  2264. DestScan^[i].g := (Pixel shr 8) and $FF;
  2265. DestScan^[i].b := (Pixel shr 16) and $FF;
  2266. if Assigned(AlphaScan) then
  2267. DestScan^[i].a := AlphaScan^[i]
  2268. else
  2269. DestScan^[i].a := $FF;
  2270. end;
  2271. end;
  2272. end;
  2273. end;
  2274. procedure TGLImage.AssignFromTexture2D(textureHandle: Cardinal);
  2275. var
  2276. oldTex: Cardinal;
  2277. begin
  2278. UnMipmap;
  2279. with CurrentGLContext.GLStates do
  2280. begin
  2281. oldTex := TextureBinding[ActiveTexture, ttTexture2D];
  2282. TextureBinding[ActiveTexture, ttTexture2D] := textureHandle;
  2283. gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, @FLOD[0].Width);
  2284. gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, @FLOD[0].Height);
  2285. FLOD[0].Depth := 0;
  2286. fColorFormat := GL_RGBA;
  2287. fInternalFormat := tfRGBA8;
  2288. fDataType := GL_UNSIGNED_BYTE;
  2289. fElementSize := 4;
  2290. fCubeMap := False;
  2291. fTextureArray := False;
  2292. ReallocMem(fData, DataSize);
  2293. gl.GetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, fData);
  2294. FBlank := False;
  2295. TextureBinding[ActiveTexture, ttTexture2D] := oldTex;
  2296. end;
  2297. end;
  2298. procedure TGLImage.AssignFromTexture2D(textureHandle: TGLTextureHandle);
  2299. var
  2300. oldContext: TGLContext;
  2301. contextActivate: Boolean;
  2302. begin
  2303. if Assigned(textureHandle) and (textureHandle.Handle <> 0) then
  2304. begin
  2305. oldContext := CurrentGLContext;
  2306. contextActivate := (oldContext <> textureHandle.RenderingContext);
  2307. if contextActivate then
  2308. begin
  2309. if Assigned(oldContext) then
  2310. oldContext.Deactivate;
  2311. textureHandle.RenderingContext.Activate;
  2312. end;
  2313. try
  2314. AssignFromTexture2D(textureHandle.Handle);
  2315. finally
  2316. if contextActivate then
  2317. begin
  2318. textureHandle.RenderingContext.Deactivate;
  2319. if Assigned(oldContext) then
  2320. oldContext.Activate;
  2321. end;
  2322. end;
  2323. end
  2324. else
  2325. begin
  2326. // Make image empty
  2327. UnMipmap;
  2328. FLOD[0].Width := 0;
  2329. FLOD[0].Height := 0;
  2330. FLOD[0].Depth := 0;
  2331. fColorFormat := GL_RGBA;
  2332. fInternalFormat := tfRGBA8;
  2333. fDataType := GL_UNSIGNED_BYTE;
  2334. fElementSize := 4;
  2335. fCubeMap := False;
  2336. fTextureArray := False;
  2337. ReallocMem(fData, DataSize);
  2338. end;
  2339. end;
  2340. function TGLImage.Create32BitsBitmap: TBitmap;
  2341. var
  2342. y, x, x4: Integer;
  2343. pSrc, pDest: PAnsiChar;
  2344. begin
  2345. if FBlank then
  2346. begin
  2347. Result := nil;
  2348. Exit;
  2349. end;
  2350. Narrow;
  2351. Result := TBitmap.Create;
  2352. Result.PixelFormat := pf32bit;
  2353. Result.Width := Width;
  2354. Result.Height := Height;
  2355. if Height > 0 then
  2356. begin
  2357. pSrc := @PAnsiChar(fData)[Width * 4 * (Height - 1)];
  2358. for y := 0 to Height - 1 do
  2359. begin
  2360. pDest := Result.ScanLine[y];
  2361. for x := 0 to Width - 1 do
  2362. begin
  2363. x4 := x * 4;
  2364. pDest[x4 + 0] := pSrc[x4 + 2];
  2365. pDest[x4 + 1] := pSrc[x4 + 1];
  2366. pDest[x4 + 2] := pSrc[x4 + 0];
  2367. pDest[x4 + 3] := pSrc[x4 + 3];
  2368. end;
  2369. Dec(pSrc, Width * 4);
  2370. end;
  2371. end;
  2372. end;
  2373. procedure TGLImage.SetWidth(val: Integer);
  2374. begin
  2375. if val <> FLOD[0].Width then
  2376. begin
  2377. Assert(val >= 0);
  2378. FLOD[0].Width := val;
  2379. FBlank := True;
  2380. end;
  2381. end;
  2382. procedure TGLImage.SetHeight(const val: Integer);
  2383. begin
  2384. if val <> FLOD[0].Height then
  2385. begin
  2386. Assert(val >= 0);
  2387. FLOD[0].Height := val;
  2388. FBlank := True;
  2389. end;
  2390. end;
  2391. procedure TGLImage.SetDepth(const val: Integer);
  2392. begin
  2393. if val <> FLOD[0].Depth then
  2394. begin
  2395. Assert(val >= 0);
  2396. FLOD[0].Depth := val;
  2397. FBlank := True;
  2398. end;
  2399. end;
  2400. procedure TGLImage.SetCubeMap(const val: Boolean);
  2401. begin
  2402. if val <> fCubeMap then
  2403. begin
  2404. fCubeMap := val;
  2405. FBlank := True;
  2406. end;
  2407. end;
  2408. procedure TGLImage.SetArray(const val: Boolean);
  2409. begin
  2410. if val <> fTextureArray then
  2411. begin
  2412. fTextureArray := val;
  2413. FBlank := True;
  2414. end;
  2415. end;
  2416. procedure TGLImage.SetColorFormatDataType(const AColorFormat, ADataType: Cardinal);
  2417. begin
  2418. if FBlank then
  2419. begin
  2420. fDataType := ADataType;
  2421. fColorFormat := AColorFormat;
  2422. Exit;
  2423. end;
  2424. fOldDataType := fDataType;
  2425. fOldColorFormat := fColorFormat;
  2426. fDataType := ADataType;
  2427. fColorFormat := AColorFormat;
  2428. fElementSize := GetTextureElementSize(fColorFormat, fDataType);
  2429. DataConvertTask;
  2430. end;
  2431. function TGLImage.GetScanLine(index: Integer): PGLPixel32Array;
  2432. begin
  2433. Narrow;
  2434. Result := PGLPixel32Array(@fData[index * GetWidth]);
  2435. end;
  2436. procedure TGLImage.SetAlphaFromIntensity;
  2437. var
  2438. i: Integer;
  2439. begin
  2440. Narrow;
  2441. for i := 0 to (DataSize div 4) - 1 do
  2442. with FData^[i] do
  2443. a := (Integer(r) + Integer(g) + Integer(b)) div 3;
  2444. end;
  2445. procedure TGLImage.SetAlphaTransparentForColor(const aColor: TColor);
  2446. var
  2447. color: TGLPixel24;
  2448. begin
  2449. color.r := GetRValue(aColor);
  2450. color.g := GetGValue(aColor);
  2451. color.b := GetBValue(aColor);
  2452. SetAlphaTransparentForColor(color);
  2453. end;
  2454. procedure TGLImage.SetAlphaTransparentForColor(const aColor: TGLPixel32);
  2455. var
  2456. color: TGLPixel24;
  2457. begin
  2458. color.r := aColor.r;
  2459. color.g := aColor.g;
  2460. color.b := aColor.b;
  2461. SetAlphaTransparentForColor(color);
  2462. end;
  2463. procedure TGLImage.SetAlphaTransparentForColor(const aColor: TGLPixel24);
  2464. var
  2465. i: Integer;
  2466. intCol: Integer;
  2467. begin
  2468. Narrow;
  2469. intCol := (PInteger(@aColor)^) and $FFFFFF;
  2470. for i := 0 to (DataSize div 4) - 1 do
  2471. if PInteger(@FData[i])^ and $FFFFFF = intCol then
  2472. FData^[i].a := 0
  2473. else
  2474. FData^[i].a := 255;
  2475. end;
  2476. procedure TGLImage.SetAlphaToValue(const aValue: Byte);
  2477. var
  2478. i: Integer;
  2479. begin
  2480. Narrow;
  2481. for i := 0 to (DataSize div 4) - 1 do
  2482. FData^[i].a := aValue
  2483. end;
  2484. procedure TGLImage.SetAlphaToFloatValue(const aValue: Single);
  2485. begin
  2486. SetAlphaToValue(Byte(Trunc(aValue * 255) and 255));
  2487. end;
  2488. procedure TGLImage.InvertAlpha;
  2489. var
  2490. i: Integer;
  2491. begin
  2492. Narrow;
  2493. for i := (DataSize div 4) - 1 downto 0 do
  2494. FData^[i].a := 255 - FData^[i].a;
  2495. end;
  2496. procedure TGLImage.SqrtAlpha;
  2497. var
  2498. i: Integer;
  2499. sqrt255Array: PSqrt255Array;
  2500. begin
  2501. Narrow;
  2502. sqrt255Array := GetSqrt255Array;
  2503. for i := 0 to (DataSize div 4) - 1 do
  2504. with FData^[i] do
  2505. a := sqrt255Array^[(Integer(r) + Integer(g) + Integer(b)) div 3];
  2506. end;
  2507. procedure TGLImage.BrightnessCorrection(const factor: Single);
  2508. begin
  2509. if Assigned(FData) then
  2510. begin
  2511. Narrow;
  2512. BrightenRGBAArray(Data, DataSize div 4, factor);
  2513. end;
  2514. end;
  2515. procedure TGLImage.GammaCorrection(const gamma: Single);
  2516. begin
  2517. if Assigned(FData) then
  2518. begin
  2519. Narrow;
  2520. GammaCorrectRGBAArray(Data, DataSize div 4, gamma);
  2521. end;
  2522. end;
  2523. procedure TGLImage.DownSampleByFactor2;
  2524. type
  2525. T2Pixel32 = packed array[0..1] of TGLPixel32;
  2526. P2Pixel32 = ^T2Pixel32;
  2527. procedure ProcessRowPascal(pDest: PGLPixel32; pLineA, pLineB: P2Pixel32; n:
  2528. Integer);
  2529. var
  2530. i: Integer;
  2531. begin
  2532. for i := 0 to n - 1 do
  2533. begin
  2534. pDest^.r := (pLineA^[0].r + pLineA^[1].r + pLineB^[0].r +
  2535. pLineB^[1].r) shr 2;
  2536. pDest^.g := (pLineA^[0].g + pLineA^[1].g + pLineB^[0].g +
  2537. pLineB^[1].g) shr 2;
  2538. pDest^.b := (pLineA^[0].b + pLineA^[1].b + pLineB^[0].b +
  2539. pLineB^[1].b) shr 2;
  2540. pDest^.a := (pLineA^[0].a + pLineA^[1].a + pLineB^[0].a +
  2541. pLineB^[1].a) shr 2;
  2542. Inc(pLineA);
  2543. Inc(pLineB);
  2544. Inc(pDest);
  2545. end;
  2546. end; // }
  2547. var
  2548. y, w2, h2: Integer;
  2549. pDest: PGLPixel32;
  2550. pLineA, pLineB: P2Pixel32;
  2551. begin
  2552. if (GetWidth <= 1) or (GetHeight <= 1) then
  2553. Exit;
  2554. Narrow;
  2555. w2 := GetWidth shr 1;
  2556. h2 := GetHeight shr 1;
  2557. pDest := @fData[0];
  2558. pLineA := @fData[0];
  2559. pLineB := @fData[Width];
  2560. for y := 0 to h2 - 1 do
  2561. begin
  2562. ProcessRowPascal(pDest, pLineA, pLineB, w2);
  2563. Inc(pDest, w2);
  2564. Inc(pLineA, Width);
  2565. Inc(pLineB, Width);
  2566. end;
  2567. FLOD[0].Width := w2;
  2568. FLOD[0].Height := h2;
  2569. ReallocMem(fData, DataSize);
  2570. end;
  2571. procedure TGLImage.ReadPixels(const area: TRect);
  2572. begin
  2573. UnMipmap;
  2574. FLOD[0].Width := (area.Right - area.Left) and $FFFC;
  2575. FLOD[0].Height := (area.Bottom - area.Top);
  2576. FLOD[0].Depth := 0;
  2577. fColorFormat := GL_RGBA;
  2578. fInternalFormat := tfRGBA8;
  2579. fDataType := GL_UNSIGNED_BYTE;
  2580. fElementSize := 4;
  2581. fCubeMap := false;
  2582. fTextureArray := false;
  2583. fBlank := false;
  2584. ReallocMem(FData, DataSize);
  2585. gl.ReadPixels(0, 0, GetWidth, GetHeight, GL_RGBA, GL_UNSIGNED_BYTE, FData);
  2586. end;
  2587. procedure TGLImage.DrawPixels(const x, y: Single);
  2588. begin
  2589. if fBlank or IsEmpty then
  2590. Exit;
  2591. // Assert(not CurrentGLContext.GLStates.ForwardContext);
  2592. gl.RasterPos2f(x, y);
  2593. gl.DrawPixels(Width, Height, fColorFormat, fDataType, FData);
  2594. end;
  2595. procedure TGLImage.GrayScaleToNormalMap(const scale: Single;
  2596. wrapX: Boolean = True; wrapY: Boolean = True);
  2597. var
  2598. x, y: Integer;
  2599. dcx, dcy: Single;
  2600. invLen: Single;
  2601. maskX, maskY: Integer;
  2602. curRow, nextRow, prevRow: PGLPixel32Array;
  2603. normalMapBuffer: PGLPixel32Array;
  2604. p: PGLPixel32;
  2605. begin
  2606. if Assigned(FData) then
  2607. begin
  2608. Narrow;
  2609. GetMem(normalMapBuffer, DataSize);
  2610. try
  2611. maskX := Width - 1;
  2612. maskY := Height - 1;
  2613. p := @normalMapBuffer[0];
  2614. for y := 0 to Height - 1 do
  2615. begin
  2616. curRow := GetScanLine(y);
  2617. if wrapY then
  2618. begin
  2619. prevRow := GetScanLine((y - 1) and maskY);
  2620. nextRow := GetScanLine((y + 1) and maskY);
  2621. end
  2622. else
  2623. begin
  2624. if y > 0 then
  2625. prevRow := GetScanLine(y - 1)
  2626. else
  2627. prevRow := curRow;
  2628. if y < Height - 1 then
  2629. nextRow := GetScanLine(y + 1)
  2630. else
  2631. nextRow := curRow;
  2632. end;
  2633. for x := 0 to Width - 1 do
  2634. begin
  2635. if wrapX then
  2636. dcx := scale * (curRow^[(x - 1) and maskX].g - curRow^[(x + 1) and
  2637. maskX].g)
  2638. else
  2639. begin
  2640. if x = 0 then
  2641. dcx := scale * (curRow^[x].g - curRow^[x + 1].g)
  2642. else if x < Width - 1 then
  2643. dcx := scale * (curRow^[x - 1].g - curRow^[x].g)
  2644. else
  2645. dcx := scale * (curRow^[x - 1].g - curRow^[x + 1].g);
  2646. end;
  2647. dcy := scale * (prevRow^[x].g - nextRow^[x].g);
  2648. invLen := 127 * RSqrt(dcx * dcx + dcy * dcy + 1);
  2649. with p^ do
  2650. begin
  2651. r := Integer(Round(128 + ClampValue(dcx * invLen, -128, 127)));
  2652. g := Integer(Round(128 + ClampValue(dcy * invLen, -128, 127)));
  2653. b := Integer(Round(128 + ClampValue(invLen, -128, 127)));
  2654. a := 255;
  2655. end;
  2656. Inc(p);
  2657. end;
  2658. end;
  2659. Move(normalMapBuffer^, FData^, DataSize);
  2660. finally
  2661. FreeMem(normalMapBuffer);
  2662. end;
  2663. end;
  2664. end;
  2665. procedure TGLImage.NormalizeNormalMap;
  2666. var
  2667. x, y: Integer;
  2668. sr, sg, sb: Single;
  2669. invLen: Single;
  2670. curRow: PGLPixel32Array;
  2671. p: PGLPixel32;
  2672. const
  2673. cInv128: Single = 1 / 128;
  2674. begin
  2675. if not IsEmpty and not Blank then
  2676. begin
  2677. Narrow;
  2678. for y := 0 to Height - 1 do
  2679. begin
  2680. curRow := @FData[y * GetWidth];
  2681. for x := 0 to GetWidth - 1 do
  2682. begin
  2683. p := @curRow[x];
  2684. sr := (p^.r - 128) * cInv128;
  2685. sg := (p^.g - 128) * cInv128;
  2686. sb := (p^.b - 128) * cInv128;
  2687. invLen := RSqrt(sr * sr + sg * sg + sb * sb);
  2688. p^.r := Round(128 + 127 * ClampValue(sr * invLen, -1, 1));
  2689. p^.g := Round(128 + 127 * ClampValue(sg * invLen, -1, 1));
  2690. p^.b := Round(128 + 127 * ClampValue(sb * invLen, -1, 1));
  2691. end;
  2692. end;
  2693. end;
  2694. end;
  2695. procedure TGLImage.SetBlank(const Value: boolean);
  2696. begin
  2697. if not Value and not IsEmpty then
  2698. ReallocMem(FData, DataSize);
  2699. FBlank := Value;
  2700. end;
  2701. procedure TGLImage.AssignToBitmap(aBitmap: TBitmap);
  2702. var
  2703. y: integer;
  2704. pSrc, pDest: PAnsiChar;
  2705. begin
  2706. Narrow;
  2707. aBitmap.Width := GetWidth;
  2708. aBitmap.Height := GetHeight;
  2709. aBitmap.PixelFormat := pf32bit;
  2710. if FVerticalReverseOnAssignFromBitmap then
  2711. begin
  2712. for y := 0 to GetHeight - 1 do
  2713. begin
  2714. pSrc := @PAnsiChar(FData)[y * (GetWidth * 4)];
  2715. pDest := aBitmap.ScanLine[y];
  2716. BGRA32ToRGBA32(pSrc, pDest, GetWidth);
  2717. end;
  2718. end
  2719. else
  2720. begin
  2721. for y := 0 to GetHeight - 1 do
  2722. begin
  2723. pSrc := @PAnsiChar(FData)[y * (GetWidth * 4)];
  2724. pDest := aBitmap.ScanLine[GetHeight - 1 - y];
  2725. BGRA32ToRGBA32(pSrc, pDest, GetWidth);
  2726. end;
  2727. end;
  2728. end;
  2729. procedure TGLImage.GenerateMipmap(AFilter: TImageFilterFunction);
  2730. begin
  2731. if not FBlank then
  2732. inherited GenerateMipmap(AFilter);
  2733. end;
  2734. procedure TGLImage.UnMipmap;
  2735. begin
  2736. inherited UnMipmap;
  2737. if not (fBlank or IsEmpty) then
  2738. ReallocMem(FData, DataSize);
  2739. end;
  2740. procedure TGLImage.DataConvertTask;
  2741. var
  2742. oldLOD: TGLImagePiramid;
  2743. newData: Pointer;
  2744. ptr: PByte;
  2745. L: TGLImageLODRange;
  2746. d: Integer;
  2747. begin
  2748. oldLOD := FLOD;
  2749. if IsVolume then
  2750. begin
  2751. // Message Hint 'TGLImage.DataConvertTask not yet implemented for volume images'
  2752. end
  2753. else
  2754. begin
  2755. GetMem(newData, DataSize);
  2756. d := MaxInteger(GetDepth, 1);
  2757. try
  2758. for L := FLevelCount - 1 downto 0 do
  2759. begin
  2760. ptr := newData;
  2761. Inc(ptr, oldLOD[L].Offset);
  2762. ConvertImage(GetLevelAddress(L), ptr, fOldColorFormat, fColorFormat,
  2763. fOldDataType, fDataType, oldLOD[L].Width, oldLOD[L].Height * d);
  2764. end;
  2765. FreeMem(fData);
  2766. fData := newData;
  2767. except
  2768. FreeMem(newData);
  2769. GLSLogger.LogError(Format(strCantConvertImg, [ClassName]));
  2770. SetErrorImage;
  2771. end;
  2772. end;
  2773. end;
  2774. function GraphicClassForExtension(const anExtension: string): TGraphicClass;
  2775. var
  2776. i: integer;
  2777. sl: TStringList;
  2778. buf: string;
  2779. begin
  2780. Result := nil;
  2781. if anExtension = '' then
  2782. Exit;
  2783. if anExtension[1] = '.' then
  2784. buf := Copy(anExtension, 2, MaxInt)
  2785. else
  2786. buf := anExtension;
  2787. sl := TStringList.Create;
  2788. try
  2789. HackTPictureRegisteredFormats(sl);
  2790. i := sl.IndexOfName(buf);
  2791. if i >= 0 then
  2792. Result := TGraphicClass(sl.Objects[i]);
  2793. finally
  2794. sl.Free;
  2795. end;
  2796. end;
  2797. type
  2798. PFileFormat = ^TFileFormat;
  2799. TFileFormat = record
  2800. GraphicClass: TGraphicClass;
  2801. Extension: string;
  2802. Description: string;
  2803. DescResID: integer;
  2804. end;
  2805. // HackTPictureRegisteredFormats
  2806. {$IFOPT R+}
  2807. {$DEFINE HackTPictureRegisteredFormats_Disable_RangeCheck}
  2808. {$R-}
  2809. {$ENDIF}
  2810. procedure HackTPictureRegisteredFormats(destList: TStrings);
  2811. var
  2812. pRegisterFileFormat, pCallGetFileFormat, pGetFileFormats, pFileFormats: PAnsiChar;
  2813. iCall: cardinal;
  2814. i: integer;
  2815. list: TList;
  2816. fileFormat: PFileFormat;
  2817. begin
  2818. {$MESSAGE WARN 'HackTPictureRegisteredFormats will crash when Graphics.pas is compiled with the 'Use Debug DCUs' option'}
  2819. pRegisterFileFormat := PAnsiChar(@TPicture.RegisterFileFormat);
  2820. if pRegisterFileFormat[0] = #$FF then // in case of BPL redirector
  2821. pRegisterFileFormat := PAnsiChar(PCardinal(PCardinal(@pRegisterFileFormat[2])^)^);
  2822. pCallGetFileFormat := @pRegisterFileFormat[16];
  2823. iCall := PCardinal(pCallGetFileFormat)^;
  2824. pGetFileFormats := @pCallGetFileFormat[iCall + 4];
  2825. pFileFormats := PAnsiChar(PCardinal(@pGetFileFormats[2])^);
  2826. list := TList(PCardinal(pFileFormats)^);
  2827. if list <> nil then
  2828. begin
  2829. for i := 0 to list.Count - 1 do
  2830. begin
  2831. fileFormat := PFileFormat(list[i]);
  2832. destList.AddObject(fileFormat.Extension + '=' + fileFormat.Description,
  2833. TObject(fileFormat.GraphicClass));
  2834. end;
  2835. end;
  2836. end;
  2837. {$IFDEF HackTPictureRegisteredFormats_Disable_RangeCheck}
  2838. {$R+}
  2839. {$UNDEF HackTPictureRegisteredFormats_Disable_RangeCheck}
  2840. {$ENDIF}
  2841. //---------------------------------------------------
  2842. initialization
  2843. //---------------------------------------------------
  2844. finalization
  2845. FreeAndNil(vRasterFileFormats);
  2846. end.