12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 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 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.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- #include "Model_lwo.h"
- /*
- ======================================================================
- Converted from lwobject sample prog from LW 6.5 SDK.
- ======================================================================
- */
- /*
- ======================================================================
- lwFreeClip()
- Free memory used by an lwClip.
- ====================================================================== */
- void lwFreeClip( lwClip *clip )
- {
- if ( clip ) {
- lwListFree( clip->ifilter, (void (__cdecl *)(void *))lwFreePlugin );
- lwListFree( clip->pfilter, (void (__cdecl *)(void *))lwFreePlugin );
- switch( clip->type ) {
- case ID_STIL: {
- if ( clip->source.still.name ) Mem_Free( clip->source.still.name );
- break;
- }
- case ID_ISEQ: {
- if ( clip->source.seq.suffix ) Mem_Free( clip->source.seq.suffix );
- if ( clip->source.seq.prefix ) Mem_Free( clip->source.seq.prefix );
- break;
- }
- case ID_ANIM: {
- if ( clip->source.anim.server ) Mem_Free( clip->source.anim.server );
- if ( clip->source.anim.name ) Mem_Free( clip->source.anim.name );
- break;
- }
- case ID_XREF: {
- if ( clip->source.xref.string ) Mem_Free( clip->source.xref.string );
- break;
- }
- case ID_STCC: {
- if ( clip->source.cycle.name ) Mem_Free( clip->source.cycle.name );
- break;
- }
- }
- Mem_Free( clip );
- }
- }
- /*
- ======================================================================
- lwGetClip()
- Read image references from a CLIP chunk in an LWO2 file.
- ====================================================================== */
- lwClip *lwGetClip( idFile *fp, int cksize )
- {
- lwClip *clip;
- lwPlugin *filt;
- unsigned int id;
- unsigned short sz;
- int pos, rlen;
- /* allocate the Clip structure */
- clip = (lwClip*)Mem_ClearedAlloc( sizeof( lwClip ) );
- if ( !clip ) goto Fail;
- clip->contrast.val = 1.0f;
- clip->brightness.val = 1.0f;
- clip->saturation.val = 1.0f;
- clip->gamma.val = 1.0f;
- /* remember where we started */
- set_flen( 0 );
- pos = fp->Tell();
- /* index */
- clip->index = getI4( fp );
- /* first subchunk header */
- clip->type = getU4( fp );
- sz = getU2( fp );
- if ( 0 > get_flen() ) goto Fail;
- sz += sz & 1;
- set_flen( 0 );
- switch ( clip->type ) {
- case ID_STIL:
- clip->source.still.name = getS0( fp );
- break;
- case ID_ISEQ:
- clip->source.seq.digits = getU1( fp );
- clip->source.seq.flags = getU1( fp );
- clip->source.seq.offset = getI2( fp );
- clip->source.seq.start = getI2( fp );
- clip->source.seq.end = getI2( fp );
- clip->source.seq.prefix = getS0( fp );
- clip->source.seq.suffix = getS0( fp );
- break;
- case ID_ANIM:
- clip->source.anim.name = getS0( fp );
- clip->source.anim.server = getS0( fp );
- rlen = get_flen();
- clip->source.anim.data = getbytes( fp, sz - rlen );
- break;
- case ID_XREF:
- clip->source.xref.index = getI4( fp );
- clip->source.xref.string = getS0( fp );
- break;
- case ID_STCC:
- clip->source.cycle.lo = getI2( fp );
- clip->source.cycle.hi = getI2( fp );
- clip->source.cycle.name = getS0( fp );
- break;
- default:
- break;
- }
- /* error while reading current subchunk? */
- rlen = get_flen();
- if ( rlen < 0 || rlen > sz ) goto Fail;
- /* skip unread parts of the current subchunk */
- if ( rlen < sz )
- fp->Seek( sz - rlen, FS_SEEK_CUR );
- /* end of the CLIP chunk? */
- rlen = fp->Tell() - pos;
- if ( cksize < rlen ) goto Fail;
- if ( cksize == rlen )
- return clip;
- /* process subchunks as they're encountered */
- id = getU4( fp );
- sz = getU2( fp );
- if ( 0 > get_flen() ) goto Fail;
- while ( 1 ) {
- sz += sz & 1;
- set_flen( 0 );
- switch ( id ) {
- case ID_TIME:
- clip->start_time = getF4( fp );
- clip->duration = getF4( fp );
- clip->frame_rate = getF4( fp );
- break;
- case ID_CONT:
- clip->contrast.val = getF4( fp );
- clip->contrast.eindex = getVX( fp );
- break;
- case ID_BRIT:
- clip->brightness.val = getF4( fp );
- clip->brightness.eindex = getVX( fp );
- break;
- case ID_SATR:
- clip->saturation.val = getF4( fp );
- clip->saturation.eindex = getVX( fp );
- break;
- case ID_HUE:
- clip->hue.val = getF4( fp );
- clip->hue.eindex = getVX( fp );
- break;
- case ID_GAMM:
- clip->gamma.val = getF4( fp );
- clip->gamma.eindex = getVX( fp );
- break;
- case ID_NEGA:
- clip->negative = getU2( fp );
- break;
- case ID_IFLT:
- case ID_PFLT:
- filt = (lwPlugin*)Mem_ClearedAlloc( sizeof( lwPlugin ) );
- if ( !filt ) goto Fail;
- filt->name = getS0( fp );
- filt->flags = getU2( fp );
- rlen = get_flen();
- filt->data = getbytes( fp, sz - rlen );
- if ( id == ID_IFLT ) {
- lwListAdd( (void**)&clip->ifilter, filt );
- clip->nifilters++;
- }
- else {
- lwListAdd( (void**)&clip->pfilter, filt );
- clip->npfilters++;
- }
- break;
- default:
- break;
- }
- /* error while reading current subchunk? */
- rlen = get_flen();
- if ( rlen < 0 || rlen > sz ) goto Fail;
- /* skip unread parts of the current subchunk */
- if ( rlen < sz )
- fp->Seek( sz - rlen, FS_SEEK_CUR );
- /* end of the CLIP chunk? */
- rlen = fp->Tell() - pos;
- if ( cksize < rlen ) goto Fail;
- if ( cksize == rlen ) break;
- /* get the next chunk header */
- set_flen( 0 );
- id = getU4( fp );
- sz = getU2( fp );
- if ( 6 != get_flen() ) goto Fail;
- }
- return clip;
- Fail:
- lwFreeClip( clip );
- return NULL;
- }
- /*
- ======================================================================
- lwFindClip()
- Returns an lwClip pointer, given a clip index.
- ====================================================================== */
- lwClip *lwFindClip( lwClip *list, int index )
- {
- lwClip *clip;
- clip = list;
- while ( clip ) {
- if ( clip->index == index ) break;
- clip = clip->next;
- }
- return clip;
- }
- /*
- ======================================================================
- lwFreeEnvelope()
- Free the memory used by an lwEnvelope.
- ====================================================================== */
- void lwFree( void *ptr ) {
- Mem_Free( ptr );
- }
- void lwFreeEnvelope( lwEnvelope *env )
- {
- if ( env ) {
- if ( env->name ) Mem_Free( env->name );
- lwListFree( env->key, lwFree );
- lwListFree( env->cfilter, (void (__cdecl *)(void *))lwFreePlugin );
- Mem_Free( env );
- }
- }
- static int compare_keys( lwKey *k1, lwKey *k2 )
- {
- return k1->time > k2->time ? 1 : k1->time < k2->time ? -1 : 0;
- }
- /*
- ======================================================================
- lwGetEnvelope()
- Read an ENVL chunk from an LWO2 file.
- ====================================================================== */
- lwEnvelope *lwGetEnvelope( idFile *fp, int cksize )
- {
- lwEnvelope *env;
- lwKey *key;
- lwPlugin *plug;
- unsigned int id;
- unsigned short sz;
- float f[ 4 ];
- int i, nparams, pos, rlen;
- /* allocate the Envelope structure */
- env = (lwEnvelope*)Mem_ClearedAlloc( sizeof( lwEnvelope ) );
- if ( !env ) goto Fail;
- /* remember where we started */
- set_flen( 0 );
- pos = fp->Tell();
- /* index */
- env->index = getVX( fp );
- /* first subchunk header */
- id = getU4( fp );
- sz = getU2( fp );
- if ( 0 > get_flen() ) goto Fail;
- /* process subchunks as they're encountered */
- while ( 1 ) {
- sz += sz & 1;
- set_flen( 0 );
- switch ( id ) {
- case ID_TYPE:
- env->type = getU2( fp );
- break;
- case ID_NAME:
- env->name = getS0( fp );
- break;
- case ID_PRE:
- env->behavior[ 0 ] = getU2( fp );
- break;
- case ID_POST:
- env->behavior[ 1 ] = getU2( fp );
- break;
- case ID_KEY:
- key = (lwKey*)Mem_ClearedAlloc( sizeof( lwKey ) );
- if ( !key ) goto Fail;
- key->time = getF4( fp );
- key->value = getF4( fp );
- lwListInsert( (void**)&env->key, key, (int (__cdecl *)(void *,void *))compare_keys );
- env->nkeys++;
- break;
- case ID_SPAN:
- if ( !key ) goto Fail;
- key->shape = getU4( fp );
- nparams = ( sz - 4 ) / 4;
- if ( nparams > 4 ) nparams = 4;
- for ( i = 0; i < nparams; i++ )
- f[ i ] = getF4( fp );
- switch ( key->shape ) {
- case ID_TCB:
- key->tension = f[ 0 ];
- key->continuity = f[ 1 ];
- key->bias = f[ 2 ];
- break;
- case ID_BEZI:
- case ID_HERM:
- case ID_BEZ2:
- for ( i = 0; i < nparams; i++ )
- key->param[ i ] = f[ i ];
- break;
- }
- break;
- case ID_CHAN:
- plug = (lwPlugin*)Mem_ClearedAlloc( sizeof( lwPlugin ) );
- if ( !plug ) goto Fail;
- plug->name = getS0( fp );
- plug->flags = getU2( fp );
- plug->data = getbytes( fp, sz - get_flen() );
- lwListAdd( (void**)&env->cfilter, plug );
- env->ncfilters++;
- break;
- default:
- break;
- }
- /* error while reading current subchunk? */
- rlen = get_flen();
- if ( rlen < 0 || rlen > sz ) goto Fail;
- /* skip unread parts of the current subchunk */
- if ( rlen < sz )
- fp->Seek( sz - rlen, FS_SEEK_CUR );
- /* end of the ENVL chunk? */
- rlen = fp->Tell() - pos;
- if ( cksize < rlen ) goto Fail;
- if ( cksize == rlen ) break;
- /* get the next subchunk header */
- set_flen( 0 );
- id = getU4( fp );
- sz = getU2( fp );
- if ( 6 != get_flen() ) goto Fail;
- }
- return env;
- Fail:
- lwFreeEnvelope( env );
- return NULL;
- }
- /*
- ======================================================================
- lwFindEnvelope()
- Returns an lwEnvelope pointer, given an envelope index.
- ====================================================================== */
- lwEnvelope *lwFindEnvelope( lwEnvelope *list, int index )
- {
- lwEnvelope *env;
- env = list;
- while ( env ) {
- if ( env->index == index ) break;
- env = env->next;
- }
- return env;
- }
- /*
- ======================================================================
- range()
- Given the value v of a periodic function, returns the equivalent value
- v2 in the principal interval [lo, hi]. If i isn't NULL, it receives
- the number of wavelengths between v and v2.
- v2 = v - i * (hi - lo)
- For example, range( 3 pi, 0, 2 pi, i ) returns pi, with i = 1.
- ====================================================================== */
- static float range( float v, float lo, float hi, int *i )
- {
- float v2, r = hi - lo;
- if ( r == 0.0 ) {
- if ( i ) *i = 0;
- return lo;
- }
- v2 = lo + v - r * ( float ) floor(( double ) v / r );
- if ( i ) *i = -( int )(( v2 - v ) / r + ( v2 > v ? 0.5 : -0.5 ));
- return v2;
- }
- /*
- ======================================================================
- hermite()
- Calculate the Hermite coefficients.
- ====================================================================== */
- static void hermite( float t, float *h1, float *h2, float *h3, float *h4 )
- {
- float t2, t3;
- t2 = t * t;
- t3 = t * t2;
- *h2 = 3.0f * t2 - t3 - t3;
- *h1 = 1.0f - *h2;
- *h4 = t3 - t2;
- *h3 = *h4 - t2 + t;
- }
- /*
- ======================================================================
- bezier()
- Interpolate the value of a 1D Bezier curve.
- ====================================================================== */
- static float bezier( float x0, float x1, float x2, float x3, float t )
- {
- float a, b, c, t2, t3;
- t2 = t * t;
- t3 = t2 * t;
- c = 3.0f * ( x1 - x0 );
- b = 3.0f * ( x2 - x1 ) - c;
- a = x3 - x0 - c - b;
- return a * t3 + b * t2 + c * t + x0;
- }
- /*
- ======================================================================
- bez2_time()
- Find the t for which bezier() returns the input time. The handle
- endpoints of a BEZ2 curve represent the control points, and these have
- (time, value) coordinates, so time is used as both a coordinate and a
- parameter for this curve type.
- ====================================================================== */
- static float bez2_time( float x0, float x1, float x2, float x3, float time,
- float *t0, float *t1 )
- {
- float v, t;
- t = *t0 + ( *t1 - *t0 ) * 0.5f;
- v = bezier( x0, x1, x2, x3, t );
- if ( idMath::Fabs( time - v ) > .0001f ) {
- if ( v > time )
- *t1 = t;
- else
- *t0 = t;
- return bez2_time( x0, x1, x2, x3, time, t0, t1 );
- }
- else
- return t;
- }
- /*
- ======================================================================
- bez2()
- Interpolate the value of a BEZ2 curve.
- ====================================================================== */
- static float bez2( lwKey *key0, lwKey *key1, float time )
- {
- float x, y, t, t0 = 0.0f, t1 = 1.0f;
- if ( key0->shape == ID_BEZ2 )
- x = key0->time + key0->param[ 2 ];
- else
- x = key0->time + ( key1->time - key0->time ) / 3.0f;
- t = bez2_time( key0->time, x, key1->time + key1->param[ 0 ], key1->time,
- time, &t0, &t1 );
- if ( key0->shape == ID_BEZ2 )
- y = key0->value + key0->param[ 3 ];
- else
- y = key0->value + key0->param[ 1 ] / 3.0f;
- return bezier( key0->value, y, key1->param[ 1 ] + key1->value, key1->value, t );
- }
- /*
- ======================================================================
- outgoing()
- Return the outgoing tangent to the curve at key0. The value returned
- for the BEZ2 case is used when extrapolating a linear pre behavior and
- when interpolating a non-BEZ2 span.
- ====================================================================== */
- static float outgoing( lwKey *key0, lwKey *key1 )
- {
- float a, b, d, t, out;
- switch ( key0->shape )
- {
- case ID_TCB:
- a = ( 1.0f - key0->tension )
- * ( 1.0f + key0->continuity )
- * ( 1.0f + key0->bias );
- b = ( 1.0f - key0->tension )
- * ( 1.0f - key0->continuity )
- * ( 1.0f - key0->bias );
- d = key1->value - key0->value;
- if ( key0->prev ) {
- t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
- out = t * ( a * ( key0->value - key0->prev->value ) + b * d );
- }
- else
- out = b * d;
- break;
- case ID_LINE:
- d = key1->value - key0->value;
- if ( key0->prev ) {
- t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
- out = t * ( key0->value - key0->prev->value + d );
- }
- else
- out = d;
- break;
- case ID_BEZI:
- case ID_HERM:
- out = key0->param[ 1 ];
- if ( key0->prev )
- out *= ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
- break;
- case ID_BEZ2:
- out = key0->param[ 3 ] * ( key1->time - key0->time );
- if ( idMath::Fabs( key0->param[ 2 ] ) > 1e-5f )
- out /= key0->param[ 2 ];
- else
- out *= 1e5f;
- break;
- case ID_STEP:
- default:
- out = 0.0f;
- break;
- }
- return out;
- }
- /*
- ======================================================================
- incoming()
- Return the incoming tangent to the curve at key1. The value returned
- for the BEZ2 case is used when extrapolating a linear post behavior.
- ====================================================================== */
- static float incoming( lwKey *key0, lwKey *key1 )
- {
- float a, b, d, t, in;
- switch ( key1->shape )
- {
- case ID_LINE:
- d = key1->value - key0->value;
- if ( key1->next ) {
- t = ( key1->time - key0->time ) / ( key1->next->time - key0->time );
- in = t * ( key1->next->value - key1->value + d );
- }
- else
- in = d;
- break;
- case ID_TCB:
- a = ( 1.0f - key1->tension )
- * ( 1.0f - key1->continuity )
- * ( 1.0f + key1->bias );
- b = ( 1.0f - key1->tension )
- * ( 1.0f + key1->continuity )
- * ( 1.0f - key1->bias );
- d = key1->value - key0->value;
- if ( key1->next ) {
- t = ( key1->time - key0->time ) / ( key1->next->time - key0->time );
- in = t * ( b * ( key1->next->value - key1->value ) + a * d );
- }
- else
- in = a * d;
- break;
- case ID_BEZI:
- case ID_HERM:
- in = key1->param[ 0 ];
- if ( key1->next )
- in *= ( key1->time - key0->time ) / ( key1->next->time - key0->time );
- break;
- return in;
- case ID_BEZ2:
- in = key1->param[ 1 ] * ( key1->time - key0->time );
- if ( idMath::Fabs( key1->param[ 0 ] ) > 1e-5f )
- in /= key1->param[ 0 ];
- else
- in *= 1e5f;
- break;
- case ID_STEP:
- default:
- in = 0.0f;
- break;
- }
- return in;
- }
- /*
- ======================================================================
- evalEnvelope()
- Given a list of keys and a time, returns the interpolated value of the
- envelope at that time.
- ====================================================================== */
- float evalEnvelope( lwEnvelope *env, float time )
- {
- lwKey *key0, *key1, *skey, *ekey;
- float t, h1, h2, h3, h4, in, out, offset = 0.0f;
- int noff;
- /* if there's no key, the value is 0 */
- if ( env->nkeys == 0 ) return 0.0f;
- /* if there's only one key, the value is constant */
- if ( env->nkeys == 1 )
- return env->key->value;
- /* find the first and last keys */
- skey = ekey = env->key;
- while ( ekey->next ) ekey = ekey->next;
- /* use pre-behavior if time is before first key time */
- if ( time < skey->time ) {
- switch ( env->behavior[ 0 ] )
- {
- case BEH_RESET:
- return 0.0f;
- case BEH_CONSTANT:
- return skey->value;
- case BEH_REPEAT:
- time = range( time, skey->time, ekey->time, NULL );
- break;
- case BEH_OSCILLATE:
- time = range( time, skey->time, ekey->time, &noff );
- if ( noff % 2 )
- time = ekey->time - skey->time - time;
- break;
- case BEH_OFFSET:
- time = range( time, skey->time, ekey->time, &noff );
- offset = noff * ( ekey->value - skey->value );
- break;
- case BEH_LINEAR:
- out = outgoing( skey, skey->next )
- / ( skey->next->time - skey->time );
- return out * ( time - skey->time ) + skey->value;
- }
- }
- /* use post-behavior if time is after last key time */
- else if ( time > ekey->time ) {
- switch ( env->behavior[ 1 ] )
- {
- case BEH_RESET:
- return 0.0f;
- case BEH_CONSTANT:
- return ekey->value;
- case BEH_REPEAT:
- time = range( time, skey->time, ekey->time, NULL );
- break;
- case BEH_OSCILLATE:
- time = range( time, skey->time, ekey->time, &noff );
- if ( noff % 2 )
- time = ekey->time - skey->time - time;
- break;
- case BEH_OFFSET:
- time = range( time, skey->time, ekey->time, &noff );
- offset = noff * ( ekey->value - skey->value );
- break;
- case BEH_LINEAR:
- in = incoming( ekey->prev, ekey )
- / ( ekey->time - ekey->prev->time );
- return in * ( time - ekey->time ) + ekey->value;
- }
- }
- /* get the endpoints of the interval being evaluated */
- key0 = env->key;
- while ( time > key0->next->time )
- key0 = key0->next;
- key1 = key0->next;
- /* check for singularities first */
- if ( time == key0->time )
- return key0->value + offset;
- else if ( time == key1->time )
- return key1->value + offset;
- /* get interval length, time in [0, 1] */
- t = ( time - key0->time ) / ( key1->time - key0->time );
- /* interpolate */
- switch ( key1->shape )
- {
- case ID_TCB:
- case ID_BEZI:
- case ID_HERM:
- out = outgoing( key0, key1 );
- in = incoming( key0, key1 );
- hermite( t, &h1, &h2, &h3, &h4 );
- return h1 * key0->value + h2 * key1->value + h3 * out + h4 * in + offset;
- case ID_BEZ2:
- return bez2( key0, key1, time ) + offset;
- case ID_LINE:
- return key0->value + t * ( key1->value - key0->value ) + offset;
- case ID_STEP:
- return key0->value + offset;
- default:
- return offset;
- }
- }
- /*
- ======================================================================
- lwListFree()
- Free the items in a list.
- ====================================================================== */
- void lwListFree( void *list, void ( *freeNode )( void * ))
- {
- lwNode *node, *next;
- node = ( lwNode * ) list;
- while ( node ) {
- next = node->next;
- freeNode( node );
- node = next;
- }
- }
- /*
- ======================================================================
- lwListAdd()
- Append a node to a list.
- ====================================================================== */
- void lwListAdd( void **list, void *node )
- {
- lwNode *head, *tail;
- head = *(( lwNode ** ) list );
- if ( !head ) {
- *list = node;
- return;
- }
- while ( head ) {
- tail = head;
- head = head->next;
- }
- tail->next = ( lwNode * ) node;
- (( lwNode * ) node )->prev = tail;
- }
- /*
- ======================================================================
- lwListInsert()
- Insert a node into a list in sorted order.
- ====================================================================== */
- void lwListInsert( void **vlist, void *vitem, int ( *compare )( void *, void * ))
- {
- lwNode **list, *item, *node, *prev;
- if ( !*vlist ) {
- *vlist = vitem;
- return;
- }
- list = ( lwNode ** ) vlist;
- item = ( lwNode * ) vitem;
- node = *list;
- prev = NULL;
- while ( node ) {
- if ( 0 < compare( node, item )) break;
- prev = node;
- node = node->next;
- }
- if ( !prev ) {
- *list = item;
- node->prev = item;
- item->next = node;
- }
- else if ( !node ) {
- prev->next = item;
- item->prev = prev;
- }
- else {
- item->next = node;
- item->prev = prev;
- prev->next = item;
- node->prev = item;
- }
- }
- /*
- ======================================================================
- flen
- This accumulates a count of the number of bytes read. Callers can set
- it at the beginning of a sequence of reads and then retrieve it to get
- the number of bytes actually read. If one of the I/O functions fails,
- flen is set to an error code, after which the I/O functions ignore
- read requests until flen is reset.
- ====================================================================== */
- #define FLEN_ERROR -9999
- static int flen;
- void set_flen( int i ) { flen = i; }
- int get_flen( void ) { return flen; }
- void *getbytes( idFile *fp, int size )
- {
- void *data;
- if ( flen == FLEN_ERROR ) return NULL;
- if ( size < 0 ) {
- flen = FLEN_ERROR;
- return NULL;
- }
- data = Mem_ClearedAlloc( size );
- if ( !data ) {
- flen = FLEN_ERROR;
- return NULL;
- }
- if ( size != fp->Read( data, size ) ) {
- flen = FLEN_ERROR;
- Mem_Free( data );
- return NULL;
- }
- flen += size;
- return data;
- }
- void skipbytes( idFile *fp, int n )
- {
- if ( flen == FLEN_ERROR ) return;
- if ( fp->Seek( n, FS_SEEK_CUR ))
- flen = FLEN_ERROR;
- else
- flen += n;
- }
- int getI1( idFile *fp )
- {
- int i, c;
- if ( flen == FLEN_ERROR ) return 0;
- c = 0;
- i = fp->Read(&c, 1);
- if ( i < 0 ) {
- flen = FLEN_ERROR;
- return 0;
- }
- if ( c > 127 ) c -= 256;
- flen += 1;
- return c;
- }
- short getI2( idFile *fp )
- {
- short i;
- if ( flen == FLEN_ERROR ) return 0;
- if ( 2 != fp->Read( &i, 2 )) {
- flen = FLEN_ERROR;
- return 0;
- }
- BigRevBytes( &i, 2, 1 );
- flen += 2;
- return i;
- }
- int getI4( idFile *fp )
- {
- int i;
- if ( flen == FLEN_ERROR ) return 0;
- if ( 4 != fp->Read( &i, 4 )) {
- flen = FLEN_ERROR;
- return 0;
- }
- BigRevBytes( &i, 4, 1 );
- flen += 4;
- return i;
- }
- unsigned char getU1( idFile *fp )
- {
- int i, c;
- if ( flen == FLEN_ERROR ) return 0;
- c = 0;
- i = fp->Read(&c, 1);
- if ( i < 0 ) {
- flen = FLEN_ERROR;
- return 0;
- }
- flen += 1;
- return c;
- }
- unsigned short getU2( idFile *fp )
- {
- unsigned short i;
- if ( flen == FLEN_ERROR ) return 0;
- if ( 2 != fp->Read( &i, 2 )) {
- flen = FLEN_ERROR;
- return 0;
- }
- BigRevBytes( &i, 2, 1 );
- flen += 2;
- return i;
- }
- unsigned int getU4( idFile *fp )
- {
- unsigned int i;
- if ( flen == FLEN_ERROR ) return 0;
- if ( 4 != fp->Read( &i, 4 )) {
- flen = FLEN_ERROR;
- return 0;
- }
- BigRevBytes( &i, 4, 1 );
- flen += 4;
- return i;
- }
- int getVX( idFile *fp )
- {
- byte c;
- int i;
- if ( flen == FLEN_ERROR ) return 0;
- c = 0;
- if (fp->Read(&c, 1) == -1) {
- return 0;
- }
- if ( c != 0xFF ) {
- i = c << 8;
- c = 0;
- if (fp->Read(&c, 1) == -1) {
- return 0;
- }
- i |= c;
- flen += 2;
- }
- else {
- c = 0;
- if (fp->Read(&c, 1) == -1) {
- return 0;
- }
- i = c << 16;
- c = 0;
- if (fp->Read(&c, 1) == -1) {
- return 0;
- }
- i |= c << 8;
- c = 0;
- if (fp->Read(&c, 1) == -1) {
- return 0;
- }
- i |= c;
- flen += 4;
- }
- return i;
- }
- float getF4( idFile *fp )
- {
- float f;
- if ( flen == FLEN_ERROR ) return 0.0f;
- if ( 4 != fp->Read( &f, 4 ) ) {
- flen = FLEN_ERROR;
- return 0.0f;
- }
- BigRevBytes( &f, 4, 1 );
- flen += 4;
- if ( FLOAT_IS_DENORMAL( f ) ) {
- f = 0.0f;
- }
- return f;
- }
- char *getS0( idFile *fp )
- {
- char *s;
- int i, c, len, pos;
- if ( flen == FLEN_ERROR ) return NULL;
- pos = fp->Tell();
- for ( i = 1; ; i++ ) {
- c = 0;
- if (fp->Read(&c, 1) == -1) {
- flen = FLEN_ERROR;
- return NULL;
- }
- if ( c == 0 ) break;
- }
- if ( i == 1 ) {
- if ( fp->Seek( pos + 2, FS_SEEK_SET ))
- flen = FLEN_ERROR;
- else
- flen += 2;
- return NULL;
- }
- len = i + ( i & 1 );
- s = (char*)Mem_ClearedAlloc( len );
- if ( !s ) {
- flen = FLEN_ERROR;
- return NULL;
- }
- if ( fp->Seek( pos, FS_SEEK_SET )) {
- flen = FLEN_ERROR;
- return NULL;
- }
- if ( len != fp->Read( s, len )) {
- flen = FLEN_ERROR;
- return NULL;
- }
- flen += len;
- return s;
- }
- int sgetI1( unsigned char **bp )
- {
- int i;
- if ( flen == FLEN_ERROR ) return 0;
- i = **bp;
- if ( i > 127 ) i -= 256;
- flen += 1;
- *bp++;
- return i;
- }
- short sgetI2( unsigned char **bp )
- {
- short i;
- if ( flen == FLEN_ERROR ) return 0;
- memcpy( &i, *bp, 2 );
- BigRevBytes( &i, 2, 1 );
- flen += 2;
- *bp += 2;
- return i;
- }
- int sgetI4( unsigned char **bp )
- {
- int i;
- if ( flen == FLEN_ERROR ) return 0;
- memcpy( &i, *bp, 4 );
- BigRevBytes( &i, 4, 1 );
- flen += 4;
- *bp += 4;
- return i;
- }
- unsigned char sgetU1( unsigned char **bp )
- {
- unsigned char c;
- if ( flen == FLEN_ERROR ) return 0;
- c = **bp;
- flen += 1;
- *bp++;
- return c;
- }
- unsigned short sgetU2( unsigned char **bp )
- {
- unsigned char *buf = *bp;
- unsigned short i;
- if ( flen == FLEN_ERROR ) return 0;
- i = ( buf[ 0 ] << 8 ) | buf[ 1 ];
- flen += 2;
- *bp += 2;
- return i;
- }
- unsigned int sgetU4( unsigned char **bp )
- {
- unsigned int i;
- if ( flen == FLEN_ERROR ) return 0;
- memcpy( &i, *bp, 4 );
- BigRevBytes( &i, 4, 1 );
- flen += 4;
- *bp += 4;
- return i;
- }
- int sgetVX( unsigned char **bp )
- {
- unsigned char *buf = *bp;
- int i;
- if ( flen == FLEN_ERROR ) return 0;
- if ( buf[ 0 ] != 0xFF ) {
- i = buf[ 0 ] << 8 | buf[ 1 ];
- flen += 2;
- *bp += 2;
- }
- else {
- i = ( buf[ 1 ] << 16 ) | ( buf[ 2 ] << 8 ) | buf[ 3 ];
- flen += 4;
- *bp += 4;
- }
- return i;
- }
- float sgetF4( unsigned char **bp )
- {
- float f;
- if ( flen == FLEN_ERROR ) return 0.0f;
- memcpy( &f, *bp, 4 );
- BigRevBytes( &f, 4, 1 );
- flen += 4;
- *bp += 4;
- if ( FLOAT_IS_DENORMAL( f ) ) {
- f = 0.0f;
- }
- return f;
- }
- char *sgetS0( unsigned char **bp )
- {
- char *s;
- unsigned char *buf = *bp;
- int len;
- if ( flen == FLEN_ERROR ) return NULL;
- len = strlen( (const char*)buf ) + 1;
- if ( len == 1 ) {
- flen += 2;
- *bp += 2;
- return NULL;
- }
- len += len & 1;
- s = (char*)Mem_ClearedAlloc( len );
- if ( !s ) {
- flen = FLEN_ERROR;
- return NULL;
- }
- memcpy( s, buf, len );
- flen += len;
- *bp += len;
- return s;
- }
- /*
- ======================================================================
- lwFreeLayer()
- Free memory used by an lwLayer.
- ====================================================================== */
- void lwFreeLayer( lwLayer *layer )
- {
- if ( layer ) {
- if ( layer->name ) Mem_Free( layer->name );
- lwFreePoints( &layer->point );
- lwFreePolygons( &layer->polygon );
- lwListFree( layer->vmap, (void (__cdecl *)(void *))lwFreeVMap );
- Mem_Free( layer );
- }
- }
- /*
- ======================================================================
- lwFreeObject()
- Free memory used by an lwObject.
- ====================================================================== */
- void lwFreeObject( lwObject *object )
- {
- if ( object ) {
- lwListFree( object->layer, (void (__cdecl *)(void *))lwFreeLayer );
- lwListFree( object->env, (void (__cdecl *)(void *))lwFreeEnvelope );
- lwListFree( object->clip, (void (__cdecl *)(void *))lwFreeClip );
- lwListFree( object->surf, (void (__cdecl *)(void *))lwFreeSurface );
- lwFreeTags( &object->taglist );
- Mem_Free( object );
- }
- }
- /*
- ======================================================================
- lwGetObject()
- Returns the contents of a LightWave object, given its filename, or
- NULL if the file couldn't be loaded. On failure, failID and failpos
- can be used to diagnose the cause.
- 1. If the file isn't an LWO2 or an LWOB, failpos will contain 12 and
- failID will be unchanged.
- 2. If an error occurs while reading, failID will contain the most
- recently read IFF chunk ID, and failpos will contain the value
- returned by fp->Tell() at the time of the failure.
- 3. If the file couldn't be opened, or an error occurs while reading
- the first 12 bytes, both failID and failpos will be unchanged.
- If you don't need this information, failID and failpos can be NULL.
- ====================================================================== */
- lwObject *lwGetObject( const char *filename, unsigned int *failID, int *failpos )
- {
- idFile *fp = NULL;
- lwObject *object;
- lwLayer *layer;
- lwNode *node;
- int id, formsize, type, cksize;
- int i, rlen;
- fp = fileSystem->OpenFileRead( filename );
- if ( !fp ) {
- return NULL;
- }
- /* read the first 12 bytes */
- set_flen( 0 );
- id = getU4( fp );
- formsize = getU4( fp );
- type = getU4( fp );
- if ( 12 != get_flen() ) {
- fileSystem->CloseFile( fp );
- return NULL;
- }
- /* is this a LW object? */
- if ( id != ID_FORM ) {
- fileSystem->CloseFile( fp );
- if ( failpos ) *failpos = 12;
- return NULL;
- }
- if ( type != ID_LWO2 ) {
- fileSystem->CloseFile( fp );
- if ( type == ID_LWOB )
- return lwGetObject5( filename, failID, failpos );
- else {
- if ( failpos ) *failpos = 12;
- return NULL;
- }
- }
- /* allocate an object and a default layer */
- object = (lwObject*)Mem_ClearedAlloc( sizeof( lwObject ) );
- if ( !object ) goto Fail;
- layer = (lwLayer*)Mem_ClearedAlloc( sizeof( lwLayer ) );
- if ( !layer ) goto Fail;
- object->layer = layer;
- object->timeStamp = fp->Timestamp();
- /* get the first chunk header */
- id = getU4( fp );
- cksize = getU4( fp );
- if ( 0 > get_flen() ) goto Fail;
- /* process chunks as they're encountered */
- while ( 1 ) {
- cksize += cksize & 1;
- switch ( id )
- {
- case ID_LAYR:
- if ( object->nlayers > 0 ) {
- layer = (lwLayer*)Mem_ClearedAlloc( sizeof( lwLayer ) );
- if ( !layer ) goto Fail;
- lwListAdd( (void**)&object->layer, layer );
- }
- object->nlayers++;
- set_flen( 0 );
- layer->index = getU2( fp );
- layer->flags = getU2( fp );
- layer->pivot[ 0 ] = getF4( fp );
- layer->pivot[ 1 ] = getF4( fp );
- layer->pivot[ 2 ] = getF4( fp );
- layer->name = getS0( fp );
- rlen = get_flen();
- if ( rlen < 0 || rlen > cksize ) goto Fail;
- if ( rlen <= cksize - 2 )
- layer->parent = getU2( fp );
- rlen = get_flen();
- if ( rlen < cksize )
- fp->Seek( cksize - rlen, FS_SEEK_CUR );
- break;
- case ID_PNTS:
- if ( !lwGetPoints( fp, cksize, &layer->point ))
- goto Fail;
- break;
- case ID_POLS:
- if ( !lwGetPolygons( fp, cksize, &layer->polygon,
- layer->point.offset ))
- goto Fail;
- break;
- case ID_VMAP:
- case ID_VMAD:
- node = ( lwNode * ) lwGetVMap( fp, cksize, layer->point.offset,
- layer->polygon.offset, id == ID_VMAD );
- if ( !node ) goto Fail;
- lwListAdd( (void**)&layer->vmap, node );
- layer->nvmaps++;
- break;
- case ID_PTAG:
- if ( !lwGetPolygonTags( fp, cksize, &object->taglist,
- &layer->polygon ))
- goto Fail;
- break;
- case ID_BBOX:
- set_flen( 0 );
- for ( i = 0; i < 6; i++ )
- layer->bbox[ i ] = getF4( fp );
- rlen = get_flen();
- if ( rlen < 0 || rlen > cksize ) goto Fail;
- if ( rlen < cksize )
- fp->Seek( cksize - rlen, FS_SEEK_CUR );
- break;
- case ID_TAGS:
- if ( !lwGetTags( fp, cksize, &object->taglist ))
- goto Fail;
- break;
- case ID_ENVL:
- node = ( lwNode * ) lwGetEnvelope( fp, cksize );
- if ( !node ) goto Fail;
- lwListAdd( (void**)&object->env, node );
- object->nenvs++;
- break;
- case ID_CLIP:
- node = ( lwNode * ) lwGetClip( fp, cksize );
- if ( !node ) goto Fail;
- lwListAdd( (void**)&object->clip, node );
- object->nclips++;
- break;
- case ID_SURF:
- node = ( lwNode * ) lwGetSurface( fp, cksize );
- if ( !node ) goto Fail;
- lwListAdd( (void**)&object->surf, node );
- object->nsurfs++;
- break;
- case ID_DESC:
- case ID_TEXT:
- case ID_ICON:
- default:
- fp->Seek( cksize, FS_SEEK_CUR );
- break;
- }
- /* end of the file? */
- if ( formsize <= fp->Tell() - 8 ) break;
- /* get the next chunk header */
- set_flen( 0 );
- id = getU4( fp );
- cksize = getU4( fp );
- if ( 8 != get_flen() ) goto Fail;
- }
- fileSystem->CloseFile( fp );
- fp = NULL;
- if ( object->nlayers == 0 )
- object->nlayers = 1;
- layer = object->layer;
- while ( layer ) {
- lwGetBoundingBox( &layer->point, layer->bbox );
- lwGetPolyNormals( &layer->point, &layer->polygon );
- if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail;
- if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist,
- &object->surf, &object->nsurfs )) goto Fail;
- lwGetVertNormals( &layer->point, &layer->polygon );
- if ( !lwGetPointVMaps( &layer->point, layer->vmap )) goto Fail;
- if ( !lwGetPolyVMaps( &layer->polygon, layer->vmap )) goto Fail;
- layer = layer->next;
- }
- return object;
- Fail:
- if ( failID ) *failID = id;
- if ( fp ) {
- if ( failpos ) *failpos = fp->Tell();
- fileSystem->CloseFile( fp );
- }
- lwFreeObject( object );
- return NULL;
- }
- /* IDs specific to LWOB */
- #define ID_SRFS LWID_('S','R','F','S')
- #define ID_FLAG LWID_('F','L','A','G')
- #define ID_VLUM LWID_('V','L','U','M')
- #define ID_VDIF LWID_('V','D','I','F')
- #define ID_VSPC LWID_('V','S','P','C')
- #define ID_RFLT LWID_('R','F','L','T')
- #define ID_BTEX LWID_('B','T','E','X')
- #define ID_CTEX LWID_('C','T','E','X')
- #define ID_DTEX LWID_('D','T','E','X')
- #define ID_LTEX LWID_('L','T','E','X')
- #define ID_RTEX LWID_('R','T','E','X')
- #define ID_STEX LWID_('S','T','E','X')
- #define ID_TTEX LWID_('T','T','E','X')
- #define ID_TFLG LWID_('T','F','L','G')
- #define ID_TSIZ LWID_('T','S','I','Z')
- #define ID_TCTR LWID_('T','C','T','R')
- #define ID_TFAL LWID_('T','F','A','L')
- #define ID_TVEL LWID_('T','V','E','L')
- #define ID_TCLR LWID_('T','C','L','R')
- #define ID_TVAL LWID_('T','V','A','L')
- #define ID_TAMP LWID_('T','A','M','P')
- #define ID_TIMG LWID_('T','I','M','G')
- #define ID_TAAS LWID_('T','A','A','S')
- #define ID_TREF LWID_('T','R','E','F')
- #define ID_TOPC LWID_('T','O','P','C')
- #define ID_SDAT LWID_('S','D','A','T')
- #define ID_TFP0 LWID_('T','F','P','0')
- #define ID_TFP1 LWID_('T','F','P','1')
- /*
- ======================================================================
- add_clip()
- Add a clip to the clip list. Used to store the contents of an RIMG or
- TIMG surface subchunk.
- ====================================================================== */
- static int add_clip( char *s, lwClip **clist, int *nclips )
- {
- lwClip *clip;
- char *p;
- clip = (lwClip*)Mem_ClearedAlloc( sizeof( lwClip ) );
- if ( !clip ) return 0;
- clip->contrast.val = 1.0f;
- clip->brightness.val = 1.0f;
- clip->saturation.val = 1.0f;
- clip->gamma.val = 1.0f;
- if ( p = strstr( s, "(sequence)" )) {
- p[ -1 ] = 0;
- clip->type = ID_ISEQ;
- clip->source.seq.prefix = s;
- clip->source.seq.digits = 3;
- }
- else {
- clip->type = ID_STIL;
- clip->source.still.name = s;
- }
- *nclips++;
- clip->index = *nclips;
- lwListAdd( (void**)clist, clip );
- return clip->index;
- }
- /*
- ======================================================================
- add_tvel()
- Add a triple of envelopes to simulate the old texture velocity
- parameters.
- ====================================================================== */
- static int add_tvel( float pos[], float vel[], lwEnvelope **elist, int *nenvs )
- {
- lwEnvelope *env;
- lwKey *key0, *key1;
- int i;
- for ( i = 0; i < 3; i++ ) {
- env = (lwEnvelope*)Mem_ClearedAlloc( sizeof( lwEnvelope ) );
- key0 = (lwKey*)Mem_ClearedAlloc( sizeof( lwKey ) );
- key1 = (lwKey*)Mem_ClearedAlloc( sizeof( lwKey ) );
- if ( !env || !key0 || !key1 ) return 0;
- key0->next = key1;
- key0->value = pos[ i ];
- key0->time = 0.0f;
- key1->prev = key0;
- key1->value = pos[ i ] + vel[ i ] * 30.0f;
- key1->time = 1.0f;
- key0->shape = key1->shape = ID_LINE;
- env->index = *nenvs + i + 1;
- env->type = 0x0301 + i;
- env->name = (char*)Mem_ClearedAlloc( 11 );
- if ( env->name ) {
- strcpy( env->name, "Position.X" );
- env->name[ 9 ] += i;
- }
- env->key = key0;
- env->nkeys = 2;
- env->behavior[ 0 ] = BEH_LINEAR;
- env->behavior[ 1 ] = BEH_LINEAR;
- lwListAdd( (void**)elist, env );
- }
- *nenvs += 3;
- return env->index - 2;
- }
- /*
- ======================================================================
- get_texture()
- Create a new texture for BTEX, CTEX, etc. subchunks.
- ====================================================================== */
- static lwTexture *get_texture( char *s )
- {
- lwTexture *tex;
- tex = (lwTexture*)Mem_ClearedAlloc( sizeof( lwTexture ) );
- if ( !tex ) return NULL;
- tex->tmap.size.val[ 0 ] =
- tex->tmap.size.val[ 1 ] =
- tex->tmap.size.val[ 2 ] = 1.0f;
- tex->opacity.val = 1.0f;
- tex->enabled = 1;
- if ( strstr( s, "Image Map" )) {
- tex->type = ID_IMAP;
- if ( strstr( s, "Planar" )) tex->param.imap.projection = 0;
- else if ( strstr( s, "Cylindrical" )) tex->param.imap.projection = 1;
- else if ( strstr( s, "Spherical" )) tex->param.imap.projection = 2;
- else if ( strstr( s, "Cubic" )) tex->param.imap.projection = 3;
- else if ( strstr( s, "Front" )) tex->param.imap.projection = 4;
- tex->param.imap.aa_strength = 1.0f;
- tex->param.imap.amplitude.val = 1.0f;
- Mem_Free( s );
- }
- else {
- tex->type = ID_PROC;
- tex->param.proc.name = s;
- }
- return tex;
- }
- /*
- ======================================================================
- lwGetSurface5()
- Read an lwSurface from an LWOB file.
- ====================================================================== */
- lwSurface *lwGetSurface5( idFile *fp, int cksize, lwObject *obj )
- {
- lwSurface *surf;
- lwTexture *tex;
- lwPlugin *shdr;
- char *s;
- float v[ 3 ];
- unsigned int id, flags;
- unsigned short sz;
- int pos, rlen, i;
- /* allocate the Surface structure */
- surf = (lwSurface*)Mem_ClearedAlloc( sizeof( lwSurface ) );
- if ( !surf ) goto Fail;
- /* non-zero defaults */
- surf->color.rgb[ 0 ] = 0.78431f;
- surf->color.rgb[ 1 ] = 0.78431f;
- surf->color.rgb[ 2 ] = 0.78431f;
- surf->diffuse.val = 1.0f;
- surf->glossiness.val = 0.4f;
- surf->bump.val = 1.0f;
- surf->eta.val = 1.0f;
- surf->sideflags = 1;
- /* remember where we started */
- set_flen( 0 );
- pos = fp->Tell();
- /* name */
- surf->name = getS0( fp );
- /* first subchunk header */
- id = getU4( fp );
- sz = getU2( fp );
- if ( 0 > get_flen() ) goto Fail;
- /* process subchunks as they're encountered */
- while ( 1 ) {
- sz += sz & 1;
- set_flen( 0 );
- switch ( id ) {
- case ID_COLR:
- surf->color.rgb[ 0 ] = getU1( fp ) / 255.0f;
- surf->color.rgb[ 1 ] = getU1( fp ) / 255.0f;
- surf->color.rgb[ 2 ] = getU1( fp ) / 255.0f;
- break;
- case ID_FLAG:
- flags = getU2( fp );
- if ( flags & 4 ) surf->smooth = 1.56207f;
- if ( flags & 8 ) surf->color_hilite.val = 1.0f;
- if ( flags & 16 ) surf->color_filter.val = 1.0f;
- if ( flags & 128 ) surf->dif_sharp.val = 0.5f;
- if ( flags & 256 ) surf->sideflags = 3;
- if ( flags & 512 ) surf->add_trans.val = 1.0f;
- break;
- case ID_LUMI:
- surf->luminosity.val = getI2( fp ) / 256.0f;
- break;
- case ID_VLUM:
- surf->luminosity.val = getF4( fp );
- break;
- case ID_DIFF:
- surf->diffuse.val = getI2( fp ) / 256.0f;
- break;
- case ID_VDIF:
- surf->diffuse.val = getF4( fp );
- break;
- case ID_SPEC:
- surf->specularity.val = getI2( fp ) / 256.0f;
- break;
- case ID_VSPC:
- surf->specularity.val = getF4( fp );
- break;
- case ID_GLOS:
- surf->glossiness.val = ( float ) logf( ( float) getU2( fp )) / 20.7944f;
- break;
- case ID_SMAN:
- surf->smooth = getF4( fp );
- break;
- case ID_REFL:
- surf->reflection.val.val = getI2( fp ) / 256.0f;
- break;
- case ID_RFLT:
- surf->reflection.options = getU2( fp );
- break;
- case ID_RIMG:
- s = getS0( fp );
- surf->reflection.cindex = add_clip( s, &obj->clip, &obj->nclips );
- surf->reflection.options = 3;
- break;
- case ID_RSAN:
- surf->reflection.seam_angle = getF4( fp );
- break;
- case ID_TRAN:
- surf->transparency.val.val = getI2( fp ) / 256.0f;
- break;
- case ID_RIND:
- surf->eta.val = getF4( fp );
- break;
- case ID_BTEX:
- s = (char*)getbytes( fp, sz );
- tex = get_texture( s );
- lwListAdd( (void**)&surf->bump.tex, tex );
- break;
- case ID_CTEX:
- s = (char*)getbytes( fp, sz );
- tex = get_texture( s );
- lwListAdd( (void**)&surf->color.tex, tex );
- break;
- case ID_DTEX:
- s = (char*)getbytes( fp, sz );
- tex = get_texture( s );
- lwListAdd( (void**)&surf->diffuse.tex, tex );
- break;
- case ID_LTEX:
- s = (char*)getbytes( fp, sz );
- tex = get_texture( s );
- lwListAdd( (void**)&surf->luminosity.tex, tex );
- break;
- case ID_RTEX:
- s = (char*)getbytes( fp, sz );
- tex = get_texture( s );
- lwListAdd( (void**)&surf->reflection.val.tex, tex );
- break;
- case ID_STEX:
- s = (char*)getbytes( fp, sz );
- tex = get_texture( s );
- lwListAdd( (void**)&surf->specularity.tex, tex );
- break;
- case ID_TTEX:
- s = (char*)getbytes( fp, sz );
- tex = get_texture( s );
- lwListAdd( (void**)&surf->transparency.val.tex, tex );
- break;
- case ID_TFLG:
- flags = getU2( fp );
- if ( flags & 1 ) i = 0;
- if ( flags & 2 ) i = 1;
- if ( flags & 4 ) i = 2;
- tex->axis = i;
- if ( tex->type == ID_IMAP )
- tex->param.imap.axis = i;
- else
- tex->param.proc.axis = i;
- if ( flags & 8 ) tex->tmap.coord_sys = 1;
- if ( flags & 16 ) tex->negative = 1;
- if ( flags & 32 ) tex->param.imap.pblend = 1;
- if ( flags & 64 ) {
- tex->param.imap.aa_strength = 1.0f;
- tex->param.imap.aas_flags = 1;
- }
- break;
- case ID_TSIZ:
- for ( i = 0; i < 3; i++ )
- tex->tmap.size.val[ i ] = getF4( fp );
- break;
- case ID_TCTR:
- for ( i = 0; i < 3; i++ )
- tex->tmap.center.val[ i ] = getF4( fp );
- break;
- case ID_TFAL:
- for ( i = 0; i < 3; i++ )
- tex->tmap.falloff.val[ i ] = getF4( fp );
- break;
- case ID_TVEL:
- for ( i = 0; i < 3; i++ )
- v[ i ] = getF4( fp );
- tex->tmap.center.eindex = add_tvel( tex->tmap.center.val, v,
- &obj->env, &obj->nenvs );
- break;
- case ID_TCLR:
- if ( tex->type == ID_PROC )
- for ( i = 0; i < 3; i++ )
- tex->param.proc.value[ i ] = getU1( fp ) / 255.0f;
- break;
- case ID_TVAL:
- tex->param.proc.value[ 0 ] = getI2( fp ) / 256.0f;
- break;
- case ID_TAMP:
- if ( tex->type == ID_IMAP )
- tex->param.imap.amplitude.val = getF4( fp );
- break;
- case ID_TIMG:
- s = getS0( fp );
- tex->param.imap.cindex = add_clip( s, &obj->clip, &obj->nclips );
- break;
- case ID_TAAS:
- tex->param.imap.aa_strength = getF4( fp );
- tex->param.imap.aas_flags = 1;
- break;
- case ID_TREF:
- tex->tmap.ref_object = (char*)getbytes( fp, sz );
- break;
- case ID_TOPC:
- tex->opacity.val = getF4( fp );
- break;
- case ID_TFP0:
- if ( tex->type == ID_IMAP )
- tex->param.imap.wrapw.val = getF4( fp );
- break;
- case ID_TFP1:
- if ( tex->type == ID_IMAP )
- tex->param.imap.wraph.val = getF4( fp );
- break;
- case ID_SHDR:
- shdr = (lwPlugin*)Mem_ClearedAlloc( sizeof( lwPlugin ) );
- if ( !shdr ) goto Fail;
- shdr->name = (char*)getbytes( fp, sz );
- lwListAdd( (void**)&surf->shader, shdr );
- surf->nshaders++;
- break;
- case ID_SDAT:
- shdr->data = getbytes( fp, sz );
- break;
- default:
- break;
- }
- /* error while reading current subchunk? */
- rlen = get_flen();
- if ( rlen < 0 || rlen > sz ) goto Fail;
- /* skip unread parts of the current subchunk */
- if ( rlen < sz )
- fp->Seek( sz - rlen, FS_SEEK_CUR );
- /* end of the SURF chunk? */
- if ( cksize <= fp->Tell() - pos )
- break;
- /* get the next subchunk header */
- set_flen( 0 );
- id = getU4( fp );
- sz = getU2( fp );
- if ( 6 != get_flen() ) goto Fail;
- }
- return surf;
- Fail:
- if ( surf ) lwFreeSurface( surf );
- return NULL;
- }
- /*
- ======================================================================
- lwGetPolygons5()
- Read polygon records from a POLS chunk in an LWOB file. The polygons
- are added to the array in the lwPolygonList.
- ====================================================================== */
- int lwGetPolygons5( idFile *fp, int cksize, lwPolygonList *plist, int ptoffset )
- {
- lwPolygon *pp;
- lwPolVert *pv;
- unsigned char *buf, *bp;
- int i, j, nv, nverts, npols;
- if ( cksize == 0 ) return 1;
- /* read the whole chunk */
- set_flen( 0 );
- buf = (unsigned char*)getbytes( fp, cksize );
- if ( !buf ) goto Fail;
- /* count the polygons and vertices */
- nverts = 0;
- npols = 0;
- bp = buf;
- while ( bp < buf + cksize ) {
- nv = sgetU2( &bp );
- nverts += nv;
- npols++;
- bp += 2 * nv;
- i = sgetI2( &bp );
- if ( i < 0 ) bp += 2; /* detail polygons */
- }
- if ( !lwAllocPolygons( plist, npols, nverts ))
- goto Fail;
- /* fill in the new polygons */
- bp = buf;
- pp = plist->pol + plist->offset;
- pv = plist->pol[ 0 ].v + plist->voffset;
- for ( i = 0; i < npols; i++ ) {
- nv = sgetU2( &bp );
- pp->nverts = nv;
- pp->type = ID_FACE;
- if ( !pp->v ) pp->v = pv;
- for ( j = 0; j < nv; j++ )
- pv[ j ].index = sgetU2( &bp ) + ptoffset;
- j = sgetI2( &bp );
- if ( j < 0 ) {
- j = -j;
- bp += 2;
- }
- j -= 1;
- pp->surf = ( lwSurface * ) j;
- pp++;
- pv += nv;
- }
- Mem_Free( buf );
- return 1;
- Fail:
- if ( buf ) Mem_Free( buf );
- lwFreePolygons( plist );
- return 0;
- }
- /*
- ======================================================================
- getLWObject5()
- Returns the contents of an LWOB, given its filename, or NULL if the
- file couldn't be loaded. On failure, failID and failpos can be used
- to diagnose the cause.
- 1. If the file isn't an LWOB, failpos will contain 12 and failID will
- be unchanged.
- 2. If an error occurs while reading an LWOB, failID will contain the
- most recently read IFF chunk ID, and failpos will contain the
- value returned by fp->Tell() at the time of the failure.
- 3. If the file couldn't be opened, or an error occurs while reading
- the first 12 bytes, both failID and failpos will be unchanged.
- If you don't need this information, failID and failpos can be NULL.
- ====================================================================== */
- lwObject *lwGetObject5( const char *filename, unsigned int *failID, int *failpos )
- {
- idFile *fp = NULL;
- lwObject *object;
- lwLayer *layer;
- lwNode *node;
- int id, formsize, type, cksize;
- /* open the file */
- //fp = fopen( filename, "rb" );
- //if ( !fp ) return NULL;
- /* read the first 12 bytes */
- fp = fileSystem->OpenFileRead( filename );
- if ( !fp ) {
- return NULL;
- }
- set_flen( 0 );
- id = getU4( fp );
- formsize = getU4( fp );
- type = getU4( fp );
- if ( 12 != get_flen() ) {
- fileSystem->CloseFile( fp );
- return NULL;
- }
- /* LWOB? */
- if ( id != ID_FORM || type != ID_LWOB ) {
- fileSystem->CloseFile( fp );
- if ( failpos ) *failpos = 12;
- return NULL;
- }
- /* allocate an object and a default layer */
- object = (lwObject*)Mem_ClearedAlloc( sizeof( lwObject ) );
- if ( !object ) goto Fail2;
- layer = (lwLayer*)Mem_ClearedAlloc( sizeof( lwLayer ) );
- if ( !layer ) goto Fail2;
- object->layer = layer;
- object->nlayers = 1;
- /* get the first chunk header */
- id = getU4( fp );
- cksize = getU4( fp );
- if ( 0 > get_flen() ) goto Fail2;
- /* process chunks as they're encountered */
- while ( 1 ) {
- cksize += cksize & 1;
- switch ( id )
- {
- case ID_PNTS:
- if ( !lwGetPoints( fp, cksize, &layer->point ))
- goto Fail2;
- break;
- case ID_POLS:
- if ( !lwGetPolygons5( fp, cksize, &layer->polygon,
- layer->point.offset ))
- goto Fail2;
- break;
- case ID_SRFS:
- if ( !lwGetTags( fp, cksize, &object->taglist ))
- goto Fail2;
- break;
- case ID_SURF:
- node = ( lwNode * ) lwGetSurface5( fp, cksize, object );
- if ( !node ) goto Fail2;
- lwListAdd( (void**)&object->surf, node );
- object->nsurfs++;
- break;
- default:
- fp->Seek( cksize, FS_SEEK_CUR );
- break;
- }
- /* end of the file? */
- if ( formsize <= fp->Tell() - 8 ) break;
- /* get the next chunk header */
- set_flen( 0 );
- id = getU4( fp );
- cksize = getU4( fp );
- if ( 8 != get_flen() ) goto Fail2;
- }
- fileSystem->CloseFile( fp );
- fp = NULL;
- lwGetBoundingBox( &layer->point, layer->bbox );
- lwGetPolyNormals( &layer->point, &layer->polygon );
- if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail2;
- if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist,
- &object->surf, &object->nsurfs )) goto Fail2;
- lwGetVertNormals( &layer->point, &layer->polygon );
- return object;
- Fail2:
- if ( failID ) *failID = id;
- if ( fp ) {
- if ( failpos ) *failpos = fp->Tell();
- fileSystem->CloseFile( fp );
- }
- lwFreeObject( object );
- return NULL;
- }
- /*
- ======================================================================
- lwFreePoints()
- Free the memory used by an lwPointList.
- ====================================================================== */
- void lwFreePoints( lwPointList *point )
- {
- int i;
- if ( point ) {
- if ( point->pt ) {
- for ( i = 0; i < point->count; i++ ) {
- if ( point->pt[ i ].pol ) Mem_Free( point->pt[ i ].pol );
- if ( point->pt[ i ].vm ) Mem_Free( point->pt[ i ].vm );
- }
- Mem_Free( point->pt );
- }
- memset( point, 0, sizeof( lwPointList ));
- }
- }
- /*
- ======================================================================
- lwFreePolygons()
- Free the memory used by an lwPolygonList.
- ====================================================================== */
- void lwFreePolygons( lwPolygonList *plist )
- {
- int i, j;
- if ( plist ) {
- if ( plist->pol ) {
- for ( i = 0; i < plist->count; i++ ) {
- if ( plist->pol[ i ].v ) {
- for ( j = 0; j < plist->pol[ i ].nverts; j++ )
- if ( plist->pol[ i ].v[ j ].vm )
- Mem_Free( plist->pol[ i ].v[ j ].vm );
- }
- }
- if ( plist->pol[ 0 ].v )
- Mem_Free( plist->pol[ 0 ].v );
- Mem_Free( plist->pol );
- }
- memset( plist, 0, sizeof( lwPolygonList ));
- }
- }
- /*
- ======================================================================
- lwGetPoints()
- Read point records from a PNTS chunk in an LWO2 file. The points are
- added to the array in the lwPointList.
- ====================================================================== */
- int lwGetPoints( idFile *fp, int cksize, lwPointList *point )
- {
- float *f;
- int np, i, j;
- if ( cksize == 1 ) return 1;
- /* extend the point array to hold the new points */
- np = cksize / 12;
- point->offset = point->count;
- point->count += np;
- lwPoint *oldpt = point->pt;
- point->pt = (lwPoint*)Mem_Alloc( point->count * sizeof( lwPoint ) );
- if ( !point->pt ) return 0;
- if ( oldpt ) {
- memcpy( point->pt, oldpt, point->offset * sizeof( lwPoint ) );
- Mem_Free( oldpt );
- }
- memset( &point->pt[ point->offset ], 0, np * sizeof( lwPoint ) );
- /* read the whole chunk */
- f = ( float * ) getbytes( fp, cksize );
- if ( !f ) return 0;
- BigRevBytes( f, 4, np * 3 );
- /* assign position values */
- for ( i = 0, j = 0; i < np; i++, j += 3 ) {
- point->pt[ i ].pos[ 0 ] = f[ j ];
- point->pt[ i ].pos[ 1 ] = f[ j + 1 ];
- point->pt[ i ].pos[ 2 ] = f[ j + 2 ];
- }
- Mem_Free( f );
- return 1;
- }
- /*
- ======================================================================
- lwGetBoundingBox()
- Calculate the bounding box for a point list, but only if the bounding
- box hasn't already been initialized.
- ====================================================================== */
- void lwGetBoundingBox( lwPointList *point, float bbox[] )
- {
- int i, j;
- if ( point->count == 0 ) return;
- for ( i = 0; i < 6; i++ )
- if ( bbox[ i ] != 0.0f ) return;
- bbox[ 0 ] = bbox[ 1 ] = bbox[ 2 ] = 1e20f;
- bbox[ 3 ] = bbox[ 4 ] = bbox[ 5 ] = -1e20f;
- for ( i = 0; i < point->count; i++ ) {
- for ( j = 0; j < 3; j++ ) {
- if ( bbox[ j ] > point->pt[ i ].pos[ j ] )
- bbox[ j ] = point->pt[ i ].pos[ j ];
- if ( bbox[ j + 3 ] < point->pt[ i ].pos[ j ] )
- bbox[ j + 3 ] = point->pt[ i ].pos[ j ];
- }
- }
- }
- /*
- ======================================================================
- lwAllocPolygons()
- Allocate or extend the polygon arrays to hold new records.
- ====================================================================== */
- int lwAllocPolygons( lwPolygonList *plist, int npols, int nverts )
- {
- int i;
- plist->offset = plist->count;
- plist->count += npols;
- lwPolygon *oldpol = plist->pol;
- plist->pol = (lwPolygon*)Mem_Alloc( plist->count * sizeof( lwPolygon ) );
- if ( !plist->pol ) return 0;
- if ( oldpol ) {
- memcpy( plist->pol, oldpol, plist->offset * sizeof( lwPolygon ) );
- Mem_Free( oldpol );
- }
- memset( plist->pol + plist->offset, 0, npols * sizeof( lwPolygon ) );
- plist->voffset = plist->vcount;
- plist->vcount += nverts;
- lwPolVert *oldpolv = plist->pol[0].v;
- plist->pol[0].v = (lwPolVert*)Mem_Alloc( plist->vcount * sizeof( lwPolVert ) );
- if ( !plist->pol[ 0 ].v ) return 0;
- if ( oldpolv ) {
- memcpy( plist->pol[0].v, oldpolv, plist->voffset * sizeof( lwPolVert ) );
- Mem_Free( oldpolv );
- }
- memset( plist->pol[ 0 ].v + plist->voffset, 0, nverts * sizeof( lwPolVert ) );
- /* fix up the old vertex pointers */
- for ( i = 1; i < plist->offset; i++ )
- plist->pol[ i ].v = plist->pol[ i - 1 ].v + plist->pol[ i - 1 ].nverts;
- return 1;
- }
- /*
- ======================================================================
- lwGetPolygons()
- Read polygon records from a POLS chunk in an LWO2 file. The polygons
- are added to the array in the lwPolygonList.
- ====================================================================== */
- int lwGetPolygons( idFile *fp, int cksize, lwPolygonList *plist, int ptoffset )
- {
- lwPolygon *pp;
- lwPolVert *pv;
- unsigned char *buf, *bp;
- int i, j, flags, nv, nverts, npols;
- unsigned int type;
- if ( cksize == 0 ) return 1;
- /* read the whole chunk */
- set_flen( 0 );
- type = getU4( fp );
- buf = (unsigned char*)getbytes( fp, cksize - 4 );
- if ( cksize != get_flen() ) goto Fail;
- /* count the polygons and vertices */
- nverts = 0;
- npols = 0;
- bp = buf;
- while ( bp < buf + cksize - 4 ) {
- nv = sgetU2( &bp );
- nv &= 0x03FF;
- nverts += nv;
- npols++;
- for ( i = 0; i < nv; i++ )
- j = sgetVX( &bp );
- }
- if ( !lwAllocPolygons( plist, npols, nverts ))
- goto Fail;
- /* fill in the new polygons */
- bp = buf;
- pp = plist->pol + plist->offset;
- pv = plist->pol[ 0 ].v + plist->voffset;
- for ( i = 0; i < npols; i++ ) {
- nv = sgetU2( &bp );
- flags = nv & 0xFC00;
- nv &= 0x03FF;
- pp->nverts = nv;
- pp->flags = flags;
- pp->type = type;
- if ( !pp->v ) pp->v = pv;
- for ( j = 0; j < nv; j++ )
- pp->v[ j ].index = sgetVX( &bp ) + ptoffset;
- pp++;
- pv += nv;
- }
- Mem_Free( buf );
- return 1;
- Fail:
- if ( buf ) Mem_Free( buf );
- lwFreePolygons( plist );
- return 0;
- }
- /*
- ======================================================================
- lwGetPolyNormals()
- Calculate the polygon normals. By convention, LW's polygon normals
- are found as the cross product of the first and last edges. It's
- undefined for one- and two-point polygons.
- ====================================================================== */
- void lwGetPolyNormals( lwPointList *point, lwPolygonList *polygon )
- {
- int i, j;
- float p1[ 3 ], p2[ 3 ], pn[ 3 ], v1[ 3 ], v2[ 3 ];
- for ( i = 0; i < polygon->count; i++ ) {
- if ( polygon->pol[ i ].nverts < 3 ) continue;
- for ( j = 0; j < 3; j++ ) {
- // FIXME: track down why indexes are way out of range
- p1[ j ] = point->pt[ polygon->pol[ i ].v[ 0 ].index ].pos[ j ];
- p2[ j ] = point->pt[ polygon->pol[ i ].v[ 1 ].index ].pos[ j ];
- pn[ j ] = point->pt[ polygon->pol[ i ].v[ polygon->pol[ i ].nverts - 1 ].index ].pos[ j ];
- }
- for ( j = 0; j < 3; j++ ) {
- v1[ j ] = p2[ j ] - p1[ j ];
- v2[ j ] = pn[ j ] - p1[ j ];
- }
- cross( v1, v2, polygon->pol[ i ].norm );
- normalize( polygon->pol[ i ].norm );
- }
- }
- /*
- ======================================================================
- lwGetPointPolygons()
- For each point, fill in the indexes of the polygons that share the
- point. Returns 0 if any of the memory allocations fail, otherwise
- returns 1.
- ====================================================================== */
- int lwGetPointPolygons( lwPointList *point, lwPolygonList *polygon )
- {
- int i, j, k;
- /* count the number of polygons per point */
- for ( i = 0; i < polygon->count; i++ )
- for ( j = 0; j < polygon->pol[ i ].nverts; j++ )
- ++point->pt[ polygon->pol[ i ].v[ j ].index ].npols;
- /* alloc per-point polygon arrays */
- for ( i = 0; i < point->count; i++ ) {
- if ( point->pt[ i ].npols == 0 ) continue;
- point->pt[ i ].pol = (int*)Mem_ClearedAlloc( point->pt[ i ].npols * sizeof( int ) );
- if ( !point->pt[ i ].pol ) return 0;
- point->pt[ i ].npols = 0;
- }
- /* fill in polygon array for each point */
- for ( i = 0; i < polygon->count; i++ ) {
- for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) {
- k = polygon->pol[ i ].v[ j ].index;
- point->pt[ k ].pol[ point->pt[ k ].npols ] = i;
- ++point->pt[ k ].npols;
- }
- }
- return 1;
- }
- /*
- ======================================================================
- lwResolvePolySurfaces()
- Convert tag indexes into actual lwSurface pointers. If any polygons
- point to tags for which no corresponding surface can be found, a
- default surface is created.
- ====================================================================== */
- int lwResolvePolySurfaces( lwPolygonList *polygon, lwTagList *tlist,
- lwSurface **surf, int *nsurfs )
- {
- lwSurface **s, *st;
- int i, index;
- if ( tlist->count == 0 ) return 1;
- s = (lwSurface**)Mem_ClearedAlloc( tlist->count * sizeof( lwSurface * ) );
- if ( !s ) return 0;
- for ( i = 0; i < tlist->count; i++ ) {
- st = *surf;
- while ( st ) {
- if ( !strcmp( st->name, tlist->tag[ i ] )) {
- s[ i ] = st;
- break;
- }
- st = st->next;
- }
- }
- for ( i = 0; i < polygon->count; i++ ) {
- index = ( int ) polygon->pol[ i ].surf;
- if ( index < 0 || index > tlist->count ) return 0;
- if ( !s[ index ] ) {
- s[ index ] = lwDefaultSurface();
- if ( !s[ index ] ) return 0;
- s[ index ]->name = (char*)Mem_ClearedAlloc( strlen( tlist->tag[ index ] ) + 1 );
- if ( !s[ index ]->name ) return 0;
- strcpy( s[ index ]->name, tlist->tag[ index ] );
- lwListAdd( (void**)surf, s[ index ] );
- *nsurfs = *nsurfs + 1;
- }
- polygon->pol[ i ].surf = s[ index ];
- }
- Mem_Free( s );
- return 1;
- }
- /*
- ======================================================================
- lwGetVertNormals()
- Calculate the vertex normals. For each polygon vertex, sum the
- normals of the polygons that share the point. If the normals of the
- current and adjacent polygons form an angle greater than the max
- smoothing angle for the current polygon's surface, the normal of the
- adjacent polygon is excluded from the sum. It's also excluded if the
- polygons aren't in the same smoothing group.
- Assumes that lwGetPointPolygons(), lwGetPolyNormals() and
- lwResolvePolySurfaces() have already been called.
- ====================================================================== */
- void lwGetVertNormals( lwPointList *point, lwPolygonList *polygon )
- {
- int j, k, n, g, h, p;
- float a;
- for ( j = 0; j < polygon->count; j++ ) {
- for ( n = 0; n < polygon->pol[ j ].nverts; n++ ) {
- for ( k = 0; k < 3; k++ )
- polygon->pol[ j ].v[ n ].norm[ k ] = polygon->pol[ j ].norm[ k ];
- if ( polygon->pol[ j ].surf->smooth <= 0 ) continue;
- p = polygon->pol[ j ].v[ n ].index;
- for ( g = 0; g < point->pt[ p ].npols; g++ ) {
- h = point->pt[ p ].pol[ g ];
- if ( h == j ) continue;
- if ( polygon->pol[ j ].smoothgrp != polygon->pol[ h ].smoothgrp )
- continue;
- a = vecangle( polygon->pol[ j ].norm, polygon->pol[ h ].norm );
- if ( a > polygon->pol[ j ].surf->smooth ) continue;
- for ( k = 0; k < 3; k++ )
- polygon->pol[ j ].v[ n ].norm[ k ] += polygon->pol[ h ].norm[ k ];
- }
- normalize( polygon->pol[ j ].v[ n ].norm );
- }
- }
- }
- /*
- ======================================================================
- lwFreeTags()
- Free memory used by an lwTagList.
- ====================================================================== */
- void lwFreeTags( lwTagList *tlist )
- {
- int i;
- if ( tlist ) {
- if ( tlist->tag ) {
- for ( i = 0; i < tlist->count; i++ )
- if ( tlist->tag[ i ] ) {
- Mem_Free( tlist->tag[ i ] );
- }
- Mem_Free( tlist->tag );
- }
- memset( tlist, 0, sizeof( lwTagList ));
- }
- }
- /*
- ======================================================================
- lwGetTags()
- Read tag strings from a TAGS chunk in an LWO2 file. The tags are
- added to the lwTagList array.
- ====================================================================== */
- int lwGetTags( idFile *fp, int cksize, lwTagList *tlist )
- {
- char *buf, *bp;
- int i, len, ntags;
- if ( cksize == 0 ) return 1;
- /* read the whole chunk */
- set_flen( 0 );
- buf = (char*)getbytes( fp, cksize );
- if ( !buf ) return 0;
- /* count the strings */
- ntags = 0;
- bp = buf;
- while ( bp < buf + cksize ) {
- len = strlen( bp ) + 1;
- len += len & 1;
- bp += len;
- ++ntags;
- }
- /* expand the string array to hold the new tags */
- tlist->offset = tlist->count;
- tlist->count += ntags;
- char **oldtag = tlist->tag;
- tlist->tag = (char**)Mem_Alloc( tlist->count * sizeof( char * ) );
- if ( !tlist->tag ) goto Fail;
- if ( oldtag ) {
- memcpy( tlist->tag, oldtag, tlist->offset * sizeof( char * ) );
- Mem_Free( oldtag );
- }
- memset( &tlist->tag[ tlist->offset ], 0, ntags * sizeof( char * ) );
- /* copy the new tags to the tag array */
- bp = buf;
- for ( i = 0; i < ntags; i++ )
- tlist->tag[ i + tlist->offset ] = sgetS0( (unsigned char**)&bp );
- Mem_Free( buf );
- return 1;
- Fail:
- if ( buf ) Mem_Free( buf );
- return 0;
- }
- /*
- ======================================================================
- lwGetPolygonTags()
- Read polygon tags from a PTAG chunk in an LWO2 file.
- ====================================================================== */
- int lwGetPolygonTags( idFile *fp, int cksize, lwTagList *tlist, lwPolygonList *plist )
- {
- unsigned int type;
- int rlen = 0, i, j;
- set_flen( 0 );
- type = getU4( fp );
- rlen = get_flen();
- if ( rlen < 0 ) return 0;
- if ( type != ID_SURF && type != ID_PART && type != ID_SMGP ) {
- fp->Seek( cksize - 4, FS_SEEK_CUR );
- return 1;
- }
- while ( rlen < cksize ) {
- i = getVX( fp ) + plist->offset;
- j = getVX( fp ) + tlist->offset;
- rlen = get_flen();
- if ( rlen < 0 || rlen > cksize ) return 0;
- switch ( type ) {
- case ID_SURF: plist->pol[ i ].surf = ( lwSurface * ) j; break;
- case ID_PART: plist->pol[ i ].part = j; break;
- case ID_SMGP: plist->pol[ i ].smoothgrp = j; break;
- }
- }
- return 1;
- }
- /*
- ======================================================================
- lwFreePlugin()
- Free the memory used by an lwPlugin.
- ====================================================================== */
- void lwFreePlugin( lwPlugin *p )
- {
- if ( p ) {
- if ( p->ord ) Mem_Free( p->ord );
- if ( p->name ) Mem_Free( p->name );
- if ( p->data ) Mem_Free( p->data );
- Mem_Free( p );
- }
- }
- /*
- ======================================================================
- lwFreeTexture()
- Free the memory used by an lwTexture.
- ====================================================================== */
- void lwFreeTexture( lwTexture *t )
- {
- if ( t ) {
- if ( t->ord ) Mem_Free( t->ord );
- switch ( t->type ) {
- case ID_IMAP:
- if ( t->param.imap.vmap_name ) Mem_Free( t->param.imap.vmap_name );
- break;
- case ID_PROC:
- if ( t->param.proc.name ) Mem_Free( t->param.proc.name );
- if ( t->param.proc.data ) Mem_Free( t->param.proc.data );
- break;
- case ID_GRAD:
- if ( t->param.grad.key ) Mem_Free( t->param.grad.key );
- if ( t->param.grad.ikey ) Mem_Free( t->param.grad.ikey );
- break;
- }
- if ( t->tmap.ref_object ) Mem_Free( t->tmap.ref_object );
- Mem_Free( t );
- }
- }
- /*
- ======================================================================
- lwFreeSurface()
- Free the memory used by an lwSurface.
- ====================================================================== */
- void lwFreeSurface( lwSurface *surf )
- {
- if ( surf ) {
- if ( surf->name ) Mem_Free( surf->name );
- if ( surf->srcname ) Mem_Free( surf->srcname );
- lwListFree( surf->shader, (void (__cdecl *)(void *))lwFreePlugin );
- lwListFree( surf->color.tex, (void (__cdecl *)(void *))lwFreeTexture );
- lwListFree( surf->luminosity.tex, (void (__cdecl *)(void *))lwFreeTexture );
- lwListFree( surf->diffuse.tex, (void (__cdecl *)(void *))lwFreeTexture );
- lwListFree( surf->specularity.tex, (void (__cdecl *)(void *))lwFreeTexture );
- lwListFree( surf->glossiness.tex, (void (__cdecl *)(void *))lwFreeTexture );
- lwListFree( surf->reflection.val.tex, (void (__cdecl *)(void *))lwFreeTexture );
- lwListFree( surf->transparency.val.tex, (void (__cdecl *)(void *))lwFreeTexture );
- lwListFree( surf->eta.tex, (void (__cdecl *)(void *))lwFreeTexture );
- lwListFree( surf->translucency.tex, (void (__cdecl *)(void *))lwFreeTexture );
- lwListFree( surf->bump.tex, (void (__cdecl *)(void *))lwFreeTexture );
- Mem_Free( surf );
- }
- }
- /*
- ======================================================================
- lwGetTHeader()
- Read a texture map header from a SURF.BLOK in an LWO2 file. This is
- the first subchunk in a BLOK, and its contents are common to all three
- texture types.
- ====================================================================== */
- int lwGetTHeader( idFile *fp, int hsz, lwTexture *tex )
- {
- unsigned int id;
- unsigned short sz;
- int pos, rlen;
- /* remember where we started */
- set_flen( 0 );
- pos = fp->Tell();
- /* ordinal string */
- tex->ord = getS0( fp );
- /* first subchunk header */
- id = getU4( fp );
- sz = getU2( fp );
- if ( 0 > get_flen() ) return 0;
- /* process subchunks as they're encountered */
- while ( 1 ) {
- sz += sz & 1;
- set_flen( 0 );
- switch ( id ) {
- case ID_CHAN:
- tex->chan = getU4( fp );
- break;
- case ID_OPAC:
- tex->opac_type = getU2( fp );
- tex->opacity.val = getF4( fp );
- tex->opacity.eindex = getVX( fp );
- break;
- case ID_ENAB:
- tex->enabled = getU2( fp );
- break;
- case ID_NEGA:
- tex->negative = getU2( fp );
- break;
- case ID_AXIS:
- tex->axis = getU2( fp );
- break;
- default:
- break;
- }
- /* error while reading current subchunk? */
- rlen = get_flen();
- if ( rlen < 0 || rlen > sz ) return 0;
- /* skip unread parts of the current subchunk */
- if ( rlen < sz )
- fp->Seek( sz - rlen, FS_SEEK_CUR );
- /* end of the texture header subchunk? */
- if ( hsz <= fp->Tell() - pos )
- break;
- /* get the next subchunk header */
- set_flen( 0 );
- id = getU4( fp );
- sz = getU2( fp );
- if ( 6 != get_flen() ) return 0;
- }
- set_flen( fp->Tell() - pos );
- return 1;
- }
- /*
- ======================================================================
- lwGetTMap()
- Read a texture map from a SURF.BLOK in an LWO2 file. The TMAP
- defines the mapping from texture to world or object coordinates.
- ====================================================================== */
- int lwGetTMap( idFile *fp, int tmapsz, lwTMap *tmap )
- {
- unsigned int id;
- unsigned short sz;
- int rlen, pos, i;
- pos = fp->Tell();
- id = getU4( fp );
- sz = getU2( fp );
- if ( 0 > get_flen() ) return 0;
- while ( 1 ) {
- sz += sz & 1;
- set_flen( 0 );
- switch ( id ) {
- case ID_SIZE:
- for ( i = 0; i < 3; i++ )
- tmap->size.val[ i ] = getF4( fp );
- tmap->size.eindex = getVX( fp );
- break;
- case ID_CNTR:
- for ( i = 0; i < 3; i++ )
- tmap->center.val[ i ] = getF4( fp );
- tmap->center.eindex = getVX( fp );
- break;
- case ID_ROTA:
- for ( i = 0; i < 3; i++ )
- tmap->rotate.val[ i ] = getF4( fp );
- tmap->rotate.eindex = getVX( fp );
- break;
- case ID_FALL:
- tmap->fall_type = getU2( fp );
- for ( i = 0; i < 3; i++ )
- tmap->falloff.val[ i ] = getF4( fp );
- tmap->falloff.eindex = getVX( fp );
- break;
- case ID_OREF:
- tmap->ref_object = getS0( fp );
- break;
- case ID_CSYS:
- tmap->coord_sys = getU2( fp );
- break;
- default:
- break;
- }
- /* error while reading the current subchunk? */
- rlen = get_flen();
- if ( rlen < 0 || rlen > sz ) return 0;
- /* skip unread parts of the current subchunk */
- if ( rlen < sz )
- fp->Seek( sz - rlen, FS_SEEK_CUR );
- /* end of the TMAP subchunk? */
- if ( tmapsz <= fp->Tell() - pos )
- break;
- /* get the next subchunk header */
- set_flen( 0 );
- id = getU4( fp );
- sz = getU2( fp );
- if ( 6 != get_flen() ) return 0;
- }
- set_flen( fp->Tell() - pos );
- return 1;
- }
- /*
- ======================================================================
- lwGetImageMap()
- Read an lwImageMap from a SURF.BLOK in an LWO2 file.
- ====================================================================== */
- int lwGetImageMap( idFile *fp, int rsz, lwTexture *tex )
- {
- unsigned int id;
- unsigned short sz;
- int rlen, pos;
- pos = fp->Tell();
- id = getU4( fp );
- sz = getU2( fp );
- if ( 0 > get_flen() ) return 0;
- while ( 1 ) {
- sz += sz & 1;
- set_flen( 0 );
- switch ( id ) {
- case ID_TMAP:
- if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
- break;
- case ID_PROJ:
- tex->param.imap.projection = getU2( fp );
- break;
- case ID_VMAP:
- tex->param.imap.vmap_name = getS0( fp );
- break;
- case ID_AXIS:
- tex->param.imap.axis = getU2( fp );
- break;
- case ID_IMAG:
- tex->param.imap.cindex = getVX( fp );
- break;
- case ID_WRAP:
- tex->param.imap.wrapw_type = getU2( fp );
- tex->param.imap.wraph_type = getU2( fp );
- break;
- case ID_WRPW:
- tex->param.imap.wrapw.val = getF4( fp );
- tex->param.imap.wrapw.eindex = getVX( fp );
- break;
- case ID_WRPH:
- tex->param.imap.wraph.val = getF4( fp );
- tex->param.imap.wraph.eindex = getVX( fp );
- break;
- case ID_AAST:
- tex->param.imap.aas_flags = getU2( fp );
- tex->param.imap.aa_strength = getF4( fp );
- break;
- case ID_PIXB:
- tex->param.imap.pblend = getU2( fp );
- break;
- case ID_STCK:
- tex->param.imap.stck.val = getF4( fp );
- tex->param.imap.stck.eindex = getVX( fp );
- break;
- case ID_TAMP:
- tex->param.imap.amplitude.val = getF4( fp );
- tex->param.imap.amplitude.eindex = getVX( fp );
- break;
- default:
- break;
- }
- /* error while reading the current subchunk? */
- rlen = get_flen();
- if ( rlen < 0 || rlen > sz ) return 0;
- /* skip unread parts of the current subchunk */
- if ( rlen < sz )
- fp->Seek( sz - rlen, FS_SEEK_CUR );
- /* end of the image map? */
- if ( rsz <= fp->Tell() - pos )
- break;
- /* get the next subchunk header */
- set_flen( 0 );
- id = getU4( fp );
- sz = getU2( fp );
- if ( 6 != get_flen() ) return 0;
- }
- set_flen( fp->Tell() - pos );
- return 1;
- }
- /*
- ======================================================================
- lwGetProcedural()
- Read an lwProcedural from a SURF.BLOK in an LWO2 file.
- ====================================================================== */
- int lwGetProcedural( idFile *fp, int rsz, lwTexture *tex )
- {
- unsigned int id;
- unsigned short sz;
- int rlen, pos;
- pos = fp->Tell();
- id = getU4( fp );
- sz = getU2( fp );
- if ( 0 > get_flen() ) return 0;
- while ( 1 ) {
- sz += sz & 1;
- set_flen( 0 );
- switch ( id ) {
- case ID_TMAP:
- if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
- break;
- case ID_AXIS:
- tex->param.proc.axis = getU2( fp );
- break;
- case ID_VALU:
- tex->param.proc.value[ 0 ] = getF4( fp );
- if ( sz >= 8 ) tex->param.proc.value[ 1 ] = getF4( fp );
- if ( sz >= 12 ) tex->param.proc.value[ 2 ] = getF4( fp );
- break;
- case ID_FUNC:
- tex->param.proc.name = getS0( fp );
- rlen = get_flen();
- tex->param.proc.data = getbytes( fp, sz - rlen );
- break;
- default:
- break;
- }
- /* error while reading the current subchunk? */
- rlen = get_flen();
- if ( rlen < 0 || rlen > sz ) return 0;
- /* skip unread parts of the current subchunk */
- if ( rlen < sz )
- fp->Seek( sz - rlen, FS_SEEK_CUR );
- /* end of the procedural block? */
- if ( rsz <= fp->Tell() - pos )
- break;
- /* get the next subchunk header */
- set_flen( 0 );
- id = getU4( fp );
- sz = getU2( fp );
- if ( 6 != get_flen() ) return 0;
- }
- set_flen( fp->Tell() - pos );
- return 1;
- }
- /*
- ======================================================================
- lwGetGradient()
- Read an lwGradient from a SURF.BLOK in an LWO2 file.
- ====================================================================== */
- int lwGetGradient( idFile *fp, int rsz, lwTexture *tex )
- {
- unsigned int id;
- unsigned short sz;
- int rlen, pos, i, j, nkeys;
- pos = fp->Tell();
- id = getU4( fp );
- sz = getU2( fp );
- if ( 0 > get_flen() ) return 0;
- while ( 1 ) {
- sz += sz & 1;
- set_flen( 0 );
- switch ( id ) {
- case ID_TMAP:
- if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
- break;
- case ID_PNAM:
- tex->param.grad.paramname = getS0( fp );
- break;
- case ID_INAM:
- tex->param.grad.itemname = getS0( fp );
- break;
- case ID_GRST:
- tex->param.grad.start = getF4( fp );
- break;
- case ID_GREN:
- tex->param.grad.end = getF4( fp );
- break;
- case ID_GRPT:
- tex->param.grad.repeat = getU2( fp );
- break;
- case ID_FKEY:
- nkeys = sz / sizeof( lwGradKey );
- tex->param.grad.key = (lwGradKey*)Mem_ClearedAlloc( nkeys * sizeof( lwGradKey ) );
- if ( !tex->param.grad.key ) return 0;
- for ( i = 0; i < nkeys; i++ ) {
- tex->param.grad.key[ i ].value = getF4( fp );
- for ( j = 0; j < 4; j++ )
- tex->param.grad.key[ i ].rgba[ j ] = getF4( fp );
- }
- break;
- case ID_IKEY:
- nkeys = sz / 2;
- tex->param.grad.ikey = (short*)Mem_ClearedAlloc( nkeys * sizeof( short ) );
- if ( !tex->param.grad.ikey ) return 0;
- for ( i = 0; i < nkeys; i++ )
- tex->param.grad.ikey[ i ] = getU2( fp );
- break;
- default:
- break;
- }
- /* error while reading the current subchunk? */
- rlen = get_flen();
- if ( rlen < 0 || rlen > sz ) return 0;
- /* skip unread parts of the current subchunk */
- if ( rlen < sz )
- fp->Seek( sz - rlen, FS_SEEK_CUR );
- /* end of the gradient? */
- if ( rsz <= fp->Tell() - pos )
- break;
- /* get the next subchunk header */
- set_flen( 0 );
- id = getU4( fp );
- sz = getU2( fp );
- if ( 6 != get_flen() ) return 0;
- }
- set_flen( fp->Tell() - pos );
- return 1;
- }
- /*
- ======================================================================
- lwGetTexture()
- Read an lwTexture from a SURF.BLOK in an LWO2 file.
- ====================================================================== */
- lwTexture *lwGetTexture( idFile *fp, int bloksz, unsigned int type )
- {
- lwTexture *tex;
- unsigned short sz;
- int ok;
- tex = (lwTexture*)Mem_ClearedAlloc( sizeof( lwTexture ) );
- if ( !tex ) return NULL;
- tex->type = type;
- tex->tmap.size.val[ 0 ] =
- tex->tmap.size.val[ 1 ] =
- tex->tmap.size.val[ 2 ] = 1.0f;
- tex->opacity.val = 1.0f;
- tex->enabled = 1;
- sz = getU2( fp );
- if ( !lwGetTHeader( fp, sz, tex )) {
- Mem_Free( tex );
- return NULL;
- }
- sz = bloksz - sz - 6;
- switch ( type ) {
- case ID_IMAP: ok = lwGetImageMap( fp, sz, tex ); break;
- case ID_PROC: ok = lwGetProcedural( fp, sz, tex ); break;
- case ID_GRAD: ok = lwGetGradient( fp, sz, tex ); break;
- default:
- ok = !fp->Seek( sz, FS_SEEK_CUR );
- }
- if ( !ok ) {
- lwFreeTexture( tex );
- return NULL;
- }
- set_flen( bloksz );
- return tex;
- }
- /*
- ======================================================================
- lwGetShader()
- Read a shader record from a SURF.BLOK in an LWO2 file.
- ====================================================================== */
- lwPlugin *lwGetShader( idFile *fp, int bloksz )
- {
- lwPlugin *shdr;
- unsigned int id;
- unsigned short sz;
- int hsz, rlen, pos;
- shdr = (lwPlugin*)Mem_ClearedAlloc( sizeof( lwPlugin ) );
- if ( !shdr ) return NULL;
- pos = fp->Tell();
- set_flen( 0 );
- hsz = getU2( fp );
- shdr->ord = getS0( fp );
- id = getU4( fp );
- sz = getU2( fp );
- if ( 0 > get_flen() ) goto Fail;
- while ( hsz > 0 ) {
- sz += sz & 1;
- hsz -= sz;
- if ( id == ID_ENAB ) {
- shdr->flags = getU2( fp );
- break;
- }
- else {
- fp->Seek( sz, FS_SEEK_CUR );
- id = getU4( fp );
- sz = getU2( fp );
- }
- }
- id = getU4( fp );
- sz = getU2( fp );
- if ( 0 > get_flen() ) goto Fail;
- while ( 1 ) {
- sz += sz & 1;
- set_flen( 0 );
- switch ( id ) {
- case ID_FUNC:
- shdr->name = getS0( fp );
- rlen = get_flen();
- shdr->data = getbytes( fp, sz - rlen );
- break;
- default:
- break;
- }
- /* error while reading the current subchunk? */
- rlen = get_flen();
- if ( rlen < 0 || rlen > sz ) goto Fail;
- /* skip unread parts of the current subchunk */
- if ( rlen < sz )
- fp->Seek( sz - rlen, FS_SEEK_CUR );
- /* end of the shader block? */
- if ( bloksz <= fp->Tell() - pos )
- break;
- /* get the next subchunk header */
- set_flen( 0 );
- id = getU4( fp );
- sz = getU2( fp );
- if ( 6 != get_flen() ) goto Fail;
- }
- set_flen( fp->Tell() - pos );
- return shdr;
- Fail:
- lwFreePlugin( shdr );
- return NULL;
- }
- /*
- ======================================================================
- compare_textures()
- compare_shaders()
- Callbacks for the lwListInsert() function, which is called to add
- textures to surface channels and shaders to surfaces.
- ====================================================================== */
- static int compare_textures( lwTexture *a, lwTexture *b )
- {
- return strcmp( a->ord, b->ord );
- }
- static int compare_shaders( lwPlugin *a, lwPlugin *b )
- {
- return strcmp( a->ord, b->ord );
- }
- /*
- ======================================================================
- add_texture()
- Finds the surface channel (lwTParam or lwCParam) to which a texture is
- applied, then calls lwListInsert().
- ====================================================================== */
- static int add_texture( lwSurface *surf, lwTexture *tex )
- {
- lwTexture **list;
- switch ( tex->chan ) {
- case ID_COLR: list = &surf->color.tex; break;
- case ID_LUMI: list = &surf->luminosity.tex; break;
- case ID_DIFF: list = &surf->diffuse.tex; break;
- case ID_SPEC: list = &surf->specularity.tex; break;
- case ID_GLOS: list = &surf->glossiness.tex; break;
- case ID_REFL: list = &surf->reflection.val.tex; break;
- case ID_TRAN: list = &surf->transparency.val.tex; break;
- case ID_RIND: list = &surf->eta.tex; break;
- case ID_TRNL: list = &surf->translucency.tex; break;
- case ID_BUMP: list = &surf->bump.tex; break;
- default: return 0;
- }
- lwListInsert( (void**)list, tex, (int (__cdecl *)(void *,void *))compare_textures );
- return 1;
- }
- /*
- ======================================================================
- lwDefaultSurface()
- Allocate and initialize a surface.
- ====================================================================== */
- lwSurface *lwDefaultSurface( void )
- {
- lwSurface *surf;
- surf = (lwSurface*)Mem_ClearedAlloc( sizeof( lwSurface ) );
- if ( !surf ) return NULL;
- surf->color.rgb[ 0 ] = 0.78431f;
- surf->color.rgb[ 1 ] = 0.78431f;
- surf->color.rgb[ 2 ] = 0.78431f;
- surf->diffuse.val = 1.0f;
- surf->glossiness.val = 0.4f;
- surf->bump.val = 1.0f;
- surf->eta.val = 1.0f;
- surf->sideflags = 1;
- return surf;
- }
- /*
- ======================================================================
- lwGetSurface()
- Read an lwSurface from an LWO2 file.
- ====================================================================== */
- lwSurface *lwGetSurface( idFile *fp, int cksize )
- {
- lwSurface *surf;
- lwTexture *tex;
- lwPlugin *shdr;
- unsigned int id, type;
- unsigned short sz;
- int pos, rlen;
- /* allocate the Surface structure */
- surf = (lwSurface*)Mem_ClearedAlloc( sizeof( lwSurface ) );
- if ( !surf ) goto Fail;
- /* non-zero defaults */
- surf->color.rgb[ 0 ] = 0.78431f;
- surf->color.rgb[ 1 ] = 0.78431f;
- surf->color.rgb[ 2 ] = 0.78431f;
- surf->diffuse.val = 1.0f;
- surf->glossiness.val = 0.4f;
- surf->bump.val = 1.0f;
- surf->eta.val = 1.0f;
- surf->sideflags = 1;
- /* remember where we started */
- set_flen( 0 );
- pos = fp->Tell();
- /* names */
- surf->name = getS0( fp );
- surf->srcname = getS0( fp );
- /* first subchunk header */
- id = getU4( fp );
- sz = getU2( fp );
- if ( 0 > get_flen() ) goto Fail;
- /* process subchunks as they're encountered */
- while ( 1 ) {
- sz += sz & 1;
- set_flen( 0 );
- switch ( id ) {
- case ID_COLR:
- surf->color.rgb[ 0 ] = getF4( fp );
- surf->color.rgb[ 1 ] = getF4( fp );
- surf->color.rgb[ 2 ] = getF4( fp );
- surf->color.eindex = getVX( fp );
- break;
- case ID_LUMI:
- surf->luminosity.val = getF4( fp );
- surf->luminosity.eindex = getVX( fp );
- break;
- case ID_DIFF:
- surf->diffuse.val = getF4( fp );
- surf->diffuse.eindex = getVX( fp );
- break;
- case ID_SPEC:
- surf->specularity.val = getF4( fp );
- surf->specularity.eindex = getVX( fp );
- break;
- case ID_GLOS:
- surf->glossiness.val = getF4( fp );
- surf->glossiness.eindex = getVX( fp );
- break;
- case ID_REFL:
- surf->reflection.val.val = getF4( fp );
- surf->reflection.val.eindex = getVX( fp );
- break;
- case ID_RFOP:
- surf->reflection.options = getU2( fp );
- break;
- case ID_RIMG:
- surf->reflection.cindex = getVX( fp );
- break;
- case ID_RSAN:
- surf->reflection.seam_angle = getF4( fp );
- break;
- case ID_TRAN:
- surf->transparency.val.val = getF4( fp );
- surf->transparency.val.eindex = getVX( fp );
- break;
- case ID_TROP:
- surf->transparency.options = getU2( fp );
- break;
- case ID_TIMG:
- surf->transparency.cindex = getVX( fp );
- break;
- case ID_RIND:
- surf->eta.val = getF4( fp );
- surf->eta.eindex = getVX( fp );
- break;
- case ID_TRNL:
- surf->translucency.val = getF4( fp );
- surf->translucency.eindex = getVX( fp );
- break;
- case ID_BUMP:
- surf->bump.val = getF4( fp );
- surf->bump.eindex = getVX( fp );
- break;
- case ID_SMAN:
- surf->smooth = getF4( fp );
- break;
- case ID_SIDE:
- surf->sideflags = getU2( fp );
- break;
- case ID_CLRH:
- surf->color_hilite.val = getF4( fp );
- surf->color_hilite.eindex = getVX( fp );
- break;
- case ID_CLRF:
- surf->color_filter.val = getF4( fp );
- surf->color_filter.eindex = getVX( fp );
- break;
- case ID_ADTR:
- surf->add_trans.val = getF4( fp );
- surf->add_trans.eindex = getVX( fp );
- break;
- case ID_SHRP:
- surf->dif_sharp.val = getF4( fp );
- surf->dif_sharp.eindex = getVX( fp );
- break;
- case ID_GVAL:
- surf->glow.val = getF4( fp );
- surf->glow.eindex = getVX( fp );
- break;
- case ID_LINE:
- surf->line.enabled = 1;
- if ( sz >= 2 ) surf->line.flags = getU2( fp );
- if ( sz >= 6 ) surf->line.size.val = getF4( fp );
- if ( sz >= 8 ) surf->line.size.eindex = getVX( fp );
- break;
- case ID_ALPH:
- surf->alpha_mode = getU2( fp );
- surf->alpha = getF4( fp );
- break;
- case ID_AVAL:
- surf->alpha = getF4( fp );
- break;
- case ID_BLOK:
- type = getU4( fp );
- switch ( type ) {
- case ID_IMAP:
- case ID_PROC:
- case ID_GRAD:
- tex = lwGetTexture( fp, sz - 4, type );
- if ( !tex ) goto Fail;
- if ( !add_texture( surf, tex ))
- lwFreeTexture( tex );
- set_flen( 4 + get_flen() );
- break;
- case ID_SHDR:
- shdr = lwGetShader( fp, sz - 4 );
- if ( !shdr ) goto Fail;
- lwListInsert( (void**)&surf->shader, shdr, (int (__cdecl *)(void *,void *))compare_shaders );
- ++surf->nshaders;
- set_flen( 4 + get_flen() );
- break;
- }
- break;
- default:
- break;
- }
- /* error while reading current subchunk? */
- rlen = get_flen();
- if ( rlen < 0 || rlen > sz ) goto Fail;
- /* skip unread parts of the current subchunk */
- if ( rlen < sz )
- fp->Seek( sz - rlen, FS_SEEK_CUR );
- /* end of the SURF chunk? */
- if ( cksize <= fp->Tell() - pos )
- break;
- /* get the next subchunk header */
- set_flen( 0 );
- id = getU4( fp );
- sz = getU2( fp );
- if ( 6 != get_flen() ) goto Fail;
- }
- return surf;
- Fail:
- if ( surf ) lwFreeSurface( surf );
- return NULL;
- }
- float dot( float a[], float b[] )
- {
- return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ];
- }
- void cross( float a[], float b[], float c[] )
- {
- c[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ];
- c[ 1 ] = a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ];
- c[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ];
- }
- void normalize( float v[] )
- {
- float r;
- r = ( float ) idMath::Sqrt( dot( v, v ));
- if ( r > 0 ) {
- v[ 0 ] /= r;
- v[ 1 ] /= r;
- v[ 2 ] /= r;
- }
- }
- /*
- ======================================================================
- lwFreeVMap()
- Free memory used by an lwVMap.
- ====================================================================== */
- void lwFreeVMap( lwVMap *vmap )
- {
- if ( vmap ) {
- if ( vmap->name ) Mem_Free( vmap->name );
- if ( vmap->vindex ) Mem_Free( vmap->vindex );
- if ( vmap->pindex ) Mem_Free( vmap->pindex );
- if ( vmap->val ) {
- if ( vmap->val[ 0 ] ) Mem_Free( vmap->val[ 0 ] );
- Mem_Free( vmap->val );
- }
- Mem_Free( vmap );
- }
- }
- /*
- ======================================================================
- lwGetVMap()
- Read an lwVMap from a VMAP or VMAD chunk in an LWO2.
- ====================================================================== */
- lwVMap *lwGetVMap( idFile *fp, int cksize, int ptoffset, int poloffset,
- int perpoly )
- {
- unsigned char *buf, *bp;
- lwVMap *vmap;
- float *f;
- int i, j, npts, rlen;
- /* read the whole chunk */
- set_flen( 0 );
- buf = (unsigned char*)getbytes( fp, cksize );
- if ( !buf ) return NULL;
- vmap = (lwVMap*)Mem_ClearedAlloc( sizeof( lwVMap ) );
- if ( !vmap ) {
- Mem_Free( buf );
- return NULL;
- }
- /* initialize the vmap */
- vmap->perpoly = perpoly;
- bp = buf;
- set_flen( 0 );
- vmap->type = sgetU4( &bp );
- vmap->dim = sgetU2( &bp );
- vmap->name = sgetS0( &bp );
- rlen = get_flen();
- /* count the vmap records */
- npts = 0;
- while ( bp < buf + cksize ) {
- i = sgetVX( &bp );
- if ( perpoly )
- i = sgetVX( &bp );
- bp += vmap->dim * sizeof( float );
- ++npts;
- }
- /* allocate the vmap */
- vmap->nverts = npts;
- vmap->vindex = (int*)Mem_ClearedAlloc( npts * sizeof( int ) );
- if ( !vmap->vindex ) goto Fail;
- if ( perpoly ) {
- vmap->pindex = (int*)Mem_ClearedAlloc( npts * sizeof( int ) );
- if ( !vmap->pindex ) goto Fail;
- }
- if ( vmap->dim > 0 ) {
- vmap->val = (float**)Mem_ClearedAlloc( npts * sizeof( float * ) );
- if ( !vmap->val ) goto Fail;
- f = (float*)Mem_ClearedAlloc( npts * vmap->dim * sizeof( float ) );
- if ( !f ) goto Fail;
- for ( i = 0; i < npts; i++ )
- vmap->val[ i ] = f + i * vmap->dim;
- }
- /* fill in the vmap values */
- bp = buf + rlen;
- for ( i = 0; i < npts; i++ ) {
- vmap->vindex[ i ] = sgetVX( &bp );
- if ( perpoly )
- vmap->pindex[ i ] = sgetVX( &bp );
- for ( j = 0; j < vmap->dim; j++ )
- vmap->val[ i ][ j ] = sgetF4( &bp );
- }
- Mem_Free( buf );
- return vmap;
- Fail:
- if ( buf ) Mem_Free( buf );
- lwFreeVMap( vmap );
- return NULL;
- }
- /*
- ======================================================================
- lwGetPointVMaps()
- Fill in the lwVMapPt structure for each point.
- ====================================================================== */
- int lwGetPointVMaps( lwPointList *point, lwVMap *vmap )
- {
- lwVMap *vm;
- int i, j, n;
- /* count the number of vmap values for each point */
- vm = vmap;
- while ( vm ) {
- if ( !vm->perpoly )
- for ( i = 0; i < vm->nverts; i++ )
- ++point->pt[ vm->vindex[ i ]].nvmaps;
- vm = vm->next;
- }
- /* allocate vmap references for each mapped point */
- for ( i = 0; i < point->count; i++ ) {
- if ( point->pt[ i ].nvmaps ) {
- point->pt[ i ].vm = (lwVMapPt*)Mem_ClearedAlloc( point->pt[ i ].nvmaps * sizeof( lwVMapPt ) );
- if ( !point->pt[ i ].vm ) return 0;
- point->pt[ i ].nvmaps = 0;
- }
- }
- /* fill in vmap references for each mapped point */
- vm = vmap;
- while ( vm ) {
- if ( !vm->perpoly ) {
- for ( i = 0; i < vm->nverts; i++ ) {
- j = vm->vindex[ i ];
- n = point->pt[ j ].nvmaps;
- point->pt[ j ].vm[ n ].vmap = vm;
- point->pt[ j ].vm[ n ].index = i;
- ++point->pt[ j ].nvmaps;
- }
- }
- vm = vm->next;
- }
- return 1;
- }
- /*
- ======================================================================
- lwGetPolyVMaps()
- Fill in the lwVMapPt structure for each polygon vertex.
- ====================================================================== */
- int lwGetPolyVMaps( lwPolygonList *polygon, lwVMap *vmap )
- {
- lwVMap *vm;
- lwPolVert *pv;
- int i, j;
- /* count the number of vmap values for each polygon vertex */
- vm = vmap;
- while ( vm ) {
- if ( vm->perpoly ) {
- for ( i = 0; i < vm->nverts; i++ ) {
- for ( j = 0; j < polygon->pol[ vm->pindex[ i ]].nverts; j++ ) {
- pv = &polygon->pol[ vm->pindex[ i ]].v[ j ];
- if ( vm->vindex[ i ] == pv->index ) {
- ++pv->nvmaps;
- break;
- }
- }
- }
- }
- vm = vm->next;
- }
- /* allocate vmap references for each mapped vertex */
- for ( i = 0; i < polygon->count; i++ ) {
- for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) {
- pv = &polygon->pol[ i ].v[ j ];
- if ( pv->nvmaps ) {
- pv->vm = (lwVMapPt*)Mem_ClearedAlloc( pv->nvmaps * sizeof( lwVMapPt ) );
- if ( !pv->vm ) return 0;
- pv->nvmaps = 0;
- }
- }
- }
- /* fill in vmap references for each mapped point */
- vm = vmap;
- while ( vm ) {
- if ( vm->perpoly ) {
- for ( i = 0; i < vm->nverts; i++ ) {
- for ( j = 0; j < polygon->pol[ vm->pindex[ i ]].nverts; j++ ) {
- pv = &polygon->pol[ vm->pindex[ i ]].v[ j ];
- if ( vm->vindex[ i ] == pv->index ) {
- pv->vm[ pv->nvmaps ].vmap = vm;
- pv->vm[ pv->nvmaps ].index = i;
- ++pv->nvmaps;
- break;
- }
- }
- }
- }
- vm = vm->next;
- }
- return 1;
- }
|