123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- /*
- ================================================================================================
- Contains the DxtEncoder implementation.
- ================================================================================================
- */
- #pragma hdrstop
- #include "DXTCodec_local.h"
- #include "DXTCodec.h"
- #define INSET_COLOR_SHIFT 4 // inset the bounding box with ( range >> shift )
- #define INSET_ALPHA_SHIFT 5 // inset alpha channel
- #define C565_5_MASK 0xF8 // 0xFF minus last three bits
- #define C565_6_MASK 0xFC // 0xFF minus last two bits
- #define NVIDIA_7X_HARDWARE_BUG_FIX // keep the DXT5 colors sorted as: max, min
- typedef uint16 word;
- typedef uint32 dword;
- /*
- ========================
- idDxtEncoder::NV4XHardwareBugFix
- ========================
- */
- void idDxtEncoder::NV4XHardwareBugFix( byte *minColor, byte *maxColor ) const {
- #ifdef ID_WIN_X86_ASM
- int minq = ( ( minColor[0] << 16 ) | ( minColor[1] << 8 ) | minColor[2] ) & 0x00F8FCF8;
- int maxq = ( ( maxColor[0] << 16 ) | ( maxColor[1] << 8 ) | maxColor[2] ) & 0x00F8FCF8;
- int mask = -( minq > maxq ) & 0x00FFFFFF;
- int min = *(int *)minColor;
- int max = *(int *)maxColor;
- min ^= max;
- max ^= ( min & mask );
- min ^= max;
- *(int *)minColor = min;
- *(int *)maxColor = max;
- #else
- if ( ColorTo565( minColor ) > ColorTo565( maxColor ) ) {
- SwapValues( minColor[0], maxColor[0] );
- SwapValues( minColor[1], maxColor[1] );
- SwapValues( minColor[2], maxColor[2] );
- }
- #endif
- }
- /*
- ========================
- idDxtEncoder::HasConstantValuePer4x4Block
- ========================
- */
- bool idDxtEncoder::HasConstantValuePer4x4Block( const byte *inBuf, int width, int height, int channel ) const {
- if ( width < 4 || height < 4 ) {
- byte value = inBuf[channel];
- for ( int k = 0; k < height; k++ ) {
- for ( int l = 0; l < width; l++ ) {
- if ( inBuf[(k*width+l)*4+channel] != value ) {
- return false;
- }
- }
- }
- return true;
- }
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- const byte *inPtr = inBuf + i * 4;
- byte value = inPtr[channel];
- for ( int k = 0; k < 4; k++ ) {
- for ( int l = 0; l < 4; l++ ) {
- if ( inPtr[(k*width+l)*4+channel] != value ) {
- return false;
- }
- }
- }
- }
- inBuf += srcPadding;
- }
- return true;
- }
- /*
- ========================
- idDxtEncoder::WriteTinyColorDXT1
- ========================
- */
- void idDxtEncoder::WriteTinyColorDXT1( const byte *inBuf, int width, int height ) {
- int numBlocks = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 );
- int stride = ( ( width * height ) / numBlocks ) * 4; // number of bytes from one block to the next
- // example: 2x8 pixels
- // numBlocks = 2
- // stride = 32 bytes (8 pixels)
- for ( int i = 0; i < numBlocks; i++ ) {
- // FIXME: This just emits a fake block based on the color at position 0,0
- EmitUShort( ColorTo565( inBuf ) );
- EmitUShort( 0 ); // dummy, never used
- EmitUInt( 0 ); // 4 color index bytes all use the first color
- inBuf += stride;
- }
- }
- /*
- ========================
- idDxtEncoder::WriteTinyColorDXT5
- ========================
- */
- void idDxtEncoder::WriteTinyColorDXT5( const byte *inBuf, int width, int height ) {
- int numBlocks = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 );
- int stride = ( ( width * height ) / numBlocks ) * 4; // number of bytes from one block to the next
- // example: 2x8 pixels
- // numBlocks = 2
- // stride = 32 bytes (8 pixels)
- for ( int i = 0; i < numBlocks; i++ ) {
- // FIXME: This just emits a fake block based on the color at position 0,0
- EmitByte( inBuf[3] );
- EmitByte( 0 ); // dummy, never used
- EmitByte( 0 ); // 6 alpha index bytes all use the first alpha
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitUShort( ColorTo565( inBuf ) );
- EmitUShort( 0 ); // dummy, never used
- EmitUInt( 0 ); // 4 color index bytes all use the first color
- inBuf += stride;
- }
- }
- /*
- ========================
- idDxtEncoder::WriteTinyColorCTX1DXT5A
- ========================
- */
- void idDxtEncoder::WriteTinyColorCTX1DXT5A( const byte *inBuf, int width, int height ) {
- int numBlocks = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 );
- int stride = ( ( width * height ) / numBlocks ) * 4; // number of bytes from one block to the next
- // example: 2x8 pixels
- // numBlocks = 2
- // stride = 32 bytes (8 pixels)
- for ( int i = 0; i < numBlocks; i++ ) {
- // FIXME: This just emits a fake block based on the color at position 0,0
- EmitByte( inBuf[0] );
- EmitByte( inBuf[1] );
- EmitByte( inBuf[0] );
- EmitByte( inBuf[1] );
- EmitUInt( 0 ); // 4 color index bytes all use the first color
- EmitByte( inBuf[3] );
- EmitByte( 0 ); // dummy, never used
- EmitByte( 0 ); // 6 alpha index bytes all use the first alpha
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- inBuf += stride;
- }
- }
- /*
- ========================
- idDxtEncoder::WriteTinyNormalMapDXT5
- ========================
- */
- void idDxtEncoder::WriteTinyNormalMapDXT5( const byte *inBuf, int width, int height ) {
- int numBlocks = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 );
- int stride = ( ( width * height ) / numBlocks ) * 4; // number of bytes from one block to the next
- // example: 2x8 pixels
- // numBlocks = 2
- // stride = 32 bytes (8 pixels)
- for ( int i = 0; i < numBlocks; i++ ) {
- // FIXME: This just emits a fake block based on the normal at position 0,0
- EmitByte( inBuf[3] );
- EmitByte( 0 ); // dummy, never used
- EmitByte( 0 ); // 6 alpha index bytes all use the first alpha
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitUShort( ColorTo565( inBuf[0], inBuf[1], inBuf[2] ) );
- EmitUShort( 0 ); // dummy, never used
- EmitUInt( 0 ); // 4 color index bytes all use the first color
- inBuf += stride;
- }
- }
- /*
- ========================
- idDxtEncoder::WriteTinyNormalMapDXN
- ========================
- */
- void idDxtEncoder::WriteTinyNormalMapDXN( const byte *inBuf, int width, int height ) {
- int numBlocks = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 );
- int stride = ( ( width * height ) / numBlocks ) * 4; // number of bytes from one block to the next
- // example: 2x8 pixels
- // numBlocks = 2
- // stride = 32 bytes (8 pixels)
- for ( int i = 0; i < numBlocks; i++ ) {
- // FIXME: This just emits a fake block based on the normal at position 0,0
- EmitByte( inBuf[0] );
- EmitByte( 0 ); // dummy, never used
- EmitByte( 0 ); // 6 alpha index bytes all use the first alpha
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( inBuf[1] );
- EmitByte( 0 ); // dummy, never used
- EmitByte( 0 ); // 6 alpha index bytes all use the first alpha
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- inBuf += stride;
- }
- }
- /*
- ========================
- idDxtEncoder::WriteTinyDXT5A
- ========================
- */
- void idDxtEncoder::WriteTinyDXT5A( const byte *inBuf, int width, int height ) {
- int numBlocks = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 );
- int stride = ( ( width * height ) / numBlocks ) * 4; // number of bytes from one block to the next
- // example: 2x8 pixels
- // numBlocks = 2
- // stride = 32 bytes (8 pixels)
- for ( int i = 0; i < numBlocks; i++ ) {
- // FIXME: This just emits a fake block based on the normal at position 0,0
- EmitByte( inBuf[0] );
- EmitByte( 0 ); // dummy, never used
- EmitByte( 0 ); // 6 alpha index bytes all use the first alpha
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- EmitByte( 0 );
- inBuf += stride;
- }
- }
- /*
- ========================
- idDxtEncoder::ExtractBlock
- params: inPtr - input image, 4 bytes per pixel
- paramO: colorBlock - 4*4 output tile, 4 bytes per pixel
- ========================
- */
- ID_INLINE void idDxtEncoder::ExtractBlock( const byte *inPtr, int width, byte *colorBlock ) const {
- for ( int j = 0; j < 4; j++ ) {
- memcpy( &colorBlock[j*4*4], inPtr, 4*4 );
- inPtr += width * 4;
- }
- }
- /*
- ========================
- SwapColors
- ========================
- */
- void SwapColors( byte *c1, byte *c2 ) {
- byte tm[3];
- memcpy( tm, c1, 3 );
- memcpy( c1, c2, 3 );
- memcpy( c2, tm, 3 );
- }
- /*
- ========================
- idDxtEncoder::GetMinMaxColorsMaxDist
- Finds the two RGB colors in a 4x4 block furthest apart. Also finds the two alpha values
- furthest apart.
- params: colorBlock - 4*4 input tile, 4 bytes per pixel
- paramO: minColor - 4 byte min color
- paramO: maxColor - 4 byte max color
- ========================
- */
- void idDxtEncoder::GetMinMaxColorsMaxDist( const byte *colorBlock, byte *minColor, byte *maxColor ) const {
- int maxDistC = -1;
- int maxDistA = -1;
- for ( int i = 0; i < 64 - 4; i += 4 ) {
- for ( int j = i + 4; j < 64; j += 4 ) {
- int dc = ColorDistance( &colorBlock[i], &colorBlock[j] );
- if ( dc > maxDistC ) {
- maxDistC = dc;
- memcpy( minColor, colorBlock+i, 3 );
- memcpy( maxColor, colorBlock+j, 3 );
- }
- int da = AlphaDistance( colorBlock[i+3], colorBlock[j+3] );
- if ( da > maxDistA ) {
- maxDistA = da;
- minColor[3] = colorBlock[i+3];
- maxColor[3] = colorBlock[j+3];
- }
- }
- }
- if ( maxColor[0] < minColor[0] ) {
- SwapColors( minColor, maxColor );
- }
- }
- /*
- ========================
- idDxtEncoder::GetMinMaxColorsLuminance
- Finds the two RGB colors in a 4x4 block furthest apart based on luminance. Also finds the two
- alpha values furthest apart.
- params: colorBlock - 4*4 input tile, 4 bytes per pixel
- paramO: minColor - 4 byte min color
- paramO: maxColor - 4 byte max color
- ========================
- */
- void idDxtEncoder::GetMinMaxColorsLuminance( const byte *colorBlock, byte *minColor, byte *maxColor ) const {
- int maxLumC = 0, minLumC = 256 * 4;
- int maxAlpha = 0, minAlpha = 256 * 4;
- for ( int i = 0; i < 16; i++ ) {
- int luminance = colorBlock[i*4+0] + colorBlock[i*4+1] * 2 + colorBlock[i*4+2];
- if ( luminance > maxLumC ) {
- maxLumC = luminance;
- memcpy( maxColor, colorBlock+i*4, 3 );
- }
- if ( luminance < minLumC ) {
- minLumC = luminance;
- memcpy( minColor, colorBlock+i*4, 3 );
- }
- int alpha = colorBlock[i*4+3];
- if ( alpha > maxAlpha ) {
- maxAlpha = alpha;
- maxColor[3] = (byte)alpha;
- }
- if ( alpha < minAlpha ) {
- minAlpha = alpha;
- minColor[3] = (byte)alpha;
- }
- }
- if ( maxColor[0] < minColor[0] ) {
- SwapColors( minColor, maxColor );
- }
- }
- /*
- ========================
- idDxtEncoder::GetSquareAlphaError
- params: colorBlock - 16 pixel block for which to find color indexes
- paramO: minAlpha - Min alpha found
- paramO: maxAlpha - Max alpha found
- return: 4 byte color index block
- ========================
- */
- int idDxtEncoder::GetSquareAlphaError( const byte *colorBlock, const int alphaOffset, const byte minAlpha, const byte maxAlpha, int lastError ) const {
- int i, j;
- byte alphas[8];
- alphas[0] = maxAlpha;
- alphas[1] = minAlpha;
- if ( maxAlpha > minAlpha ) {
- alphas[2] = ( 6 * alphas[0] + 1 * alphas[1] ) / 7;
- alphas[3] = ( 5 * alphas[0] + 2 * alphas[1] ) / 7;
- alphas[4] = ( 4 * alphas[0] + 3 * alphas[1] ) / 7;
- alphas[5] = ( 3 * alphas[0] + 4 * alphas[1] ) / 7;
- alphas[6] = ( 2 * alphas[0] + 5 * alphas[1] ) / 7;
- alphas[7] = ( 1 * alphas[0] + 6 * alphas[1] ) / 7;
- } else {
- alphas[2] = ( 4 * alphas[0] + 1 * alphas[1] ) / 5;
- alphas[3] = ( 3 * alphas[0] + 2 * alphas[1] ) / 5;
- alphas[4] = ( 2 * alphas[0] + 3 * alphas[1] ) / 5;
- alphas[5] = ( 1 * alphas[0] + 4 * alphas[1] ) / 5;
- alphas[6] = 0;
- alphas[7] = 255;
- }
- int error = 0;
- for ( i = 0; i < 16; i++ ) {
- unsigned int minDist = MAX_UNSIGNED_TYPE( int );
- byte a = colorBlock[i*4+alphaOffset];
- for ( j = 0; j < 8; j++ ) {
- unsigned int dist = AlphaDistance( a, alphas[j] );
- if ( dist < minDist ) {
- minDist = dist;
- }
- }
- error += minDist;
- if ( error >= lastError ) {
- return error;
- }
- }
- return error;
- }
- /*
- ========================
- idDxtEncoder::GetMinMaxAlphaHQ
- params: colorBlock - 4*4 input tile, 4 bytes per pixel
- paramO: minColor - 4 byte min color found
- paramO: maxColor - 4 byte max color found
- ========================
- */
- int idDxtEncoder::GetMinMaxAlphaHQ( const byte *colorBlock, const int alphaOffset, byte *minColor, byte *maxColor ) const {
- int i, j;
- byte alphaMin, alphaMax;
- int error, bestError = MAX_TYPE( int );
- alphaMin = 255;
- alphaMax = 0;
- // get alpha min / max
- for ( i = 0; i < 16; i++ ) {
- if ( colorBlock[i*4+alphaOffset] < alphaMin ) {
- alphaMin = colorBlock[i*4+alphaOffset];
- }
- if ( colorBlock[i*4+alphaOffset] > alphaMax ) {
- alphaMax = colorBlock[i*4+alphaOffset];
- }
- }
- const int ALPHA_EXPAND = 32;
- alphaMin = ( alphaMin <= ALPHA_EXPAND ) ? 0 : alphaMin - ALPHA_EXPAND;
- alphaMax = ( alphaMax >= 255 - ALPHA_EXPAND ) ? 255 : alphaMax + ALPHA_EXPAND;
- for ( i = alphaMin; i <= alphaMax; i++ ) {
- for ( j = alphaMax; j >= i; j-- ) {
- error = GetSquareAlphaError( colorBlock, alphaOffset, (byte)i, (byte)j, bestError );
- if ( error < bestError ) {
- bestError = error;
- minColor[alphaOffset] = (byte)i;
- maxColor[alphaOffset] = (byte)j;
- }
- error = GetSquareAlphaError( colorBlock, alphaOffset, (byte)j, (byte)i, bestError );
- if ( error < bestError ) {
- bestError = error;
- minColor[alphaOffset] = (byte)i;
- maxColor[alphaOffset] = (byte)j;
- }
- }
- }
- return bestError;
- }
- /*
- ========================
- idDxtEncoder::GetSquareColorsError
- params: colorBlock - 16 pixel block for which to find color indexes
- paramO: color0 - 4 byte min color found
- paramO: color1 - 4 byte max color found
- return: 4 byte color index block
- ========================
- */
- int idDxtEncoder::GetSquareColorsError( const byte *colorBlock, const unsigned short color0, const unsigned short color1, int lastError ) const {
- int i, j;
- byte colors[4][4];
- ColorFrom565( color0, colors[0] );
- ColorFrom565( color1, colors[1] );
- if ( color0 > color1 ) {
- colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
- colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
- colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
- colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
- colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
- colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
- } else {
- colors[2][0] = ( 1 * colors[0][0] + 1 * colors[1][0] ) / 2;
- colors[2][1] = ( 1 * colors[0][1] + 1 * colors[1][1] ) / 2;
- colors[2][2] = ( 1 * colors[0][2] + 1 * colors[1][2] ) / 2;
- colors[3][0] = 0;
- colors[3][1] = 0;
- colors[3][2] = 0;
- }
- int error = 0;
- for ( i = 0; i < 16; i++ ) {
- unsigned int minDist = MAX_UNSIGNED_TYPE( int );
- for ( j = 0; j < 4; j++ ) {
- unsigned int dist = ColorDistance( &colorBlock[i*4], &colors[j][0] );
- if ( dist < minDist ) {
- minDist = dist;
- }
- }
- // accumulated error
- error += minDist;
- if ( error > lastError ) {
- return error;
- }
- }
- return error;
- }
- /*
- ========================
- idDxtEncoder::GetSquareNormalYError
- params: colorBlock - 16 pixel block for which to find color indexes
- paramO: color0 - 4 byte min color found
- paramO: color1 - 4 byte max color found
- return: 4 byte color index block
- ========================
- */
- int idDxtEncoder::GetSquareNormalYError( const byte *colorBlock, const unsigned short color0, const unsigned short color1, int lastError, int scale ) const {
- int i, j;
- byte colors[4][4];
- ColorFrom565( color0, colors[0] );
- ColorFrom565( color1, colors[1] );
- if ( color0 > color1 ) {
- colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
- colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
- colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
- colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
- colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
- colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
- } else {
- colors[2][0] = ( 1 * colors[0][0] + 1 * colors[1][0] ) / 2;
- colors[2][1] = ( 1 * colors[0][1] + 1 * colors[1][1] ) / 2;
- colors[2][2] = ( 1 * colors[0][2] + 1 * colors[1][2] ) / 2;
- colors[3][0] = 0;
- colors[3][1] = 0;
- colors[3][2] = 0;
- }
- int error = 0;
- for ( i = 0; i < 16; i++ ) {
- unsigned int minDist = MAX_UNSIGNED_TYPE( int );
- for ( j = 0; j < 4; j++ ) {
- float r = (float) colorBlock[i*4+1] / scale;
- float s = (float) colors[j][1] / scale;
- unsigned int dist = idMath::Ftoi( ( r - s ) * ( r - s ) );
- if ( dist < minDist ) {
- minDist = dist;
- }
- }
- // accumulated error
- error += minDist;
- if ( error > lastError ) {
- return error;
- }
- }
- return error;
- }
- /*
- ========================
- idDxtEncoder::GetMinMaxColorsHQ
- Uses an exhaustive search to find the two RGB colors that produce the least error when used to
- compress the 4x4 block. Also finds the minimum and maximum alpha values.
- params: colorBlock - 4*4 input tile, 4 bytes per pixel
- paramO: minColor - 4 byte min color found
- paramO: maxColor - 4 byte max color found
- ========================
- */
- int idDxtEncoder::GetMinMaxColorsHQ( const byte *colorBlock, byte *minColor, byte *maxColor, bool noBlack ) const {
- int i;
- int i0, i1, i2, j0, j1, j2;
- unsigned short minColor565, maxColor565, bestMinColor565, bestMaxColor565;
- byte bboxMin[3], bboxMax[3], minAxisDist[3];
- int error, bestError = MAX_TYPE( int );
- bboxMin[0] = bboxMin[1] = bboxMin[2] = 255;
- bboxMax[0] = bboxMax[1] = bboxMax[2] = 0;
- // get color bbox
- for ( i = 0; i < 16; i++ ) {
- if ( colorBlock[i*4+0] < bboxMin[0] ) {
- bboxMin[0] = colorBlock[i*4+0];
- }
- if ( colorBlock[i*4+1] < bboxMin[1] ) {
- bboxMin[1] = colorBlock[i*4+1];
- }
- if ( colorBlock[i*4+2] < bboxMin[2] ) {
- bboxMin[2] = colorBlock[i*4+2];
- }
- if ( colorBlock[i*4+0] > bboxMax[0] ) {
- bboxMax[0] = colorBlock[i*4+0];
- }
- if ( colorBlock[i*4+1] > bboxMax[1] ) {
- bboxMax[1] = colorBlock[i*4+1];
- }
- if ( colorBlock[i*4+2] > bboxMax[2] ) {
- bboxMax[2] = colorBlock[i*4+2];
- }
- }
- // decrease range for 565 encoding
- bboxMin[0] >>= 3;
- bboxMin[1] >>= 2;
- bboxMin[2] >>= 3;
- bboxMax[0] >>= 3;
- bboxMax[1] >>= 2;
- bboxMax[2] >>= 3;
- // get the minimum distance the end points of the line must be apart along each axis
- for ( i = 0; i < 3; i++ ) {
- minAxisDist[i] = ( bboxMax[i] - bboxMin[i] );
- if ( minAxisDist[i] >= 16 ) {
- minAxisDist[i] = minAxisDist[i] * 3 / 4;
- } else if ( minAxisDist[i] >= 8 ) {
- minAxisDist[i] = minAxisDist[i] * 2 / 4;
- } else if ( minAxisDist[i] >= 4 ) {
- minAxisDist[i] = minAxisDist[i] * 1 / 4;
- } else {
- minAxisDist[i] = 0;
- }
- }
- // expand the bounding box
- const int C565_BBOX_EXPAND = 1;
- bboxMin[0] = ( bboxMin[0] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[0] - C565_BBOX_EXPAND;
- bboxMin[1] = ( bboxMin[1] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[1] - C565_BBOX_EXPAND;
- bboxMin[2] = ( bboxMin[2] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[2] - C565_BBOX_EXPAND;
- bboxMax[0] = ( bboxMax[0] >= (255>>3)-C565_BBOX_EXPAND ) ? (255>>3) : bboxMax[0] + C565_BBOX_EXPAND;
- bboxMax[1] = ( bboxMax[1] >= (255>>2)-C565_BBOX_EXPAND ) ? (255>>2) : bboxMax[1] + C565_BBOX_EXPAND;
- bboxMax[2] = ( bboxMax[2] >= (255>>3)-C565_BBOX_EXPAND ) ? (255>>3) : bboxMax[2] + C565_BBOX_EXPAND;
- bestMinColor565 = 0;
- bestMaxColor565 = 0;
- for ( i0 = bboxMin[0]; i0 <= bboxMax[0]; i0++ ) {
- for ( j0 = bboxMax[0]; j0 >= bboxMin[0]; j0-- ) {
- if ( abs( i0 - j0 ) < minAxisDist[0] ) {
- continue;
- }
- for ( i1 = bboxMin[1]; i1 <= bboxMax[1]; i1++ ) {
- for ( j1 = bboxMax[1]; j1 >= bboxMin[1]; j1-- ) {
- if ( abs( i1 - j1 ) < minAxisDist[1] ) {
- continue;
- }
- for ( i2 = bboxMin[2]; i2 <= bboxMax[2]; i2++ ) {
- for ( j2 = bboxMax[2]; j2 >= bboxMin[2]; j2-- ) {
- if ( abs( i2 - j2 ) < minAxisDist[2] ) {
- continue;
- }
- minColor565 = (unsigned short)( ( i0 << 11 ) | ( i1 << 5 ) | ( i2 << 0 ) );
- maxColor565 = (unsigned short)( ( j0 << 11 ) | ( j1 << 5 ) | ( j2 << 0 ) );
- if ( !noBlack ) {
- error = GetSquareColorsError( colorBlock, maxColor565, minColor565, bestError );
- if ( error < bestError ) {
- bestError = error;
- bestMinColor565 = minColor565;
- bestMaxColor565 = maxColor565;
- }
- } else {
- if ( minColor565 <= maxColor565 ) {
- SwapValues( minColor565, maxColor565 );
- }
- }
- error = GetSquareColorsError( colorBlock, minColor565, maxColor565, bestError );
- if ( error < bestError ) {
- bestError = error;
- bestMinColor565 = minColor565;
- bestMaxColor565 = maxColor565;
- }
- }
- }
- }
- }
- }
- }
- ColorFrom565( bestMinColor565, minColor );
- ColorFrom565( bestMaxColor565, maxColor );
- return bestError;
- }
- /*
- ========================
- idDxtEncoder::GetSquareCTX1Error
- params: colorBlock - 16 pixel block for which to find color indexes
- paramO: color0 - Min color found
- paramO: color1 - Max color found
- return: 4 byte color index block
- ========================
- */
- int idDxtEncoder::GetSquareCTX1Error( const byte *colorBlock, const byte *color0, const byte *color1, int lastError ) const {
- int i, j;
- byte colors[4][4];
- colors[0][0] = color0[0];
- colors[0][1] = color0[1];
- colors[1][0] = color1[0];
- colors[1][1] = color1[1];
- colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
- colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
- colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
- colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
- int error = 0;
- for ( i = 0; i < 16; i++ ) {
- unsigned int minDist = MAX_UNSIGNED_TYPE( int );
- for ( j = 0; j < 4; j++ ) {
- unsigned int dist = CTX1Distance( &colorBlock[i*4], &colors[j][0] );
- if ( dist < minDist ) {
- minDist = dist;
- }
- }
- // accumulated error
- error += minDist;
- if ( error > lastError ) {
- return error;
- }
- }
- return error;
- }
- /*
- ========================
- idDxtEncoder::GetMinMaxCTX1HQ
- Uses an exhaustive search to find the two RGB colors that produce the least error when used to
- compress the 4x4 block. Also finds the minimum and maximum alpha values.
- params: colorBlock - 4*4 input tile, 4 bytes per pixel
- paramO: minColor - 4 byte Min color found
- paramO: maxColor - 4 byte Max color found
- ========================
- */
- int idDxtEncoder::GetMinMaxCTX1HQ( const byte *colorBlock, byte *minColor, byte *maxColor ) const {
- int i;
- int i0, i1, j0, j1;
- byte curMinColor[2], curMaxColor[2];
- byte bboxMin[2], bboxMax[2], minAxisDist[2];
- int error, bestError = MAX_TYPE( int );
- bboxMin[0] = bboxMin[1] = 255;
- bboxMax[0] = bboxMax[1] = 0;
- // get color bbox
- for ( i = 0; i < 16; i++ ) {
- if ( colorBlock[i*4+0] < bboxMin[0] ) {
- bboxMin[0] = colorBlock[i*4+0];
- }
- if ( colorBlock[i*4+1] < bboxMin[1] ) {
- bboxMin[1] = colorBlock[i*4+1];
- }
- if ( colorBlock[i*4+0] > bboxMax[0] ) {
- bboxMax[0] = colorBlock[i*4+0];
- }
- if ( colorBlock[i*4+1] > bboxMax[1] ) {
- bboxMax[1] = colorBlock[i*4+1];
- }
- }
- // get the minimum distance the end points of the line must be apart along each axis
- for ( i = 0; i < 2; i++ ) {
- minAxisDist[i] = ( bboxMax[i] - bboxMin[i] );
- if ( minAxisDist[i] >= 64 ) {
- minAxisDist[i] = minAxisDist[i] * 3 / 4;
- } else if ( minAxisDist[i] >= 32 ) {
- minAxisDist[i] = minAxisDist[i] * 2 / 4;
- } else if ( minAxisDist[i] >= 16 ) {
- minAxisDist[i] = minAxisDist[i] * 1 / 4;
- } else {
- minAxisDist[i] = 0;
- }
- }
- // expand the bounding box
- const int CXT1_BBOX_EXPAND = 6;
- bboxMin[0] = ( bboxMin[0] <= CXT1_BBOX_EXPAND ) ? 0 : bboxMin[0] - CXT1_BBOX_EXPAND;
- bboxMin[1] = ( bboxMin[1] <= CXT1_BBOX_EXPAND ) ? 0 : bboxMin[1] - CXT1_BBOX_EXPAND;
- bboxMax[0] = ( bboxMax[0] >= 255 - CXT1_BBOX_EXPAND ) ? 255 : bboxMax[0] + CXT1_BBOX_EXPAND;
- bboxMax[1] = ( bboxMax[1] >= 255 - CXT1_BBOX_EXPAND ) ? 255 : bboxMax[1] + CXT1_BBOX_EXPAND;
- for ( i0 = bboxMin[0]; i0 <= bboxMax[0]; i0++ ) {
- for ( j0 = bboxMax[0]; j0 >= bboxMin[0]; j0-- ) {
- if ( abs( i0 - j0 ) < minAxisDist[0] ) {
- continue;
- }
- for ( i1 = bboxMin[1]; i1 <= bboxMax[1]; i1++ ) {
- for ( j1 = bboxMax[1]; j1 >= bboxMin[1]; j1-- ) {
- if ( abs( i1 - j1 ) < minAxisDist[1] ) {
- continue;
- }
- curMinColor[0] = (byte)i0;
- curMinColor[1] = (byte)i1;
- curMaxColor[0] = (byte)j0;
- curMaxColor[1] = (byte)j1;
- error = GetSquareCTX1Error( colorBlock, curMinColor, curMaxColor, bestError );
- if ( error < bestError ) {
- bestError = error;
- memcpy( minColor, curMinColor, 2 );
- memcpy( maxColor, curMaxColor, 2 );
- }
- }
- }
- }
- }
- return bestError;
- }
- /*
- ========================
- idDxtEncoder::GetMinMaxNormalYHQ
- Uses an exhaustive search to find the two RGB colors that produce the least error when used to
- compress the 4x4 block. Also finds the minimum and maximum alpha values.
- params: colorBlock - 4*4 input tile, 4 bytes per pixel
- paramO: minColor - 4 byte Min color found
- paramO: maxColor - 4 byte Max color found
- ========================
- */
- int idDxtEncoder::GetMinMaxNormalYHQ( const byte *colorBlock, byte *minColor, byte *maxColor, bool noBlack, int scale ) const {
- unsigned short bestMinColor565, bestMaxColor565;
- byte bboxMin[3], bboxMax[3];
- int error, bestError = MAX_TYPE( int );
- bboxMin[1] = 255;
- bboxMax[1] = 0;
- // get color bbox
- for ( int i = 0; i < 16; i++ ) {
- if ( colorBlock[i*4+1] < bboxMin[1] ) {
- bboxMin[1] = colorBlock[i*4+1];
- }
- if ( colorBlock[i*4+1] > bboxMax[1] ) {
- bboxMax[1] = colorBlock[i*4+1];
- }
- }
- // decrease range for 565 encoding
- bboxMin[1] >>= 2;
- bboxMax[1] >>= 2;
- // expand the bounding box
- const int C565_BBOX_EXPAND = 1;
- bboxMin[1] = ( bboxMin[1] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[1] - C565_BBOX_EXPAND;
- bboxMax[1] = ( bboxMax[1] >= (255>>2)-C565_BBOX_EXPAND ) ? (255>>2) : bboxMax[1] + C565_BBOX_EXPAND;
- bestMinColor565 = 0;
- bestMaxColor565 = 0;
- for ( int i1 = bboxMin[1]; i1 <= bboxMax[1]; i1++ ) {
- for ( int j1 = bboxMax[1]; j1 >= bboxMin[1]; j1-- ) {
- if ( abs( i1 - j1 ) < 0 ) {
- continue;
- }
- unsigned short minColor565 = (unsigned short)i1 << 5;
- unsigned short maxColor565 = (unsigned short)j1 << 5;
- if ( !noBlack ) {
- error = GetSquareNormalYError( colorBlock, maxColor565, minColor565, bestError, scale );
- if ( error < bestError ) {
- bestError = error;
- bestMinColor565 = minColor565;
- bestMaxColor565 = maxColor565;
- }
- } else {
- if ( minColor565 <= maxColor565 ) {
- SwapValues( minColor565, maxColor565 );
- }
- }
- error = GetSquareNormalYError( colorBlock, minColor565, maxColor565, bestError, scale );
- if ( error < bestError ) {
- bestError = error;
- bestMinColor565 = minColor565;
- bestMaxColor565 = maxColor565;
- }
- }
- }
- ColorFrom565( bestMinColor565, minColor );
- ColorFrom565( bestMaxColor565, maxColor );
- int bias = colorBlock[0*4+0];
- int size = colorBlock[0*4+2];
- minColor[0] = maxColor[0] = (byte)bias;
- minColor[2] = maxColor[2] = (byte)size;
- return bestError;
- }
- #if defined( ID_WIN_X86_ASM )
- ALIGN16( static float SIMD_SSE2_float_scale[4] ) = { 2.0f / 255.0f, 2.0f / 255.0f, 2.0f / 255.0f, 2.0f / 255.0f };
- ALIGN16( static float SIMD_SSE2_float_descale[4] ) = { 255.0f / 2.0f, 255.0f / 2.0f, 255.0f / 2.0f, 255.0f / 2.0f };
- ALIGN16( static float SIMD_SSE2_float_zero[4] ) = { 0.0f, 0.0f, 0.0f, 0.0f };
- ALIGN16( static float SIMD_SSE2_float_one[4] ) = { 1.0f, 1.0f, 1.0f, 1.0f };
- ALIGN16( static float SIMD_SSE2_float_half[4] ) = { 0.5f, 0.5f, 0.5f, 0.5f };
- ALIGN16( static float SIMD_SSE2_float_255[4] ) = { 255.0f, 255.0f, 255.0f, 255.0f };
- ALIGN16( static float SIMD_SP_rsqrt_c0[4] ) = { 3.0f, 3.0f, 3.0f, 3.0f };
- ALIGN16( static float SIMD_SP_rsqrt_c1[4] ) = { -0.5f, -0.5f, -0.5f, -0.5f };
- ALIGN16( static dword SIMD_SSE2_dword_maskFirstThree[4] ) = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
- ALIGN16( static dword SIMD_SSE2_dword_maskWords[4] ) = { 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x00000000 };
- #define R_SHUFFLE_PS( x, y, z, w ) (( (w) & 3 ) << 6 | ( (z) & 3 ) << 4 | ( (y) & 3 ) << 2 | ( (x) & 3 ))
- #endif
- /*
- ========================
- NormalDistanceDXT1
- ========================
- */
- int NormalDistanceDXT1( const int *vector, const int *normalized ) {
- #if defined( ID_WIN_X86_ASM )
- int result;
- __asm {
- mov esi, vector
- mov edi, normalized
- cvtdq2ps xmm0, [esi]
- mulps xmm0, SIMD_SSE2_float_scale
- subps xmm0, SIMD_SSE2_float_one
- pand xmm0, SIMD_SSE2_dword_maskFirstThree
- movaps xmm1, xmm0
- mulps xmm1, xmm1
- pshufd xmm2, xmm1, R_SHUFFLE_PS( 2, 3, 0, 1 )
- addps xmm2, xmm1
- pshufd xmm1, xmm2, R_SHUFFLE_PS( 1, 0, 1, 0 )
- addps xmm2, xmm1
- rsqrtps xmm1, xmm2
- mulps xmm2, xmm1
- mulps xmm2, xmm1
- subps xmm2, SIMD_SP_rsqrt_c0
- mulps xmm1, SIMD_SP_rsqrt_c1
- mulps xmm2, xmm1
- mulps xmm0, xmm2
- addps xmm0, SIMD_SSE2_float_one
- mulps xmm0, SIMD_SSE2_float_descale
- addps xmm0, SIMD_SSE2_float_half
- maxps xmm0, SIMD_SSE2_float_zero
- minps xmm0, SIMD_SSE2_float_255
- cvttps2dq xmm0, xmm0
- psubd xmm0, [edi]
- pand xmm0, SIMD_SSE2_dword_maskWords
- pmullw xmm0, xmm0
- pshufd xmm1, xmm0, R_SHUFFLE_PS( 2, 3, 0, 1 )
- paddd xmm0, xmm1
- pshufd xmm1, xmm0, R_SHUFFLE_PS( 1, 0, 1, 0 )
- paddd xmm0, xmm1
- movd result, xmm0
- }
- return result;
- #else
- float floatNormal[3];
- byte intNormal[4];
- floatNormal[0] = vector[0] * ( 2.0f / 255.0f ) - 1.0f;
- floatNormal[1] = vector[1] * ( 2.0f / 255.0f ) - 1.0f;
- floatNormal[2] = vector[2] * ( 2.0f / 255.0f ) - 1.0f;
- float rcplen = idMath::InvSqrt( floatNormal[0] * floatNormal[0] + floatNormal[1] * floatNormal[1] + floatNormal[2] * floatNormal[2] );
- floatNormal[0] *= rcplen;
- floatNormal[1] *= rcplen;
- floatNormal[2] *= rcplen;
- intNormal[0] = idMath::Ftob( ( floatNormal[0] + 1.0f ) * ( 255.0f / 2.0f ) + 0.5f );
- intNormal[1] = idMath::Ftob( ( floatNormal[1] + 1.0f ) * ( 255.0f / 2.0f ) + 0.5f );
- intNormal[2] = idMath::Ftob( ( floatNormal[2] + 1.0f ) * ( 255.0f / 2.0f ) + 0.5f );
- int result = ( ( intNormal[ 0 ] - normalized[ 0 ] ) * ( intNormal[ 0 ] - normalized[ 0 ] ) ) +
- ( ( intNormal[ 1 ] - normalized[ 1 ] ) * ( intNormal[ 1 ] - normalized[ 1 ] ) ) +
- ( ( intNormal[ 2 ] - normalized[ 2 ] ) * ( intNormal[ 2 ] - normalized[ 2 ] ) );
- return result;
- #endif
- }
- /*
- ========================
- NormalDistanceDXT5
- ========================
- */
- int NormalDistanceDXT5( const int *vector, const int *normalized ) {
- #if defined( ID_WIN_X86_ASM )
- int result;
- __asm {
- mov esi, vector
- mov edi, normalized
- #if 0 // object-space
- pshufd xmm0, [esi], R_SHUFFLE_PS( 0, 1, 3, 2 )
- #else
- pshufd xmm0, [esi], R_SHUFFLE_PS( 1, 2, 3, 0 )
- #endif
- cvtdq2ps xmm0, xmm0
- mulps xmm0, SIMD_SSE2_float_scale
- subps xmm0, SIMD_SSE2_float_one
- pand xmm0, SIMD_SSE2_dword_maskFirstThree
- movaps xmm1, xmm0
- mulps xmm1, xmm1
- pshufd xmm2, xmm1, R_SHUFFLE_PS( 2, 3, 0, 1 )
- addps xmm2, xmm1
- pshufd xmm1, xmm2, R_SHUFFLE_PS( 1, 0, 1, 0 )
- addps xmm2, xmm1
- rsqrtps xmm1, xmm2
- mulps xmm2, xmm1
- mulps xmm2, xmm1
- subps xmm2, SIMD_SP_rsqrt_c0
- mulps xmm1, SIMD_SP_rsqrt_c1
- mulps xmm2, xmm1
- mulps xmm0, xmm2
- addps xmm0, SIMD_SSE2_float_one
- mulps xmm0, SIMD_SSE2_float_descale
- addps xmm0, SIMD_SSE2_float_half
- maxps xmm0, SIMD_SSE2_float_zero
- minps xmm0, SIMD_SSE2_float_255
- cvttps2dq xmm0, xmm0
- #if 0 // object-space
- pshufd xmm3, [edi], R_SHUFFLE_PS( 0, 1, 3, 2 )
- #else
- pshufd xmm3, [edi], R_SHUFFLE_PS( 1, 2, 3, 0 )
- #endif
- psubd xmm0, xmm3
- pand xmm0, SIMD_SSE2_dword_maskWords
- pmullw xmm0, xmm0
- pshufd xmm1, xmm0, R_SHUFFLE_PS( 2, 3, 0, 1 )
- paddd xmm0, xmm1
- pshufd xmm1, xmm0, R_SHUFFLE_PS( 1, 0, 1, 0 )
- paddd xmm0, xmm1
- movd result, xmm0
- }
- return result;
- #else
- #if 0 // object-space
- const int c0 = 0;
- const int c1 = 1;
- const int c2 = 3;
- #else
- const int c0 = 1;
- const int c1 = 2;
- const int c2 = 3;
- #endif
- float floatNormal[3];
- byte intNormal[4];
- floatNormal[0] = vector[c0] / 255.0f * 2.0f - 1.0f;
- floatNormal[1] = vector[c1] / 255.0f * 2.0f - 1.0f;
- floatNormal[2] = vector[c2] / 255.0f * 2.0f - 1.0f;
- float rcplen = idMath::InvSqrt( floatNormal[0] * floatNormal[0] + floatNormal[1] * floatNormal[1] + floatNormal[2] * floatNormal[2] );
- floatNormal[0] *= rcplen;
- floatNormal[1] *= rcplen;
- floatNormal[2] *= rcplen;
- intNormal[c0] = idMath::Ftob( ( floatNormal[0] + 1.0f ) / 2.0f * 255.0f + 0.5f );
- intNormal[c1] = idMath::Ftob( ( floatNormal[1] + 1.0f ) / 2.0f * 255.0f + 0.5f );
- intNormal[c2] = idMath::Ftob( ( floatNormal[2] + 1.0f ) / 2.0f * 255.0f + 0.5f );
- int result = ( ( intNormal[ c0 ] - normalized[ c0 ] ) * ( intNormal[ c0 ] - normalized[ c0 ] ) ) +
- ( ( intNormal[ c1 ] - normalized[ c1 ] ) * ( intNormal[ c1 ] - normalized[ c1 ] ) ) +
- ( ( intNormal[ c2 ] - normalized[ c2 ] ) * ( intNormal[ c2 ] - normalized[ c2 ] ) );
- return result;
- #endif
- }
- /*
- ========================
- idDxtEncoder::GetSquareNormalsDXT1Error
- params: colorBlock - 4*4 input tile, 4 bytes per pixel
- paramO: color0 - 4 byte Min color found
- paramO: color1 - 4 byte Max color found
- return: 4 byte color index block
- ========================
- */
- int idDxtEncoder::GetSquareNormalsDXT1Error( const int *colorBlock, const unsigned short color0, const unsigned short color1, int lastError, unsigned int &colorIndices ) const {
- byte byteColors[2][4];
- ALIGN16( int colors[4][4] );
- ColorFrom565( color0, byteColors[0] );
- ColorFrom565( color1, byteColors[1] );
- for ( int i = 0; i < 4; i++ ) {
- colors[0][i] = byteColors[0][i];
- colors[1][i] = byteColors[1][i];
- }
- if ( color0 > color1 ) {
- colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
- colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
- colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
- colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
- colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
- colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
- } else {
- assert( color0 == color1 );
- colors[2][0] = ( 1 * colors[0][0] + 1 * colors[1][0] ) / 2;
- colors[2][1] = ( 1 * colors[0][1] + 1 * colors[1][1] ) / 2;
- colors[2][2] = ( 1 * colors[0][2] + 1 * colors[1][2] ) / 2;
- colors[3][0] = 0;
- colors[3][1] = 0;
- colors[3][2] = 0;
- }
- int error = 0;
- int tempColorIndices[16];
- for ( int i = 0; i < 16; i++ ) {
- unsigned int minDist = MAX_UNSIGNED_TYPE( int );
- for ( int j = 0; j < 4; j++ ) {
- unsigned int dist = NormalDistanceDXT1( &colors[j][0], &colorBlock[i*4] );
- if ( dist < minDist ) {
- minDist = dist;
- tempColorIndices[i] = j;
- }
- }
- // accumulated error
- error += minDist;
- if ( error > lastError ) {
- return error;
- }
- }
- colorIndices = 0;
- for ( int i = 0; i < 16; i++ ) {
- colorIndices |= ( tempColorIndices[i] << (unsigned int)( i << 1 ) );
- }
- return error;
- }
- /*
- ========================
- idDxtEncoder::GetMinMaxNormalsDXT1HQ
- Uses an exhaustive search to find the two RGB colors that produce the least error when used to
- compress the 4x4 block. Also finds the minimum and maximum alpha values.
- params: colorBlock - 4*4 input tile, 4 bytes per pixel
- paramO: minColor - 4 byte Min color found
- paramO: maxColor - 4 byte Max color found
- ========================
- */
- int idDxtEncoder::GetMinMaxNormalsDXT1HQ( const byte *colorBlock, byte *minColor, byte *maxColor, unsigned int &colorIndices, bool noBlack ) const {
- int i;
- int i0, i1, i2, j0, j1, j2;
- unsigned short bestMinColor565 = 0;
- unsigned short bestMaxColor565 = 0;
- byte bboxMin[3], bboxMax[3], minAxisDist[3];
- int error, bestError = MAX_TYPE( int );
- unsigned int tempColorIndices;
- ALIGN16( int intColorBlock[16*4] );
- bboxMin[0] = bboxMin[1] = bboxMin[2] = 128;
- bboxMax[0] = bboxMax[1] = bboxMax[2] = 128;
- // get color bbox
- for ( i = 0; i < 16; i++ ) {
- if ( colorBlock[i*4+0] < bboxMin[0] ) {
- bboxMin[0] = colorBlock[i*4+0];
- }
- if ( colorBlock[i*4+1] < bboxMin[1] ) {
- bboxMin[1] = colorBlock[i*4+1];
- }
- if ( colorBlock[i*4+2] < bboxMin[2] ) {
- bboxMin[2] = colorBlock[i*4+2];
- }
- if ( colorBlock[i*4+0] > bboxMax[0] ) {
- bboxMax[0] = colorBlock[i*4+0];
- }
- if ( colorBlock[i*4+1] > bboxMax[1] ) {
- bboxMax[1] = colorBlock[i*4+1];
- }
- if ( colorBlock[i*4+2] > bboxMax[2] ) {
- bboxMax[2] = colorBlock[i*4+2];
- }
- }
- for ( int i = 0; i < 64; i++ ) {
- intColorBlock[i] = colorBlock[i];
- }
- // decrease range for 565 encoding
- bboxMin[0] >>= 3;
- bboxMin[1] >>= 2;
- bboxMin[2] >>= 3;
- bboxMax[0] >>= 3;
- bboxMax[1] >>= 2;
- bboxMax[2] >>= 3;
- // get the minimum distance the end points of the line must be apart along each axis
- for ( i = 0; i < 3; i++ ) {
- minAxisDist[i] = 0;
- }
- // expand the bounding box
- const int C565_BBOX_EXPAND = 2;
- bboxMin[0] = ( bboxMin[0] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[0] - C565_BBOX_EXPAND;
- bboxMin[1] = ( bboxMin[1] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[1] - C565_BBOX_EXPAND;
- bboxMin[2] = ( bboxMin[2] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[2] - C565_BBOX_EXPAND;
- bboxMax[0] = ( bboxMax[0] >= (255>>3)-C565_BBOX_EXPAND ) ? (255>>3) : bboxMax[0] + C565_BBOX_EXPAND;
- bboxMax[1] = ( bboxMax[1] >= (255>>2)-C565_BBOX_EXPAND ) ? (255>>2) : bboxMax[1] + C565_BBOX_EXPAND;
- bboxMax[2] = ( bboxMax[2] >= (255>>3)-C565_BBOX_EXPAND ) ? (255>>3) : bboxMax[2] + C565_BBOX_EXPAND;
- for ( i0 = bboxMin[0]; i0 <= bboxMax[0]; i0++ ) {
- for ( j0 = bboxMax[0]; j0 >= bboxMin[0]; j0-- ) {
- if ( abs( i0 - j0 ) < minAxisDist[0] ) {
- continue;
- }
- for ( i1 = bboxMin[1]; i1 <= bboxMax[1]; i1++ ) {
- for ( j1 = bboxMax[1]; j1 >= bboxMin[1]; j1-- ) {
- if ( abs( i1 - j1 ) < minAxisDist[1] ) {
- continue;
- }
- for ( i2 = bboxMin[2]; i2 <= bboxMax[2]; i2++ ) {
- for ( j2 = bboxMax[2]; j2 >= bboxMin[2]; j2-- ) {
- if ( abs( i2 - j2 ) < minAxisDist[2] ) {
- continue;
- }
- unsigned short minColor565 = (unsigned short)( ( i0 << 11 ) | ( i1 << 5 ) | ( i2 << 0 ) );
- unsigned short maxColor565 = (unsigned short)( ( j0 << 11 ) | ( j1 << 5 ) | ( j2 << 0 ) );
- if ( !noBlack ) {
- error = GetSquareNormalsDXT1Error( intColorBlock, maxColor565, minColor565, bestError, tempColorIndices );
- if ( error < bestError ) {
- bestError = error;
- bestMinColor565 = minColor565;
- bestMaxColor565 = maxColor565;
- colorIndices = tempColorIndices;
- }
- } else {
- if ( minColor565 <= maxColor565 ) {
- SwapValues( minColor565, maxColor565 );
- }
- }
- error = GetSquareNormalsDXT1Error( intColorBlock, minColor565, maxColor565, bestError, tempColorIndices );
- if ( error < bestError ) {
- bestError = error;
- bestMinColor565 = minColor565;
- bestMaxColor565 = maxColor565;
- colorIndices = tempColorIndices;
- }
- }
- }
- }
- }
- }
- }
- ColorFrom565( bestMinColor565, minColor );
- ColorFrom565( bestMaxColor565, maxColor );
- return bestError;
- }
- /*
- ========================
- idDxtEncoder::GetSquareNormalsDXT5Error
- params: normalBlock - 16 pixel block for which to find normal indexes
- paramO: minNormal - Min normal found
- paramO: maxNormal - Max normal found
- ========================
- */
- int idDxtEncoder::GetSquareNormalsDXT5Error( const int *normalBlock, const byte *minNormal, const byte *maxNormal, int lastError, unsigned int &colorIndices, byte *alphaIndices ) const {
- byte alphas[8];
- byte colors[4][4];
- unsigned short smin = ColorTo565( minNormal );
- unsigned short smax = ColorTo565( maxNormal );
- ColorFrom565( smax, colors[0] );
- ColorFrom565( smin, colors[1] );
- if ( smax > smin ) {
- colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
- colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
- colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
- colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
- colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
- colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
- } else {
- assert( smax == smin );
- colors[2][0] = ( 1 * colors[0][0] + 1 * colors[1][0] ) / 2;
- colors[2][1] = ( 1 * colors[0][1] + 1 * colors[1][1] ) / 2;
- colors[2][2] = ( 1 * colors[0][2] + 1 * colors[1][2] ) / 2;
- colors[3][0] = 0;
- colors[3][1] = 0;
- colors[3][2] = 0;
- }
- alphas[0] = maxNormal[3];
- alphas[1] = minNormal[3];
- if ( maxNormal[3] > minNormal[3] ) {
- alphas[2] = ( 6 * alphas[0] + 1 * alphas[1] ) / 7;
- alphas[3] = ( 5 * alphas[0] + 2 * alphas[1] ) / 7;
- alphas[4] = ( 4 * alphas[0] + 3 * alphas[1] ) / 7;
- alphas[5] = ( 3 * alphas[0] + 4 * alphas[1] ) / 7;
- alphas[6] = ( 2 * alphas[0] + 5 * alphas[1] ) / 7;
- alphas[7] = ( 1 * alphas[0] + 6 * alphas[1] ) / 7;
- } else {
- alphas[2] = ( 4 * alphas[0] + 1 * alphas[1] ) / 5;
- alphas[3] = ( 3 * alphas[0] + 2 * alphas[1] ) / 5;
- alphas[4] = ( 2 * alphas[0] + 3 * alphas[1] ) / 5;
- alphas[5] = ( 1 * alphas[0] + 4 * alphas[1] ) / 5;
- alphas[6] = 0;
- alphas[7] = 255;
- }
- int error = 0;
- int tempColorIndices[16];
- int tempAlphaIndices[16];
- for ( int i = 0; i < 16; i++ ) {
- ALIGN16( int normal[4] );
- unsigned int minDist = MAX_UNSIGNED_TYPE( int );
- for ( int j = 0; j < 4; j++ ) {
- normal[0] = colors[j][0];
- normal[1] = colors[j][1];
- normal[2] = colors[j][2];
- for ( int k = 0; k < 8; k++ ) {
- normal[3] = alphas[k];
- unsigned int dist = NormalDistanceDXT5( normal, &normalBlock[i*4] );
- if ( dist < minDist ) {
- minDist = dist;
- tempColorIndices[i] = j;
- tempAlphaIndices[i] = k;
- }
- }
- }
- error += minDist;
- if ( error >= lastError ) {
- return error;
- }
- }
- alphaIndices[0] = byte( (tempAlphaIndices[ 0] >> 0) | (tempAlphaIndices[ 1] << 3) | (tempAlphaIndices[ 2] << 6) );
- alphaIndices[1] = byte( (tempAlphaIndices[ 2] >> 2) | (tempAlphaIndices[ 3] << 1) | (tempAlphaIndices[ 4] << 4) | (tempAlphaIndices[ 5] << 7) );
- alphaIndices[2] = byte( (tempAlphaIndices[ 5] >> 1) | (tempAlphaIndices[ 6] << 2) | (tempAlphaIndices[ 7] << 5) );
- alphaIndices[3] = byte( (tempAlphaIndices[ 8] >> 0) | (tempAlphaIndices[ 9] << 3) | (tempAlphaIndices[10] << 6) );
- alphaIndices[4] = byte( (tempAlphaIndices[10] >> 2) | (tempAlphaIndices[11] << 1) | (tempAlphaIndices[12] << 4) | (tempAlphaIndices[13] << 7) );
- alphaIndices[5] = byte( (tempAlphaIndices[13] >> 1) | (tempAlphaIndices[14] << 2) | (tempAlphaIndices[15] << 5) );
- colorIndices = 0;
- for ( int i = 0; i < 16; i++ ) {
- colorIndices |= ( tempColorIndices[i] << (unsigned int)( i << 1 ) );
- }
- return error;
- }
- /*
- ========================
- idDxtEncoder::GetMinMaxNormalsDXT5HQ
- Uses an exhaustive search to find the two RGB colors that produce the least error when used to
- compress the 4x4 block. Also finds the minimum and maximum alpha values.
- params: colorBlock - 4*4 input tile, 4 bytes per pixel
- paramO: minColor - 4 byte Min color found
- paramO: maxColor - 4 byte Max color found
- ========================
- */
- int idDxtEncoder::GetMinMaxNormalsDXT5HQ( const byte *colorBlock, byte *minColor, byte *maxColor, unsigned int &colorIndices, byte *alphaIndices ) const {
- int i;
- int i0, i1, i3, j0, j1, j3;
- byte bboxMin[4], bboxMax[4], minAxisDist[4];
- byte tmin[4], tmax[4];
- int error, bestError = MAX_TYPE( int );
- unsigned int tempColorIndices;
- byte tempAlphaIndices[6];
- ALIGN16( int intColorBlock[16*4] );
- bboxMin[0] = bboxMin[1] = bboxMin[2] = bboxMin[3] = 255;
- bboxMax[0] = bboxMax[1] = bboxMax[2] = bboxMax[3] = 0;
- // get color bbox
- for ( i = 0; i < 16; i++ ) {
- if ( colorBlock[i*4+0] < bboxMin[0] ) {
- bboxMin[0] = colorBlock[i*4+0];
- }
- if ( colorBlock[i*4+1] < bboxMin[1] ) {
- bboxMin[1] = colorBlock[i*4+1];
- }
- if ( colorBlock[i*4+2] < bboxMin[2] ) {
- bboxMin[2] = colorBlock[i*4+2];
- }
- if ( colorBlock[i*4+3] < bboxMin[3] ) {
- bboxMin[3] = colorBlock[i*4+3];
- }
- if ( colorBlock[i*4+0] > bboxMax[0] ) {
- bboxMax[0] = colorBlock[i*4+0];
- }
- if ( colorBlock[i*4+1] > bboxMax[1] ) {
- bboxMax[1] = colorBlock[i*4+1];
- }
- if ( colorBlock[i*4+2] > bboxMax[2] ) {
- bboxMax[2] = colorBlock[i*4+2];
- }
- if ( colorBlock[i*4+3] > bboxMax[3] ) {
- bboxMax[3] = colorBlock[i*4+3];
- }
- }
- for ( int i = 0; i < 64; i++ ) {
- intColorBlock[i] = colorBlock[i];
- }
- // decrease range for 565 encoding
- bboxMin[0] >>= 3;
- bboxMin[1] >>= 2;
- bboxMax[0] >>= 3;
- bboxMax[1] >>= 2;
- // get the minimum distance the end points of the line must be apart along each axis
- for ( i = 0; i < 4; i++ ) {
- minAxisDist[i] = 0;
- }
- // expand the bounding box
- const int C565_BBOX_EXPAND = 2;
- const int ALPHA_BBOX_EXPAND = 32;
- bboxMin[0] = ( bboxMin[0] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[0] - C565_BBOX_EXPAND;
- bboxMin[1] = ( bboxMin[1] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[1] - C565_BBOX_EXPAND;
- bboxMin[3] = ( bboxMin[3] <= ALPHA_BBOX_EXPAND ) ? 0 : bboxMin[3] - ALPHA_BBOX_EXPAND;
- bboxMax[0] = ( bboxMax[0] >= (255>>3)-C565_BBOX_EXPAND ) ? (255>>3) : bboxMax[0] + C565_BBOX_EXPAND;
- bboxMax[1] = ( bboxMax[1] >= (255>>2)-C565_BBOX_EXPAND ) ? (255>>2) : bboxMax[1] + C565_BBOX_EXPAND;
- bboxMax[3] = ( bboxMax[3] >= (255)-ALPHA_BBOX_EXPAND ) ? (255) : bboxMax[3] + ALPHA_BBOX_EXPAND;
- for ( i0 = bboxMin[0]; i0 <= bboxMax[0]; i0++ ) {
- for ( j0 = bboxMax[0]; j0 >= bboxMin[0]; j0-- ) {
- if ( abs( i0 - j0 ) < minAxisDist[0] ) {
- continue;
- }
- for ( i1 = bboxMin[1]; i1 <= bboxMax[1]; i1++ ) {
- for ( j1 = bboxMax[1]; j1 >= bboxMin[1]; j1-- ) {
- if ( abs( i1 - j1 ) < minAxisDist[1] ) {
- continue;
- }
- tmin[0] = (byte)j0 << 3;
- tmin[1] = (byte)j1 << 2;
- tmin[2] = 0;
- tmax[0] = (byte)i0 << 3;
- tmax[1] = (byte)i1 << 2;
- tmax[2] = 0;
- for ( i3 = bboxMin[3]; i3 <= bboxMax[3]; i3++ ) {
- for ( j3 = bboxMax[3]; j3 >= bboxMin[3]; j3-- ) {
- if ( abs( i3 - j3 ) < minAxisDist[3] ) {
- continue;
- }
- tmin[3] = (byte)j3;
- tmax[3] = (byte)i3;
- error = GetSquareNormalsDXT5Error( intColorBlock, tmin, tmax, bestError, tempColorIndices, tempAlphaIndices );
- if ( error < bestError ) {
- bestError = error;
- memcpy( minColor, tmin, 4 );
- memcpy( maxColor, tmax, 4 );
- colorIndices = tempColorIndices;
- memcpy( alphaIndices, tempAlphaIndices, 6 );
- }
- tmin[3] = (byte)i3;
- tmax[3] = (byte)j3;
- error = GetSquareNormalsDXT5Error( intColorBlock, tmin, tmax, bestError, tempColorIndices, tempAlphaIndices );
- if ( error < bestError ) {
- bestError = error;
- memcpy( minColor, tmin, 4 );
- memcpy( maxColor, tmax, 4 );
- colorIndices = tempColorIndices;
- memcpy( alphaIndices, tempAlphaIndices, 6 );
- }
- }
- }
- }
- }
- }
- }
- return bestError;
- }
- /*
- ========================
- idDxtEncoder::GetMinMaxNormalsDXT5HQFast
- Uses an exhaustive search to find the two RGB colors that produce the least error when used to
- compress the 4x4 block. Also finds the minimum and maximum alpha values.
- params: colorBlock - 4*4 input tile, 4 bytes per pixel
- paramO: minColor - 4 byte Min color found
- paramO: maxColor - 4 byte Max color found
- ========================
- */
- int idDxtEncoder::GetMinMaxNormalsDXT5HQFast( const byte *colorBlock, byte *minColor, byte *maxColor, unsigned int &colorIndices, byte *alphaIndices ) const {
- int i0, i1, i2, i3, j0, j1, j2, j3;
- byte bboxMin[4], bboxMax[4], minAxisDist[4];
- byte tmin[4], tmax[4];
- int error, bestError = MAX_TYPE( int );
- unsigned int tempColorIndices;
- byte tempAlphaIndices[6];
- ALIGN16( int intColorBlock[16*4] );
- bboxMin[0] = bboxMin[1] = bboxMin[2] = bboxMin[3] = 255;
- bboxMax[0] = bboxMax[1] = bboxMax[2] = bboxMax[3] = 0;
- // get color bbox
- for ( int i = 0; i < 16; i++ ) {
- if ( colorBlock[i*4+0] < bboxMin[0] ) {
- bboxMin[0] = colorBlock[i*4+0];
- }
- if ( colorBlock[i*4+1] < bboxMin[1] ) {
- bboxMin[1] = colorBlock[i*4+1];
- }
- if ( colorBlock[i*4+2] < bboxMin[2] ) {
- bboxMin[2] = colorBlock[i*4+2];
- }
- if ( colorBlock[i*4+3] < bboxMin[3] ) {
- bboxMin[3] = colorBlock[i*4+3];
- }
- if ( colorBlock[i*4+0] > bboxMax[0] ) {
- bboxMax[0] = colorBlock[i*4+0];
- }
- if ( colorBlock[i*4+1] > bboxMax[1] ) {
- bboxMax[1] = colorBlock[i*4+1];
- }
- if ( colorBlock[i*4+2] > bboxMax[2] ) {
- bboxMax[2] = colorBlock[i*4+2];
- }
- if ( colorBlock[i*4+3] > bboxMax[3] ) {
- bboxMax[3] = colorBlock[i*4+3];
- }
- }
- for ( int i = 0; i < 64; i++ ) {
- intColorBlock[i] = colorBlock[i];
- }
- // decrease range for 565 encoding
- bboxMin[0] >>= 3;
- bboxMin[1] >>= 2;
- bboxMin[2] >>= 3;
- bboxMax[0] >>= 3;
- bboxMax[1] >>= 2;
- bboxMax[2] >>= 3;
- bboxMin[3] = 0;
- bboxMax[3] = 255;
- // get the minimum distance the end points of the line must be apart along each axis
- for ( int i = 0; i < 4; i++ ) {
- minAxisDist[i] = 0;
- }
- // expand the bounding box
- const int C565_BBOX_EXPAND = 1;
- const int ALPHA_BBOX_EXPAND = 128;
- #if 0 // object-space
- bboxMin[0] = ( bboxMin[0] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[0] - C565_BBOX_EXPAND;
- bboxMax[0] = ( bboxMax[0] >= (255>>3)-C565_BBOX_EXPAND ) ? (255>>3) : bboxMax[0] + C565_BBOX_EXPAND;
- bboxMin[2] = 0;
- bboxMax[2] = 0;
- #else
- bboxMin[0] = 0;
- bboxMax[0] = 0;
- bboxMin[2] = ( bboxMin[2] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[2] - C565_BBOX_EXPAND;
- bboxMax[2] = ( bboxMax[2] >= (255>>2)-C565_BBOX_EXPAND ) ? (255>>2) : bboxMax[2] + C565_BBOX_EXPAND;
- #endif
- bboxMin[1] = ( bboxMin[1] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[1] - C565_BBOX_EXPAND;
- bboxMax[1] = ( bboxMax[1] >= (255>>2)-C565_BBOX_EXPAND ) ? (255>>2) : bboxMax[1] + C565_BBOX_EXPAND;
- bboxMin[3] = ( bboxMin[3] <= ALPHA_BBOX_EXPAND ) ? 0 : bboxMin[3] - ALPHA_BBOX_EXPAND;
- bboxMax[3] = ( bboxMax[3] >= (255)-ALPHA_BBOX_EXPAND ) ? (255) : bboxMax[3] + ALPHA_BBOX_EXPAND;
- for ( i0 = bboxMin[0]; i0 <= bboxMax[0]; i0++ ) {
- for ( j0 = bboxMax[0]; j0 >= bboxMin[0]; j0-- ) {
- if ( abs( i0 - j0 ) < minAxisDist[0] ) {
- continue;
- }
- for ( i1 = bboxMin[1]; i1 <= bboxMax[1]; i1++ ) {
- for ( j1 = bboxMax[1]; j1 >= bboxMin[1]; j1-- ) {
- if ( abs( i1 - j1 ) < minAxisDist[1] ) {
- continue;
- }
- for ( i2 = bboxMin[2]; i2 <= bboxMax[2]; i2++ ) {
- for ( j2 = bboxMax[2]; j2 >= bboxMin[2]; j2-- ) {
- if ( abs( i2 - j2 ) < minAxisDist[2] ) {
- continue;
- }
- unsigned short minColor565 = (unsigned short)( ( i0 << 11 ) | ( i1 << 5 ) | i2 );
- unsigned short maxColor565 = (unsigned short)( ( j0 << 11 ) | ( j1 << 5 ) | j2 );
- if ( minColor565 > maxColor565 ) {
- SwapValues( minColor565, maxColor565 );
- }
- error = GetSquareNormalsDXT1Error( intColorBlock, maxColor565, minColor565, bestError, tempColorIndices );
- if ( error < bestError ) {
- bestError = error;
- ColorFrom565( minColor565, minColor );
- ColorFrom565( maxColor565, maxColor );
- colorIndices = tempColorIndices;
- }
- }
- }
- }
- }
- }
- }
- bestError = MAX_TYPE( int );
- memcpy( tmin, minColor, 4 );
- memcpy( tmax, maxColor, 4 );
- for ( i3 = bboxMin[3]; i3 <= bboxMax[3]; i3++ ) {
- for ( j3 = bboxMax[3]; j3 >= bboxMin[3]; j3-- ) {
- if ( abs( i3 - j3 ) < minAxisDist[3] ) {
- continue;
- }
- tmin[3] = (byte)j3;
- tmax[3] = (byte)i3;
- error = GetSquareNormalsDXT5Error( intColorBlock, tmin, tmax, bestError, tempColorIndices, tempAlphaIndices );
- if ( error < bestError ) {
- bestError = error;
- memcpy( minColor, tmin, 4 );
- memcpy( maxColor, tmax, 4 );
- colorIndices = tempColorIndices;
- memcpy( alphaIndices, tempAlphaIndices, 6 );
- }
- tmin[3] = (byte)i3;
- tmax[3] = (byte)j3;
- error = GetSquareNormalsDXT5Error( intColorBlock, tmin, tmax, bestError, tempColorIndices, tempAlphaIndices );
- if ( error < bestError ) {
- bestError = error;
- memcpy( minColor, tmin, 4 );
- memcpy( maxColor, tmax, 4 );
- colorIndices = tempColorIndices;
- memcpy( alphaIndices, tempAlphaIndices, 6 );
- }
- }
- }
- return bestError;
- }
- /*
- ========================
- idDxtEncoder::FindColorIndices
- params: colorBlock - 16 pixel block for which find color indexes
- paramO: color0 - Min color found
- paramO: color1 - Max color found
- return: 4 byte color index block
- ========================
- */
- int idDxtEncoder::FindColorIndices( const byte *colorBlock, const unsigned short color0, const unsigned short color1, unsigned int &result ) const {
- int i, j;
- unsigned int indexes[16];
- byte colors[4][4];
- ColorFrom565( color0, colors[0] );
- ColorFrom565( color1, colors[1] );
- if ( color0 > color1 ) {
- colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
- colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
- colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
- colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
- colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
- colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
- } else {
- colors[2][0] = ( 1 * colors[0][0] + 1 * colors[1][0] ) / 2;
- colors[2][1] = ( 1 * colors[0][1] + 1 * colors[1][1] ) / 2;
- colors[2][2] = ( 1 * colors[0][2] + 1 * colors[1][2] ) / 2;
- colors[3][0] = 0;
- colors[3][1] = 0;
- colors[3][2] = 0;
- }
- int error = 0;
- for ( i = 0; i < 16; i++ ) {
- unsigned int minDist = MAX_UNSIGNED_TYPE( int );
- for ( j = 0; j < 4; j++ ) {
- unsigned int dist = ColorDistance( &colorBlock[i*4], &colors[j][0] );
- if ( dist < minDist ) {
- minDist = dist;
- indexes[i] = j;
- }
- }
- // accumulated error
- error += minDist;
- }
- result = 0;
- for ( i = 0; i < 16; i++ ) {
- result |= ( indexes[i] << (unsigned int)( i << 1 ) );
- }
- return error;
- }
- /*
- ========================
- idDxtEncoder::FindAlphaIndices
- params: colorBlock - 16 pixel block for which find alpha indexes
- paramO: alpha0 - Min alpha found
- paramO: alpha1 - Max alpha found
- params: rindexes - 6 byte alpha index block
- return: error metric for this compression
- ========================
- */
- int idDxtEncoder::FindAlphaIndices( const byte *colorBlock, const int alphaOffset, const byte alpha0, const byte alpha1, byte *rindexes ) const {
- int i, j;
- unsigned int indexes[16];
- byte alphas[8];
- alphas[0] = alpha0;
- alphas[1] = alpha1;
- if ( alpha0 > alpha1 ) {
- alphas[2] = ( 6 * alpha0 + 1 * alpha1 ) / 7;
- alphas[3] = ( 5 * alpha0 + 2 * alpha1 ) / 7;
- alphas[4] = ( 4 * alpha0 + 3 * alpha1 ) / 7;
- alphas[5] = ( 3 * alpha0 + 4 * alpha1 ) / 7;
- alphas[6] = ( 2 * alpha0 + 5 * alpha1 ) / 7;
- alphas[7] = ( 1 * alpha0 + 6 * alpha1 ) / 7;
- } else {
- alphas[2] = ( 4 * alpha0 + 1 * alpha1 ) / 5;
- alphas[3] = ( 3 * alpha0 + 2 * alpha1 ) / 5;
- alphas[4] = ( 2 * alpha0 + 3 * alpha1 ) / 5;
- alphas[5] = ( 1 * alpha0 + 4 * alpha1 ) / 5;
- alphas[6] = 0;
- alphas[7] = 255;
- }
- int error = 0;
- for ( i = 0; i < 16; i++ ) {
- unsigned int minDist = MAX_UNSIGNED_TYPE( int );
- byte a = colorBlock[i*4+alphaOffset];
- for ( j = 0; j < 8; j++ ) {
- unsigned int dist = AlphaDistance( a, alphas[j] );
- if ( dist < minDist ) {
- minDist = dist;
- indexes[i] = j;
- }
- }
- error += minDist;
- }
- rindexes[0] = byte( (indexes[ 0] >> 0) | (indexes[ 1] << 3) | (indexes[ 2] << 6) );
- rindexes[1] = byte( (indexes[ 2] >> 2) | (indexes[ 3] << 1) | (indexes[ 4] << 4) | (indexes[ 5] << 7) );
- rindexes[2] = byte( (indexes[ 5] >> 1) | (indexes[ 6] << 2) | (indexes[ 7] << 5) );
- rindexes[3] = byte( (indexes[ 8] >> 0) | (indexes[ 9] << 3) | (indexes[10] << 6) );
- rindexes[4] = byte( (indexes[10] >> 2) | (indexes[11] << 1) | (indexes[12] << 4) | (indexes[13] << 7) );
- rindexes[5] = byte( (indexes[13] >> 1) | (indexes[14] << 2) | (indexes[15] << 5) );
- return error;
- }
- /*
- ========================
- idDxtEncoder::FindCTX1Indices
- params: colorBlock - 16 pixel block for which find color indexes
- paramO: color0 - Min color found
- paramO: color1 - Max color found
- return: 4 byte color index block
- ========================
- */
- int idDxtEncoder::FindCTX1Indices( const byte *colorBlock, const byte *color0, const byte *color1, unsigned int &result ) const {
- int i, j;
- unsigned int indexes[16];
- byte colors[4][4];
- colors[0][0] = color1[0];
- colors[0][1] = color1[1];
- colors[1][0] = color0[0];
- colors[1][1] = color0[1];
- colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
- colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
- colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
- colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
- int error = 0;
- for ( i = 0; i < 16; i++ ) {
- unsigned int minDist = MAX_UNSIGNED_TYPE( int );
- for ( j = 0; j < 4; j++ ) {
- unsigned int dist = CTX1Distance( &colorBlock[i*4], &colors[j][0] );
- if ( dist < minDist ) {
- minDist = dist;
- indexes[i] = j;
- }
- }
- // accumulated error
- error += minDist;
- }
- result = 0;
- for ( i = 0; i < 16; i++ ) {
- result |= ( indexes[i] << (unsigned int)( i << 1 ) );
- }
- return error;
- }
- /*
- ========================
- idDxtEncoder::CompressImageDXT1HQ
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressImageDXT1HQ( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- unsigned int colorIndices1;
- unsigned int colorIndices2;
- byte col1[4];
- byte col2[4];
- int error1;
- int error2;
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- if ( width > 4 && ( width & 3 ) != 0 ) {
- return;
- }
- if ( height > 4 && ( height & 3 ) != 0 ) {
- return;
- }
- if ( width < 4 || height < 4 ) {
- WriteTinyColorDXT1( inBuf, width, height );
- return;
- }
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- GetMinMaxColorsHQ( block, col1, col2, false );
- // Write out color data. Try and find minimum error for the two encoding methods.
- unsigned short scol1 = ColorTo565( col1 );
- unsigned short scol2 = ColorTo565( col2 );
- error1 = FindColorIndices( block, scol1, scol2, colorIndices1 );
- error2 = FindColorIndices( block, scol2, scol1, colorIndices2 );
- if ( error1 < error2 ) {
- EmitUShort( scol1 );
- EmitUShort( scol2 );
- EmitUInt( colorIndices1 );
- } else {
- EmitUShort( scol2 );
- EmitUShort( scol1 );
- EmitUInt( colorIndices2 );
- }
- //idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- //idLib::Printf( "\r100%%\n" );
- }
- /*
- ========================
- idDxtEncoder::CompressImageDXT5HQ
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressImageDXT5HQ( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- byte alphaIndices1[6];
- byte alphaIndices2[6];
- unsigned int colorIndices;
- byte col1[4];
- byte col2[4];
- int error1;
- int error2;
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- if ( width > 4 && ( width & 3 ) != 0 ) {
- return;
- }
- if ( height > 4 && ( height & 3 ) != 0 ) {
- return;
- }
- if ( width < 4 || height < 4 ) {
- WriteTinyColorDXT5( inBuf, width, height );
- return;
- }
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- GetMinMaxColorsHQ( block, col1, col2, true );
- GetMinMaxAlphaHQ( block, 3, col1, col2 );
- // Write out alpha data. Try and find minimum error for the two encoding methods.
- error1 = FindAlphaIndices( block, 3, col1[3], col2[3], alphaIndices1 );
- error2 = FindAlphaIndices( block, 3, col2[3], col1[3], alphaIndices2 );
- if ( error1 < error2 ) {
- EmitByte( col1[3] );
- EmitByte( col2[3] );
- EmitByte( alphaIndices1[0] );
- EmitByte( alphaIndices1[1] );
- EmitByte( alphaIndices1[2] );
- EmitByte( alphaIndices1[3] );
- EmitByte( alphaIndices1[4] );
- EmitByte( alphaIndices1[5] );
- } else {
- EmitByte( col2[3] );
- EmitByte( col1[3] );
- EmitByte( alphaIndices2[0] );
- EmitByte( alphaIndices2[1] );
- EmitByte( alphaIndices2[2] );
- EmitByte( alphaIndices2[3] );
- EmitByte( alphaIndices2[4] );
- EmitByte( alphaIndices2[5] );
- }
- #ifdef NVIDIA_7X_HARDWARE_BUG_FIX
- NV4XHardwareBugFix( col2, col1 );
- #endif
- // Write out color data. Always take the path with 4 interpolated values.
- unsigned short scol1 = ColorTo565( col1 );
- unsigned short scol2 = ColorTo565( col2 );
- EmitUShort( scol1 );
- EmitUShort( scol2 );
- FindColorIndices( block, scol1, scol2, colorIndices );
- EmitUInt( colorIndices );
- //idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- //idLib::Printf( "\r100%%\n" );
- }
- /*
- ========================
- idDxtEncoder::CompressImageCTX1HQ
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressImageCTX1HQ( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- unsigned int colorIndices;
- byte col1[4];
- byte col2[4];
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- if ( width > 4 && ( width & 3 ) != 0 ) {
- return;
- }
- if ( height > 4 && ( height & 3 ) != 0 ) {
- return;
- }
- if ( width < 4 || height < 4 ) {
- WriteTinyColorCTX1DXT5A( inBuf, width, height );
- return;
- }
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- GetMinMaxCTX1HQ( block, col1, col2 );
- EmitByte( col2[0] );
- EmitByte( col2[1] );
- EmitByte( col1[0] );
- EmitByte( col1[1] );
- FindCTX1Indices( block, col1, col2, colorIndices );
- EmitUInt( colorIndices );
- //idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- //idLib::Printf( "\r100%%\n" );
- }
- /*
- ========================
- idDxtEncoder::ScaleYCoCg
- params: colorBlock - 16 pixel block for which find color indexes
- ========================
- */
- void idDxtEncoder::ScaleYCoCg( byte *colorBlock ) const {
- ALIGN16( byte minColor[4] );
- ALIGN16( byte maxColor[4] );
- minColor[0] = minColor[1] = minColor[2] = minColor[3] = 255;
- maxColor[0] = maxColor[1] = maxColor[2] = maxColor[3] = 0;
- for ( int i = 0; i < 16; i++ ) {
- if ( colorBlock[i*4+0] < minColor[0] ) {
- minColor[0] = colorBlock[i*4+0];
- }
- if ( colorBlock[i*4+1] < minColor[1] ) {
- minColor[1] = colorBlock[i*4+1];
- }
- if ( colorBlock[i*4+0] > maxColor[0] ) {
- maxColor[0] = colorBlock[i*4+0];
- }
- if ( colorBlock[i*4+1] > maxColor[1] ) {
- maxColor[1] = colorBlock[i*4+1];
- }
- }
- int m0 = abs( minColor[0] - 128 );
- int m1 = abs( minColor[1] - 128 );
- int m2 = abs( maxColor[0] - 128 );
- int m3 = abs( maxColor[1] - 128 );
- if ( m1 > m0 ) m0 = m1;
- if ( m3 > m2 ) m2 = m3;
- if ( m2 > m0 ) m0 = m2;
- const int s0 = 128 / 2 - 1;
- const int s1 = 128 / 4 - 1;
- int scale = 1 + ( m0 <= s0 ) + 2 * ( m0 <= s1 );
- for ( int i = 0; i < 16; i++ ) {
- colorBlock[i*4+0] = byte( ( colorBlock[i*4+0] - 128 ) * scale + 128 );
- colorBlock[i*4+1] = byte( ( colorBlock[i*4+1] - 128 ) * scale + 128 );
- colorBlock[i*4+2] = byte( ( scale - 1 ) << 3 );
- }
- }
- /*
- ========================
- idDxtEncoder::CompressYCoCgDXT5HQ
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressYCoCgDXT5HQ( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- byte alphaIndices1[6];
- byte alphaIndices2[6];
- unsigned int colorIndices;
- byte col1[4];
- byte col2[4];
- int error1;
- int error2;
- assert( HasConstantValuePer4x4Block( inBuf, width, height, 2 ) );
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- if ( width > 4 && ( width & 3 ) != 0 ) {
- return;
- }
- if ( height > 4 && ( height & 3 ) != 0 ) {
- return;
- }
- if ( width < 4 || height < 4 ) {
- WriteTinyColorDXT5( inBuf, width, height );
- return;
- }
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- ScaleYCoCg( block );
- GetMinMaxColorsHQ( block, col1, col2, true );
- GetMinMaxAlphaHQ( block, 3, col1, col2 );
- // Write out alpha data. Try and find minimum error for the two encoding methods.
- error1 = FindAlphaIndices( block, 3, col1[3], col2[3], alphaIndices1 );
- error2 = FindAlphaIndices( block, 3, col2[3], col1[3], alphaIndices2 );
- if ( error1 < error2 ) {
- EmitByte( col1[3] );
- EmitByte( col2[3] );
- EmitByte( alphaIndices1[0] );
- EmitByte( alphaIndices1[1] );
- EmitByte( alphaIndices1[2] );
- EmitByte( alphaIndices1[3] );
- EmitByte( alphaIndices1[4] );
- EmitByte( alphaIndices1[5] );
- } else {
- EmitByte( col2[3] );
- EmitByte( col1[3] );
- EmitByte( alphaIndices2[0] );
- EmitByte( alphaIndices2[1] );
- EmitByte( alphaIndices2[2] );
- EmitByte( alphaIndices2[3] );
- EmitByte( alphaIndices2[4] );
- EmitByte( alphaIndices2[5] );
- }
- #ifdef NVIDIA_7X_HARDWARE_BUG_FIX
- NV4XHardwareBugFix( col2, col1 );
- #endif
- // Write out color data. Always take the path with 4 interpolated values.
- unsigned short scol1 = ColorTo565( col1 );
- unsigned short scol2 = ColorTo565( col2 );
- EmitUShort( scol1 );
- EmitUShort( scol2 );
- FindColorIndices( block, scol1, scol2, colorIndices );
- EmitUInt( colorIndices );
- //idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- //idLib::Printf( "\r100%%\n" );
- }
- /*
- ========================
- idDxtEncoder::CompressYCoCgCTX1DXT5AHQ
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressYCoCgCTX1DXT5AHQ( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- byte alphaIndices1[6];
- byte alphaIndices2[6];
- unsigned int colorIndices;
- byte col1[4];
- byte col2[4];
- int error1;
- int error2;
- assert( HasConstantValuePer4x4Block( inBuf, width, height, 2 ) );
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- if ( width > 4 && ( width & 3 ) != 0 ) {
- return;
- }
- if ( height > 4 && ( height & 3 ) != 0 ) {
- return;
- }
- if ( width < 4 || height < 4 ) {
- WriteTinyColorCTX1DXT5A( inBuf, width, height );
- return;
- }
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- GetMinMaxAlphaHQ( block, 3, col1, col2 );
- // Write out alpha data. Try and find minimum error for the two encoding methods.
- error1 = FindAlphaIndices( block, 3, col1[3], col2[3], alphaIndices1 );
- error2 = FindAlphaIndices( block, 3, col2[3], col1[3], alphaIndices2 );
- if ( error1 < error2 ) {
- EmitByte( col1[3] );
- EmitByte( col2[3] );
- EmitByte( alphaIndices1[0] );
- EmitByte( alphaIndices1[1] );
- EmitByte( alphaIndices1[2] );
- EmitByte( alphaIndices1[3] );
- EmitByte( alphaIndices1[4] );
- EmitByte( alphaIndices1[5] );
- } else {
- EmitByte( col2[3] );
- EmitByte( col1[3] );
- EmitByte( alphaIndices2[0] );
- EmitByte( alphaIndices2[1] );
- EmitByte( alphaIndices2[2] );
- EmitByte( alphaIndices2[3] );
- EmitByte( alphaIndices2[4] );
- EmitByte( alphaIndices2[5] );
- }
- GetMinMaxCTX1HQ( block, col1, col2 );
- EmitByte( col2[0] );
- EmitByte( col2[1] );
- EmitByte( col1[0] );
- EmitByte( col1[1] );
- FindCTX1Indices( block, col1, col2, colorIndices );
- EmitUInt( colorIndices );
- //idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- //idLib::Printf( "\r100%%\n" );
- }
- /*
- ========================
- idDxtEncoder::RotateNormalsDXT1
- ========================
- */
- void idDxtEncoder::RotateNormalsDXT1( byte *block ) const {
- byte rotatedBlock[64];
- byte col1[4];
- byte col2[4];
- int bestError = MAX_TYPE( int );
- int bestRotation = 0;
- for ( int i = 0; i < 32; i += 1 ) {
- int r = ( i << 3 ) | ( i >> 2 );
- float angle = ( r / 255.0f ) * idMath::PI;
- float s = sin( angle );
- float c = cos( angle );
- for ( int j = 0; j < 16; j++ ) {
- float x = block[j*4+0] / 255.0f * 2.0f - 1.0f;
- float y = block[j*4+1] / 255.0f * 2.0f - 1.0f;
- float rx = c * x - s * y;
- float ry = s * x + c * y;
- rotatedBlock[j*4+0] = idMath::Ftob( ( rx + 1.0f ) / 2.0f * 255.0f );
- rotatedBlock[j*4+1] = idMath::Ftob( ( ry + 1.0f ) / 2.0f * 255.0f );
- }
- int error = GetMinMaxColorsHQ( rotatedBlock, col1, col2, true );
- if ( error < bestError ) {
- bestError = error;
- bestRotation = r;
- }
- }
- float angle = ( bestRotation / 255.0f ) * idMath::PI;
- float s = sin( angle );
- float c = cos( angle );
- for ( int j = 0; j < 16; j++ ) {
- float x = block[j*4+0] / 255.0f * 2.0f - 1.0f;
- float y = block[j*4+1] / 255.0f * 2.0f - 1.0f;
- float rx = c * x - s * y;
- float ry = s * x + c * y;
- block[j*4+0] = idMath::Ftob( ( rx + 1.0f ) / 2.0f * 255.0f );
- block[j*4+1] = idMath::Ftob( ( ry + 1.0f ) / 2.0f * 255.0f );
- block[j*4+2] = (byte)bestRotation;
- }
- }
- /*
- ========================
- idDxtEncoder::CompressNormalMapDXT1HQ
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressNormalMapDXT1HQ( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- unsigned int colorIndices;
- byte col1[4];
- byte col2[4];
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- if ( width > 4 && ( width & 3 ) != 0 ) {
- return;
- }
- if ( height > 4 && ( height & 3 ) != 0 ) {
- return;
- }
- if ( width < 4 || height < 4 ) {
- WriteTinyColorDXT1( inBuf, width, height );
- return;
- }
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- for ( int k = 0; k < 16; k++ ) {
- block[k*4+2] = 0;
- }
- GetMinMaxColorsHQ( block, col1, col2, true );
- // Write out color data. Always take the path with 4 interpolated values.
- unsigned short scol1 = ColorTo565( col1 );
- unsigned short scol2 = ColorTo565( col2 );
- EmitUShort( scol1 );
- EmitUShort( scol2 );
- FindColorIndices( block, scol1, scol2, colorIndices );
- EmitUInt( colorIndices );
- //idLib::Printf( "\r%3d%%", ( j * width + i * 4 ) * 100 / ( width * height ) );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- //idLib::Printf( "\r100%%\n" );
- }
- /*
- ========================
- idDxtEncoder::CompressNormalMapDXT1RenormalizeHQ
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressNormalMapDXT1RenormalizeHQ( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- unsigned int colorIndices;
- byte col1[4];
- byte col2[4];
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- if ( width > 4 && ( width & 3 ) != 0 ) {
- return;
- }
- if ( height > 4 && ( height & 3 ) != 0 ) {
- return;
- }
- if ( width < 4 || height < 4 ) {
- WriteTinyColorDXT1( inBuf, width, height );
- return;
- }
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- // clear alpha channel
- for ( int k = 0; k < 16; k++ ) {
- block[k*4+3] = 0;
- }
- GetMinMaxNormalsDXT1HQ( block, col1, col2, colorIndices, true );
- // Write out color data. Always take the path with 4 interpolated values.
- unsigned short scol1 = ColorTo565( col1 );
- unsigned short scol2 = ColorTo565( col2 );
- EmitUShort( scol1 );
- EmitUShort( scol2 );
- EmitUInt( colorIndices );
- ////idLib::Printf( "\r%3d%%", ( j * width + i * 4 ) * 100 / ( width * height ) );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- ////idLib::Printf( "\r100%%\n" );
- }
- #define USE_SCALE 1
- #define USE_BIAS 1
- static int c_blocks;
- static int c_scaled;
- static int c_scaled2x;
- static int c_scaled4x;
- static int c_differentBias;
- static int c_biasHelped;
- /*
- ========================
- idDxtEncoder::BiasScaleNormalY
- * scale2x = 33%
- * scale4x = 23%
- * bias + scale2x = 30%
- * bias + scale4x = 55%
- ========================
- */
- void idDxtEncoder::BiasScaleNormalY( byte *colorBlock ) const {
- byte minColor = 255;
- byte maxColor = 0;
- for ( int i = 0; i < 16; i++ ) {
- if ( colorBlock[i*4+1] < minColor ) {
- minColor = colorBlock[i*4+1];
- }
- if ( colorBlock[i*4+1] > maxColor ) {
- maxColor = colorBlock[i*4+1];
- }
- }
- int bestBias = 128;
- int bestRange = Max( abs( minColor - bestBias ), abs( maxColor - bestBias ) );
- #if USE_BIAS
- for ( int i = 0; i < 32; i++ ) {
- int bias = ( ( i << 3 ) | ( i >> 2 ) ) - 4;
- int range = Max( abs( minColor - bias ), abs( maxColor - bias ) );
- if ( range < bestRange ) {
- bestRange = range;
- bestBias = bias;
- }
- }
- #endif
- const int s0 = 128 / 2 - 1;
- const int s1 = 128 / 4 - 1;
- #if USE_SCALE
- int scale = 1 + ( bestRange <= s0 ) + 2 * ( bestRange <= s1 );
- #else
- int scale = 1;
- #endif
- if ( scale == 1 ) {
- bestBias = 128;
- } else {
- c_scaled++;
- if ( scale == 2 ) c_scaled2x++;
- if ( scale == 4 ) c_scaled4x++;
- if ( bestBias != 128 ) {
- c_differentBias++;
- int r = Max( abs( minColor - 128 ), abs( maxColor - 128 ) );
- int s = 1 + ( r <= s0 ) + 2 * ( r <= s1 );
- if ( scale > s ) {
- c_biasHelped++;
- }
- }
- }
- c_blocks++;
- for ( int i = 0; i < 16; i++ ) {
- colorBlock[i*4+0] = byte( bestBias + 4 );
- colorBlock[i*4+1] = byte( ( colorBlock[i*4+1] - bestBias ) * scale + 128 );
- colorBlock[i*4+2] = byte( ( scale - 1 ) << 3 );
- }
- }
- /*
- ========================
- idDxtEncoder::RotateNormalsDXT5
- ========================
- */
- void idDxtEncoder::RotateNormalsDXT5( byte *block ) const {
- byte rotatedBlock[64];
- byte col1[4];
- byte col2[4];
- int bestError = MAX_TYPE( int );
- int bestRotation = 0;
- int bestScale = 1;
- for ( int i = 0; i < 32; i += 1 ) {
- int r = ( i << 3 ) | ( i >> 2 );
- float angle = ( r / 255.0f ) * idMath::PI;
- float s = sin( angle );
- float c = cos( angle );
- for ( int j = 0; j < 16; j++ ) {
- float x = block[j*4+3] / 255.0f * 2.0f - 1.0f;
- float y = block[j*4+1] / 255.0f * 2.0f - 1.0f;
- float rx = c * x - s * y;
- float ry = s * x + c * y;
- rotatedBlock[j*4+3] = idMath::Ftob( ( rx + 1.0f ) / 2.0f * 255.0f );
- rotatedBlock[j*4+1] = idMath::Ftob( ( ry + 1.0f ) / 2.0f * 255.0f );
- }
- #if USE_SCALE
- byte minColor = 255;
- byte maxColor = 0;
- for ( int j = 0; j < 16; j++ ) {
- if ( rotatedBlock[j*4+1] < minColor ) {
- minColor = rotatedBlock[j*4+1];
- }
- if ( rotatedBlock[j*4+1] > maxColor ) {
- maxColor = rotatedBlock[j*4+1];
- }
- }
- const int s0 = 128 / 2 - 1;
- const int s1 = 128 / 4 - 1;
- int range = Max( abs( minColor - 128 ), abs( maxColor - 128 ) );
- int scale = 1 + ( range <= s0 ) + 2 * ( range <= s1 );
- for ( int j = 0; j < 16; j++ ) {
- rotatedBlock[j*4+1] = byte( ( rotatedBlock[j*4+1] - 128 ) * scale + 128 );
- }
- #endif
- int errorY = GetMinMaxNormalYHQ( rotatedBlock, col1, col2, true, scale );
- int errorX = GetMinMaxAlphaHQ( rotatedBlock, 3, col1, col2 );
- int error = errorX + errorY;
- if ( error < bestError ) {
- bestError = error;
- bestRotation = r;
- bestScale = scale;
- }
- }
- float angle = ( bestRotation / 255.0f ) * idMath::PI;
- float s = sin( angle );
- float c = cos( angle );
- for ( int j = 0; j < 16; j++ ) {
- float x = block[j*4+3] / 255.0f * 2.0f - 1.0f;
- float y = block[j*4+1] / 255.0f * 2.0f - 1.0f;
- float rx = c * x - s * y;
- float ry = s * x + c * y;
- block[j*4+0] = (byte)bestRotation;
- block[j*4+1] = idMath::Ftob( ( ry + 1.0f ) / 2.0f * 255.0f );
- block[j*4+3] = idMath::Ftob( ( rx + 1.0f ) / 2.0f * 255.0f );
- #if USE_SCALE
- block[j*4+1] = byte( ( block[j*4+1] - 128 ) * bestScale + 128 );
- block[j*4+2] = byte( ( bestScale - 1 ) << 3 );
- #endif
- }
- }
- /*
- ========================
- idDxtEncoder::CompressNormalMapDXT5HQ
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressNormalMapDXT5HQ( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- byte alphaIndices1[6];
- byte alphaIndices2[6];
- unsigned int colorIndices;
- byte col1[4];
- byte col2[4];
- int error1;
- int error2;
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- if ( width > 4 && ( width & 3 ) != 0 ) {
- return;
- }
- if ( height > 4 && ( height & 3 ) != 0 ) {
- return;
- }
- if ( width < 4 || height < 4 ) {
- WriteTinyColorDXT5( inBuf, width, height );
- return;
- }
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- // swizzle components
- for ( int k = 0; k < 16; k++ ) {
- block[k*4+3] = block[k*4+0];
- block[k*4+0] = 0;
- block[k*4+2] = 0;
- }
- //BiasScaleNormalY( block );
- //RotateNormalsDXT5( block );
- GetMinMaxNormalYHQ( block, col1, col2, true, 1 );
- GetMinMaxAlphaHQ( block, 3, col1, col2 );
- // Write out alpha data. Try and find minimum error for the two encoding methods.
- error1 = FindAlphaIndices( block, 3, col1[3], col2[3], alphaIndices1 );
- error2 = FindAlphaIndices( block, 3, col2[3], col1[3], alphaIndices2 );
- if ( error1 < error2 ) {
- EmitByte( col1[3] );
- EmitByte( col2[3] );
- EmitByte( alphaIndices1[0] );
- EmitByte( alphaIndices1[1] );
- EmitByte( alphaIndices1[2] );
- EmitByte( alphaIndices1[3] );
- EmitByte( alphaIndices1[4] );
- EmitByte( alphaIndices1[5] );
- } else {
- EmitByte( col2[3] );
- EmitByte( col1[3] );
- EmitByte( alphaIndices2[0] );
- EmitByte( alphaIndices2[1] );
- EmitByte( alphaIndices2[2] );
- EmitByte( alphaIndices2[3] );
- EmitByte( alphaIndices2[4] );
- EmitByte( alphaIndices2[5] );
- }
- #ifdef NVIDIA_7X_HARDWARE_BUG_FIX
- NV4XHardwareBugFix( col2, col1 );
- #endif
- // Write out color data. Always take the path with 4 interpolated values.
- unsigned short scol1 = ColorTo565( col1 );
- unsigned short scol2 = ColorTo565( col2 );
- EmitUShort( scol1 );
- EmitUShort( scol2 );
- FindColorIndices( block, scol1, scol2, colorIndices );
- EmitUInt( colorIndices );
- //idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- //idLib::Printf( "\r100%%\n" );
- }
- /*
- ========================
- idDxtEncoder::CompressNormalMapDXT5RenormalizeHQ
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressNormalMapDXT5RenormalizeHQ( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- unsigned int colorIndices;
- byte alphaIndices[6];
- byte col1[4];
- byte col2[4];
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- if ( width > 4 && ( width & 3 ) != 0 ) {
- return;
- }
- if ( height > 4 && ( height & 3 ) != 0 ) {
- return;
- }
- if ( width < 4 || height < 4 ) {
- WriteTinyColorDXT5( inBuf, width, height );
- return;
- }
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- // swizzle components
- for ( int k = 0; k < 16; k++ ) {
- #if 0 // object-space
- block[k*4+3] = block[k*4+2];
- block[k*4+2] = 0;
- #else
- block[k*4+3] = block[k*4+0];
- block[k*4+0] = 0;
- #endif
- }
- GetMinMaxNormalsDXT5HQFast( block, col1, col2, colorIndices, alphaIndices );
- EmitByte( col2[3] );
- EmitByte( col1[3] );
- EmitByte( alphaIndices[0] );
- EmitByte( alphaIndices[1] );
- EmitByte( alphaIndices[2] );
- EmitByte( alphaIndices[3] );
- EmitByte( alphaIndices[4] );
- EmitByte( alphaIndices[5] );
- unsigned short scol1 = ColorTo565( col1 );
- unsigned short scol2 = ColorTo565( col2 );
- EmitUShort( scol2 );
- EmitUShort( scol1 );
- EmitUInt( colorIndices );
- ////idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- ////idLib::Printf( "\r100%%\n" );
- }
- /*
- ========================
- idDxtEncoder::CompressNormalMapDXN2HQ
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressNormalMapDXN2HQ( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- byte alphaIndices1[6];
- byte alphaIndices2[6];
- byte col1[4];
- byte col2[4];
- int error1;
- int error2;
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- if ( width > 4 && ( width & 3 ) != 0 ) {
- return;
- }
- if ( height > 4 && ( height & 3 ) != 0 ) {
- return;
- }
- if ( width < 4 || height < 4 ) {
- WriteTinyColorDXT5( inBuf, width, height );
- return;
- }
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- for ( int k = 0; k < 2; k++ ) {
- GetMinMaxAlphaHQ( block, k, col1, col2 );
- // Write out alpha data. Try and find minimum error for the two encoding methods.
- error1 = FindAlphaIndices( block, k, col1[k], col2[k], alphaIndices1 );
- error2 = FindAlphaIndices( block, k, col2[k], col1[k], alphaIndices2 );
- if ( error1 < error2 ) {
- EmitByte( col1[k] );
- EmitByte( col2[k] );
- EmitByte( alphaIndices1[0] );
- EmitByte( alphaIndices1[1] );
- EmitByte( alphaIndices1[2] );
- EmitByte( alphaIndices1[3] );
- EmitByte( alphaIndices1[4] );
- EmitByte( alphaIndices1[5] );
- } else {
- EmitByte( col2[k] );
- EmitByte( col1[k] );
- EmitByte( alphaIndices2[0] );
- EmitByte( alphaIndices2[1] );
- EmitByte( alphaIndices2[2] );
- EmitByte( alphaIndices2[3] );
- EmitByte( alphaIndices2[4] );
- EmitByte( alphaIndices2[5] );
- }
- }
- //idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- //idLib::Printf( "\r100%%\n" );
- }
- /*
- ========================
- idDxtEncoder::GetMinMaxBBox
- Takes the extents of the bounding box of the colors in the 4x4 block in RGB space.
- Also finds the minimum and maximum alpha values.
- params: colorBlock - 4*4 input tile, 4 bytes per pixel
- paramO: minColor - 4 byte Min color found
- paramO: maxColor - 4 byte Max color found
- ========================
- */
- ID_INLINE void idDxtEncoder::GetMinMaxBBox( const byte *colorBlock, byte *minColor, byte *maxColor ) const {
- minColor[0] = minColor[1] = minColor[2] = minColor[3] = 255;
- maxColor[0] = maxColor[1] = maxColor[2] = maxColor[3] = 0;
- for ( int i = 0; i < 16; i++ ) {
- if ( colorBlock[i*4+0] < minColor[0] ) {
- minColor[0] = colorBlock[i*4+0];
- }
- if ( colorBlock[i*4+1] < minColor[1] ) {
- minColor[1] = colorBlock[i*4+1];
- }
- if ( colorBlock[i*4+2] < minColor[2] ) {
- minColor[2] = colorBlock[i*4+2];
- }
- if ( colorBlock[i*4+3] < minColor[3] ) {
- minColor[3] = colorBlock[i*4+3];
- }
- if ( colorBlock[i*4+0] > maxColor[0] ) {
- maxColor[0] = colorBlock[i*4+0];
- }
- if ( colorBlock[i*4+1] > maxColor[1] ) {
- maxColor[1] = colorBlock[i*4+1];
- }
- if ( colorBlock[i*4+2] > maxColor[2] ) {
- maxColor[2] = colorBlock[i*4+2];
- }
- if ( colorBlock[i*4+3] > maxColor[3] ) {
- maxColor[3] = colorBlock[i*4+3];
- }
- }
- }
- /*
- ========================
- idDxtEncoder::InsetColorsBBox
- ========================
- */
- ID_INLINE void idDxtEncoder::InsetColorsBBox( byte *minColor, byte *maxColor ) const {
- byte inset[4];
- inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_COLOR_SHIFT;
- inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_COLOR_SHIFT;
- inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_COLOR_SHIFT;
- inset[3] = ( maxColor[3] - minColor[3] ) >> INSET_ALPHA_SHIFT;
- minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
- minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
- minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255;
- minColor[3] = ( minColor[3] + inset[3] <= 255 ) ? minColor[3] + inset[3] : 255;
- maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
- maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
- maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0;
- maxColor[3] = ( maxColor[3] >= inset[3] ) ? maxColor[3] - inset[3] : 0;
- }
- /*
- ========================
- idDxtEncoder::SelectColorsDiagonal
- ========================
- */
- void idDxtEncoder::SelectColorsDiagonal( const byte *colorBlock, byte *minColor, byte *maxColor ) const {
- byte mid0 = byte( ( (int) minColor[0] + maxColor[0] + 1 ) >> 1 );
- byte mid1 = byte( ( (int) minColor[1] + maxColor[1] + 1 ) >> 1 );
- byte mid2 = byte( ( (int) minColor[2] + maxColor[2] + 1 ) >> 1 );
- #if 0
- // using the covariance is the best way to select the diagonal
- int side0 = 0;
- int side1 = 0;
- for ( int i = 0; i < 16; i++ ) {
- int b0 = colorBlock[i*4+0] - mid0;
- int b1 = colorBlock[i*4+1] - mid1;
- int b2 = colorBlock[i*4+2] - mid2;
- side0 += ( b0 * b1 );
- side1 += ( b1 * b2 );
- }
- byte mask0 = -( side0 < 0 );
- byte mask1 = -( side1 < 0 );
- #else
- // calculating the covariance of just the sign bits is much faster and gives almost the same result
- int side0 = 0;
- int side1 = 0;
- for ( int i = 0; i < 16; i++ ) {
- byte b0 = colorBlock[i*4+0] >= mid0;
- byte b1 = colorBlock[i*4+1] >= mid1;
- byte b2 = colorBlock[i*4+2] >= mid2;
- side0 += ( b0 ^ b1 );
- side1 += ( b1 ^ b2 );
- }
- byte mask0 = -( side0 > 8 );
- byte mask1 = -( side1 > 8 );
- #endif
- byte c0 = minColor[0];
- byte c1 = maxColor[0];
- byte c2 = minColor[2];
- byte c3 = maxColor[2];
- c0 ^= c1;
- mask0 &= c0;
- c1 ^= mask0;
- c0 ^= c1;
- c2 ^= c3;
- mask1 &= c2;
- c3 ^= mask1;
- c2 ^= c3;
- minColor[0] = c0;
- maxColor[0] = c1;
- minColor[2] = c2;
- maxColor[2] = c3;
- if ( ColorTo565( minColor ) > ColorTo565( maxColor ) ) {
- SwapValues( minColor[0], maxColor[0] );
- SwapValues( minColor[1], maxColor[1] );
- SwapValues( minColor[2], maxColor[2] );
- }
- }
- /*
- ========================
- idDxtEncoder::EmitColorIndices
- params: colorBlock - 16 pixel block for which find color indexes
- paramO: minColor - Min color found
- paramO: maxColor - Max color found
- return: 4 byte color index block
- ========================
- */
- void idDxtEncoder::EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor ) {
- #if 1
- ALIGN16( uint16 colors[4][4] );
- unsigned int result = 0;
- colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
- colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
- colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
- colors[0][3] = 0;
- colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
- colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
- colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
- colors[1][3] = 0;
- colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
- colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
- colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
- colors[2][3] = 0;
- colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
- colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
- colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
- colors[3][3] = 0;
- // uses sum of absolute differences instead of squared distance to find the best match
- for ( int i = 15; i >= 0; i-- ) {
- int c0, c1, c2, c3, m, d0, d1, d2, d3;
- c0 = colorBlock[i*4+0];
- c1 = colorBlock[i*4+1];
- c2 = colorBlock[i*4+2];
- c3 = colorBlock[i*4+3];
- m = colors[0][0] - c0;
- d0 = abs( m );
- m = colors[1][0] - c0;
- d1 = abs( m );
- m = colors[2][0] - c0;
- d2 = abs( m );
- m = colors[3][0] - c0;
- d3 = abs( m );
- m = colors[0][1] - c1;
- d0 += abs( m );
- m = colors[1][1] - c1;
- d1 += abs( m );
- m = colors[2][1] - c1;
- d2 += abs( m );
- m = colors[3][1] - c1;
- d3 += abs( m );
- m = colors[0][2] - c2;
- d0 += abs( m );
- m = colors[1][2] - c2;
- d1 += abs( m );
- m = colors[2][2] - c2;
- d2 += abs( m );
- m = colors[3][2] - c2;
- d3 += abs( m );
- #if 0
- int b0 = d0 > d2;
- int b1 = d1 > d3;
- int b2 = d0 > d3;
- int b3 = d1 > d2;
- int b4 = d0 > d1;
- int b5 = d2 > d3;
- result |= ( ( !b3 & b4 ) | ( b2 & b5 ) | ( ( ( b0 & b3 ) | ( b1 & b2 ) ) << 1 ) ) << ( i << 1 );
- #else
- bool b0 = d0 > d3;
- bool b1 = d1 > d2;
- bool b2 = d0 > d2;
- bool b3 = d1 > d3;
- bool b4 = d2 > d3;
- int x0 = b1 & b2;
- int x1 = b0 & b3;
- int x2 = b0 & b4;
- result |= ( x2 | ( ( x0 | x1 ) << 1 ) ) << ( i << 1 );
- #endif
- }
- EmitUInt( result );
- #elif 1
- byte colors[4][4];
- unsigned int indexes[16];
- colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 6 );
- colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 5 );
- colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 6 );
- colors[0][3] = 0;
- colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 6 );
- colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 5 );
- colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 6 );
- colors[1][3] = 0;
- colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
- colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
- colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
- colors[2][3] = 0;
- colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
- colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
- colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
- colors[3][3] = 0;
- for ( int i = 0; i < 16; i++ ) {
- int c0, c1, c2, m, d, minDist;
- c0 = colorBlock[i*4+0];
- c1 = colorBlock[i*4+1];
- c2 = colorBlock[i*4+2];
- m = colors[0][0] - c0;
- d = m * m;
- m = colors[0][1] - c1;
- d += m * m;
- m = colors[0][2] - c2;
- d += m * m;
- minDist = d;
- indexes[i] = 0;
- m = colors[1][0] - c0;
- d = m * m;
- m = colors[1][1] - c1;
- d += m * m;
- m = colors[1][2] - c2;
- d += m * m;
- if ( d < minDist ) {
- minDist = d;
- indexes[i] = 1;
- }
- m = colors[2][0] - c0;
- d = m * m;
- m = colors[2][1] - c1;
- d += m * m;
- m = colors[2][2] - c2;
- d += m * m;
- if ( d < minDist ) {
- minDist = d;
- indexes[i] = 2;
- }
- m = colors[3][0] - c0;
- d = m * m;
- m = colors[3][1] - c1;
- d += m * m;
- m = colors[3][2] - c2;
- d += m * m;
- if ( d < minDist ) {
- minDist = d;
- indexes[i] = 3;
- }
- }
- unsigned int result = 0;
- for ( int i = 0; i < 16; i++ ) {
- result |= ( indexes[i] << (unsigned int)( i << 1 ) );
- }
- EmitUInt( result );
- #else
- byte colors[4][4];
- unsigned int indexes[16];
- colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 6 );
- colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 5 );
- colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 6 );
- colors[0][3] = 0;
- colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 6 );
- colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 5 );
- colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 6 );
- colors[1][3] = 0;
- colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
- colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
- colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
- colors[2][3] = 0;
- colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
- colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
- colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
- colors[3][3] = 0;
- for ( int i = 0; i < 16; i++ ) {
- unsigned int minDist = (255*255)*4;
- for ( int j = 0; j < 4; j++ ) {
- unsigned int dist = ColorDistance( &colorBlock[i*4], &colors[j][0] );
- if ( dist < minDist ) {
- minDist = dist;
- indexes[i] = j;
- }
- }
- }
- unsigned int result = 0;
- for ( int i = 0; i < 16; i++ ) {
- result |= ( indexes[i] << (unsigned int)( i << 1 ) );
- }
- EmitUInt( result );
- #endif
- }
- /*
- ========================
- idDxtEncoder::EmitColorAlphaIndices
- params: colorBlock - 16 pixel block for which find color indexes
- paramO: minColor - Min color found
- paramO: maxColor - Max color found
- return: 4 byte color index block
- ========================
- */
- void idDxtEncoder::EmitColorAlphaIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor ) {
- ALIGN16( uint16 colors[4][4] );
- unsigned int result = 0;
- colors[0][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
- colors[0][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
- colors[0][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
- colors[0][3] = 255;
- colors[1][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
- colors[1][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
- colors[1][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
- colors[1][3] = 255;
- colors[2][0] = ( colors[0][0] + colors[1][0] ) / 2;
- colors[2][1] = ( colors[0][1] + colors[1][1] ) / 2;
- colors[2][2] = ( colors[0][2] + colors[1][2] ) / 2;
- colors[2][3] = 255;
- colors[3][0] = 0;
- colors[3][1] = 0;
- colors[3][2] = 0;
- colors[3][3] = 0;
- // uses sum of absolute differences instead of squared distance to find the best match
- for ( int i = 15; i >= 0; i-- ) {
- int c0, c1, c2, c3, m, d0, d1, d2;
- c0 = colorBlock[i*4+0];
- c1 = colorBlock[i*4+1];
- c2 = colorBlock[i*4+2];
- c3 = colorBlock[i*4+3];
- m = colors[0][0] - c0;
- d0 = abs( m );
- m = colors[1][0] - c0;
- d1 = abs( m );
- m = colors[2][0] - c0;
- d2 = abs( m );
- m = colors[0][1] - c1;
- d0 += abs( m );
- m = colors[1][1] - c1;
- d1 += abs( m );
- m = colors[2][1] - c1;
- d2 += abs( m );
- m = colors[0][2] - c2;
- d0 += abs( m );
- m = colors[1][2] - c2;
- d1 += abs( m );
- m = colors[2][2] - c2;
- d2 += abs( m );
- unsigned int b0 = d2 > d0;
- unsigned int b1 = d2 > d1;
- unsigned int b2 = d1 > d0;
- unsigned int b3 = c3 < 128;
- result |= ( ( ( b0 & b1 | b3 ) << 1 ) | ( b2 ^ b1 | b3 ) ) << ( i << 1 );
- }
- EmitUInt( result );
- }
- /*
- ========================
- idDxtEncoder::EmitCTX1Indices
- params: colorBlock - 16 pixel block for which find color indexes
- paramO: minColor - Min color found
- paramO: maxColor - Max color found
- return: 4 byte color index block
- ========================
- */
- void idDxtEncoder::EmitCTX1Indices( const byte *colorBlock, const byte *minColor, const byte *maxColor ) {
- ALIGN16( uint16 colors[4][2] );
- unsigned int result = 0;
- colors[0][0] = maxColor[0];
- colors[0][1] = maxColor[1];
- colors[1][0] = minColor[0];
- colors[1][1] = minColor[1];
- colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
- colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
- colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
- colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
- for ( int i = 15; i >= 0; i-- ) {
- int c0, c1, m, d0, d1, d2, d3;
- c0 = colorBlock[i*4+0];
- c1 = colorBlock[i*4+1];
- m = colors[0][0] - c0;
- d0 = abs( m );
- m = colors[1][0] - c0;
- d1 = abs( m );
- m = colors[2][0] - c0;
- d2 = abs( m );
- m = colors[3][0] - c0;
- d3 = abs( m );
- m = colors[0][1] - c1;
- d0 += abs( m );
- m = colors[1][1] - c1;
- d1 += abs( m );
- m = colors[2][1] - c1;
- d2 += abs( m );
- m = colors[3][1] - c1;
- d3 += abs( m );
- bool b0 = d0 > d3;
- bool b1 = d1 > d2;
- bool b2 = d0 > d2;
- bool b3 = d1 > d3;
- bool b4 = d2 > d3;
- int x0 = b1 & b2;
- int x1 = b0 & b3;
- int x2 = b0 & b4;
- result |= ( x2 | ( ( x0 | x1 ) << 1 ) ) << ( i << 1 );
- }
- EmitUInt( result );
- }
- /*
- ========================
- idDxtEncoder::EmitAlphaIndices
- params: colorBlock - 16 pixel block for which find alpha indexes
- paramO: minAlpha - Min alpha found
- paramO: maxAlpha - Max alpha found
- ========================
- */
- void idDxtEncoder::EmitAlphaIndices( const byte *colorBlock, const int offset, const byte minAlpha, const byte maxAlpha ) {
- assert( maxAlpha >= minAlpha );
- const int ALPHA_RANGE = 7;
- #if 1
- byte ab1, ab2, ab3, ab4, ab5, ab6, ab7;
- ALIGN16( byte indexes[16] );
- ab1 = ( 13 * maxAlpha + 1 * minAlpha + ALPHA_RANGE ) / (ALPHA_RANGE*2);
- ab2 = ( 11 * maxAlpha + 3 * minAlpha + ALPHA_RANGE ) / (ALPHA_RANGE*2);
- ab3 = ( 9 * maxAlpha + 5 * minAlpha + ALPHA_RANGE ) / (ALPHA_RANGE*2);
- ab4 = ( 7 * maxAlpha + 7 * minAlpha + ALPHA_RANGE ) / (ALPHA_RANGE*2);
- ab5 = ( 5 * maxAlpha + 9 * minAlpha + ALPHA_RANGE ) / (ALPHA_RANGE*2);
- ab6 = ( 3 * maxAlpha + 11 * minAlpha + ALPHA_RANGE ) / (ALPHA_RANGE*2);
- ab7 = ( 1 * maxAlpha + 13 * minAlpha + ALPHA_RANGE ) / (ALPHA_RANGE*2);
- colorBlock += offset;
- for ( int i = 0; i < 16; i++ ) {
- byte a = colorBlock[i*4];
- int b1 = ( a >= ab1 );
- int b2 = ( a >= ab2 );
- int b3 = ( a >= ab3 );
- int b4 = ( a >= ab4 );
- int b5 = ( a >= ab5 );
- int b6 = ( a >= ab6 );
- int b7 = ( a >= ab7 );
- int index = ( 8 - b1 - b2 - b3 - b4 - b5 - b6 - b7 ) & 7;
- indexes[i] = byte( index ^ ( 2 > index ) );
- }
- EmitByte( (indexes[ 0] >> 0) | (indexes[ 1] << 3) | (indexes[ 2] << 6) );
- EmitByte( (indexes[ 2] >> 2) | (indexes[ 3] << 1) | (indexes[ 4] << 4) | (indexes[ 5] << 7) );
- EmitByte( (indexes[ 5] >> 1) | (indexes[ 6] << 2) | (indexes[ 7] << 5) );
- EmitByte( (indexes[ 8] >> 0) | (indexes[ 9] << 3) | (indexes[10] << 6) );
- EmitByte( (indexes[10] >> 2) | (indexes[11] << 1) | (indexes[12] << 4) | (indexes[13] << 7) );
- EmitByte( (indexes[13] >> 1) | (indexes[14] << 2) | (indexes[15] << 5) );
- #elif 0
- ALIGN16( byte indexes[16] );
- byte delta = maxAlpha - minAlpha;
- byte half = delta >> 1;
- byte bias = delta / ( 2 * ALPHA_RANGE );
- byte bottom = minAlpha + bias;
- byte top = maxAlpha - bias;
- colorBlock += offset;
- for ( int i = 0; i < 16; i++ ) {
- byte a = colorBlock[i*4];
- if ( a <= bottom ) {
- indexes[i] = 1;
- } else if ( a >= top ) {
- indexes[i] = 0;
- } else {
- indexes[i] = (ALPHA_RANGE+1) + ( ( minAlpha - a ) * ALPHA_RANGE - half ) / delta;
- }
- }
- EmitByte( (indexes[ 0] >> 0) | (indexes[ 1] << 3) | (indexes[ 2] << 6) );
- EmitByte( (indexes[ 2] >> 2) | (indexes[ 3] << 1) | (indexes[ 4] << 4) | (indexes[ 5] << 7) );
- EmitByte( (indexes[ 5] >> 1) | (indexes[ 6] << 2) | (indexes[ 7] << 5) );
- EmitByte( (indexes[ 8] >> 0) | (indexes[ 9] << 3) | (indexes[10] << 6) );
- EmitByte( (indexes[10] >> 2) | (indexes[11] << 1) | (indexes[12] << 4) | (indexes[13] << 7) );
- EmitByte( (indexes[13] >> 1) | (indexes[14] << 2) | (indexes[15] << 5) );
- #elif 0
- ALIGN16( byte indexes[16] );
- byte delta = maxAlpha - minAlpha;
- byte half = delta >> 1;
- byte bias = delta / ( 2 * ALPHA_RANGE );
- byte bottom = minAlpha + bias;
- byte top = maxAlpha - bias;
- colorBlock += offset;
- for ( int i = 0; i < 16; i++ ) {
- byte a = colorBlock[i*4];
- int index = (ALPHA_RANGE+1) + ( ( minAlpha - a ) * ALPHA_RANGE - half ) / delta;
- int c0 = a > bottom;
- int c1 = a < top;
- indexes[i] = ( index & -( c0 & c1 ) ) | ( c0 ^ 1 );
- }
- EmitByte( (indexes[ 0] >> 0) | (indexes[ 1] << 3) | (indexes[ 2] << 6) );
- EmitByte( (indexes[ 2] >> 2) | (indexes[ 3] << 1) | (indexes[ 4] << 4) | (indexes[ 5] << 7) );
- EmitByte( (indexes[ 5] >> 1) | (indexes[ 6] << 2) | (indexes[ 7] << 5) );
- EmitByte( (indexes[ 8] >> 0) | (indexes[ 9] << 3) | (indexes[10] << 6) );
- EmitByte( (indexes[10] >> 2) | (indexes[11] << 1) | (indexes[12] << 4) | (indexes[13] << 7) );
- EmitByte( (indexes[13] >> 1) | (indexes[14] << 2) | (indexes[15] << 5) );
- #else
- ALIGN16( byte indexes[16] );
- ALIGN16( byte alphas[8] );
- alphas[0] = maxAlpha;
- alphas[1] = minAlpha;
- alphas[2] = ( 6 * maxAlpha + 1 * minAlpha ) / ALPHA_RANGE;
- alphas[3] = ( 5 * maxAlpha + 2 * minAlpha ) / ALPHA_RANGE;
- alphas[4] = ( 4 * maxAlpha + 3 * minAlpha ) / ALPHA_RANGE;
- alphas[5] = ( 3 * maxAlpha + 4 * minAlpha ) / ALPHA_RANGE;
- alphas[6] = ( 2 * maxAlpha + 5 * minAlpha ) / ALPHA_RANGE;
- alphas[7] = ( 1 * maxAlpha + 6 * minAlpha ) / ALPHA_RANGE;
- colorBlock += offset;
- for ( int i = 0; i < 16; i++ ) {
- int minDist = INT_MAX;
- byte a = colorBlock[i*4];
- for ( int j = 0; j < 8; j++ ) {
- int dist = abs( a - alphas[j] );
- if ( dist < minDist ) {
- minDist = dist;
- indexes[i] = j;
- }
- }
- }
- EmitByte( (indexes[ 0] >> 0) | (indexes[ 1] << 3) | (indexes[ 2] << 6) );
- EmitByte( (indexes[ 2] >> 2) | (indexes[ 3] << 1) | (indexes[ 4] << 4) | (indexes[ 5] << 7) );
- EmitByte( (indexes[ 5] >> 1) | (indexes[ 6] << 2) | (indexes[ 7] << 5) );
- EmitByte( (indexes[ 8] >> 0) | (indexes[ 9] << 3) | (indexes[10] << 6) );
- EmitByte( (indexes[10] >> 2) | (indexes[11] << 1) | (indexes[12] << 4) | (indexes[13] << 7) );
- EmitByte( (indexes[13] >> 1) | (indexes[14] << 2) | (indexes[15] << 5) );
- #endif
- }
- /*
- ========================
- idDxtEncoder::CompressImageDXT1Fast_Generic
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressImageDXT1Fast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- ALIGN16( byte minColor[4] );
- ALIGN16( byte maxColor[4] );
- assert( width >= 4 && ( width & 3 ) == 0 );
- assert( height >= 4 && ( height & 3 ) == 0 );
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- GetMinMaxBBox( block, minColor, maxColor );
- //SelectColorsDiagonal( block, minColor, maxColor );
- InsetColorsBBox( minColor, maxColor );
- EmitUShort( ColorTo565( maxColor ) );
- EmitUShort( ColorTo565( minColor ) );
- EmitColorIndices( block, minColor, maxColor );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- }
- /*
- ========================
- idDxtEncoder::CompressImageDXT1AlphaFast_Generic
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressImageDXT1AlphaFast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- ALIGN16( byte minColor[4] );
- ALIGN16( byte maxColor[4] );
- assert( width >= 4 && ( width & 3 ) == 0 );
- assert( height >= 4 && ( height & 3 ) == 0 );
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- GetMinMaxBBox( block, minColor, maxColor );
- byte minAlpha = minColor[3];
- //SelectColorsDiagonal( block, minColor, maxColor );
- InsetColorsBBox( minColor, maxColor );
- if ( minAlpha >= 128 ) {
- EmitUShort( ColorTo565( maxColor ) );
- EmitUShort( ColorTo565( minColor ) );
- EmitColorIndices( block, minColor, maxColor );
- } else {
- EmitUShort( ColorTo565( minColor ) );
- EmitUShort( ColorTo565( maxColor ) );
- EmitColorAlphaIndices( block, minColor, maxColor );
- }
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- }
- /*
- ========================
- idDxtEncoder::CompressImageDXT5Fast_Generic
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressImageDXT5Fast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- ALIGN16( byte minColor[4] );
- ALIGN16( byte maxColor[4] );
- assert( width >= 4 && ( width & 3 ) == 0 );
- assert( height >= 4 && ( height & 3 ) == 0 );
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- GetMinMaxBBox( block, minColor, maxColor );
- //SelectColorsDiagonal( block, minColor, maxColor );
- InsetColorsBBox( minColor, maxColor );
- EmitByte( maxColor[3] );
- EmitByte( minColor[3] );
- EmitAlphaIndices( block, 3, minColor[3], maxColor[3] );
- #ifdef NVIDIA_7X_HARDWARE_BUG_FIX
- // the colors are already always guaranteed to be sorted properly
- #endif
- EmitUShort( ColorTo565( maxColor ) );
- EmitUShort( ColorTo565( minColor ) );
- EmitColorIndices( block, minColor, maxColor );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- }
- /*
- ========================
- idDxtEncoder::ScaleYCoCg
- ========================
- */
- void idDxtEncoder::ScaleYCoCg( byte *colorBlock, byte *minColor, byte *maxColor ) const {
- int m0 = abs( minColor[0] - 128 );
- int m1 = abs( minColor[1] - 128 );
- int m2 = abs( maxColor[0] - 128 );
- int m3 = abs( maxColor[1] - 128 );
- if ( m1 > m0 ) m0 = m1;
- if ( m3 > m2 ) m2 = m3;
- if ( m2 > m0 ) m0 = m2;
- const int s0 = 128 / 2 - 1;
- const int s1 = 128 / 4 - 1;
- int mask0 = -( m0 <= s0 );
- int mask1 = -( m0 <= s1 );
- int scale = 1 + ( 1 & mask0 ) + ( 2 & mask1 );
- minColor[0] = byte( ( minColor[0] - 128 ) * scale + 128 );
- minColor[1] = byte( ( minColor[1] - 128 ) * scale + 128 );
- minColor[2] = byte( ( scale - 1 ) << 3 );
- maxColor[0] = byte( ( maxColor[0] - 128 ) * scale + 128 );
- maxColor[1] = byte( ( maxColor[1] - 128 ) * scale + 128 );
- maxColor[2] = byte( ( scale - 1 ) << 3 );
- for ( int i = 0; i < 16; i++ ) {
- colorBlock[i*4+0] = byte( ( colorBlock[i*4+0] - 128 ) * scale + 128 );
- colorBlock[i*4+1] = byte( ( colorBlock[i*4+1] - 128 ) * scale + 128 );
- }
- }
- /*
- ========================
- idDxtEncoder::InsetYCoCgBBox
- ========================
- */
- ID_INLINE void idDxtEncoder::InsetYCoCgBBox( byte *minColor, byte *maxColor ) const {
- #if 0
- byte inset[4];
- inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_COLOR_SHIFT;
- inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_COLOR_SHIFT;
- inset[3] = ( maxColor[3] - minColor[3] ) >> INSET_ALPHA_SHIFT;
- minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
- minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
- minColor[3] = ( minColor[3] + inset[3] <= 255 ) ? minColor[3] + inset[3] : 255;
- maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
- maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
- maxColor[3] = ( maxColor[3] >= inset[3] ) ? maxColor[3] - inset[3] : 0;
- minColor[0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
- minColor[1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
- maxColor[0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
- maxColor[1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
- #elif 0
- float inset[4];
- float minf[4];
- float maxf[4];
- for ( int i = 0; i < 4; i++ ) {
- minf[i] = minColor[i] / 255.0f;
- maxf[i] = maxColor[i] / 255.0f;
- }
- inset[0] = ( maxf[0] - minf[0] ) / 16.0f;
- inset[1] = ( maxf[1] - minf[1] ) / 16.0f;
- inset[2] = ( maxf[2] - minf[2] ) / 16.0f;
- inset[3] = ( maxf[3] - minf[3] ) / 32.0f;
- for ( int i = 0; i < 4; i++ ) {
- minf[i] = ( minf[i] + inset[i] <= 1.0f ) ? minf[i] + inset[i] : 1.0f;
- maxf[i] = ( maxf[i] >= inset[i] ) ? maxf[i] - inset[i] : 0;
- }
- minColor[0] = ((int)floor( minf[0] * 31 )) & ( ( 1 << 5 ) - 1 );
- minColor[1] = ((int)floor( minf[1] * 63 )) & ( ( 1 << 6 ) - 1 );
- maxColor[0] = ((int)ceil( maxf[0] * 31 )) & ( ( 1 << 5 ) - 1 );
- maxColor[1] = ((int)ceil( maxf[1] * 63 )) & ( ( 1 << 6 ) - 1 );
- minColor[0] = ( minColor[0] << 3 ) | ( minColor[0] >> 2 );
- minColor[1] = ( minColor[1] << 2 ) | ( minColor[1] >> 4 );
- maxColor[0] = ( maxColor[0] << 3 ) | ( maxColor[0] >> 2 );
- maxColor[1] = ( maxColor[1] << 2 ) | ( maxColor[1] >> 4 );
- minColor[3] = (int)floor( minf[3] * 255.0f );
- maxColor[3] = (int)ceil( maxf[3] * 255.0f );
- #elif 0
- int inset[4];
- int mini[4];
- int maxi[4];
- inset[0] = ( maxColor[0] - minColor[0] );
- inset[1] = ( maxColor[1] - minColor[1] );
- inset[3] = ( maxColor[3] - minColor[3] );
- mini[0] = ( minColor[0] << INSET_COLOR_SHIFT ) + inset[0];
- mini[1] = ( minColor[1] << INSET_COLOR_SHIFT ) + inset[1];
- mini[3] = ( minColor[3] << INSET_ALPHA_SHIFT ) + inset[3];
- maxi[0] = ( maxColor[0] << INSET_COLOR_SHIFT ) - inset[0];
- maxi[1] = ( maxColor[1] << INSET_COLOR_SHIFT ) - inset[1];
- maxi[3] = ( maxColor[3] << INSET_ALPHA_SHIFT ) - inset[3];
- mini[0] = ( mini[0] - ((1<<(3))-1) ) >> (INSET_COLOR_SHIFT+3);
- mini[1] = ( mini[1] - ((1<<(3))-1) ) >> (INSET_COLOR_SHIFT+2);
- mini[3] = ( mini[3] - ((1<<(2))-1) ) >> (INSET_ALPHA_SHIFT+0);
- maxi[0] = ( maxi[0] + ((1<<(3))-1) ) >> (INSET_COLOR_SHIFT+3);
- maxi[1] = ( maxi[1] + ((1<<(3))-1) ) >> (INSET_COLOR_SHIFT+2);
- maxi[3] = ( maxi[3] + ((1<<(2))-1) ) >> (INSET_ALPHA_SHIFT+0);
- if ( mini[0] < 0 ) mini[0] = 0;
- if ( mini[1] < 0 ) mini[1] = 0;
- if ( mini[3] < 0 ) mini[3] = 0;
- if ( maxi[0] > 31 ) maxi[0] = 31;
- if ( maxi[1] > 63 ) maxi[1] = 63;
- if ( maxi[3] > 255 ) maxi[3] = 255;
- minColor[0] = ( mini[0] << 3 ) | ( mini[0] >> 2 );
- minColor[1] = ( mini[1] << 2 ) | ( mini[1] >> 4 );
- minColor[3] = mini[3];
- maxColor[0] = ( maxi[0] << 3 ) | ( maxi[0] >> 2 );
- maxColor[1] = ( maxi[1] << 2 ) | ( maxi[1] >> 4 );
- maxColor[3] = maxi[3];
- #elif 1
- int inset[4];
- int mini[4];
- int maxi[4];
- inset[0] = ( maxColor[0] - minColor[0] ) - ((1<<(INSET_COLOR_SHIFT-1))-1);
- inset[1] = ( maxColor[1] - minColor[1] ) - ((1<<(INSET_COLOR_SHIFT-1))-1);
- inset[3] = ( maxColor[3] - minColor[3] ) - ((1<<(INSET_ALPHA_SHIFT-1))-1);
- mini[0] = ( ( minColor[0] << INSET_COLOR_SHIFT ) + inset[0] ) >> INSET_COLOR_SHIFT;
- mini[1] = ( ( minColor[1] << INSET_COLOR_SHIFT ) + inset[1] ) >> INSET_COLOR_SHIFT;
- mini[3] = ( ( minColor[3] << INSET_ALPHA_SHIFT ) + inset[3] ) >> INSET_ALPHA_SHIFT;
- maxi[0] = ( ( maxColor[0] << INSET_COLOR_SHIFT ) - inset[0] ) >> INSET_COLOR_SHIFT;
- maxi[1] = ( ( maxColor[1] << INSET_COLOR_SHIFT ) - inset[1] ) >> INSET_COLOR_SHIFT;
- maxi[3] = ( ( maxColor[3] << INSET_ALPHA_SHIFT ) - inset[3] ) >> INSET_ALPHA_SHIFT;
- mini[0] = ( mini[0] >= 0 ) ? mini[0] : 0;
- mini[1] = ( mini[1] >= 0 ) ? mini[1] : 0;
- mini[3] = ( mini[3] >= 0 ) ? mini[3] : 0;
- maxi[0] = ( maxi[0] <= 255 ) ? maxi[0] : 255;
- maxi[1] = ( maxi[1] <= 255 ) ? maxi[1] : 255;
- maxi[3] = ( maxi[3] <= 255 ) ? maxi[3] : 255;
- minColor[0] = byte( ( mini[0] & C565_5_MASK ) | ( mini[0] >> 5 ) );
- minColor[1] = byte( ( mini[1] & C565_6_MASK ) | ( mini[1] >> 6 ) );
- minColor[3] = byte( mini[3] );
- maxColor[0] = byte( ( maxi[0] & C565_5_MASK ) | ( maxi[0] >> 5 ) );
- maxColor[1] = byte( ( maxi[1] & C565_6_MASK ) | ( maxi[1] >> 6 ) );
- maxColor[3] = byte( maxi[3] );
- #endif
- }
- /*
- ========================
- idDxtEncoder::InsetYCoCgAlpaBBox
- ========================
- */
- ID_INLINE void idDxtEncoder::InsetYCoCgAlpaBBox( byte *minColor, byte *maxColor ) const {
- int inset[4];
- int mini[4];
- int maxi[4];
- inset[0] = ( maxColor[0] - minColor[0] ) - ((1<<(INSET_COLOR_SHIFT-1))-1);
- inset[1] = ( maxColor[1] - minColor[1] ) - ((1<<(INSET_COLOR_SHIFT-1))-1);
- inset[2] = ( maxColor[2] - minColor[2] ) - ((1<<(INSET_COLOR_SHIFT-1))-1);
- inset[3] = ( maxColor[3] - minColor[3] ) - ((1<<(INSET_ALPHA_SHIFT-1))-1);
- mini[0] = ( ( minColor[0] << INSET_COLOR_SHIFT ) + inset[0] ) >> INSET_COLOR_SHIFT;
- mini[1] = ( ( minColor[1] << INSET_COLOR_SHIFT ) + inset[1] ) >> INSET_COLOR_SHIFT;
- mini[2] = ( ( minColor[2] << INSET_COLOR_SHIFT ) + inset[2] ) >> INSET_COLOR_SHIFT;
- mini[3] = ( ( minColor[3] << INSET_ALPHA_SHIFT ) + inset[3] ) >> INSET_ALPHA_SHIFT;
- maxi[0] = ( ( maxColor[0] << INSET_COLOR_SHIFT ) - inset[0] ) >> INSET_COLOR_SHIFT;
- maxi[1] = ( ( maxColor[1] << INSET_COLOR_SHIFT ) - inset[1] ) >> INSET_COLOR_SHIFT;
- maxi[2] = ( ( maxColor[2] << INSET_COLOR_SHIFT ) - inset[2] ) >> INSET_COLOR_SHIFT;
- maxi[3] = ( ( maxColor[3] << INSET_ALPHA_SHIFT ) - inset[3] ) >> INSET_ALPHA_SHIFT;
- mini[0] = ( mini[0] >= 0 ) ? mini[0] : 0;
- mini[1] = ( mini[1] >= 0 ) ? mini[1] : 0;
- mini[2] = ( mini[2] >= 0 ) ? mini[2] : 0;
- mini[3] = ( mini[3] >= 0 ) ? mini[3] : 0;
- maxi[0] = ( maxi[0] <= 255 ) ? maxi[0] : 255;
- maxi[1] = ( maxi[1] <= 255 ) ? maxi[1] : 255;
- maxi[2] = ( maxi[2] <= 255 ) ? maxi[2] : 255;
- maxi[3] = ( maxi[3] <= 255 ) ? maxi[3] : 255;
- minColor[0] = byte( ( mini[0] & C565_5_MASK ) | ( mini[0] >> 5 ) );
- minColor[1] = byte( ( mini[1] & C565_6_MASK ) | ( mini[1] >> 6 ) );
- minColor[2] = byte( ( mini[2] & C565_5_MASK ) | ( mini[2] >> 5 ) );
- minColor[3] = byte( mini[3] );
- maxColor[0] = byte( ( maxi[0] & C565_5_MASK ) | ( maxi[0] >> 5 ) );
- maxColor[1] = byte( ( maxi[1] & C565_6_MASK ) | ( maxi[1] >> 6 ) );
- maxColor[2] = byte( ( maxi[2] & C565_5_MASK ) | ( maxi[2] >> 5 ) );
- maxColor[3] = byte( maxi[3] );
- }
- /*
- ========================
- idDxtEncoder::SelectYCoCgDiagonal
- ========================
- */
- void idDxtEncoder::SelectYCoCgDiagonal( const byte *colorBlock, byte *minColor, byte *maxColor ) const {
- byte side = 0;
- byte mid0 = byte( ( (int) minColor[0] + maxColor[0] + 1 ) >> 1 );
- byte mid1 = byte( ( (int) minColor[1] + maxColor[1] + 1 ) >> 1 );
- for ( int i = 0; i < 16; i++ ) {
- byte b0 = colorBlock[i*4+0] >= mid0;
- byte b1 = colorBlock[i*4+1] >= mid1;
- side += ( b0 ^ b1 );
- }
- byte mask = -( side > 8 );
- #if defined NVIDIA_7X_HARDWARE_BUG_FIX
- mask &= -( minColor[0] != maxColor[0] );
- #endif
- byte c0 = minColor[1];
- byte c1 = maxColor[1];
- c0 ^= c1;
- mask &= c0;
- c1 ^= mask;
- c0 ^= c1;
- minColor[1] = c0;
- maxColor[1] = c1;
- }
- /*
- ========================
- idDxtEncoder::CompressYCoCgDXT5Fast_Generic
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressYCoCgDXT5Fast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- ALIGN16( byte minColor[4] );
- ALIGN16( byte maxColor[4] );
- //assert( HasConstantValuePer4x4Block( inBuf, width, height, 2 ) );
- assert( width >= 4 && ( width & 3 ) == 0 );
- assert( height >= 4 && ( height & 3 ) == 0 );
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- GetMinMaxBBox( block, minColor, maxColor );
- ScaleYCoCg( block, minColor, maxColor );
- InsetYCoCgBBox( minColor, maxColor );
- SelectYCoCgDiagonal( block, minColor, maxColor );
- EmitByte( maxColor[3] );
- EmitByte( minColor[3] );
- EmitAlphaIndices( block, 3, minColor[3], maxColor[3] );
- #ifdef NVIDIA_7X_HARDWARE_BUG_FIX
- // the colors are already sorted when selecting the diagonal
- #endif
- EmitUShort( ColorTo565( maxColor ) );
- EmitUShort( ColorTo565( minColor ) );
- EmitColorIndices( block, minColor, maxColor );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- }
- /*
- ========================
- idDxtEncoder::CompressYCoCgAlphaDXT5Fast
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressYCoCgAlphaDXT5Fast( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- ALIGN16( byte minColor[4] );
- ALIGN16( byte maxColor[4] );
- assert( width >= 4 && ( width & 3 ) == 0 );
- assert( height >= 4 && ( height & 3 ) == 0 );
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- // scale down the chroma of texels that are close to gray with low luminance
- for ( int k = 0; k < 16; k++ ) {
- if ( abs( block[k*4+0] - 132 ) <= 8 &&
- abs( block[k*4+2] - 132 ) <= 8 &&
- block[k*4+3] < 96 ) {
- block[k*4+0] = ( block[k*4+0] - 132 ) / 2 + 132;
- block[k*4+2] = ( block[k*4+2] - 132 ) / 2 + 132;
- }
- }
- GetMinMaxBBox( block, minColor, maxColor );
- InsetYCoCgAlpaBBox( minColor, maxColor );
- SelectColorsDiagonal( block, minColor, maxColor );
- EmitByte( maxColor[3] );
- EmitByte( minColor[3] );
- EmitAlphaIndices( block, 3, minColor[3], maxColor[3] );
- #ifdef NVIDIA_7X_HARDWARE_BUG_FIX
- // the colors are already sorted when selecting the diagonal
- #endif
- EmitUShort( ColorTo565( maxColor ) );
- EmitUShort( ColorTo565( minColor ) );
- EmitColorIndices( block, minColor, maxColor );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- }
- /*
- ========================
- idDxtEncoder::CompressYCoCgCTX1DXT5AFast_Generic
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressYCoCgCTX1DXT5AFast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- ALIGN16( byte minColor[4] );
- ALIGN16( byte maxColor[4] );
- assert( HasConstantValuePer4x4Block( inBuf, width, height, 2 ) );
- assert( width >= 4 && ( width & 3 ) == 0 );
- assert( height >= 4 && ( height & 3 ) == 0 );
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- GetMinMaxBBox( block, minColor, maxColor );
- SelectYCoCgDiagonal( block, minColor, maxColor );
- InsetColorsBBox( minColor, maxColor );
- EmitByte( maxColor[3] );
- EmitByte( minColor[3] );
- EmitAlphaIndices( block, 3, minColor[3], maxColor[3] );
- EmitByte( maxColor[0] );
- EmitByte( maxColor[1] );
- EmitByte( minColor[0] );
- EmitByte( minColor[1] );
- EmitCTX1Indices( block, minColor, maxColor );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- }
- /*
- ========================
- idDxtEncoder::EmitGreenIndices
- params: block - block for which to find green indices
- paramO: minGreen - Min green found
- paramO: maxGreen - Max green found
- ========================
- */
- void idDxtEncoder::EmitGreenIndices( const byte *block, const int offset, const byte minGreen, const byte maxGreen ) {
- assert( maxGreen >= minGreen );
- const int COLOR_RANGE = 3;
- #if 1
- byte yb1 = ( 5 * maxGreen + 1 * minGreen + COLOR_RANGE ) / ( 2 * COLOR_RANGE );
- byte yb2 = ( 3 * maxGreen + 3 * minGreen + COLOR_RANGE ) / ( 2 * COLOR_RANGE );
- byte yb3 = ( 1 * maxGreen + 5 * minGreen + COLOR_RANGE ) / ( 2 * COLOR_RANGE );
- unsigned int result = 0;
- block += offset;
- for ( int i = 15; i >= 0; i-- ) {
- result <<= 2;
- byte y = block[i*4];
- int b1 = ( y >= yb1 );
- int b2 = ( y >= yb2 );
- int b3 = ( y >= yb3 );
- int index = ( 4 - b1 - b2 - b3 ) & 3;
- index ^= ( 2 > index );
- result |= index;
- }
- EmitUInt( result );
- #else
- byte green[4];
- green[0] = maxGreen;
- green[1] = minGreen;
- green[2] = ( 2 * green[0] + 1 * green[1] ) / 3;
- green[3] = ( 1 * green[0] + 2 * green[1] ) / 3;
- unsigned int result = 0;
- block += offset;
- for ( int i = 15; i >= 0; i-- ) {
- result <<= 2;
- byte y = block[i*4];
- int minDist = INT_MAX;
- int index;
- for ( int j = 0; j < 4; j++ ) {
- int dist = abs( y - green[j] );
- if ( dist < minDist ) {
- minDist = dist;
- index = j;
- }
- }
- result |= index;
- }
- EmitUInt( result );
- #endif
- }
- /*
- ========================
- idDxtEncoder::InsetNormalsBBoxDXT5
- ========================
- */
- void idDxtEncoder::InsetNormalsBBoxDXT5( byte *minNormal, byte *maxNormal ) const {
- int inset[4];
- int mini[4];
- int maxi[4];
- inset[3] = ( maxNormal[3] - minNormal[3] ) - ((1<<(INSET_ALPHA_SHIFT-1))-1);
- inset[1] = ( maxNormal[1] - minNormal[1] ) - ((1<<(INSET_COLOR_SHIFT-1))-1);
- mini[3] = ( ( minNormal[3] << INSET_ALPHA_SHIFT ) + inset[3] ) >> INSET_ALPHA_SHIFT;
- mini[1] = ( ( minNormal[1] << INSET_COLOR_SHIFT ) + inset[1] ) >> INSET_COLOR_SHIFT;
- maxi[3] = ( ( maxNormal[3] << INSET_ALPHA_SHIFT ) - inset[3] ) >> INSET_ALPHA_SHIFT;
- maxi[1] = ( ( maxNormal[1] << INSET_COLOR_SHIFT ) - inset[1] ) >> INSET_COLOR_SHIFT;
- mini[3] = ( mini[3] >= 0 ) ? mini[3] : 0;
- mini[1] = ( mini[1] >= 0 ) ? mini[1] : 0;
- maxi[3] = ( maxi[3] <= 255 ) ? maxi[3] : 255;
- maxi[1] = ( maxi[1] <= 255 ) ? maxi[1] : 255;
- minNormal[3] = byte( mini[3] );
- minNormal[1] = byte( ( mini[1] & C565_6_MASK ) | ( mini[1] >> 6 ) );
- maxNormal[3] = byte( maxi[3] );
- maxNormal[1] = byte( ( maxi[1] & C565_6_MASK ) | ( maxi[1] >> 6 ) );
- }
- /*
- ========================
- idDxtEncoder::InsetNormalsBBox3Dc
- ========================
- */
- void idDxtEncoder::InsetNormalsBBox3Dc( byte *minNormal, byte *maxNormal ) const {
- int inset[4];
- int mini[4];
- int maxi[4];
- inset[0] = ( maxNormal[0] - minNormal[0] ) - ((1<<(INSET_ALPHA_SHIFT-1))-1);
- inset[1] = ( maxNormal[1] - minNormal[1] ) - ((1<<(INSET_ALPHA_SHIFT-1))-1);
- mini[0] = ( ( minNormal[0] << INSET_ALPHA_SHIFT ) + inset[0] ) >> INSET_ALPHA_SHIFT;
- mini[1] = ( ( minNormal[1] << INSET_ALPHA_SHIFT ) + inset[1] ) >> INSET_ALPHA_SHIFT;
- maxi[0] = ( ( maxNormal[0] << INSET_ALPHA_SHIFT ) - inset[0] ) >> INSET_ALPHA_SHIFT;
- maxi[1] = ( ( maxNormal[1] << INSET_ALPHA_SHIFT ) - inset[1] ) >> INSET_ALPHA_SHIFT;
- mini[0] = ( mini[0] >= 0 ) ? mini[0] : 0;
- mini[1] = ( mini[1] >= 0 ) ? mini[1] : 0;
- maxi[0] = ( maxi[0] <= 255 ) ? maxi[0] : 255;
- maxi[1] = ( maxi[1] <= 255 ) ? maxi[1] : 255;
- minNormal[0] = (byte)mini[0];
- minNormal[1] = (byte)mini[1];
- maxNormal[0] = (byte)maxi[0];
- maxNormal[1] = (byte)maxi[1];
- }
- /*
- ========================
- idDxtEncoder::CompressNormalMapDXT5Fast_Generic
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressNormalMapDXT5Fast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- ALIGN16( byte normal1[4] );
- ALIGN16( byte normal2[4] );
- assert( width >= 4 && ( width & 3 ) == 0 );
- assert( height >= 4 && ( height & 3 ) == 0 );
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- GetMinMaxBBox( block, normal1, normal2 );
- InsetNormalsBBoxDXT5( normal1, normal2 );
- // Write out Nx into alpha channel.
- EmitByte( normal2[3] );
- EmitByte( normal1[3] );
- EmitAlphaIndices( block, 3, normal1[3], normal2[3] );
- // Write out Ny into green channel.
- EmitUShort( ColorTo565( block[0], normal2[1], block[2] ) );
- EmitUShort( ColorTo565( block[0], normal1[1], block[2] ) );
- EmitGreenIndices( block, 1, normal1[1], normal2[1] );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- }
- /*
- ========================
- idDxtEncoder::CompressImageDXN1Fast_Generic
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressImageDXN1Fast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- ALIGN16( byte min[4] );
- ALIGN16( byte max[4] );
- assert( width >= 4 && ( width & 3 ) == 0 );
- assert( height >= 4 && ( height & 3 ) == 0 );
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- GetMinMaxBBox( block, min, max );
- InsetNormalsBBox3Dc( min, max );
- // Write out an alpha channel.
- EmitByte( max[0] );
- EmitByte( min[0] );
- EmitAlphaIndices( block, 0, min[0], max[0] );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- }
- /*
- ========================
- idDxtEncoder::CompressNormalMapDXN2Fast_Generic
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::CompressNormalMapDXN2Fast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte block[64] );
- ALIGN16( byte normal1[4] );
- ALIGN16( byte normal2[4] );
- assert( width >= 4 && ( width & 3 ) == 0 );
- assert( height >= 4 && ( height & 3 ) == 0 );
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
- for ( int i = 0; i < width; i += 4 ) {
- ExtractBlock( inBuf + i * 4, width, block );
- GetMinMaxBBox( block, normal1, normal2 );
- InsetNormalsBBox3Dc( normal1, normal2 );
- // Write out Nx as an alpha channel.
- EmitByte( normal2[0] );
- EmitByte( normal1[0] );
- EmitAlphaIndices( block, 0, normal1[0], normal2[0] );
- // Write out Ny as an alpha channel.
- EmitByte( normal2[1] );
- EmitByte( normal1[1] );
- EmitAlphaIndices( block, 1, normal1[1], normal2[1] );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- }
- /*
- ========================
- idDxtEncoder::DecodeDXNAlphaValues
- ========================
- */
- void idDxtEncoder::DecodeDXNAlphaValues( const byte *inBuf, byte *values ) {
- int i;
- unsigned int indices;
- byte alphas[8];
- if ( inBuf[0] <= inBuf[1] ) {
- alphas[0] = inBuf[0];
- alphas[1] = inBuf[1];
- alphas[2] = ( 4 * alphas[0] + 1 * alphas[1] ) / 5;
- alphas[3] = ( 3 * alphas[0] + 2 * alphas[1] ) / 5;
- alphas[4] = ( 2 * alphas[0] + 3 * alphas[1] ) / 5;
- alphas[5] = ( 1 * alphas[0] + 4 * alphas[1] ) / 5;
- alphas[6] = 0;
- alphas[7] = 255;
- } else {
- alphas[0] = inBuf[0];
- alphas[1] = inBuf[1];
- alphas[2] = ( 6 * alphas[0] + 1 * alphas[1] ) / 7;
- alphas[3] = ( 5 * alphas[0] + 2 * alphas[1] ) / 7;
- alphas[4] = ( 4 * alphas[0] + 3 * alphas[1] ) / 7;
- alphas[5] = ( 3 * alphas[0] + 4 * alphas[1] ) / 7;
- alphas[6] = ( 2 * alphas[0] + 5 * alphas[1] ) / 7;
- alphas[7] = ( 1 * alphas[0] + 6 * alphas[1] ) / 7;
- }
- indices = (int)inBuf[2] | ( (int)inBuf[3] << 8 ) | ( (int)inBuf[4] << 16 );
- for ( i = 0; i < 8; i++ ) {
- values[i] = alphas[indices & 7];
- indices >>= 3;
- }
- indices = (int)inBuf[5] | ( (int)inBuf[6] << 8 ) | ( (int)inBuf[7] << 16 );
- for ( i = 8; i < 16; i++ ) {
- values[i] = alphas[indices & 7];
- indices >>= 3;
- }
- }
- /*
- ========================
- idDxtEncoder::EncodeNormalRGBIndices
- params: values - 16 normal block for which to find normal Y indices
- paramO: min - Min grayscale value
- paramO: max - Max grayscale value
- ========================
- */
- void idDxtEncoder::EncodeNormalRGBIndices( byte *outBuf, const byte min, const byte max, const byte *values ) {
- const int COLOR_RANGE = 3;
- byte maskedMin, maskedMax, mid, yb1, yb2, yb3;
- maskedMax = max & C565_6_MASK;
- maskedMin = min & C565_6_MASK;
- mid = ( maskedMax - maskedMin ) / ( 2 * COLOR_RANGE );
- yb1 = maskedMax - mid;
- yb2 = ( 2 * maskedMax + 1 * maskedMin ) / COLOR_RANGE - mid;
- yb3 = ( 1 * maskedMax + 2 * maskedMin ) / COLOR_RANGE - mid;
- unsigned int result = 0;
- for ( int i = 15; i >= 0; i-- ) {
- result <<= 2;
- byte y = values[i];
- int b1 = ( y >= yb1 );
- int b2 = ( y >= yb2 );
- int b3 = ( y >= yb3 );
- int index = ( 4 - b1 - b2 - b3 ) & 3;
- index ^= ( 2 > index );
- result |= index;
- }
- unsigned short maskedMax5 = (max & C565_5_MASK) >> 3;
- unsigned short maskedMin5 = (min & C565_5_MASK) >> 3;
-
- unsigned short smax = (maskedMax5 << 11) | (maskedMax << 3) | maskedMax5;
- unsigned short smin = (maskedMin5 << 11) | (maskedMin << 3) | maskedMin5;
- outBuf[0] = byte( ( smax >> 0 ) & 0xFF );
- outBuf[1] = byte( ( smax >> 8 ) & 0xFF );
- outBuf[2] = byte( ( smin >> 0 ) & 0xFF );
- outBuf[3] = byte( ( smin >> 8 ) & 0xFF );
- outBuf[4] = byte( ( result >> 0 ) & 0xFF );
- outBuf[5] = byte( ( result >> 8 ) & 0xFF );
- outBuf[6] = byte( ( result >> 16 ) & 0xFF );
- outBuf[7] = byte( ( result >> 24 ) & 0xFF );
- }
- /*
- ========================
- idDxtEncoder::ConvertNormalMapDXN2_DXT5
- params: inBuf - normal map compressed in DXN2 format
- paramO: outBuf - result of compression in DXT5 format
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::ConvertNormalMapDXN2_DXT5( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte values[16] );
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- if ( width > 4 && ( width & 3 ) != 0 ) {
- return;
- }
- if ( height > 4 && ( height & 3 ) != 0 ) {
- return;
- }
- if ( width < 4 || height < 4 ) {
- assert( 0 );
- return;
- }
- for ( int j = 0; j < height; j += 4 ) {
- for ( int i = 0; i < width; i += 4, inBuf += 16, outBuf += 16 ) {
- // decode normal Y stored as a DXT5 alpha channel
- DecodeDXNAlphaValues( inBuf + 0, values );
- // copy normal X
- memcpy( outBuf + 0, inBuf + 8, 8 );
- // get the min/max Y
- byte minNormalY = 255;
- byte maxNormalY = 0;
- for ( int i = 0; i < 16; i++ ) {
- if ( values[i] < minNormalY ) {
- minNormalY = values[i];
- }
- if ( values[i] > maxNormalY ) {
- maxNormalY = values[i];
- }
- }
- // encode normal Y into DXT5 color channels
- EncodeNormalRGBIndices( outBuf + 8, minNormalY, maxNormalY, values );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- }
- /*
- ========================
- idDxtEncoder::DecodeNormalYValues
- ========================
- */
- void idDxtEncoder::DecodeNormalYValues( const byte *inBuf, byte &min, byte &max, byte *values ) {
- int i;
- unsigned int indexes;
- unsigned short normal0, normal1;
- byte normalsY[4];
- normal0 = inBuf[0] | (inBuf[1] << 8);
- normal1 = inBuf[2] | (inBuf[3] << 8);
- assert( normal0 >= normal1 );
- normalsY[0] = GreenFrom565( normal0 );
- normalsY[1] = GreenFrom565( normal1 );
- normalsY[2] = ( 2 * normalsY[0] + 1 * normalsY[1] ) / 3;
- normalsY[3] = ( 1 * normalsY[0] + 2 * normalsY[1] ) / 3;
- indexes = (unsigned int)inBuf[4] | ((unsigned int)inBuf[5]<<8) | ((unsigned int)inBuf[6]<<16) | ((unsigned int)inBuf[7]<<24);
- for ( i = 0; i < 16; i++ ) {
- values[i] = normalsY[indexes & 3];
- indexes >>= 2;
- }
- max = normalsY[0];
- min = normalsY[1];
- }
- /*
- ========================
- idDxtEncoder::EncodeDXNAlphaValues
- ========================
- */
- void idDxtEncoder::EncodeDXNAlphaValues( byte *outBuf, const byte min, const byte max, const byte *values ) {
- int i;
- byte alphas[8];
- int j;
- unsigned int indexes[16];
- alphas[0] = max;
- alphas[1] = min;
- alphas[2] = ( 6 * alphas[0] + 1 * alphas[1] ) / 7;
- alphas[3] = ( 5 * alphas[0] + 2 * alphas[1] ) / 7;
- alphas[4] = ( 4 * alphas[0] + 3 * alphas[1] ) / 7;
- alphas[5] = ( 3 * alphas[0] + 4 * alphas[1] ) / 7;
- alphas[6] = ( 2 * alphas[0] + 5 * alphas[1] ) / 7;
- alphas[7] = ( 1 * alphas[0] + 6 * alphas[1] ) / 7;
- int error = 0;
- for ( i = 0; i < 16; i++ ) {
- int minDist = MAX_TYPE( int );
- byte a = values[i];
- for ( j = 0; j < 8; j++ ) {
- int dist = AlphaDistance( a, alphas[j] );
- if ( dist < minDist ) {
- minDist = dist;
- indexes[i] = j;
- }
- }
- error += minDist;
- }
- outBuf[0] = max;
- outBuf[1] = min;
- outBuf[2] = byte( (indexes[ 0] >> 0) | (indexes[ 1] << 3) | (indexes[ 2] << 6) );
- outBuf[3] = byte( (indexes[ 2] >> 2) | (indexes[ 3] << 1) | (indexes[ 4] << 4) | (indexes[ 5] << 7) );
- outBuf[4] = byte( (indexes[ 5] >> 1) | (indexes[ 6] << 2) | (indexes[ 7] << 5) );
- outBuf[5] = byte( (indexes[ 8] >> 0) | (indexes[ 9] << 3) | (indexes[10] << 6) );
- outBuf[6] = byte( (indexes[10] >> 2) | (indexes[11] << 1) | (indexes[12] << 4) | (indexes[13] << 7) );
- outBuf[7] = byte( (indexes[13] >> 1) | (indexes[14] << 2) | (indexes[15] << 5) );
- }
- /*
- ========================
- idDxtEncoder::ConvertNormalMapDXT5_DXN2
- params: inBuf - image to compress
- paramO: outBuf - result of compression
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::ConvertNormalMapDXT5_DXN2( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte values[16] );
- byte minNormalY, maxNormalY;
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- if ( width > 4 && ( width & 3 ) != 0 ) {
- return;
- }
- if ( height > 4 && ( height & 3 ) != 0 ) {
- return;
- }
- if ( width < 4 || height < 4 ) {
- assert( 0 );
- return;
- }
- for ( int j = 0; j < height; j += 4 ) {
- for ( int i = 0; i < width; i += 4, inBuf += 16, outBuf += 16 ) {
- // decode normal Y stored as a DXT5 alpha channel
- DecodeNormalYValues( inBuf + 8, minNormalY, maxNormalY, values );
- memcpy( outBuf + 8, inBuf + 0, 8 );
- // encode normal Y into DXT5 green channel
- EncodeDXNAlphaValues( outBuf + 0, minNormalY, maxNormalY, values );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- }
- /*
- ========================
- idDxtEncoder::ConvertImageDXN1_DXT1
- params: inBuf - normal map compressed in DXN1 format
- paramO: outBuf - result of compression in DXT1 format
- params: width - width of image
- params: height - height of image
- ========================
- */
- void idDxtEncoder::ConvertImageDXN1_DXT1( const byte *inBuf, byte *outBuf, int width, int height ) {
- ALIGN16( byte values[16] );
- this->width = width;
- this->height = height;
- this->outData = outBuf;
- if ( width > 4 && ( width & 3 ) != 0 ) {
- return;
- }
- if ( height > 4 && ( height & 3 ) != 0 ) {
- return;
- }
- if ( width < 4 || height < 4 ) {
- assert( 0 );
- return;
- }
- for ( int j = 0; j < height; j += 4 ) {
- for ( int i = 0; i < width; i += 4, inBuf += 8, outBuf += 8 ) {
- // decode single channel stored as a DXT5 alpha channel
- DecodeDXNAlphaValues( inBuf + 0, values );
- // get the min/max
- byte min = 255;
- byte max = 0;
- for ( int i = 0; i < 16; i++ ) {
- if ( values[i] < min ) {
- min = values[i];
- }
- if ( values[i] > max ) {
- max = values[i];
- }
- }
- // encode single channel into DXT1
- EncodeNormalRGBIndices( outBuf + 0, min, max, values );
- }
- outData += dstPadding;
- inBuf += srcPadding;
- }
- }
|