GLS.Graphics.pas 129 KB

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