123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991 |
- //
- // The graphics engine GXScene https://github.com/glscene
- //
- unit GXS.Graphics;
- (*
- Utility class and functions to manipulate a bitmap in OpenGL's default
- byte order (GL_RGBA vs TBitmap's GL_BGRA)
- Note: TgxBitmap32 has support for Alex Denissov's Graphics32 library
- (http://www.g32.org), just make sure the USE_GRAPHICS32 conditionnal
- is active in Scene.inc and recompile.
- *)
- interface
- {$I Stage.Defines.inc}
- uses
- Winapi.Windows,
- System.Classes,
- System.SysUtils,
- System.SyncObjs,
- System.UITypes,
- System.Math,
- FMX.Graphics,
- FMX.Dialogs,
- FMX.Types,
- FMX.Consts,
- {$IFDEF USE_GRAPHICS32}
- GR32,
- {$ENDIF}
- Stage.OpenGL4,
- Stage.VectorGeometry,
- Stage.Utils,
- Stage.TextureFormat,
- Stage.Strings,
- GXS.PersistentClasses,
- GXS.ApplicationFileIO,
- GXS.Context,
- GXS.ImageUtils,
- GXS.Color;
- type
- TgxPixel24 = packed record
- r, g, b: Byte;
- end;
- PgxPixel24 = ^TgxPixel24;
- TgxPixel32 = packed record
- r, g, b, a: Byte;
- end;
- PgxPixel32 = ^TgxPixel32;
- TgxPixel32Array = array[0..MaxInt shr 3] of TgxPixel32;
- PgxPixel32Array = ^TgxPixel32Array;
- TgxLODStreamingState = (ssKeeping, ssLoading, ssLoaded, ssTransfered);
- TgxImageLevelDesc = record
- Width: Integer;
- Height: Integer;
- Depth: Integer;
- PBO: TgxUnpackPBOHandle;
- MapAddress: Pointer;
- Offset: LongWord;
- StreamOffset: LongWord;
- Size: LongWord;
- State: TgxLODStreamingState;
- end;
- TgxImageLODRange = 0..15;
- TgxImagePiramid = array[TgxImageLODRange] of TgxImageLevelDesc;
- TgxBaseImage = class(TgxDataFile)
- private
- FSourceStream: TStream;
- FStreamLevel: TgxImageLODRange;
- FFinishEvent: TgxFinishTaskEvent;
- {$IFDEF USE_SERVICE_CONTEXT}
- procedure ImageStreamingTask; stdcall;
- {$ENDIF}
- protected
- fData: PgxPixel32Array;
- FLOD: TgxImagePiramid;
- fLevelCount: TgxImageLODRange;
- fColorFormat: Cardinal;
- fInternalFormat: TglInternalFormat;
- fDataType: Cardinal;
- fElementSize: Integer;
- fCubeMap: Boolean;
- fTextureArray: Boolean;
- function GetData: PgxPixel32Array; virtual;
- function GetWidth: Integer;
- function GetHeight: Integer;
- function GetDepth: Integer;
- function GetLevelAddress(ALevel: Byte): Pointer; overload;
- function GetLevelAddress(ALevel, AFace: Byte): Pointer; overload;
- function GetLevelWidth(ALOD: TgxImageLODRange): Integer;
- function GetLevelHeight(ALOD: TgxImageLODRange): Integer;
- function GetLevelDepth(ALOD: TgxImageLODRange): Integer;
- function GetLevelPBO(ALOD: TgxImageLODRange): TgxUnpackPBOHandle;
- function GetLevelOffset(ALOD: TgxImageLODRange): Integer;
- function GetLevelSizeInByte(ALOD: TgxImageLODRange): Integer;
- function GetLevelStreamingState(ALOD: TgxImageLODRange): TgxLODStreamingState;
- procedure SetLevelStreamingState(ALOD: TgxImageLODRange; AState: TgxLODStreamingState);
- procedure SaveHeader;
- procedure LoadHeader;
- procedure StartStreaming;
- procedure DoStreaming;
- public
- constructor Create; reintroduce; virtual;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- function GetTextureTarget: TGLTextureTarget;
- // Registers the bitmap's content as an OpenGL texture map.
- procedure RegisterAsOpenRXTexture(
- AHandle: TgxTextureHandle;
- aMipmapGen: Boolean;
- aTexFormat: NativeUInt;
- out texWidth: integer;
- out texHeight: integer;
- out texDepth: integer); virtual;
- // Assigns from any Texture.
- function AssignFromTexture(
- AHandle: TgxTextureHandle;
- const CastToFormat: Boolean;
- const intFormat: TglInternalFormat = tfRGBA8;
- const colorFormat: NativeUInt = 0;
- const dataType: NativeUInt = 0): Boolean; virtual;
- (* Convert vertical cross format of non compressed, non mipmaped image
- to six face of cube map *)
- function ConvertCrossToCubeMap: Boolean;
- // Convert flat image to volume by dividing it into slice.
- function ConvertToVolume(const col, row: Integer; const MakeArray: Boolean): Boolean;
- // Return size in byte of all image
- function DataSize: Cardinal;
- // True if the bitmap is empty (ie. width or height is zero).
- function IsEmpty: Boolean;
- function IsCompressed: Boolean;
- function IsVolume: Boolean;
- // Narrow image data to simple RGBA8 ubyte
- procedure Narrow;
- // Generate LOD pyramid
- procedure GenerateMipmap(AFilter: TImageFilterFunction); virtual;
- // Leave top level and remove other
- procedure UnMipmap; virtual;
- // Direct Access to image data
- property Data: PgxPixel32Array read GetData;
- // Set image of error.
- procedure SetErrorImage;
- // Recalculate levels information based on first level.
- procedure UpdateLevelsInfo;
- property LevelWidth[ALOD: TgxImageLODRange]: Integer
- read GetLevelWidth;
- property LevelHeight[ALOD: TgxImageLODRange]: Integer
- read GetLevelHeight;
- property LevelDepth[ALOD: TgxImageLODRange]: Integer
- read GetLevelDepth;
- property LevelPixelBuffer[ALOD: TgxImageLODRange]: TgxUnpackPBOHandle
- read GetLevelPBO;
- // LOD offset in byte
- property LevelOffset[ALOD: TgxImageLODRange]: Integer
- read GetLevelOffset;
- // LOD size in byte
- property LevelSizeInByte[ALOD: TgxImageLODRange]: Integer
- read GetLevelSizeInByte;
- property LevelStreamingState[ALOD: TgxImageLODRange]: TgxLODStreamingState
- read GetLevelStreamingState write SetLevelStreamingState;
- // Number of levels.
- property LevelCount: TgxImageLODRange read fLevelCount;
- property InternalFormat: TglInternalFormat read FInternalFormat;
- property ColorFormat: Cardinal read fColorFormat;
- property DataType: Cardinal read fDataType;
- property ElementSize: Integer read fElementSize;
- property CubeMap: Boolean read fCubeMap;
- property TextureArray: Boolean read fTextureArray;
- end;
- TgxBaseImageClass = class of TgxBaseImage;
- (* Contains and manipulates a 32 bits (24+8) bitmap.
- This is the base class for preparing and manipulating textures in GXS.Scene,
- this function does not rely on a windows handle and should be used for
- in-memory manipulations only.
- 16 bits textures are automatically converted to 24 bits and an opaque (255)
- alpha channel is assumed for all planes, the byte order is as specified
- in GL_RGBA. If 32 bits is used in this class, it can however output 16 bits texture
- data for use in OpenGL.
- The class has support for registering its content as a texture, as well
- as for directly drawing/reading from the current OpenGL buffer. *)
- TgxImage = class(TgxBaseImage)
- private
- FVerticalReverseOnAssignFromBitmap: Boolean;
- FBlank: boolean;
- fOldColorFormat: Cardinal;
- fOldDataType: Cardinal;
- procedure DataConvertTask;
- protected
- procedure SetWidth(val: Integer);
- procedure SetHeight(const val: Integer);
- procedure SetDepth(const val: Integer);
- procedure SetBlank(const Value: boolean);
- procedure SetCubeMap(const val: Boolean);
- procedure SetArray(const val: Boolean);
- function GetScanLine(index: Integer): PgxPixel32Array;
- procedure AssignFrom24BitsBitmap(aBitmap: TBitmap);
- procedure AssignFrom32BitsBitmap(aBitmap: TBitmap);
- {$IFDEF USE_GRAPHICS32}
- procedure AssignFromBitmap32(aBitmap32: TBitmap32);
- {$ENDIF}
- procedure AssignFromPngImage(aPngImage: TBitmapImage);
- public
- constructor Create; override;
- destructor Destroy; override;
- // Accepts TgxImage and TGraphic subclasses.
- procedure Assign(Source: TPersistent); override;
- (* Assigns from a 24 bits bitmap without swapping RGB.
- This is faster than a regular assignment, but R and B channels
- will be reversed (from what you would view in a TImage). Suitable
- if you do your own drawing and reverse RGB on the drawing side.
- If you're after speed, don't forget to set the bitmap's dimensions
- to a power of two! *)
- procedure AssignFromBitmap24WithoutRGBSwap(aBitmap: TBitmap);
- (* Assigns from a 2D Texture.
- The context which holds the texture must be active and the texture
- handle valid. *)
- procedure AssignFromTexture2D(textureHandle: Cardinal); overload;
- (* Assigns from a Texture handle.
- If the handle is invalid, the bitmap32 will be empty. *)
- procedure AssignFromTexture2D(textureHandle: TgxTextureHandle); overload;
- // Create a 32 bits TBitmap from self content.
- function Create32BitsBitmap: TBitmap;
- // Width of the bitmap.
- property Width: Integer read GetWidth write SetWidth;
- // Height of the bitmap.
- property Height: Integer read GetHeight write SetHeight;
- // Depth of the bitmap.
- property Depth: Integer read GetDepth write SetDepth;
- // OpenGL color format
- property ColorFormat: Cardinal read fColorFormat;
- // Recommended texture internal format
- property InternalFormat: TglInternalFormat read FInternalFormat write
- FInternalFormat;
- // OpenGL data type
- property DataType: Cardinal read fDataType;
- // Size in bytes of pixel or block
- property ElementSize: Integer read fElementSize;
- property CubeMap: Boolean read fCubeMap write SetCubeMap;
- property TextureArray: Boolean read fTextureArray write SetArray;
- (* Access to a specific Bitmap ScanLine. index should be in the [0; Height[ range.
- Warning : this function is NOT protected against invalid indexes,
- and invoking it is invalid if the bitmap is Empty. *)
- property ScanLine[index: Integer]: PgxPixel32Array read GetScanLine;
- property VerticalReverseOnAssignFromBitmap: Boolean read
- FVerticalReverseOnAssignFromBitmap write
- FVerticalReverseOnAssignFromBitmap;
- (* Set Blank to true if you actually don't need to allocate data in main memory.
- Useful for textures that are generated by the GPU on the fly. *)
- property Blank: boolean read FBlank write SetBlank;
- // Recast image OpenGL data type and color format.
- procedure SetColorFormatDataType(const AColorFormat, ADataType: Cardinal);
- (* Set Alpha channel values to the pixel intensity.
- The intensity is calculated as the mean of RGB components. *)
- procedure SetAlphaFromIntensity;
- (* Set Alpha channel to 0 for pixels of given color, 255 for others).
- This makes pixels of given color totally transparent while the others
- are completely opaque. *)
- procedure SetAlphaTransparentForColor(const aColor: TColor); overload;
- procedure SetAlphaTransparentForColor(const aColor: TgxPixel32); overload;
- procedure SetAlphaTransparentForColor(const aColor: TgxPixel24); overload;
- // Set Alpha channel values to given byte value.
- procedure SetAlphaToValue(const aValue: Byte);
- // Set Alpha channel values to given float [0..1] value.
- procedure SetAlphaToFloatValue(const aValue: Single);
- (* Inverts the AlphaChannel component.
- What was transparent becomes opaque and vice-versa. *)
- procedure InvertAlpha;
- // AlphaChannel components are replaced by their sqrt.
- procedure SqrtAlpha;
- // Apply a brightness (scaled saturating) correction to the RGB components.
- procedure BrightnessCorrection(const factor: Single);
- // Apply a gamma correction to the RGB components.
- procedure GammaCorrection(const gamma: Single);
- (* Downsample the bitmap by a factor of 2 in both dimensions.
- If one of the dimensions is 1 or less, does nothing. *)
- procedure DownSampleByFactor2;
- (* Reads the given area from the current active OpenGL rendering context.
- The best spot for reading pixels is within a SceneViewer's PostRender
- event : the scene has been fully rendered and the OpenGL context
- is still active. *)
- procedure ReadPixels(const area: TRect);
- (* Draws the whole bitmap at given position in the current OpenGL context.
- This function must be called with a rendering context active.
- Blending and Alpha channel functions are not altered by this function
- and must be adjusted separately. *)
- procedure DrawPixels(const x, y: Single);
- (* Converts a grayscale 'elevation' bitmap to normal map.
- Actually, only the Green component in the original bitmap is used. *)
- procedure GrayScaleToNormalMap(const scale: Single;
- wrapX: Boolean = True; wrapY: Boolean = True);
- // Assumes the bitmap content is a normal map and normalizes all pixels.
- procedure NormalizeNormalMap;
- //Converts a TImage back into a TBitmap
- procedure AssignToBitmap(aBitmap: TBitmap);
- // Generate level of detail.
- procedure GenerateMipmap(AFilter: TImageFilterFunction); override;
- // Clear all levels except first.
- procedure UnMipmap; override;
- end;
- TgxBitmap32 = TgxImage;
- TRasterFileFormat = class
- public
- BaseImageClass: TgxBaseImageClass;
- Extension: string;
- Description: string;
- DescResID: Integer;
- end;
- // Stores registered raster file Formatx.
- TRasterFileFormatsList = class(TgxPersistentObjectList)
- public
- destructor Destroy; override;
- procedure Add(const Ext, Desc: string; DescID: Integer; AClass: TgxBaseImageClass);
- function FindExt(ext: string): TgxBaseImageClass;
- function FindFromFileName(const fileName: string): TgxBaseImageClass;
- function FindFromStream(const AStream: TStream): TgxBaseImageClass;
- procedure Remove(AClass: TgxBaseImageClass);
- procedure BuildFilterStrings(imageFileClass: TgxBaseImageClass;
- var descriptions, filters: string;
- formatsThatCanBeOpened: Boolean = True;
- formatsThatCanBeSaved: Boolean = False);
- function FindExtByIndex(index: Integer;
- formatsThatCanBeOpened: Boolean = True;
- formatsThatCanBeSaved: Boolean = False): string;
- end;
- EInvalidRasterFile = class(Exception);
- procedure Div2(var Value: Integer);
- procedure BGR24ToRGB24(src, dest: Pointer; pixelCount: Integer);
- procedure BGR24ToRGBA32(src, dest: Pointer; pixelCount: Integer);
- procedure RGB24ToRGBA32(src, dest: Pointer; pixelCount: Integer);
- procedure BGRA32ToRGBA32(src, dest: Pointer; pixelCount: Integer);
- procedure GammaCorrectRGBArray(base: Pointer; pixelCount: Integer; gamma: Single);
- procedure BrightenRGBArray(base: Pointer; pixelCount: Integer; factor: Single);
- // Read access to the list of registered vector file formats
- function GetRasterFileFormats: TRasterFileFormatsList;
- (* Returns an extension by its index
- in the internal image files dialogs filter.
- Use InternalImageFileFormatsFilter to obtain the filter. *)
- function RasterFileFormatExtensionByIndex(index: Integer): string;
- procedure RegisterRasterFormat(const AExtension, ADescription: string;
- AClass: TgxBaseImageClass);
- procedure UnregisterRasterFormat(AClass: TgxBaseImageClass);
- // Return an optimal number of texture pyramid
- function GetImageLodNumber(w, h, d: integer; IsVolume: Boolean): Integer;
- var
- vVerticalFlipDDS: Boolean = True;
- // ------------------------------------------------------------------
- implementation
- // ------------------------------------------------------------------
- var
- vRasterFileFormats: TRasterFileFormatsList;
- // ------- Raster File Registries ------------------
- function GetRasterFileFormats: TRasterFileFormatsList;
- begin
- if not Assigned(vRasterFileFormats) then
- vRasterFileFormats := TRasterFileFormatsList.Create;
- Result := vRasterFileFormats;
- end;
- procedure RegisterRasterFormat(const AExtension, ADescription: string;
- AClass: TgxBaseImageClass);
- begin
- RegisterClass(AClass);
- GetRasterFileFormats.Add(AExtension, ADescription, 0, AClass);
- end;
- procedure UnregisterRasterFormat(AClass: TgxBaseImageClass);
- begin
- if Assigned(vRasterFileFormats) then
- vRasterFileFormats.Remove(AClass);
- end;
- function RasterFileFormatExtensionByIndex(index: Integer): string;
- begin
- Result := GetRasterFileFormats.FindExtByIndex(index);
- end;
- destructor TRasterFileFormatsList.Destroy;
- begin
- Clean;
- inherited;
- end;
- procedure TRasterFileFormatsList.Add(const Ext, Desc: string; DescID: Integer;
- AClass: TgxBaseImageClass);
- var
- newRec: TRasterFileFormat;
- begin
- newRec := TRasterFileFormat.Create;
- with newRec do
- begin
- Extension := AnsiLowerCase(Ext);
- BaseImageClass := AClass;
- Description := Desc;
- DescResID := DescID;
- end;
- inherited Add(newRec);
- end;
- function TRasterFileFormatsList.FindExt(ext: string): TgxBaseImageClass;
- var
- i: Integer;
- begin
- ext := AnsiLowerCase(ext);
- for i := Count - 1 downto 0 do
- with TRasterFileFormat(Items[I]) do
- begin
- if Extension = ext then
- begin
- Result := BaseImageClass;
- Exit;
- end;
- end;
- Result := nil;
- end;
- function TRasterFileFormatsList.FindFromFileName(const fileName: string): TgxBaseImageClass;
- var
- Ext: string;
- begin
- Ext := ExtractFileExt(FileName);
- System.Delete(Ext, 1, 1);
- Result := FindExt(Ext);
- if not Assigned(Result) then
- raise EInvalidRasterFile.CreateFmt(strUnknownExtension,
- [Ext, 'GLFile' + UpperCase(Ext)]);
- end;
- function TRasterFileFormatsList.FindFromStream(const AStream: TStream): TgxBaseImageClass;
- var
- Ext: string;
- magic: array [0 .. 1] of LongWord;
- begin
- magic[0] := 0;
- magic[1] := 1;
- AStream.ReadBuffer(magic, 2 * SizeOf(LongWord));
- AStream.Seek(-2 * SizeOf(LongWord), 1);
- if magic[0] = $20534444 then
- Ext := 'DDS'
- else if magic[1] = $4354334F then
- Ext := 'O3TC'
- else if (magic[0] and $0000FFFF) = $00003F23 then
- Ext := 'HDR'
- else if (magic[0] = $474E5089) and (magic[1] = $0A1A0A0D) then
- Ext := 'PNG'
- else if (magic[0] = $E0FFD8FF) and (magic[1] = $464A1000) then
- Ext := 'JPG';
- Result := FindExt(Ext);
- if not Assigned(Result) then
- raise EInvalidRasterFile.CreateFmt(strUnknownExtension,
- [Ext, 'GLFile' + UpperCase(Ext)]);
- end;
- procedure TRasterFileFormatsList.Remove(AClass: TgxBaseImageClass);
- var
- i: Integer;
- begin
- for i := Count - 1 downto 0 do
- begin
- if TRasterFileFormat(Items[i]).BaseImageClass.InheritsFrom(AClass) then
- DeleteAndFree(i);
- end;
- end;
- procedure TRasterFileFormatsList.BuildFilterStrings(
- imageFileClass: TgxBaseImageClass;
- var descriptions, filters: string;
- formatsThatCanBeOpened: Boolean = True;
- formatsThatCanBeSaved: Boolean = False);
- var
- k, i: Integer;
- p: TRasterFileFormat;
- begin
- descriptions := '';
- filters := '';
- k := 0;
- for i := 0 to Count - 1 do
- begin
- p := TRasterFileFormat(Items[i]);
- if p.BaseImageClass.InheritsFrom(imageFileClass) and (p.Extension <> '')
- and ((formatsThatCanBeOpened and (dfcRead in
- p.BaseImageClass.Capabilities))
- or (formatsThatCanBeSaved and (dfcWrite in p.BaseImageClass.Capabilities))) then
- begin
- with p do
- begin
- if k <> 0 then
- begin
- descriptions := descriptions + '|';
- filters := filters + ';';
- end;
- if (Description = '') and (DescResID <> 0) then
- Description := LoadStr(DescResID);
- FmtStr(descriptions, '%s%s (*.%s)|*.%2:s', [descriptions, Description,
- Extension]);
- filters := filters + '*.' + Extension;
- Inc(k);
- end;
- end;
- end;
- if (k > 1) and (not formatsThatCanBeSaved) then
- FmtStr(descriptions, '%s (%s)|%1:s|%s',
- [sAllFilter, filters, descriptions]);
- end;
- function TRasterFileFormatsList.FindExtByIndex(index: Integer;
- formatsThatCanBeOpened: Boolean = True;
- formatsThatCanBeSaved: Boolean = False): string;
- var
- i: Integer;
- p: TRasterFileFormat;
- begin
- Result := '';
- if index > 0 then
- begin
- for i := 0 to Count - 1 do
- begin
- p := TRasterFileFormat(Items[i]);
- if (formatsThatCanBeOpened and (dfcRead in p.BaseImageClass.Capabilities))
- or (formatsThatCanBeSaved and (dfcWrite in
- p.BaseImageClass.Capabilities)) then
- begin
- if index = 1 then
- begin
- Result := p.Extension;
- Break;
- end
- else
- Dec(index);
- end;
- end;
- end;
- end;
- procedure Div2(var Value: Integer);
- begin
- Value := Value div 2;
- if Value = 0 then
- Inc(Value);
- end;
- function GetImageLodNumber(w, h, d: integer; IsVolume: Boolean): Integer;
- var
- L: Integer;
- begin
- L := 1;
- d := MaxInteger(d, 1);
- while ((w > 1) or (h > 1) or (d > 1)) do
- begin
- Div2(w);
- Div2(h);
- if IsVolume then
- Div2(d);
- Inc(L);
- end;
- Result := L;
- end;
- procedure CalcImagePiramid(var APiramid: TgxImagePiramid);
- begin
- end;
- procedure GammaCorrectRGBArray(base: Pointer; pixelCount: Integer;
- gamma: Single);
- var
- vGammaLUT: array[0..255] of Byte;
- invGamma: Single;
- i: Integer;
- ptr: PByte;
- begin
- if pixelCount < 1 then
- Exit;
- Assert(gamma > 0);
- // build LUT
- if gamma < 0.1 then
- invGamma := 10
- else
- invGamma := 1 / gamma;
- for i := 0 to 255 do
- vGammaLUT[i] := Round(255 * Power(i * (1 / 255), InvGamma));
- // perform correction
- ptr := base;
- for i := 0 to pixelCount * 3 - 1 do
- begin
- ptr^ := vGammaLUT[ptr^];
- Inc(ptr);
- end;
- end;
- procedure GammaCorrectRGBAArray(base: Pointer; pixelCount: Integer;
- gamma: Single);
- var
- vGammaLUT: array[0..255] of Byte;
- pLUT: PByteArray;
- invGamma: Single;
- i: Integer;
- ptr: PByte;
- begin
- if pixelCount < 1 then
- Exit;
- Assert(gamma > 0);
- // build LUT
- if gamma < 0.1 then
- invGamma := 10
- else
- invGamma := 1 / gamma;
- for i := 0 to 255 do
- vGammaLUT[i] := Round(255 * Power(i * (1 / 255), InvGamma));
- // perform correction
- ptr := base;
- pLUT := @vGammaLUT[0];
- for i := 0 to pixelCount - 1 do
- begin
- ptr^ := pLUT^[ptr^];
- Inc(ptr);
- ptr^ := pLUT^[ptr^];
- Inc(ptr);
- ptr^ := pLUT^[ptr^];
- Inc(ptr, 2);
- end;
- end;
- procedure BrightenRGBArray(base: Pointer; pixelCount: Integer; factor: Single);
- var
- vBrightnessLUT: array[0..255] of Byte;
- i, k: Integer;
- ptr: PByte;
- begin
- if pixelCount < 1 then
- Exit;
- Assert(factor >= 0);
- // build LUT
- for i := 0 to 255 do
- begin
- k := Round(factor * i);
- if k > 255 then
- k := 255;
- vBrightnessLUT[i] := Byte(k);
- end;
- // perform correction
- ptr := base;
- for i := 0 to pixelCount * 3 - 1 do
- begin
- ptr^ := vBrightnessLUT[ptr^];
- Inc(ptr);
- end;
- end;
- procedure BrightenRGBAArray(base: Pointer; pixelCount: Integer; factor: Single);
- var
- vBrightnessLUT: array[0..255] of Byte;
- pLUT: PByteArray;
- i: Integer;
- ptr: PByte;
- k: Integer;
- begin
- if pixelCount < 1 then
- Exit;
- Assert(factor >= 0);
- // build LUT
- for i := 0 to 255 do
- begin
- k := Round(factor * i);
- if k > 255 then
- k := 255;
- vBrightnessLUT[i] := k;
- end;
- // perform correction
- ptr := base;
- pLUT := @vBrightnessLUT[0];
- for i := 0 to pixelCount - 1 do
- begin
- ptr^ := pLUT^[ptr^];
- Inc(ptr);
- ptr^ := pLUT^[ptr^];
- Inc(ptr);
- ptr^ := pLUT^[ptr^];
- Inc(ptr, 2);
- end;
- end;
- procedure BGR24ToRGB24(src, dest: Pointer; pixelCount: Integer); register;
- begin
- while pixelCount > 0 do
- begin
- PAnsiChar(dest)[0] := PAnsiChar(src)[2];
- PAnsiChar(dest)[1] := PAnsiChar(src)[1];
- PAnsiChar(dest)[2] := PAnsiChar(src)[0];
- Inc(PAnsiChar(dest), 3);
- Inc(PAnsiChar(src), 3);
- Dec(pixelCount);
- end;
- end;
- procedure BGR24ToRGBA32(src, dest: Pointer; pixelCount: Integer);
- begin
- while pixelCount > 0 do
- begin
- PAnsiChar(dest)[0] := PAnsiChar(src)[2];
- PAnsiChar(dest)[1] := PAnsiChar(src)[1];
- PAnsiChar(dest)[2] := PAnsiChar(src)[0];
- PAnsiChar(dest)[3] := #255;
- Inc(PAnsiChar(dest), 4);
- Inc(PAnsiChar(src), 3);
- Dec(pixelCount);
- end;
- end;
- procedure RGB24ToRGBA32(src, dest: Pointer; pixelCount: Integer);
- begin
- while pixelCount > 0 do
- begin
- PAnsiChar(dest)[0] := PAnsiChar(src)[0];
- PAnsiChar(dest)[1] := PAnsiChar(src)[1];
- PAnsiChar(dest)[2] := PAnsiChar(src)[2];
- PAnsiChar(dest)[3] := #255;
- Inc(PAnsiChar(dest), 4);
- Inc(PAnsiChar(src), 3);
- Dec(pixelCount);
- end;
- end;
- procedure BGRA32ToRGBA32(src, dest: Pointer; pixelCount: Integer);
- begin
- while pixelCount > 0 do
- begin
- PAnsiChar(dest)[0] := PAnsiChar(src)[2];
- PAnsiChar(dest)[1] := PAnsiChar(src)[1];
- PAnsiChar(dest)[2] := PAnsiChar(src)[0];
- PAnsiChar(dest)[3] := PAnsiChar(src)[3];
- Inc(PAnsiChar(dest), 4);
- Inc(PAnsiChar(src), 4);
- Dec(pixelCount);
- end;
- end;
- // ------------------
- // ------------------ TgxBaseImage ------------------
- // ------------------
- constructor TgxBaseImage.Create;
- begin
- inherited Create(Self);
- FillChar(FLOD, SizeOf(TgxImagePiramid), $00);
- fLevelCount := 1; // first level always is present
- fColorFormat := GL_RGBA;
- fInternalFormat := tfRGBA8;
- fDataType := GL_UNSIGNED_BYTE;
- fElementSize := 4;
- fCubeMap := false;
- fTextureArray := false;
- end;
- destructor TgxBaseImage.Destroy;
- var
- level: TgxImageLODRange;
- begin
- if Assigned(fData) then
- begin
- FreeMem(fData);
- fData := nil;
- end;
- FreeAndNil(FFinishEvent);
- for level := 0 to High(TgxImageLODRange) do
- begin
- FLOD[level].PBO.Free;
- end;
- FSourceStream.Free;
- inherited Destroy;
- end;
- procedure TgxBaseImage.Assign(Source: TPersistent);
- var
- img: TgxBaseImage;
- size: integer;
- begin
- if Source is TgxBaseImage then
- begin
- img := Source as TgxBaseImage;
- FLOD := img.FLOD;
- fLevelCount := img.fLevelCount;
- fColorFormat := img.fColorFormat;
- fInternalFormat := img.fInternalFormat;
- fDataType := img.fDataType;
- fElementSize := img.fElementSize;
- fCubeMap := img.fCubeMap;
- fTextureArray := img.fTextureArray;
- size := img.DataSize;
- ReallocMem(FData, size);
- Move(img.fData^, fData^, size);
- end
- else if Source <> nil then
- inherited; // raise AssingError
- end;
- function TgxBaseImage.GetTextureTarget: TGLTextureTarget;
- begin
- Result := ttTexture2D;
- // Choose a texture target
- if GetHeight = 1 then
- Result := ttTexture1D;
- if FCubeMap then
- Result := ttTextureCube;
- if IsVolume then
- Result := ttTexture3D;
- if FTextureArray then
- begin
- if (GetDepth < 2) then
- Result := ttTexture1Darray
- else
- Result := ttTexture2DArray;
- if FCubeMap then
- Result := ttTextureCubeArray;
- end;
- if ((FInternalFormat >= tfFLOAT_R16)
- and (FInternalFormat <= tfFLOAT_RGBA32)) then
- Result := ttTextureRect;
- end;
- function TgxBaseImage.DataSize: Cardinal;
- var
- l: TgxImageLODRange;
- s: Cardinal;
- begin
- s := 0;
- if not IsEmpty then
- begin
- UpdateLevelsInfo;
- for l := 0 to FLevelCount - 1 do
- s := s + FLOD[l].Size;
- end;
- Result := s;
- end;
- function TgxBaseImage.GetWidth: Integer;
- begin
- Result := FLOD[0].Width;
- end;
- function TgxBaseImage.GetDepth: Integer;
- begin
- Result := FLOD[0].Depth;
- end;
- function TgxBaseImage.GetHeight: Integer;
- begin
- Result := FLOD[0].Height;
- end;
- function TgxBaseImage.GetLevelAddress(ALevel: Byte): Pointer;
- begin
- Result := FData;
- Inc(PByte(Result), FLOD[ALevel].Offset);
- end;
- function TgxBaseImage.GetLevelAddress(ALevel, AFace: Byte): Pointer;
- begin
- Result := FData;
- Inc(PByte(Result), FLOD[ALevel].Offset);
- Inc(PByte(Result), AFace*(FLOD[ALevel].Size div 6));
- end;
- function TgxBaseImage.GetLevelDepth(ALOD: TgxImageLODRange): Integer;
- begin
- Result := FLOD[ALOD].Depth;
- end;
- function TgxBaseImage.GetLevelHeight(ALOD: TgxImageLODRange): Integer;
- begin
- Result := FLOD[ALOD].Height;
- end;
- function TgxBaseImage.GetLevelOffset(ALOD: TgxImageLODRange): Integer;
- begin
- Result := FLOD[ALOD].Offset;
- end;
- function TgxBaseImage.GetLevelPBO(ALOD: TgxImageLODRange): TgxUnpackPBOHandle;
- begin
- Result := FLOD[ALOD].PBO;
- end;
- function TgxBaseImage.GetLevelSizeInByte(ALOD: TgxImageLODRange): Integer;
- begin
- Result := FLOD[ALOD].Size;
- end;
- function TgxBaseImage.GetLevelStreamingState(ALOD: TgxImageLODRange): TgxLODStreamingState;
- begin
- Result := FLOD[ALOD].State;
- end;
- function TgxBaseImage.GetLevelWidth(ALOD: TgxImageLODRange): Integer;
- begin
- Result := FLOD[ALOD].Width;
- end;
- function TgxBaseImage.IsEmpty: Boolean;
- begin
- Result := (GetWidth = 0) or (GetHeight = 0);
- end;
- function TgxBaseImage.IsCompressed: Boolean;
- begin
- Result := IsCompressedFormat(fInternalFormat);
- end;
- function TgxBaseImage.IsVolume: boolean;
- begin
- Result := (GetDepth > 0) and not fTextureArray and not fCubeMap;
- end;
- function TgxBaseImage.ConvertCrossToCubemap: Boolean;
- var
- fW, fH, cubeSize, realCubeSize, e: integer;
- lData: PByteArray;
- ptr: PGLubyte;
- i, j: integer;
- bGenMipmap: Boolean;
- begin
- Result := False;
- // Can't already be a cubemap
- if fCubeMap or fTextureArray then
- Exit;
- //this function only supports vertical cross format for now (3 wide by 4 high)
- if (GetWidth div 3 <> GetHeight div 4)
- or (GetWidth mod 3 <> 0)
- or (GetHeight mod 4 <> 0)
- or (GetDepth > 0) then
- Exit;
- bGenMipmap := FLevelCount > 1;
- UnMipmap;
- // Get the source data
- lData := PByteArray(fData);
- if IsCompressed then
- begin
- fW := (GetWidth + 3) div 4;
- fH := (GetHeight + 3) div 4;
- realCubeSize := (fH div 4) * 4;
- end
- else
- begin
- fW := GetWidth;
- fH := GetHeight;
- realCubeSize := fH div 4;
- end;
- cubeSize := fH;
- GetMem(fData, fW * fH * fElementSize);
- FLOD[0].Width := realCubeSize;
- FLOD[0].Height := realCubeSize;
- FLOD[0].Depth := 6;
- // Extract the faces
- ptr := PGLubyte(fData);
- // positive X
- for j := 0 to cubeSize - 1 do
- begin
- e := ((fH - (cubeSize + j + 1)) * fW + 2 * cubeSize) * fElementSize;
- Move(lData[E], ptr^, cubeSize * fElementSize);
- Inc(ptr, cubeSize * fElementSize);
- end;
- // negative X
- for j := 0 to cubeSize - 1 do
- begin
- Move(lData[(fH - (cubeSize + j + 1)) * fW * fElementSize],
- ptr^, cubeSize * fElementSize);
- Inc(ptr, cubeSize * fElementSize);
- end;
- // positive Y
- for j := 0 to cubeSize - 1 do
- begin
- e := ((4 * cubeSize - j - 1) * fW + cubeSize) * fElementSize;
- Move(lData[e], ptr^, cubeSize * fElementSize);
- Inc(ptr, cubeSize * fElementSize);
- end;
- // negative Y
- for j := 0 to cubeSize - 1 do
- begin
- e := ((2 * cubeSize - j - 1) * fW + cubeSize) * fElementSize;
- Move(lData[e], ptr^, cubeSize * fElementSize);
- Inc(ptr, cubeSize * fElementSize);
- end;
- // positive Z
- for j := 0 to cubeSize - 1 do
- begin
- e := ((fH - (cubeSize + j + 1)) * fW + cubeSize) * fElementSize;
- Move(lData[e], ptr^, cubeSize * fElementSize);
- Inc(ptr, cubeSize * fElementSize);
- end;
- // negative Z
- for j := 0 to cubeSize - 1 do
- for i := 0 to cubeSize - 1 do
- begin
- e := (j * fW + 2 * cubeSize - (i + 1)) * fElementSize;
- Move(lData[e], ptr^, fElementSize);
- Inc(ptr, fElementSize);
- end;
- // Set the new # of faces, width and height
- fCubeMap := true;
- FreeMem(lData);
- if bGenMipmap then
- GenerateMipmap(ImageTriangleFilter);
- Result := true;
- end;
- function TgxBaseImage.ConvertToVolume(const col, row: Integer; const MakeArray:
- Boolean): Boolean;
- var
- fW, fH, sW, sH, sD: Integer;
- lData: PByteArray;
- ptr: PGLubyte;
- i, j, k: Integer;
- begin
- Result := false;
- if fCubeMap then
- Exit;
- if (GetDepth > 0) and not fTextureArray and MakeArray then
- begin
- // Let volume be array
- fTextureArray := true;
- Result := true;
- exit;
- end;
- if fTextureArray and not MakeArray then
- begin
- // Let array be volume
- fTextureArray := false;
- Result := true;
- exit;
- end;
- Result := MakeArray;
- // Check sizes
- sD := col * row;
- if sD < 1 then
- Exit;
- if IsCompressed then
- begin
- fW := (GetWidth + 3) div 4;
- fH := (GetHeight + 3) div 4;
- end
- else
- begin
- fW := GetWidth;
- fH := GetHeight;
- end;
- sW := fW div col;
- sH := fH div row;
- if (sW = 0) or (sH = 0) then
- begin
- Result := False;
- Exit;
- end;
- // Mipmaps are not supported
- UnMipmap;
- // Get the source data
- lData := PByteArray(fData);
- GetMem(fData, sW * sH * sD * fElementSize);
- ptr := PGLubyte(fData);
- for i := 0 to row - 1 do
- for j := 0 to col - 1 do
- for k := 0 to sH - 1 do
- begin
- Move(lData[(i * fW * sH + j * sW + k * fW) * fElementSize],
- ptr^, sW * fElementSize);
- Inc(ptr, sW * fElementSize);
- end;
- if IsCompressed then
- begin
- FLOD[0].Width := sW * 4;
- FLOD[0].Height := sH * 4;
- end
- else
- begin
- FLOD[0].Width := sW;
- FLOD[0].Height := sH;
- end;
- FLOD[0].Depth := sD;
- fTextureArray := Result;
- FreeMem(lData);
- Result := True;
- end;
- procedure TgxBaseImage.SetErrorImage;
- const
- cTextureError: array[0..12287] of Byte = (
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$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,$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,
- $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,
- $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,
- $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,
- $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,
- $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,
- $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,
- $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,
- $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,
- $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,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$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,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$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,$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,
- $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,
- $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,
- $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,
- $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,
- $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,
- $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,
- $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,
- $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,
- $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,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
- $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
- );
- begin
- UnMipmap;
- FLOD[0].Width := 64;
- FLOD[0].Height := 64;
- FLOD[0].Depth := 0;
- fColorFormat := GL_RGBA;
- fInternalFormat := tfRGB8;
- fDataType := GL_UNSIGNED_BYTE;
- fElementSize := 4;
- fCubeMap := false;
- fTextureArray := false;
- FColorFormat := GL_RGB;
- ReallocMem(FData, DataSize);
- Move(cTextureError[0], FData[0], DataSize);
- end;
- procedure TgxBaseImage.SetLevelStreamingState(ALOD: TgxImageLODRange;
- AState: TgxLODStreamingState);
- begin
- FLOD[ALOD].State := AState;
- end;
- procedure TgxBaseImage.Narrow;
- var
- size: Integer;
- newData: Pointer;
- begin
- // Check for already norrow
- if (fColorFormat = GL_RGBA)
- and (GetDepth = 0)
- and (fDataType = GL_UNSIGNED_BYTE)
- and (FLevelCount = 1)
- and not (fTextureArray or fCubeMap) then
- Exit;
- UnMipmap;
- // Use image utils
- size := GetWidth * GetHeight * 4;
- GetMem(newData, size);
- try
- ConvertImage(
- fData, newData,
- fColorFormat, GL_RGBA,
- fDataType, GL_UNSIGNED_BYTE,
- GetWidth, GetHeight);
- except
- ShowMessage(Format(strCantConvertImg, [ClassName]));
- SetErrorImage;
- FreeMem(newData);
- exit;
- end;
- fInternalFormat := tfRGBA8;
- fColorFormat := GL_RGBA;
- fDataType := GL_UNSIGNED_BYTE;
- fElementSize := 4;
- fTextureArray := False;
- fCubeMap := False;
- FreeMem(fData);
- fData := newData;
- end;
- procedure TgxBaseImage.GenerateMipmap(AFilter: TImageFilterFunction);
- var
- LAddresses: TPointerArray;
- level, slice, d: Integer;
- begin
- UnMipmap;
- if IsVolume then
- begin
- fLevelCount := GetImageLodNumber(GetWidth, GetHeight, GetDepth, True);
- UpdateLevelsInfo;
- ReallocMem(FData, DataSize);
- {Message Hint 'TgxBaseImage.GenerateMipmap not yet implemented for volume images' }
- end
- else
- begin
- fLevelCount := GetImageLodNumber(GetWidth, GetHeight, GetDepth, False);
- ReallocMem(FData, DataSize);
- SetLength(LAddresses, fLevelCount-1);
- for level := 1 to fLevelCount-1 do
- LAddresses[level-1] := GetLevelAddress(level);
- d := MaxInteger(GetDepth, 1);
- for slice := 0 to d - 1 do
- begin
- Build2DMipmap(
- GetLevelAddress(0),
- LAddresses,
- fColorFormat,
- fDataType,
- AFilter,
- GetWidth,
- GetHeight);
- for level := 1 to fLevelCount-1 do
- Inc(PByte(LAddresses[level-1]), GetLevelSizeInByte(level) div d);
- end;
- end;
- end;
- procedure TgxBaseImage.UnMipmap;
- var
- level: TgxImageLODRange;
- begin
- for level := 1 to High(TgxImageLODRange) do
- begin
- FLOD[level].Width := 0;
- FLOD[level].Height := 0;
- FLOD[level].Depth := 0;
- end;
- FLevelCount := 1;
- end;
- procedure TgxBaseImage.UpdateLevelsInfo;
- var
- level: TgxImageLODRange;
- w, h, d: Integer;
- function GetSize(const level: Integer): integer;
- var
- ld, bw, bh, lsize: integer;
- begin
- if fTextureArray then
- ld := FLOD[0].Depth
- else
- ld := d;
- if ld = 0 then
- ld := 1;
- if IsCompressed then
- begin
- bw := (w + 3) div 4;
- bh := (h + 3) div 4;
- end
- else
- begin
- bw := w;
- bh := h;
- end;
- if bh = 0 then
- bh := 1;
- lsize := bw * bh * ld * fElementSize;
- if fCubeMap and not fTextureArray then
- lsize := lsize * 6;
- // Align to Double Word
- if (lsize and 3) <> 0 then
- lsize := 4 * (1 + lsize div 4);
- Result := lsize;
- end;
- begin
- w := FLOD[0].Width;
- h := FLOD[0].Height;
- d := FLOD[0].Depth;
- FLOD[0].Size := GetSize(0);
- FLOD[0].Offset := 0;
- for level := 1 to High(TgxImageLODRange) do
- begin
- Div2(w);
- Div2(h);
- if not fTextureArray then
- d := d div 2;
- FLOD[level].Width := w;
- FLOD[level].Height := h;
- FLOD[level].Depth := d;
- FLOD[level].Offset := FLOD[level - 1].Offset + FLOD[level - 1].Size;
- FLOD[level].Size := GetSize(level);
- end;
- end;
- function TgxBaseImage.GetData: PgxPixel32Array;
- begin
- Result := fData;
- end;
- procedure TgxBaseImage.RegisterAsOpenRXTexture(
- AHandle: TgxTextureHandle;
- aMipmapGen: Boolean;
- aTexFormat: NativeUInt;
- out texWidth: integer;
- out texHeight: integer;
- out texDepth: integer);
- var
- glTarget: GLEnum;
- glHandle: GLuint;
- Level: integer;
- LLevelCount, face: integer;
- bCompress, bBlank: boolean;
- w, h, d, cw, ch, maxSize: GLsizei;
- p, buffer: Pointer;
- vtcBuffer, top, bottom: PGLubyte;
- i, j, k: Integer;
- TransferMethod: 0..3;
- function blockOffset(x, y, z: Integer): Integer;
- begin
- if z >= (d and -4) then
- Result := fElementSize * (cw * ch * (d and -4) + x +
- cw * (y + ch * (z - 4 * ch)))
- else
- Result := fElementSize * (4 * (x + cw * (y + ch * floor(z / 4))) + (z and
- 3));
- if Result < 0 then
- Result := 0;
- end;
- begin
- if AHandle.Target = ttNoShape then
- exit;
- begin
- UpdateLevelsInfo;
- if Self is TgxImage then
- bBlank := TgxImage(Self).Blank
- else
- bBlank := False;
- // Check for Non-power-of-two
- if not GL_ARB_texture_non_power_of_two then
- begin
- w := RoundUpToPowerOf2(GetWidth);
- h := RoundUpToPowerOf2(GetHeight);
- d := RoundUpToPowerOf2(GetDepth);
- if GetDepth = 0 then
- d := 0;
- end
- else
- begin
- w := GetWidth;
- h := GetHeight;
- d := GetDepth;
- end;
- // Check maximum dimension
- maxSize := CurrentContext.gxStates.MaxTextureSize;
- if w > maxSize then
- w := maxSize;
- if h > maxSize then
- h := maxSize;
- texWidth := w;
- texHeight := h;
- texDepth := d;
- LLevelCount := FLevelCount;
- bCompress := IsCompressed;
- // Rescale if need and can
- buffer := nil;
- if (w <> GetWidth) or (h <> GetHeight) then
- begin
- if not ((d > 0) // not volume
- or bCompress // not compressed
- or bBlank) then // not blank
- begin
- GetMem(buffer, w * h * fElementSize);
- try
- RescaleImage(
- FData,
- buffer,
- FColorFormat,
- FDataType,
- ImageLanczos3Filter,
- GetWidth, GetHeight,
- w, h);
- LLevelCount := 1;
- except
- bBlank := true;
- end;
- end
- else
- bBlank := true;
- end;
- if Self is TgxImage then
- TgxImage(Self).FBlank := bBlank;
- glHandle := AHandle.Handle;
- glTarget := DecodeTextureTarget(AHandle.Target);
- // Hardware mipmap autogeneration
- aMipmapGen := aMipmapGen and IsTargetSupportMipmap(glTarget);
- aMipmapGen := aMipmapGen and (LLevelCount = 1);
- if aMipmapGen then
- begin
- if GL_SGIS_generate_mipmap then
- begin
- if GL_EXT_direct_state_access then
- glTexParameterf(glTarget, GL_GENERATE_MIPMAP_SGIS, GL_TRUE)
- else
- glTexParameteri(glTarget, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
- end
- else
- begin
- // Software LODs generation
- Self.GenerateMipmap(ImageTriangleFilter);
- LLevelCount := LevelCount;
- end;
- end;
- // Setup top limitation of LODs
- if GL_SGIS_texture_lod and (LLevelCount > 1) then
- if GL_EXT_direct_state_access then
- glTexParameterf(glTarget, GL_TEXTURE_MAX_LEVEL_SGIS, LLevelCount - 1)
- else
- glTexParameteri(glTarget, GL_TEXTURE_MAX_LEVEL_SGIS, LLevelCount - 1);
- // Select transfer method
- if bCompress then
- transferMethod := 1
- else
- transferMethod := 0;
- if GL_EXT_direct_state_access then
- transferMethod := transferMethod + 2;
- // if image is blank then doing only allocatation texture in videomemory
- vtcBuffer := nil;
- case AHandle.Target of
- ttTexture1D:
- for Level := 0 to LLevelCount - 1 do
- begin
- if Assigned(buffer) then
- p := buffer
- else if not bBlank then
- p := GetLevelAddress(Level)
- else
- p := nil;
- case transferMethod of
- 0: glTexImage1D(glTarget, Level, aTexFormat, w, 0, FColorFormat, FDataType, p);
- 1: glCompressedTexImage1D(glTarget, Level, aTexFormat, w, 0, GetLevelSizeInByte(Level), p);
- /// 2: glTextureImage1DEXT(glHandle, glTarget, Level, aTexFormat, w, 0, FColorFormat, FDataType, p);
- /// 3: glCompressedTexImage1DARB(glHandle, glTarget, Level, aTexFormat, w, 0, GetLevelSizeInByte(Level), p)
- end;
- Div2(w);
- end;
- ttTexture2D:
- for Level := 0 to LLevelCount - 1 do
- begin
- if Assigned(buffer) then
- p := buffer
- else if not bBlank then
- p := GetLevelAddress(Level)
- else
- p := nil;
- case transferMethod of
- 0: glTexImage2D(glTarget, Level, aTexFormat, w, h, 0, FColorFormat, FDataType, p);
- 1: glCompressedTexImage2D(glTarget, Level, aTexFormat, w, h, 0, GetLevelSizeInByte(Level), p);
- /// 2: glTextureImage2DEXT(glHandle, glTarget, Level, aTexFormat, w, h, 0, FColorFormat, FDataType, p);
- /// 3: glCompressedTextureImage2DEXT(glHandle, glTarget, Level, aTexFormat, w, h, 0, GetLevelSizeInByte(Level), p);
- end;
- Div2(w);
- Div2(h);
- end;
- ttTextureRect:
- begin
- if Assigned(buffer) then
- p := buffer
- else if not bBlank then
- p := GetLevelAddress(0)
- else
- p := nil;
- case transferMethod of
- 0: glTexImage2D(glTarget, 0, aTexFormat, w, h, 0, FColorFormat, FDataType, p);
- 1: glCompressedTexImage2D(glTarget, 0, aTexFormat, w, h, 0, GetLevelSizeInByte(0), p);
- /// 2: glTextureImage2DEXT(glHandle, glTarget, 0, aTexFormat, w, h, 0, FColorFormat, FDataType, p);
- /// 3: glCompressedTextureImage2DEXT(glHandle, glTarget, 0, aTexFormat, w, h, 0, GetLevelSizeInByte(0), p);
- end;
- end;
- ttTexture3D:
- for Level := 0 to LLevelCount - 1 do
- begin
- if Assigned(buffer) then
- p := buffer
- else if not bBlank then
- p := GetLevelAddress(Level)
- else
- p := nil;
- if GL_NV_texture_compression_vtc and bCompress then
- begin
- // Shufle blocks for Volume Texture Compression
- if Assigned(p) then
- begin
- cw := (w + 3) div 4;
- ch := (h + 3) div 4;
- if Level = 0 then
- GetMem(vtcBuffer, GetLevelSizeInByte(0));
- top := p;
- for k := 0 to d - 1 do
- for i := 0 to ch - 1 do
- for j := 0 to cw - 1 do
- begin
- bottom := vtcBuffer;
- Inc(bottom, blockOffset(j, i, k));
- Move(top^, bottom^, fElementSize);
- Inc(top, fElementSize);
- end;
- end;
- if GL_EXT_direct_state_access then
- glCompressedTexImage3D(glTarget, Level, aTexFormat, w, h, d, 0, GetLevelSizeInByte(Level), vtcBuffer)
- else
- glCompressedTexImage3D(glTarget, Level, aTexFormat, w, h, d, 0, GetLevelSizeInByte(Level), vtcBuffer);
- end
- else
- begin
- // Normal compression
- case transferMethod of
- 0: glTexImage3D(glTarget, Level, aTexFormat, w, h, d, 0, FColorFormat, FDataType, p);
- 1: glCompressedTexImage3D(glTarget, Level, aTexFormat, w, h, d, 0, GetLevelSizeInByte(Level), p);
- /// 2: glTextureImage3DEXT(glHandle, glTarget, Level, aTexFormat, w, h, d, 0, FColorFormat, FDataType, p);
- /// 3: glCompressedTextureImage3DEXT(glHandle, glTarget, Level, aTexFormat, w, h, d, 0, GetLevelSizeInByte(Level), p);
- end;
- end;
- Div2(w);
- Div2(h);
- Div2(d);
- end;
- ttTextureCube:
- for Level := 0 to LLevelCount - 1 do
- begin
- for face := GL_TEXTURE_CUBE_MAP_POSITIVE_X to
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Z do
- begin
- if Assigned(buffer) then
- p := buffer
- else if not bBlank then
- p := GetLevelAddress(Level, face - GL_TEXTURE_CUBE_MAP_POSITIVE_X)
- else
- p := nil;
- case transferMethod of
- 0: glTexImage2D(face, Level, aTexFormat, w, h, 0, FColorFormat, FDataType, p);
- 1: glCompressedTexImage2D(face, Level, aTexFormat, w, h, 0, GetLevelSizeInByte(Level) div 6, p);
- /// 2: glTextureImage2DEXT(glHandle, face, Level, aTexFormat, w, h, 0, FColorFormat, FDataType, p);
- /// 3: glCompressedTextureImage2DEXT(glHandle, face, Level, aTexFormat, w, h, 0, GetLevelSizeInByte(Level) div 6, p);
- end;
- end;
- Div2(w);
- Div2(h);
- end;
- ttTexture1DArray:
- for Level := 0 to LLevelCount - 1 do
- begin
- if Assigned(buffer) then
- p := buffer
- else if not bBlank then
- p := GetLevelAddress(Level)
- else
- p := nil;
- case transferMethod of
- 0: glTexImage2D(glTarget, Level, aTexFormat, w, h, 0, FColorFormat, FDataType, p);
- 1: glCompressedTexImage2D(glTarget, Level, aTexFormat, w, h, 0, GetLevelSizeInByte(Level), p);
- /// 2: glTextureImage2DEXT(glHandle, glTarget, Level, aTexFormat, w, h, 0, FColorFormat, FDataType, p);
- /// 3: glCompressedTextureImage2DEXT(glHandle, glTarget, Level, aTexFormat, w, h, 0, GetLevelSizeInByte(Level), p);
- end;
- Div2(w);
- end;
- ttTexture2DArray, ttTextureCubeArray:
- for Level := 0 to LLevelCount - 1 do
- begin
- if Assigned(buffer) then
- p := buffer
- else if not bBlank then
- p := GetLevelAddress(Level)
- else
- p := nil;
- case transferMethod of
- 0: glTexImage3D(glTarget, Level, aTexFormat, w, h, d, 0, FColorFormat, FDataType, p);
- 1: glCompressedTexImage3D(glTarget, Level, aTexFormat, w, h, d, 0, GetLevelSizeInByte(Level), p);
- /// 2: glTextureImage3DEXT(glHandle, glTarget, Level, aTexFormat, w, h, d, 0, FColorFormat, FDataType, p);
- /// 3: glCompressedTextureImage3DEXT(glHandle, glTarget, Level, aTexFormat, w, h, d, 0, GetLevelSizeInByte(Level), p);
- end;
- Div2(w);
- Div2(h);
- end;
- end; // of case
- if Assigned(buffer) then
- FreeMem(buffer);
- if Assigned(vtcBuffer) then
- FreeMem(vtcBuffer);
- end; // of with GL
- end;
- function TgxBaseImage.AssignFromTexture(
- AHandle: TgxTextureHandle;
- const CastToFormat: Boolean;
- const intFormat: TglInternalFormat = tfRGBA8;
- const colorFormat: NativeUInt = 0;
- const dataType: NativeUInt = 0): Boolean;
- var
- LContext: TgxContext;
- texFormat, texLod, optLod: Cardinal;
- glTarget: GLEnum;
- level, maxFace, face: Integer;
- lData: PGLubyte;
- residentFormat: TglInternalFormat;
- bCompressed: Boolean;
- vtcBuffer, top, bottom: PGLubyte;
- i, j, k: Integer;
- w, d, h, cw, ch: Integer;
- function blockOffset(x, y, z: Integer): Integer;
- begin
- if z >= (d and -4) then
- Result := fElementSize * (cw * ch * (d and -4) + x +
- cw * (y + ch * (z - 4 * ch)))
- else
- Result := fElementSize * (4 * (x + cw * (y + ch * floor(z / 4))) + (z and
- 3));
- end;
- begin
- Result := False;
- LContext := CurrentContext;
- if LContext = nil then
- begin
- LContext := AHandle.RenderingContext;
- if LContext = nil then
- exit;
- end;
- LContext.Activate;
- if AHandle.IsDataNeedUpdate then
- begin
- LContext.Deactivate;
- exit;
- end;
- glTarget := DecodeTextureTarget(AHandle.Target);
- try
- LContext.gxStates.TextureBinding[0, AHandle.Target] := AHandle.Handle;
- FLevelCount := 0;
- glGetTexParameteriv(glTarget, GL_TEXTURE_MAX_LEVEL, @texLod);
- if glTarget = GL_TEXTURE_CUBE_MAP then
- begin
- fCubeMap := true;
- maxFace := 5;
- glTarget := GL_TEXTURE_CUBE_MAP_POSITIVE_X;
- end
- else
- begin
- fCubeMap := false;
- maxFace := 0;
- end;
- fTextureArray := (glTarget = GL_TEXTURE_1D_ARRAY)
- or (glTarget = GL_TEXTURE_2D_ARRAY)
- or (glTarget = GL_TEXTURE_CUBE_MAP_ARRAY);
- repeat
- // Check level existence
- glGetTexLevelParameteriv(glTarget, FLevelCount,
- GL_TEXTURE_INTERNAL_FORMAT,
- @texFormat);
- if texFormat = 1 then
- Break;
- Inc(FLevelCount);
- if FLevelCount = 1 then
- begin
- glGetTexLevelParameteriv(glTarget, 0, GL_TEXTURE_WIDTH, @FLOD[0].Width);
- glGetTexLevelParameteriv(glTarget, 0, GL_TEXTURE_HEIGHT,@FLOD[0].Height);
- FLOD[0].Depth := 0;
- if (glTarget = GL_TEXTURE_3D)
- or (glTarget = GL_TEXTURE_2D_ARRAY)
- or (glTarget = GL_TEXTURE_CUBE_MAP_ARRAY) then
- glGetTexLevelParameteriv(glTarget, 0, GL_TEXTURE_DEPTH, @FLOD[0].Depth);
- residentFormat := OpenGLFormatToInternalFormat(texFormat);
- if CastToFormat then
- fInternalFormat := residentFormat
- else
- fInternalFormat := intFormat;
- FindCompatibleDataFormat(fInternalFormat, fColorFormat, fDataType);
- // Substitute properties if need
- if colorFormat > 0 then
- fColorFormat := colorFormat;
- if dataType > 0 then
- fDataType := dataType;
- // Get optimal number or MipMap levels
- optLod := GetImageLodNumber(GetWidth, GetHeight, GetDepth, glTarget = GL_TEXTURE_3D);
- if texLod > optLod then
- texLod := optLod;
- // Check for MipMap posibility
- if ((fInternalFormat >= tfFLOAT_R16)
- and (fInternalFormat <= tfFLOAT_RGBA32)) then
- texLod := 1;
- end;
- until FLevelCount = Integer(texLod);
- if FLevelCount > 0 then
- begin
- fElementSize := GetTextureElementSize(fColorFormat, fDataType);
- UpdateLevelsInfo;
- ReallocMem(FData, DataSize);
- lData := PGLubyte(fData);
- bCompressed := IsCompressed;
- vtcBuffer := nil;
- w := GetWidth;
- h := GetHeight;
- d := GetDepth;
- for face := 0 to maxFace do
- begin
- if fCubeMap then
- glTarget := face + GL_TEXTURE_CUBE_MAP_POSITIVE_X;
- for level := 0 to FLevelCount - 1 do
- begin
- if bCompressed then
- begin
- if {NV_texture_compression_vtc and} (d > 1) and not fTextureArray then
- begin
- if level = 0 then
- GetMem(vtcBuffer, GetLevelSizeInByte(0));
- glGetCompressedTexImage(glTarget, level, vtcBuffer);
- // Shufle blocks from VTC to S3TC
- cw := (w + 3) div 4;
- ch := (h + 3) div 4;
- top := lData;
- for k := 0 to d - 1 do
- for i := 0 to ch - 1 do
- for j := 0 to cw - 1 do
- begin
- bottom := vtcBuffer;
- Inc(bottom, blockOffset(j, i, k));
- Move(bottom^, top^, fElementSize);
- Inc(top, fElementSize);
- end;
- Div2(w);
- Div2(h);
- Div2(d);
- end
- else
- glGetCompressedTexImage(glTarget, level, lData);
- end
- else
- glGetTexImage(glTarget, level, fColorFormat, fDataType, lData);
- Inc(lData, GetLevelSizeInByte(level));
- end; // for level
- end; // for face
- if Assigned(vtcBuffer) then
- FreeMem(vtcBuffer);
- // Check memory corruption
- ReallocMem(FData, DataSize);
- end;
- if Self is TgxImage then
- begin
- TgxImage(Self).FBlank := FLevelCount = 0;
- if FLevelCount = 0 then
- begin
- UnMipmap;
- FreeMem(fData);
- fData := nil;
- end;
- end;
- glGetError;
- Result := True;
- finally
- LContext.Deactivate;
- end;
- end;
- procedure TgxBaseImage.SaveHeader;
- var
- Temp: Integer;
- LStream: TStream;
- begin
- Temp := 0;
- LStream := nil;
- try
- LStream := TFileStream.Create(ResourceName, fmOpenWrite or fmCreate);
- with LStream do
- begin
- Write(Temp, SizeOf(Integer)); // Version
- Write(FLOD[0].Width, SizeOf(Integer));
- Write(FLOD[0].Height, SizeOf(Integer));
- Write(FLOD[0].Depth, SizeOf(Integer));
- Write(fColorFormat, SizeOf(GLenum));
- Temp := Integer(fInternalFormat);
- Write(Temp, SizeOf(Integer));
- Write(fDataType, SizeOf(GLenum));
- Write(fElementSize, SizeOf(Integer));
- Write(fLevelCount, SizeOf(TgxImageLODRange));
- Temp := Integer(fCubeMap);
- Write(Temp, SizeOf(Integer));
- Temp := Integer(fTextureArray);
- Write(Temp, SizeOf(Integer));
- end;
- finally
- LStream.Free;
- end;
- end;
- procedure TgxBaseImage.LoadHeader;
- var
- Temp: Integer;
- LStream: TStream;
- begin
- LStream := nil;
- try
- LStream := TFileStream.Create(ResourceName, fmOpenRead);
- with LStream do
- begin
- Read(Temp, SizeOf(Integer)); // Version
- if Temp > 0 then
- begin
- ShowMessage(Format(strUnknownArchive, [Self.ClassType, Temp]));
- Abort;
- end;
- Read(FLOD[0].Width, SizeOf(Integer));
- Read(FLOD[0].Height, SizeOf(Integer));
- Read(FLOD[0].Depth, SizeOf(Integer));
- Read(fColorFormat, SizeOf(GLenum));
- Read(Temp, SizeOf(Integer));
- fInternalFormat := TglInternalFormat(Temp);
- Read(fDataType, SizeOf(GLenum));
- Read(fElementSize, SizeOf(Integer));
- Read(fLevelCount, SizeOf(TgxImageLODRange));
- Read(Temp, SizeOf(Integer));
- fCubeMap := Boolean(Temp);
- Read(Temp, SizeOf(Integer));
- fTextureArray := Boolean(Temp);
- UpdateLevelsInfo;
- end;
- finally
- LStream.Free;
- end;
- end;
- var
- vGlobalStreamingTaskCounter: Integer = 0;
- procedure TgxBaseImage.StartStreaming;
- var
- level: TgxImageLODRange;
- begin
- FStreamLevel := fLevelCount - 1;
- for level := 0 to High(TgxImageLODRange) do
- FLOD[level].State := ssKeeping;
- end;
- procedure TgxBaseImage.DoStreaming;
- begin
- {$IFDEF USE_SERVICE_CONTEXT}
- if Assigned(FFinishEvent) then
- begin
- if FFinishEvent.WaitFor(0) <> wrSignaled then
- exit;
- end
- else
- FFinishEvent := TFinishTaskEvent.Create;
- Inc(vGlobalStreamingTaskCounter);
- AddTaskForServiceContext(ImageStreamingTask, FFinishEvent);
- {$ENDIF}
- end;
- {$IFDEF USE_SERVICE_CONTEXT}
- procedure TgxBaseImage.ImageStreamingTask;
- var
- readSize: Integer;
- ptr: PByte;
- begin
- with FLOD[FStreamLevel] do
- begin
- if PBO = nil then
- PBO := TgxUnpackPBOHandle.Create;
- PBO.AllocateHandle;
- if PBO.IsDataNeedUpdate then
- begin
- { This may work with multiple unshared context, but never tested
- because unlikely. }
- PBO.BindBufferData(nil, MaxInteger(Size, 1024), GL_STREAM_DRAW);
- if Assigned(MapAddress) then;
- if not (glUnmapBuffer(PBO.AllocateHandle) = 1) then
- exit;
- MapAddress := PBO.MapBuffer(GL_WRITE_ONLY);
- StreamOffset := 0;
- PBO.UnBind;
- PBO.NotifyDataUpdated;
- end;
- if FSourceStream = nil then
- begin
- FSourceStream := TFileStream.Create(ResourceName + IntToHex(FStreamLevel, 2));
- end;
- // Move to position of next piece and read it
- readSize := MinInteger(Cardinal(8192 div vGlobalStreamingTaskCounter),
- Cardinal(Size - StreamOffset));
- if readSize > 0 then
- begin
- ptr := PByte(MapAddress);
- Inc(ptr, StreamOffset);
- FSourceStream.Read(ptr^, readSize);
- Inc(StreamOffset, readSize);
- end;
- Dec(vGlobalStreamingTaskCounter);
- if StreamOffset >= Size then
- begin
- PBO.Bind;
- if glUnmapBuffer(PBO.AllocateHandle) > 0 then
- State := ssLoaded;
- PBO.UnBind;
- if State <> ssLoaded then
- exit; // Can't unmap
- MapAddress := nil;
- StreamOffset := 0;
- if FStreamLevel > 0 then
- Dec(FStreamLevel);
- FSourceStream.Destroy;
- FSourceStream := nil;
- end;
- end;
- end;
- {$ENDIF}
- // ------------------
- // ------------------ TgxImage ------------------
- // ------------------
- constructor TgxImage.Create;
- begin
- inherited Create;
- SetBlank(false);
- end;
- destructor TgxImage.Destroy;
- begin
- inherited Destroy;
- end;
- procedure TgxImage.Assign(Source: TPersistent);
- var
- bmp: TBitmap;
- graphic: TBitmap;
- begin
- if (Source is TgxImage) or (Source is TgxBaseImage) then
- begin
- if Source is TgxImage then
- FBlank := TgxImage(Source).fBlank
- else
- FBlank := false;
- if not FBlank then
- inherited
- else
- begin
- FLOD := TgxImage(Source).FLOD;
- FLevelCount := TgxImage(Source).FLevelCount;
- fCubeMap := TgxImage(Source).fCubeMap;
- fColorFormat := TgxImage(Source).fColorFormat;
- fInternalFormat := TgxImage(Source).fInternalFormat;
- fDataType := TgxImage(Source).fDataType;
- fElementSize := TgxImage(Source).fElementSize;
- fTextureArray := TgxImage(Source).fTextureArray;
- end;
- end
- else if Source is TBitmap then
- begin
- if (Source is TBitmap)
- and (TBitmap(Source).PixelFormat in [TPixelFormat.RGBA16, TPixelFormat.RGBA32F])
- and (((TBitmap(Source).Width and 3) = 0) or (GL_EXT_bgra)) then
- begin
- if TBitmap(Source).PixelFormat = TPixelFormat.RGBA32F then
- AssignFrom24BitsBitmap(TBitmap(Source))
- else
- AssignFrom32BitsBitmap(TBitmap(Source))
- end
- {$IFDEF USE_PngImage_SUPPORT}
- else if Source is TPngImage then
- AssignFromPngImage(TPngImage(Source))
- {$ENDIF}
- else
- begin
- graphic := TBitmap(Source);
- bmp := TBitmap.Create;
- try
- // crossbuilder: useless to set pixelformat before setting the size ?
- // or maybe just useless at all on gtk .. as soon as
- // bmp.canvas is touched, it's the pixelformat of the device
- // no matter what was adjusted before ??
- // bmp.PixelFormat:=glpf24bit;
- // bmp.Height:=graphic.Height;
- // crossbuilder: using setsize because setting width or height while
- // the other one is zero results in not setting with/hight
- { TODO -oPW : E2129 Cannot assign to a read-only property }
- (*bmp.PixelFormat := glpf24bit;*)
- { TODO -oPW : E2010 Incompatible types: 'Integer' and 'Single' }
- (*bmp.Height := Graphic.Height;*)
- { TODO -oPW : E2015 Operator not applicable to this operand type }
- (*
- if (graphic.Width and 3) = 0 then
- begin
- bmp.Width := graphic.Width;
- bmp.Canvas.Draw(0, 0, graphic);
- end
- else
- begin
- bmp.Width := (graphic.Width and $FFFC) + 4;
- bmp.Canvas.StretchDraw(Rect(0, 0, bmp.Width, bmp.Height), graphic);
- end;
- *)
- AssignFrom24BitsBitmap(bmp);
- finally
- bmp.Free;
- end;
- end;
- end
- {$IFDEF USE_GRAPHICS32}
- else if Source is TBitmap32 then
- begin
- Narrow;
- AssignFromBitmap32(TBitmap32(Source));
- end
- {$ENDIF}
- else
- inherited;
- end;
- procedure TgxImage.AssignFrom24BitsBitmap(aBitmap: TBitmap);
- var
- y, lineSize: Integer;
- rowOffset: Int64;
- pSrc, pDest: PAnsiChar;
- begin
- Assert(aBitmap.PixelFormat = TPixelFormat.RGBA32F);
- UnMipmap;
- FLOD[0].Width := aBitmap.Width;
- FLOD[0].Height := aBitmap.Height;
- FLOD[0].Depth := 0;
- if (GL_EXT_bgra) then
- begin
- fColorFormat := GL_BGR;
- fElementSize := 3;
- end
- else
- begin
- Assert((aBitmap.Width and 3) = 0);
- fColorFormat := GL_RGBA;
- fElementSize := 4;
- end;
- fInternalFormat := tfRGBA8;
- fDataType := GL_UNSIGNED_BYTE;
- fCubeMap := false;
- fTextureArray := false;
- ReallocMem(FData, DataSize);
- FBlank := false;
- lineSize := GetWidth * fElementSize;
- if Height > 0 then
- begin
- pDest := @PAnsiChar(FData)[GetWidth * fElementSize * (GetHeight - 1)];
- if Height = 1 then
- begin
- if true {GL_EXT_bgra} then
- begin
- pSrc := BitmapScanLine(aBitmap, 0);
- Move(pSrc^, pDest^, lineSize);
- end
- else
- BGR24ToRGBA32(BitmapScanLine(aBitmap, 0), pDest, GetWidth);
- end
- else
- begin
- if VerticalReverseOnAssignFromBitmap then
- begin
- pSrc := BitmapScanLine(aBitmap, GetHeight - 1);
- rowOffset := Integer(BitmapScanLine(aBitmap, GetHeight - 2)) -
- Integer(pSrc);
- end
- else
- begin
- pSrc := BitmapScanLine(aBitmap, 0);
- rowOffset := Int64(BitmapScanLine(aBitmap, 1)) - Int64(pSrc);
- end;
- if true {GL_EXT_bgra} then
- begin
- for y := 0 to Height - 1 do
- begin
- Move(pSrc^, pDest^, lineSize);
- Dec(pDest, lineSize);
- Inc(pSrc, rowOffset);
- end;
- end
- else
- begin
- for y := 0 to Height - 1 do
- begin
- BGR24ToRGBA32(pSrc, pDest, Width);
- Dec(pDest, lineSize);
- Inc(pSrc, rowOffset);
- end;
- end;
- end;
- end;
- end;
- procedure TgxImage.AssignFromBitmap24WithoutRGBSwap(aBitmap: TBitmap);
- var
- y: Integer;
- rowOffset: Int64;
- pSrc, pDest: PAnsiChar;
- begin
- Assert(aBitmap.PixelFormat = TPixelFormat.RGBA32F);
- Assert((aBitmap.Width and 3) = 0);
- UnMipmap;
- FLOD[0].Width := aBitmap.Width;
- FLOD[0].Height := aBitmap.Height;
- FLOD[0].Depth := 0;
- fColorFormat := GL_RGBA;
- fInternalFormat := tfRGBA8;
- fDataType := GL_UNSIGNED_BYTE;
- fElementSize := 4;
- fCubeMap := false;
- fTextureArray := false;
- ReallocMem(FData, DataSize);
- FBlank := false;
- if Height > 0 then
- begin
- pDest := @PAnsiChar(FData)[Width * 4 * (Height - 1)];
- if Height = 1 then
- begin
- RGB24ToRGBA32(BitmapScanLine(aBitmap, 0), pDest, GetWidth);
- end
- else
- begin
- if VerticalReverseOnAssignFromBitmap then
- begin
- pSrc := BitmapScanLine(aBitmap, GetHeight - 1);
- rowOffset := Cardinal(BitmapScanLine(aBitmap, GetHeight - 2));
- Dec(rowOffset, Cardinal(pSrc));
- end
- else
- begin
- pSrc := BitmapScanLine(aBitmap, 0);
- rowOffset := Cardinal(BitmapScanLine(aBitmap, 1));
- Dec(rowOffset, Cardinal(pSrc));
- end;
- for y := 0 to Height - 1 do
- begin
- RGB24ToRGBA32(pSrc, pDest, GetWidth);
- Dec(pDest, GetWidth * 4);
- Inc(pSrc, rowOffset);
- end;
- end;
- end;
- end;
- procedure TgxImage.AssignFrom32BitsBitmap(aBitmap: TBitmap);
- var
- y: Integer;
- rowOffset: Int64;
- pSrc, pDest: PAnsiChar;
- begin
- Assert(aBitmap.PixelFormat = TPixelFormat.RGBA32F);
- UnMipmap;
- FLOD[0].Width := aBitmap.Width;
- FLOD[0].Height := aBitmap.Height;
- FLOD[0].Depth := 0;
- if true {GL_EXT_bgra} then
- fColorFormat := GL_BGRA
- else
- begin
- Assert((aBitmap.Width and 3) = 0);
- fColorFormat := GL_RGBA;
- end;
- fInternalFormat := tfRGBA8;
- fDataType := GL_UNSIGNED_BYTE;
- fElementSize := 4;
- fCubeMap := false;
- fTextureArray := false;
- ReallocMem(FData, DataSize);
- FBlank := false;
- if Height > 0 then
- begin
- pDest := @PAnsiChar(FData)[Width * 4 * (Height - 1)];
- if VerticalReverseOnAssignFromBitmap then
- begin
- pSrc := BitmapScanLine(aBitmap, Height - 1);
- if Height > 1 then
- begin
- rowOffset := Cardinal(BitmapScanLine(aBitmap, Height - 2));
- Dec(rowOffset, Cardinal(pSrc));
- end
- else
- rowOffset := 0;
- end
- else
- begin
- pSrc := BitmapScanLine(aBitmap, 0);
- if Height > 1 then
- begin
- rowOffset := Cardinal(BitmapScanLine(aBitmap, 1));
- Dec(rowOffset, Cardinal(pSrc));
- end
- else
- rowOffset := 0;
- end;
- if GL_EXT_bgra then
- begin
- for y := 0 to Height - 1 do
- begin
- Move(pSrc^, pDest^, Width * 4);
- Dec(pDest, Width * 4);
- Inc(pSrc, rowOffset);
- end;
- end
- else
- begin
- for y := 0 to Height - 1 do
- begin
- BGRA32ToRGBA32(pSrc, pDest, Width);
- Dec(pDest, Width * 4);
- Inc(pSrc, rowOffset);
- end;
- end;
- end;
- end;
- {$IFDEF USE_GRAPHICS32}
- procedure TgxImage.AssignFromBitmap32(aBitmap32: TBitmap32);
- var
- y: Integer;
- pSrc, pDest: PAnsiChar;
- begin
- UnMipmap;
- FLOD[0].Width := aBitmap32.Width;
- FLOD[0].Height := aBitmap32.Height;
- FLOD[0].Depth := 0;
- fColorFormat := GL_RGBA;
- fInternalFormat := tfRGBA8;
- fDataType := GL_UNSIGNED_BYTE;
- fElementSize := 4;
- fCubeMap := false;
- fTextureArray := false;
- ReallocMem(FData, DataSize);
- FBlank := false;
- if Height > 0 then
- begin
- pDest := @PAnsiChar(FData)[Width * 4 * (Height - 1)];
- for y := 0 to Height - 1 do
- begin
- if VerticalReverseOnAssignFromBitmap then
- pSrc := PAnsiChar(aBitmap32.ScanLine[Height - 1 - y])
- else
- pSrc := PAnsiChar(aBitmap32.ScanLine[y]);
- BGRA32ToRGBA32(pSrc, pDest, Width);
- Dec(pDest, Width * 4);
- end;
- end;
- end;
- {$ENDIF}
- // AlphaChannel Support
- procedure TgxImage.AssignFromPngImage(aPngImage: TBitmapImage);
- var
- i, j: Integer;
- SourceScan: PRGBQuad; //VCL->PRGBLine;
- DestScan: PgxPixel32Array;
- AlphaScan: pByteArray;
- Pixel: Integer;
- begin
- (*
- if (aPngImage.Width and 3) > 0 then
- aPngImage.Resize((aPngImage.Width and $FFFC) + 4, aPngImage.Height);
- *)
- UnMipmap;
- FLOD[0].Width := aPngImage.Width;
- FLOD[0].Height := aPngImage.Height;
- FLOD[0].Depth := 0;
- fColorFormat := GL_RGBA;
- fInternalFormat := tfRGBA8;
- fDataType := GL_UNSIGNED_BYTE;
- fElementSize := 4;
- fCubeMap := false;
- fTextureArray := false;
- ReallocMem(FData, DataSize);
- FBlank := False;
- (*
- case aPngImage.Header.ColorType of
- { Direct ScanLine (24 Bits) }
- COLOR_RGB, COLOR_RGBALPHA: for j := 1 to aPngImage.Height do
- begin
- SourceScan := aPngImage.Scanline[aPngImage.Height - j];
- AlphaScan := aPngImage.AlphaScanline[aPngImage.Height - j];
- DestScan := ScanLine[Pred(j)];
- for i := 0 to Pred(aPngImage.Width) do
- begin
- DestScan^[i].r := SourceScan^[i].rgbtRed;
- DestScan^[i].g := SourceScan^[i].rgbtGreen;
- DestScan^[i].b := SourceScan^[i].rgbtBlue;
- if Assigned(AlphaScan) then
- DestScan^[i].a := AlphaScan^[i]
- else
- DestScan^[i].a := $FF;
- end;
- end;
- else
- { Internal Decode TColor - Palette }
- for j := 1 to aPngImage.Height do
- begin
- AlphaScan := aPngImage.AlphaScanline[aPngImage.Height - j];
- DestScan := ScanLine[Pred(j)];
- for i := 0 to Pred(aPngImage.Width) do
- begin
- Pixel := aPngImage.Pixels[i, aPngImage.Height - j];
- DestScan^[i].r := Pixel and $FF;
- DestScan^[i].g := (Pixel shr 8) and $FF;
- DestScan^[i].b := (Pixel shr 16) and $FF;
- if Assigned(AlphaScan) then
- DestScan^[i].a := AlphaScan^[i]
- else
- DestScan^[i].a := $FF;
- end;
- end;
- end;
- *)
- end;
- procedure TgxImage.AssignFromTexture2D(textureHandle: Cardinal);
- var
- oldTex: Cardinal;
- begin
- UnMipmap;
- with CurrentContext.gxStates do
- begin
- oldTex := TextureBinding[ActiveTexture, ttTexture2D];
- TextureBinding[ActiveTexture, ttTexture2D] := textureHandle;
- glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, @FLOD[0].Width);
- glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, @FLOD[0].Height);
- FLOD[0].Depth := 0;
- fColorFormat := GL_RGBA;
- fInternalFormat := tfRGBA8;
- fDataType := GL_UNSIGNED_BYTE;
- fElementSize := 4;
- fCubeMap := false;
- fTextureArray := false;
- ReallocMem(FData, DataSize);
- glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, FData);
- FBlank := false;
- TextureBinding[ActiveTexture, ttTexture2D] := oldTex;
- end;
- end;
- procedure TgxImage.AssignFromTexture2D(textureHandle: TgxTextureHandle);
- var
- oldContext: TgxContext;
- contextActivate: Boolean;
- begin
- if Assigned(textureHandle) and (textureHandle.Handle <> 0) then
- begin
- oldContext := CurrentContext;
- contextActivate := (oldContext <> textureHandle.RenderingContext);
- if contextActivate then
- begin
- if Assigned(oldContext) then
- oldContext.Deactivate;
- textureHandle.RenderingContext.Activate;
- end;
- try
- AssignFromTexture2D(textureHandle.Handle);
- finally
- if contextActivate then
- begin
- textureHandle.RenderingContext.Deactivate;
- if Assigned(oldContext) then
- oldContext.Activate;
- end;
- end;
- end
- else
- begin
- // Make image empty
- UnMipmap;
- FLOD[0].Width := 0;
- FLOD[0].Height := 0;
- FLOD[0].Depth := 0;
- fColorFormat := GL_RGBA;
- fInternalFormat := tfRGBA8;
- fDataType := GL_UNSIGNED_BYTE;
- fElementSize := 4;
- fCubeMap := false;
- fTextureArray := false;
- ReallocMem(FData, DataSize);
- end;
- end;
- function TgxImage.Create32BitsBitmap: TBitmap;
- var
- y, x, x4: Integer;
- pSrc, pDest: PAnsiChar;
- begin
- if FBlank then
- begin
- Result := nil;
- exit;
- end;
- Narrow;
- Result := TBitmap.Create;
- { TODO : E2129 Cannot assign to a read-only property }
- (*Result.PixelFormat := glpf32bit;*)
- Result.Width := Width;
- Result.Height := Height;
- if Height > 0 then
- begin
- pSrc := @PAnsiChar(FData)[Width * 4 * (Height - 1)];
- for y := 0 to Height - 1 do
- begin
- pDest := BitmapScanLine(Result, y);
- for x := 0 to Width - 1 do
- begin
- x4 := x * 4;
- pDest[x4 + 0] := pSrc[x4 + 2];
- pDest[x4 + 1] := pSrc[x4 + 1];
- pDest[x4 + 2] := pSrc[x4 + 0];
- pDest[x4 + 3] := pSrc[x4 + 3];
- end;
- Dec(pSrc, Width * 4);
- end;
- end;
- end;
- procedure TgxImage.SetWidth(val: Integer);
- begin
- if val <> FLOD[0].Width then
- begin
- Assert(val >= 0);
- FLOD[0].Width := val;
- FBlank := true;
- end;
- end;
- procedure TgxImage.SetHeight(const val: Integer);
- begin
- if val <> FLOD[0].Height then
- begin
- Assert(val >= 0);
- FLOD[0].Height := val;
- FBlank := true;
- end;
- end;
- procedure TgxImage.SetDepth(const val: Integer);
- begin
- if val <> FLOD[0].Depth then
- begin
- Assert(val >= 0);
- FLOD[0].Depth := val;
- FBlank := true;
- end;
- end;
- procedure TgxImage.SetCubeMap(const val: Boolean);
- begin
- if val <> fCubeMap then
- begin
- fCubeMap := val;
- FBlank := true;
- end;
- end;
- procedure TgxImage.SetArray(const val: Boolean);
- begin
- if val <> fTextureArray then
- begin
- fTextureArray := val;
- FBlank := true;
- end;
- end;
- procedure TgxImage.SetColorFormatDataType(const AColorFormat, ADataType: GLenum);
- begin
- if fBlank then
- begin
- fDataType := ADataType;
- fColorFormat := AColorFormat;
- exit;
- end;
- fOldDataType := fDataType;
- fOldColorFormat := fColorFormat;
- fDataType := ADataType;
- fColorFormat := AColorFormat;
- fElementSize := GetTextureElementSize(fColorFormat, fDataType);
- DataConvertTask;
- end;
- function TgxImage.GetScanLine(index: Integer): PgxPixel32Array;
- begin
- Narrow;
- Result := PgxPixel32Array(@FData[index * GetWidth]);
- end;
- procedure TgxImage.SetAlphaFromIntensity;
- var
- i: Integer;
- begin
- Narrow;
- for i := 0 to (DataSize div 4) - 1 do
- with FData^[i] do
- a := (Integer(r) + Integer(g) + Integer(b)) div 3;
- end;
- procedure TgxImage.SetAlphaTransparentForColor(const aColor: TColor);
- var
- color: TgxPixel24;
- begin
- color.r := GetRValue(aColor);
- color.g := GetGValue(aColor);
- color.b := GetBValue(aColor);
- SetAlphaTransparentForColor(color);
- end;
- procedure TgxImage.SetAlphaTransparentForColor(const aColor: TgxPixel32);
- var
- color: TgxPixel24;
- begin
- color.r := aColor.r;
- color.g := aColor.g;
- color.b := aColor.b;
- SetAlphaTransparentForColor(color);
- end;
- procedure TgxImage.SetAlphaTransparentForColor(const aColor: TgxPixel24);
- var
- i: Integer;
- intCol: Integer;
- begin
- Narrow;
- intCol := (PInteger(@aColor)^) and $FFFFFF;
- for i := 0 to (DataSize div 4) - 1 do
- if PInteger(@FData[i])^ and $FFFFFF = intCol then
- FData^[i].a := 0
- else
- FData^[i].a := 255;
- end;
- procedure TgxImage.SetAlphaToValue(const aValue: Byte);
- var
- i: Integer;
- begin
- Narrow;
- for i := 0 to (DataSize div 4) - 1 do
- FData^[i].a := aValue
- end;
- procedure TgxImage.SetAlphaToFloatValue(const aValue: Single);
- begin
- SetAlphaToValue(Byte(Trunc(aValue * 255) and 255));
- end;
- procedure TgxImage.InvertAlpha;
- var
- i: Integer;
- begin
- Narrow;
- for i := (DataSize div 4) - 1 downto 0 do
- FData^[i].a := 255 - FData^[i].a;
- end;
- procedure TgxImage.SqrtAlpha;
- var
- i: Integer;
- sqrt255Array: PSqrt255Array;
- begin
- Narrow;
- sqrt255Array := GetSqrt255Array;
- for i := 0 to (DataSize div 4) - 1 do
- with FData^[i] do
- a := sqrt255Array^[(Integer(r) + Integer(g) + Integer(b)) div 3];
- end;
- procedure TgxImage.BrightnessCorrection(const factor: Single);
- begin
- if Assigned(FData) then
- begin
- Narrow;
- BrightenRGBAArray(Data, DataSize div 4, factor);
- end;
- end;
- procedure TgxImage.GammaCorrection(const gamma: Single);
- begin
- if Assigned(FData) then
- begin
- Narrow;
- GammaCorrectRGBAArray(Data, DataSize div 4, gamma);
- end;
- end;
- procedure TgxImage.DownSampleByFactor2;
- type
- T2Pixel32 = packed array[0..1] of TgxPixel32;
- P2Pixel32 = ^T2Pixel32;
- procedure ProcessRowPascal(pDest: PgxPixel32; pLineA, pLineB: P2Pixel32; n:
- Integer);
- var
- i: Integer;
- begin
- for i := 0 to n - 1 do
- begin
- pDest^.r := (pLineA^[0].r + pLineA^[1].r + pLineB^[0].r + pLineB^[1].r)
- shr 2;
- pDest^.g := (pLineA^[0].g + pLineA^[1].g + pLineB^[0].g + pLineB^[1].g)
- shr 2;
- pDest^.b := (pLineA^[0].b + pLineA^[1].b + pLineB^[0].b + pLineB^[1].b)
- shr 2;
- pDest^.a := (pLineA^[0].a + pLineA^[1].a + pLineB^[0].a + pLineB^[1].a)
- shr 2;
- Inc(pLineA);
- Inc(pLineB);
- Inc(pDest);
- end;
- end; // }
- var
- y, w2, h2: Integer;
- pDest: PgxPixel32;
- pLineA, pLineB: P2Pixel32;
- begin
- if (GetWidth <= 1) or (GetHeight <= 1) then
- Exit;
- Narrow;
- w2 := GetWidth shr 1;
- h2 := GetHeight shr 1;
- pDest := @FData[0];
- pLineA := @FData[0];
- pLineB := @FData[Width];
- begin
- for y := 0 to h2 - 1 do
- begin
- ProcessRowPascal(pDest, pLineA, pLineB, w2);
- Inc(pDest, w2);
- Inc(pLineA, Width);
- Inc(pLineB, Width);
- end;
- end;
- FLOD[0].Width := w2;
- FLOD[0].Height := h2;
- ReallocMem(FData, DataSize);
- end;
- procedure TgxImage.ReadPixels(const area: TRect);
- begin
- UnMipmap;
- FLOD[0].Width := (area.Right - area.Left) and $FFFC;
- FLOD[0].Height := (area.Bottom - area.Top);
- FLOD[0].Depth := 0;
- fColorFormat := GL_RGBA;
- fInternalFormat := tfRGBA8;
- fDataType := GL_UNSIGNED_BYTE;
- fElementSize := 4;
- fCubeMap := false;
- fTextureArray := false;
- fBlank := false;
- ReallocMem(FData, DataSize);
- glReadPixels(0, 0, GetWidth, GetHeight, GL_RGBA, GL_UNSIGNED_BYTE, FData);
- end;
- procedure TgxImage.DrawPixels(const x, y: Single);
- begin
- if fBlank or IsEmpty then
- Exit;
- Assert(not CurrentContext.gxStates.ForwardContext);
- glRasterPos2f(x, y);
- glDrawPixels(Width, Height, fColorFormat, fDataType, FData);
- end;
- procedure TgxImage.GrayScaleToNormalMap(const scale: Single;
- wrapX: Boolean = True; wrapY: Boolean = True);
- var
- x, y: Integer;
- dcx, dcy: Single;
- invLen: Single;
- maskX, maskY: Integer;
- curRow, nextRow, prevRow: PgxPixel32Array;
- normalMapBuffer: PgxPixel32Array;
- p: PgxPixel32;
- begin
- if Assigned(FData) then
- begin
- Narrow;
- GetMem(normalMapBuffer, DataSize);
- try
- maskX := Width - 1;
- maskY := Height - 1;
- p := @normalMapBuffer[0];
- for y := 0 to Height - 1 do
- begin
- curRow := GetScanLine(y);
- if wrapY then
- begin
- prevRow := GetScanLine((y - 1) and maskY);
- nextRow := GetScanLine((y + 1) and maskY);
- end
- else
- begin
- if y > 0 then
- prevRow := GetScanLine(y - 1)
- else
- prevRow := curRow;
- if y < Height - 1 then
- nextRow := GetScanLine(y + 1)
- else
- nextRow := curRow;
- end;
- for x := 0 to Width - 1 do
- begin
- if wrapX then
- dcx := scale * (curRow^[(x - 1) and maskX].g - curRow^[(x + 1) and
- maskX].g)
- else
- begin
- if x = 0 then
- dcx := scale * (curRow^[x].g - curRow^[x + 1].g)
- else if x < Width - 1 then
- dcx := scale * (curRow^[x - 1].g - curRow^[x].g)
- else
- dcx := scale * (curRow^[x - 1].g - curRow^[x + 1].g);
- end;
- dcy := scale * (prevRow^[x].g - nextRow^[x].g);
- invLen := 127 * RSqrt(dcx * dcx + dcy * dcy + 1);
- with p^ do
- begin
- r := Integer(Round(128 + ClampValue(dcx * invLen, -128, 127)));
- g := Integer(Round(128 + ClampValue(dcy * invLen, -128, 127)));
- b := Integer(Round(128 + ClampValue(invLen, -128, 127)));
- a := 255;
- end;
- Inc(p);
- end;
- end;
- Move(normalMapBuffer^, FData^, DataSize);
- finally
- FreeMem(normalMapBuffer);
- end;
- end;
- end;
- procedure TgxImage.NormalizeNormalMap;
- var
- x, y: Integer;
- sr, sg, sb: Single;
- invLen: Single;
- curRow: PgxPixel32Array;
- p: PgxPixel32;
- const
- cInv128: Single = 1 / 128;
- begin
- if not IsEmpty and not Blank then
- begin
- Narrow;
- for y := 0 to Height - 1 do
- begin
- curRow := @FData[y * GetWidth];
- for x := 0 to GetWidth - 1 do
- begin
- p := @curRow[x];
- sr := (p^.r - 128) * cInv128;
- sg := (p^.g - 128) * cInv128;
- sb := (p^.b - 128) * cInv128;
- invLen := RSqrt(sr * sr + sg * sg + sb * sb);
- p^.r := Round(128 + 127 * ClampValue(sr * invLen, -1, 1));
- p^.g := Round(128 + 127 * ClampValue(sg * invLen, -1, 1));
- p^.b := Round(128 + 127 * ClampValue(sb * invLen, -1, 1));
- end;
- end;
- end;
- end;
- procedure TgxImage.SetBlank(const Value: boolean);
- begin
- if not Value and not IsEmpty then
- ReallocMem(FData, DataSize);
- FBlank := Value;
- end;
- //Converts a TgxImage back into a TBitmap
- procedure TgxImage.AssignToBitmap(aBitmap: TBitmap); //TBitmap = TBitmap
- var
- y: integer;
- pSrc, pDest: PAnsiChar;
- begin
- Narrow;
- aBitmap.Width := GetWidth;
- aBitmap.Height := GetHeight;
- { TODO : E2129 Cannot assign to a read-only property }
- (*aBitmap.PixelFormat := glpf32bit;*)
- if FVerticalReverseOnAssignFromBitmap then
- begin
- for y := 0 to GetHeight - 1 do
- begin
- pSrc := @PAnsiChar(FData)[y * (GetWidth * 4)];
- pDest := BitmapScanLine(aBitmap, y);
- BGRA32ToRGBA32(pSrc, pDest, GetWidth);
- end;
- end
- else
- begin
- for y := 0 to GetHeight - 1 do
- begin
- pSrc := @PAnsiChar(FData)[y * (GetWidth * 4)];
- pDest := BitmapScanLine(aBitmap, GetHeight - 1 - y);
- BGRA32ToRGBA32(pSrc, pDest, GetWidth);
- end;
- end;
- end;
- procedure TgxImage.GenerateMipmap(AFilter: TImageFilterFunction);
- begin
- if not FBlank then
- inherited GenerateMipmap(AFilter);
- end;
- procedure TgxImage.UnMipmap;
- begin
- inherited UnMipmap;
- if not (fBlank or IsEmpty) then
- ReallocMem(FData, DataSize);
- end;
- procedure TgxImage.DataConvertTask;
- var
- oldLOD: TgxImagePiramid;
- newData: Pointer;
- ptr: PByte;
- L: TgxImageLODRange;
- d: Integer;
- begin
- oldLOD := FLOD;
- if IsVolume then
- begin
- (* Message Hint 'TgxImage.DataConvertTask not yet implemented for volume images' *)
- end
- else
- begin
- GetMem(newData, DataSize);
- d := MaxInteger(GetDepth, 1);
- try
- for L := FLevelCount - 1 downto 0 do
- begin
- ptr := newData;
- Inc(ptr, oldLOD[L].Offset);
- ConvertImage(
- GetLevelAddress(L), ptr,
- fOldColorFormat, fColorFormat,
- fOldDataType, fDataType,
- oldLOD[L].Width, oldLOD[L].Height * d);
- end;
- FreeMem(fData);
- fData := newData;
- except
- FreeMem(newData);
- ShowMessage(Format(strCantConvertImg, [ClassName]));
- SetErrorImage;
- end;
- end;
- end;
- //---------------------------------------------------
- initialization
- //---------------------------------------------------
- finalization
- FreeAndNil(vRasterFileFormats);
- end.
|