1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749 |
- /*
- ===========================================================================
- Copyright (C) 1999-2005 Id Software, Inc.
- This file is part of Quake III Arena source code.
- Quake III Arena 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 2 of the License,
- or (at your option) any later version.
- Quake III Arena 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 Foobar; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- ===========================================================================
- */
- #include "cmdlib.h"
- #include "mathlib.h"
- #include "bspfile.h"
- #include "imagelib.h"
- #include "threads.h"
- #include "mutex.h"
- #include "scriplib.h"
- #include "shaders.h"
- #include "mesh.h"
- #ifdef _WIN32
- //Improve floating-point consistency.
- #pragma optimize( "p", on )
- #endif
- #ifdef _WIN32
- #include "../libs/pakstuff.h"
- #endif
- #define MAX_CLUSTERS 16384
- #define MAX_PORTALS 32768
- #define MAX_FACETS 65536
- #define MAX_LIGHTS 16384
- #define LIGHTMAP_SIZE 128
- #define LIGHTMAP_PIXELSHIFT 0.5
- //#define LIGHTMAP_PATCHSHIFT
- #define PORTALFILE "PRT1"
- #define ON_EPSILON 0.1
- #define VectorSet(v, x, y, z) v[0] = x;v[1] = y;v[2] = z;
- typedef struct
- {
- vec3_t normal;
- float dist;
- } plane_t;
- #define MAX_POINTS_ON_WINDING 64
- //NOTE: whenever this is overflowed parts of lightmaps might end up not being lit
- #define MAX_POINTS_ON_FIXED_WINDING 48
- typedef struct
- {
- int numpoints;
- vec3_t points[MAX_POINTS_ON_FIXED_WINDING]; // variable sized
- } winding_t;
- typedef struct
- {
- plane_t plane; // normal pointing into neighbor
- int leaf; // neighbor
- winding_t *winding;
- vec3_t origin; // for fast clip testing
- float radius;
- } lportal_t;
- #define MAX_PORTALS_ON_LEAF 128
- typedef struct lleaf_s
- {
- int numportals;
- lportal_t *portals[MAX_PORTALS_ON_LEAF];
- //
- int numSurfaces;
- int firstSurface;
- } lleaf_t;
- typedef struct lFacet_s
- {
- int num;
- plane_t plane;
- vec3_t points[4]; //
- int numpoints;
- float lightmapCoords[4][2];
- plane_t boundaries[4]; // negative is outside the bounds
- float textureMatrix[2][4]; // texture coordinates for translucency
- float lightmapMatrix[2][4]; // lightmap texture coordinates
- vec3_t mins;
- int x, y, width, height;
- } lFacet_t;
- typedef struct lsurfaceTest_s
- {
- vec3_t mins, maxs;
- vec3_t origin;
- float radius;
- qboolean patch; // true if this is a patch
- qboolean trisoup; // true if this is a triangle soup
- int numFacets;
- lFacet_t *facets;
- mesh_t *detailMesh; // detailed mesh with points for each lmp
- shaderInfo_t *shader; // for translucency
- mutex_t *mutex;
- int numvolumes; // number of volumes casted at this surface
- //
- int always_tracelight;
- int always_vlight;
- } lsurfaceTest_t;
- //volume types
- #define VOLUME_NORMAL 0
- #define VOLUME_DIRECTED 1
- #define MAX_TRANSLUCENTFACETS 32
- typedef struct lightvolume_s
- {
- int num;
- int cluster; //cluster this light volume started in
- plane_t endplane; //end plane
- plane_t farplane; //original end plane
- vec3_t points[MAX_POINTS_ON_WINDING]; //end winding points
- plane_t planes[MAX_POINTS_ON_WINDING]; //volume bounding planes
- int numplanes; //number of volume bounding planes
- int type; //light volume type
- //list with translucent surfaces the volume went through
- int transFacets[MAX_TRANSLUCENTFACETS];
- int transSurfaces[MAX_TRANSLUCENTFACETS];
- int numtransFacets;
- //clusters already tested
- byte clusterTested[MAX_CLUSTERS/8];
- //facets already tested
- byte facetTested[MAX_FACETS/8];
- int facetNum; //number of the facet blocking the light in this volume
- int surfaceNum; //number of the surface blocking the light in this volume
- } lightvolume_t;
- //light types
- #define LIGHT_POINTRADIAL 1
- #define LIGHT_POINTSPOT 2
- #define LIGHT_POINTFAKESURFACE 3
- #define LIGHT_SURFACEDIRECTED 4
- #define LIGHT_SURFACERADIAL 5
- #define LIGHT_SURFACESPOT 6
- //light distance attenuation types
- #define LDAT_QUADRATIC 0
- #define LDAT_LINEAR 1
- #define LDAT_NOSCALE 2
- //light angle attenuation types
- #define LAAT_NORMAL 0
- #define LAAT_QUADRATIC 1
- #define LAAT_DOUBLEQUADRATIC 2
- typedef struct vlight_s
- {
- vec3_t origin; //light origin, for point lights
- winding_t w; //light winding, for area lights
- vec4_t plane; //light winding plane
- vec3_t normal; //direction of the light
- int type; //light type
- vec3_t color; //light color
- qboolean twosided; //radiates light at both sides of the winding
- int style; //light style (not used)
- int atten_disttype; //light distance attenuation type
- int atten_angletype; //light angle attenuation type
- float atten_distscale; //distance attenuation scale
- float atten_anglescale; //angle attenuation scale
- float radiusByDist; //radius by distance for spot lights
- float photons; //emitted photons
- float intensity; //intensity
- vec3_t emitColor; //full out-of-gamut value (not used)
- struct shaderInfo_s *si; //shader info
- int insolid; //set when light is in solid
- } vlight_t;
- float lightLinearScale = 1.0 / 8000;
- float lightPointScale = 7500;
- float lightAreaScale = 0.25;
- float lightFormFactorValueScale = 3;
- int lightDefaultSubdivide = 999; // vary by surface size?
- vec3_t lightAmbientColor;
- int portalclusters, numportals, numfaces;
- lleaf_t *leafs;
- lportal_t *portals;
- int numvlights = 0;
- vlight_t *vlights[MAX_LIGHTS];
- int nostitching = 0;
- int noalphashading = 0;
- int nocolorshading = 0;
- int nobackfaceculling = 0;
- int defaulttracelight = 0;
- int radiosity = 0;
- int radiosity_scale;
- int clustersurfaces[MAX_MAP_LEAFFACES];
- int numclustersurfaces = 0;
- lsurfaceTest_t *lsurfaceTest[MAX_MAP_DRAW_SURFS];
- int numfacets;
- float lightmappixelarea[MAX_MAP_LIGHTING/3];
- float *lightFloats;//[MAX_MAP_LIGHTING];
- // from polylib.c
- winding_t *AllocWinding (int points);
- void FreeWinding (winding_t *w);
- void WindingCenter (winding_t *w, vec3_t center);
- void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs);
- vec_t WindingArea (winding_t *w);
- winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist);
- void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
- vec_t epsilon, winding_t **front, winding_t **back);
- winding_t *ReverseWinding (winding_t *w);
- // from light.c
- extern char source[1024];
- extern vec3_t surfaceOrigin[ MAX_MAP_DRAW_SURFS ];
- extern int entitySurface[ MAX_MAP_DRAW_SURFS ];
- extern int samplesize;
- extern int novertexlighting;
- extern int nogridlighting;
- extern qboolean patchshadows;
- extern vec3_t gridSize;
- float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w );
- void ColorToBytes( const float *color, byte *colorBytes );
- void CountLightmaps( void );
- void GridAndVertexLighting( void );
- void SetEntityOrigins( void );
- //#define DEBUGNET
- #ifdef DEBUGNET
- #include "l_net.h"
- socket_t *debug_socket;
- /*
- =====================
- DebugNet_Setup
- =====================
- */
- void DebugNet_Setup(void)
- {
- address_t address;
- int i;
- Net_Setup();
- Net_StringToAddress("127.0.0.1:28000", &address);
- for (i = 0; i < 10; i++)
- {
- debug_socket = Net_Connect(&address, 28005 + i);
- if (debug_socket)
- break;
- }
- }
- /*
- =====================
- DebugNet_Shutdown
- =====================
- */
- void DebugNet_Shutdown(void)
- {
- netmessage_t msg;
- if (debug_socket)
- {
- NMSG_Clear(&msg);
- NMSG_WriteByte(&msg, 1);
- Net_Send(debug_socket, &msg);
- Net_Disconnect(debug_socket);
- }
- debug_socket = NULL;
- Net_Shutdown();
- }
- /*
- =====================
- DebugNet_RemoveAllPolys
- =====================
- */
- void DebugNet_RemoveAllPolys(void)
- {
- netmessage_t msg;
- if (!debug_socket)
- return;
- NMSG_Clear(&msg);
- NMSG_WriteByte(&msg, 2); //remove all debug polys
- Net_Send(debug_socket, &msg);
- }
- /*
- ====================
- DebugNet_DrawWinding
- =====================
- */
- void DebugNet_DrawWinding(winding_t *w, int color)
- {
- netmessage_t msg;
- int i;
- if (!debug_socket)
- return;
- NMSG_Clear(&msg);
- NMSG_WriteByte(&msg, 0); //draw a winding
- NMSG_WriteByte(&msg, w->numpoints); //number of points
- NMSG_WriteLong(&msg, color); //color
- for (i = 0; i < w->numpoints; i++)
- {
- NMSG_WriteFloat(&msg, w->points[i][0]);
- NMSG_WriteFloat(&msg, w->points[i][1]);
- NMSG_WriteFloat(&msg, w->points[i][2]);
- }
- Net_Send(debug_socket, &msg);
- }
- /*
- =====================
- DebugNet_DrawLine
- =====================
- */
- void DebugNet_DrawLine(vec3_t p1, vec3_t p2, int color)
- {
- netmessage_t msg;
- if (!debug_socket)
- return;
- NMSG_Clear(&msg);
- NMSG_WriteByte(&msg, 1); //draw a line
- NMSG_WriteLong(&msg, color); //color
- NMSG_WriteFloat(&msg, p1[0]);
- NMSG_WriteFloat(&msg, p1[1]);
- NMSG_WriteFloat(&msg, p1[2]);
- NMSG_WriteFloat(&msg, p2[0]);
- NMSG_WriteFloat(&msg, p2[1]);
- NMSG_WriteFloat(&msg, p2[2]);
- Net_Send(debug_socket, &msg);
- }
- /*
- =====================
- DebugNet_DrawMesh
- =====================
- */
- void DebugNet_DrawMesh(mesh_t *mesh)
- {
- int i, j;
- float dot;
- drawVert_t *v1, *v2, *v3, *v4;
- winding_t winding;
- plane_t plane;
- vec3_t d1, d2;
- for ( i = 0 ; i < mesh->width - 1 ; i++ ) {
- for ( j = 0 ; j < mesh->height - 1 ; j++ ) {
- v1 = mesh->verts + j * mesh->width + i;
- v2 = v1 + 1;
- v3 = v1 + mesh->width + 1;
- v4 = v1 + mesh->width;
- VectorSubtract( v4->xyz, v1->xyz, d1 );
- VectorSubtract( v3->xyz, v1->xyz, d2 );
- CrossProduct( d2, d1, plane.normal );
- if ( VectorNormalize( plane.normal, plane.normal ) != 0 )
- {
- plane.dist = DotProduct( v1->xyz, plane.normal );
- dot = DotProduct(plane.normal, v2->xyz) - plane.dist;
- if (fabs(dot) < 0.1)
- {
- VectorCopy(v1->xyz, winding.points[0]);
- VectorCopy(v4->xyz, winding.points[1]);
- VectorCopy(v3->xyz, winding.points[2]);
- VectorCopy(v2->xyz, winding.points[3]);
- winding.numpoints = 4;
- DebugNet_DrawWinding(&winding, 2);
- continue;
- }
- }
- winding.numpoints = 3;
- VectorCopy(v1->xyz, winding.points[0]);
- VectorCopy(v4->xyz, winding.points[1]);
- VectorCopy(v3->xyz, winding.points[2]);
- DebugNet_DrawWinding(&winding, 2);
- VectorCopy(v1->xyz, winding.points[0]);
- VectorCopy(v3->xyz, winding.points[1]);
- VectorCopy(v2->xyz, winding.points[2]);
- DebugNet_DrawWinding(&winding, 2);
- }
- }
- }
- /*
- =====================
- VL_DrawLightVolume
- =====================
- */
- int VL_ChopWinding (winding_t *in, plane_t *split, float epsilon);
- void VL_DrawLightVolume(vlight_t *light, lightvolume_t *volume)
- {
- winding_t w;
- int i;
- vec3_t p2, invlight;
- memcpy(w.points, volume->points, volume->numplanes * sizeof(vec3_t));
- w.numpoints = volume->numplanes;
- DebugNet_DrawWinding(&w, 2);
- if (volume->type == VOLUME_DIRECTED)
- {
- VectorCopy(light->normal, invlight);
- VectorInverse(invlight);
- for (i = 0; i < volume->numplanes; i++)
- {
- VectorCopy(volume->points[i], w.points[0]);
- VectorCopy(volume->points[(i+1) % volume->numplanes], w.points[1]);
- VectorMA(w.points[1], MAX_WORLD_COORD, invlight, w.points[2]);
- VectorMA(w.points[0], MAX_WORLD_COORD, invlight, w.points[3]);
- w.numpoints = 4;
- DebugNet_DrawWinding(&w, 2);
- VectorMA(volume->points[i], 8, volume->planes[i].normal, p2);
- DebugNet_DrawLine(volume->points[i], p2, 3);
- }
- }
- else
- {
- //
- VectorCopy(light->origin, w.points[0]);
- w.numpoints = 3;
- for (i = 0; i < volume->numplanes; i++)
- {
- VectorCopy(volume->points[i], w.points[1]);
- VectorCopy(volume->points[(i+1) % volume->numplanes], w.points[2]);
- VL_ChopWinding(&w, &volume->endplane, 0);
- DebugNet_DrawWinding(&w, 2);
- VectorMA(volume->points[i], 8, volume->planes[i].normal, p2);
- DebugNet_DrawLine(volume->points[i], p2, 3);
- }
- }
- }
- /*
- =============
- VL_DrawLightmapPixel
- =============
- */
- void VL_DrawLightmapPixel(int surfaceNum, int x, int y, int color)
- {
- winding_t w;
- dsurface_t *ds;
- mesh_t *mesh;
- ds = &drawSurfaces[surfaceNum];
- if (ds->surfaceType == MST_PATCH)
- {
- mesh = lsurfaceTest[surfaceNum]->detailMesh;
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[0]);
- VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[1]);
- VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[2]);
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[3]);
- w.numpoints = 4;
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[0]);
- VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[0]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[1]);
- VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[1]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[2]);
- VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[2]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[3]);
- VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[3]);
- w.numpoints = 4;
- }
- DebugNet_DrawWinding(&w, color);
- }
- /*
- ============
- VL_DrawPortals
- ============
- */
- void VL_DrawPortals(void)
- {
- int j;
- lportal_t *p;
- for (j = 0; j < numportals * 2; j++)
- {
- p = portals + j;
- DebugNet_DrawWinding(p->winding, 1);
- }
- }
- /*
- ============
- VL_DrawLeaf
- ============
- */
- void VL_DrawLeaf(int cluster)
- {
- int i;
- lleaf_t *leaf;
- lportal_t *p;
- leaf = &leafs[cluster];
- for (i = 0; i < leaf->numportals; i++)
- {
- p = leaf->portals[i];
- DebugNet_DrawWinding(p->winding, 1);
- }
- }
- #endif //DEBUGNET
- /*
- =============
- VL_SplitWinding
- =============
- */
- int VL_SplitWinding (winding_t *in, winding_t *back, plane_t *split, float epsilon)
- {
- vec_t dists[128];
- int sides[128];
- int counts[3];
- vec_t dot;
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
- winding_t out;
- winding_t *neww;
- counts[0] = counts[1] = counts[2] = 0;
- // determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
- if (!counts[SIDE_BACK])
- {
- if (!counts[SIDE_FRONT])
- return SIDE_ON;
- else
- return SIDE_FRONT;
- }
-
- if (!counts[SIDE_FRONT])
- {
- return SIDE_BACK;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- neww = &out;
- neww->numpoints = 0;
- back->numpoints = 0;
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->points[i];
- if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
- if (back->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT;
- }
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- VectorCopy (p1, back->points[back->numpoints]);
- back->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
- if (sides[i] == SIDE_BACK)
- {
- VectorCopy (p1, back->points[back->numpoints]);
- back->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
- if (back->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
- // generate a split point
- p2 = in->points[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, neww->points[neww->numpoints]);
- neww->numpoints++;
- VectorCopy (mid, back->points[back->numpoints]);
- back->numpoints++;
- }
- memcpy(in, &out, sizeof(winding_t));
-
- return SIDE_CROSS;
- }
- /*
- =====================
- VL_LinkSurfaceIntoCluster
- =====================
- */
- void VL_LinkSurfaceIntoCluster(int cluster, int surfaceNum)
- {
- lleaf_t *leaf;
- int i;
- leaf = &leafs[cluster];
- for (i = 0; i < leaf->numSurfaces; i++)
- {
- if (clustersurfaces[leaf->firstSurface + i] == surfaceNum)
- return;
- }
- for (i = numclustersurfaces; i > leaf->firstSurface + leaf->numSurfaces; i--)
- clustersurfaces[i] = clustersurfaces[i-1];
- for (i = 0; i < portalclusters; i++)
- {
- if (i == cluster)
- continue;
- if (leafs[i].firstSurface >= leaf->firstSurface + leaf->numSurfaces)
- leafs[i].firstSurface++;
- }
- clustersurfaces[leaf->firstSurface + leaf->numSurfaces] = surfaceNum;
- leaf->numSurfaces++;
- numclustersurfaces++;
- if (numclustersurfaces >= MAX_MAP_LEAFFACES)
- Error("MAX_MAP_LEAFFACES");
- }
- /*
- =====================
- VL_R_LinkSurface
- =====================
- */
- void VL_R_LinkSurface(int nodenum, int surfaceNum, winding_t *w)
- {
- int leafnum, cluster, res;
- dnode_t *node;
- dplane_t *plane;
- winding_t back;
- plane_t split;
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VL_SplitWinding (w, &back, &split, 0.1);
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- memcpy(&back, w, sizeof(winding_t));
- VL_R_LinkSurface(node->children[1], surfaceNum, &back);
- nodenum = node->children[0];
- }
- else
- {
- VL_R_LinkSurface(node->children[1], surfaceNum, &back);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- cluster = dleafs[leafnum].cluster;
- if (cluster != -1)
- {
- VL_LinkSurfaceIntoCluster(cluster, surfaceNum);
- }
- }
- /*
- =====================
- VL_LinkSurfaces
- maybe link each facet seperately instead of the test surfaces?
- =====================
- */
- void VL_LinkSurfaces(void)
- {
- int i, j;
- lsurfaceTest_t *test;
- lFacet_t *facet;
- winding_t winding;
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- for (j = 0; j < test->numFacets; j++)
- {
- facet = &test->facets[j];
- memcpy(winding.points, facet->points, facet->numpoints * sizeof(vec3_t));
- winding.numpoints = facet->numpoints;
- VL_R_LinkSurface(0, i, &winding);
- }
- }
- }
- /*
- =====================
- VL_TextureMatrixFromPoints
- =====================
- */
- void VL_TextureMatrixFromPoints( lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
- int i, j;
- float t;
- float m[3][4];
- float s;
- // This is an incredibly stupid way of solving a three variable equation
- for ( i = 0 ; i < 2 ; i++ ) {
- m[0][0] = a->xyz[0];
- m[0][1] = a->xyz[1];
- m[0][2] = a->xyz[2];
- m[0][3] = a->st[i];
- m[1][0] = b->xyz[0];
- m[1][1] = b->xyz[1];
- m[1][2] = b->xyz[2];
- m[1][3] = b->st[i];
- m[2][0] = c->xyz[0];
- m[2][1] = c->xyz[1];
- m[2][2] = c->xyz[2];
- m[2][3] = c->st[i];
- if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) > fabs(m[2][0]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[0][j];
- m[0][j] = m[1][j];
- m[1][j] = t;
- }
- } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) > fabs(m[1][0]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[0][j];
- m[0][j] = m[2][j];
- m[2][j] = t;
- }
- }
- s = 1.0 / m[0][0];
- m[0][0] *= s;
- m[0][1] *= s;
- m[0][2] *= s;
- m[0][3] *= s;
- s = m[1][0];
- m[1][0] -= m[0][0] * s;
- m[1][1] -= m[0][1] * s;
- m[1][2] -= m[0][2] * s;
- m[1][3] -= m[0][3] * s;
- s = m[2][0];
- m[2][0] -= m[0][0] * s;
- m[2][1] -= m[0][1] * s;
- m[2][2] -= m[0][2] * s;
- m[2][3] -= m[0][3] * s;
- if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[1][j];
- m[1][j] = m[2][j];
- m[2][j] = t;
- }
- }
- s = 1.0 / m[1][1];
- m[1][0] *= s;
- m[1][1] *= s;
- m[1][2] *= s;
- m[1][3] *= s;
- s = m[2][1];// / m[1][1];
- m[2][0] -= m[1][0] * s;
- m[2][1] -= m[1][1] * s;
- m[2][2] -= m[1][2] * s;
- m[2][3] -= m[1][3] * s;
- s = 1.0 / m[2][2];
- m[2][0] *= s;
- m[2][1] *= s;
- m[2][2] *= s;
- m[2][3] *= s;
- f->textureMatrix[i][2] = m[2][3];
- f->textureMatrix[i][1] = m[1][3] - f->textureMatrix[i][2] * m[1][2];
- f->textureMatrix[i][0] = m[0][3] - f->textureMatrix[i][2] * m[0][2] - f->textureMatrix[i][1] * m[0][1];
- f->textureMatrix[i][3] = 0;
- /*
- s = fabs( DotProduct( a->xyz, f->textureMatrix[i] ) - a->st[i] );
- if ( s > 0.01 ) {
- Error( "Bad textureMatrix" );
- }
- s = fabs( DotProduct( b->xyz, f->textureMatrix[i] ) - b->st[i] );
- if ( s > 0.01 ) {
- Error( "Bad textureMatrix" );
- }
- s = fabs( DotProduct( c->xyz, f->textureMatrix[i] ) - c->st[i] );
- if ( s > 0.01 ) {
- Error( "Bad textureMatrix" );
- }
- */
- }
- }
- /*
- =====================
- VL_LightmapMatrixFromPoints
- =====================
- */
- void VL_LightmapMatrixFromPoints( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
- int i, j;
- float t;
- float m[3][4], al, bl, cl;
- float s;
- int h, w, ssize;
- vec3_t mins, maxs, delta, size, planeNormal;
- drawVert_t *verts;
- static int message;
- // vertex-lit triangle model
- if ( dsurf->surfaceType == MST_TRIANGLE_SOUP ) {
- return;
- }
-
- if ( dsurf->lightmapNum < 0 ) {
- return; // doesn't need lighting
- }
- VectorClear(f->mins);
- if (dsurf->surfaceType != MST_PATCH)
- {
- ssize = samplesize;
- if (si->lightmapSampleSize)
- ssize = si->lightmapSampleSize;
- ClearBounds( mins, maxs );
- verts = &drawVerts[dsurf->firstVert];
- for ( i = 0 ; i < dsurf->numVerts ; i++ ) {
- AddPointToBounds( verts[i].xyz, mins, maxs );
- }
- // round to the lightmap resolution
- for ( i = 0 ; i < 3 ; i++ ) {
- mins[i] = ssize * floor( mins[i] / ssize );
- maxs[i] = ssize * ceil( maxs[i] / ssize );
- f->mins[i] = mins[i];
- size[i] = (maxs[i] - mins[i]) / ssize + 1;
- }
- // the two largest axis will be the lightmap size
- VectorClear(f->lightmapMatrix[0]);
- f->lightmapMatrix[0][3] = 0;
- VectorClear(f->lightmapMatrix[1]);
- f->lightmapMatrix[1][3] = 0;
- planeNormal[0] = fabs( dsurf->lightmapVecs[2][0] );
- planeNormal[1] = fabs( dsurf->lightmapVecs[2][1] );
- planeNormal[2] = fabs( dsurf->lightmapVecs[2][2] );
- if ( planeNormal[0] >= planeNormal[1] && planeNormal[0] >= planeNormal[2] ) {
- w = size[1];
- h = size[2];
- f->lightmapMatrix[0][1] = 1.0 / ssize;
- f->lightmapMatrix[1][2] = 1.0 / ssize;
- } else if ( planeNormal[1] >= planeNormal[0] && planeNormal[1] >= planeNormal[2] ) {
- w = size[0];
- h = size[2];
- f->lightmapMatrix[0][0] = 1.0 / ssize;
- f->lightmapMatrix[1][2] = 1.0 / ssize;
- } else {
- w = size[0];
- h = size[1];
- f->lightmapMatrix[0][0] = 1.0 / ssize;
- f->lightmapMatrix[1][1] = 1.0 / ssize;
- }
- if ( w > LIGHTMAP_WIDTH ) {
- VectorScale ( f->lightmapMatrix[0], (float)LIGHTMAP_SIZE/w, f->lightmapMatrix[0] );
- }
-
- if ( h > LIGHTMAP_HEIGHT ) {
- VectorScale ( f->lightmapMatrix[1], (float)LIGHTMAP_SIZE/h, f->lightmapMatrix[1] );
- }
- VectorSubtract(a->xyz, f->mins, delta);
- s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(s - a->lightmap[0]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(t - a->lightmap[1]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- VectorSubtract(b->xyz, f->mins, delta);
- s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(s - b->lightmap[0]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(t - b->lightmap[1]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- VectorSubtract(c->xyz, f->mins, delta);
- s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(s - c->lightmap[0]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(t - c->lightmap[1]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- VectorAdd(f->mins, surfaceOrigin[dsurf - drawSurfaces], f->mins);
- return;
- }
- // This is an incredibly stupid way of solving a three variable equation
- for ( i = 0 ; i < 2 ; i++ ) {
- if (i)
- al = a->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- else
- al = a->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
- m[0][0] = a->xyz[0] - f->mins[0];
- m[0][1] = a->xyz[1] - f->mins[1];
- m[0][2] = a->xyz[2] - f->mins[2];
- m[0][3] = al;
- if (i)
- bl = b->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- else
- bl = b->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
- m[1][0] = b->xyz[0] - f->mins[0];
- m[1][1] = b->xyz[1] - f->mins[1];
- m[1][2] = b->xyz[2] - f->mins[2];
- m[1][3] = bl;
- if (i)
- cl = c->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- else
- cl = c->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
- m[2][0] = c->xyz[0] - f->mins[0];
- m[2][1] = c->xyz[1] - f->mins[1];
- m[2][2] = c->xyz[2] - f->mins[2];
- m[2][3] = cl;
- if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) >= fabs(m[2][0]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[0][j];
- m[0][j] = m[1][j];
- m[1][j] = t;
- }
- } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) >= fabs(m[1][0]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[0][j];
- m[0][j] = m[2][j];
- m[2][j] = t;
- }
- }
- if (m[0][0])
- {
- s = 1.0 / m[0][0];
- m[0][0] *= s;
- m[0][1] *= s;
- m[0][2] *= s;
- m[0][3] *= s;
- s = m[1][0];
- m[1][0] -= m[0][0] * s;
- m[1][1] -= m[0][1] * s;
- m[1][2] -= m[0][2] * s;
- m[1][3] -= m[0][3] * s;
- s = m[2][0];
- m[2][0] -= m[0][0] * s;
- m[2][1] -= m[0][1] * s;
- m[2][2] -= m[0][2] * s;
- m[2][3] -= m[0][3] * s;
- }
- if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[1][j];
- m[1][j] = m[2][j];
- m[2][j] = t;
- }
- }
- if (m[1][1])
- {
- s = 1.0 / m[1][1];
- m[1][0] *= s;
- m[1][1] *= s;
- m[1][2] *= s;
- m[1][3] *= s;
- s = m[2][1];
- m[2][0] -= m[1][0] * s;
- m[2][1] -= m[1][1] * s;
- m[2][2] -= m[1][2] * s;
- m[2][3] -= m[1][3] * s;
- }
- if (m[2][2])
- {
- s = 1.0 / m[2][2];
- m[2][0] *= s;
- m[2][1] *= s;
- m[2][2] *= s;
- m[2][3] *= s;
- }
- f->lightmapMatrix[i][2] = m[2][3];
- f->lightmapMatrix[i][1] = m[1][3] - f->lightmapMatrix[i][2] * m[1][2];
- f->lightmapMatrix[i][0] = m[0][3] - f->lightmapMatrix[i][2] * m[0][2] - f->lightmapMatrix[i][1] * m[0][1];
- f->lightmapMatrix[i][3] = 0;
- VectorSubtract(a->xyz, f->mins, delta);
- s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - al );
- if ( s > 0.01 ) {
- if (!message)
- _printf( "Bad lightmapMatrix\n" );
- message = qtrue;
- }
- VectorSubtract(b->xyz, f->mins, delta);
- s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - bl );
- if ( s > 0.01 ) {
- if (!message)
- _printf( "Bad lightmapMatrix\n" );
- message = qtrue;
- }
- VectorSubtract(c->xyz, f->mins, delta);
- s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - cl );
- if ( s > 0.01 ) {
- if (!message)
- _printf( "Bad lightmapMatrix\n" );
- message = qtrue;
- }
- VectorAdd(f->mins, surfaceOrigin[dsurf - drawSurfaces], f->mins);
- }
- }
- /*
- =============
- Plane_Equal
- =============
- */
- #define NORMAL_EPSILON 0.0001
- #define DIST_EPSILON 0.02
- int Plane_Equal(plane_t *a, plane_t *b, int flip)
- {
- vec3_t normal;
- float dist;
- if (flip) {
- normal[0] = - b->normal[0];
- normal[1] = - b->normal[1];
- normal[2] = - b->normal[2];
- dist = - b->dist;
- }
- else {
- normal[0] = b->normal[0];
- normal[1] = b->normal[1];
- normal[2] = b->normal[2];
- dist = b->dist;
- }
- if (
- fabs(a->normal[0] - normal[0]) < NORMAL_EPSILON
- && fabs(a->normal[1] - normal[1]) < NORMAL_EPSILON
- && fabs(a->normal[2] - normal[2]) < NORMAL_EPSILON
- && fabs(a->dist - dist) < DIST_EPSILON )
- return qtrue;
- return qfalse;
- }
- /*
- =============
- VL_PlaneFromPoints
- =============
- */
- qboolean VL_PlaneFromPoints( plane_t *plane, const vec3_t a, const vec3_t b, const vec3_t c ) {
- vec3_t d1, d2;
- VectorSubtract( b, a, d1 );
- VectorSubtract( c, a, d2 );
- CrossProduct( d2, d1, plane->normal );
- if ( VectorNormalize( plane->normal, plane->normal ) == 0 ) {
- return qfalse;
- }
- plane->dist = DotProduct( a, plane->normal );
- return qtrue;
- }
- /*
- =====================
- VL_GenerateBoundaryForPoints
- =====================
- */
- void VL_GenerateBoundaryForPoints( plane_t *boundary, plane_t *plane, vec3_t a, vec3_t b ) {
- vec3_t d1;
- // make a perpendicular vector to the edge and the surface
- VectorSubtract( a, b, d1 );
- CrossProduct( plane->normal, d1, boundary->normal );
- VectorNormalize( boundary->normal, boundary->normal );
- boundary->dist = DotProduct( a, boundary->normal );
- }
- /*
- =====================
- VL_GenerateFacetFor3Points
- =====================
- */
- qboolean VL_GenerateFacetFor3Points( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
- //
- vec3_t dir;
- int i;
- // if we can't generate a valid plane for the points, ignore the facet
- if ( !VL_PlaneFromPoints( &f->plane, a->xyz, b->xyz, c->xyz ) ) {
- f->numpoints = 0;
- return qfalse;
- }
- f->num = numfacets++;
- VectorAdd( a->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[0] );
- VectorAdd( b->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[1] );
- VectorAdd( c->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[2] );
- f->lightmapCoords[0][0] = a->lightmap[0];
- f->lightmapCoords[0][1] = a->lightmap[1];
- f->lightmapCoords[1][0] = b->lightmap[0];
- f->lightmapCoords[1][1] = b->lightmap[1];
- f->lightmapCoords[2][0] = c->lightmap[0];
- f->lightmapCoords[2][1] = c->lightmap[1];
- VL_GenerateBoundaryForPoints( &f->boundaries[0], &f->plane, f->points[0], f->points[1] );
- VL_GenerateBoundaryForPoints( &f->boundaries[1], &f->plane, f->points[1], f->points[2] );
- VL_GenerateBoundaryForPoints( &f->boundaries[2], &f->plane, f->points[2], f->points[0] );
- for (i = 0; i < 3; i++)
- {
- VectorSubtract(f->points[(i+1)%3], f->points[i], dir);
- if (VectorLength(dir) < 0.1)
- return qfalse;
- }
- VL_TextureMatrixFromPoints( f, a, b, c );
- VL_LightmapMatrixFromPoints( dsurf, si, f, a, b, c );
- f->numpoints = 3;
- return qtrue;
- }
- /*
- =====================
- VL_GenerateFacetFor4Points
- Attempts to use four points as a planar quad
- =====================
- */
- #define PLANAR_EPSILON 0.1
- qboolean VL_GenerateFacetFor4Points( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c, drawVert_t *d ) {
- float dist;
- vec3_t dir;
- int i;
- plane_t plane;
- // if we can't generate a valid plane for the points, ignore the facet
- if ( !VL_PlaneFromPoints( &f->plane, a->xyz, b->xyz, c->xyz ) ) {
- f->numpoints = 0;
- return qfalse;
- }
- // if the fourth point is also on the plane, we can make a quad facet
- dist = DotProduct( d->xyz, f->plane.normal ) - f->plane.dist;
- if ( fabs( dist ) > PLANAR_EPSILON ) {
- f->numpoints = 0;
- return qfalse;
- }
- VectorAdd( a->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[0] );
- VectorAdd( b->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[1] );
- VectorAdd( c->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[2] );
- VectorAdd( d->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[3] );
- for (i = 1; i < 4; i++)
- {
- if ( !VL_PlaneFromPoints( &plane, f->points[i], f->points[(i+1) % 4], f->points[(i+2) % 4]) ) {
- f->numpoints = 0;
- return qfalse;
- }
- if (!Plane_Equal(&f->plane, &plane, qfalse)) {
- f->numpoints = 0;
- return qfalse;
- }
- }
- f->lightmapCoords[0][0] = a->lightmap[0];
- f->lightmapCoords[0][1] = a->lightmap[1];
- f->lightmapCoords[1][0] = b->lightmap[0];
- f->lightmapCoords[1][1] = b->lightmap[1];
- f->lightmapCoords[2][0] = c->lightmap[0];
- f->lightmapCoords[2][1] = c->lightmap[1];
- f->lightmapCoords[3][0] = d->lightmap[0];
- f->lightmapCoords[3][1] = d->lightmap[1];
- VL_GenerateBoundaryForPoints( &f->boundaries[0], &f->plane, f->points[0], f->points[1] );
- VL_GenerateBoundaryForPoints( &f->boundaries[1], &f->plane, f->points[1], f->points[2] );
- VL_GenerateBoundaryForPoints( &f->boundaries[2], &f->plane, f->points[2], f->points[3] );
- VL_GenerateBoundaryForPoints( &f->boundaries[3], &f->plane, f->points[3], f->points[0] );
- for (i = 0; i < 4; i++)
- {
- VectorSubtract(f->points[(i+1)%4], f->points[i], dir);
- if (VectorLength(dir) < 0.1)
- return qfalse;
- }
- VL_TextureMatrixFromPoints( f, a, b, c );
- VL_LightmapMatrixFromPoints( dsurf, si, f, a, b, c );
- f->num = numfacets++;
- f->numpoints = 4;
- return qtrue;
- }
- /*
- ===============
- VL_SphereFromBounds
- ===============
- */
- void VL_SphereFromBounds( vec3_t mins, vec3_t maxs, vec3_t origin, float *radius ) {
- vec3_t temp;
- VectorAdd( mins, maxs, origin );
- VectorScale( origin, 0.5, origin );
- VectorSubtract( maxs, origin, temp );
- *radius = VectorLength( temp );
- }
- /*
- ====================
- VL_FacetsForTriangleSurface
- ====================
- */
- void VL_FacetsForTriangleSurface( dsurface_t *dsurf, shaderInfo_t *si, lsurfaceTest_t *test ) {
- int i;
- drawVert_t *v1, *v2, *v3, *v4;
- int count;
- int i1, i2, i3, i4, i5, i6;
- test->patch = qfalse;
- if (dsurf->surfaceType == MST_TRIANGLE_SOUP)
- test->trisoup = qtrue;
- else
- test->trisoup = qfalse;
- test->numFacets = dsurf->numIndexes / 3;
- test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
- test->shader = si;
- count = 0;
- for ( i = 0 ; i < test->numFacets ; i++ ) {
- i1 = drawIndexes[ dsurf->firstIndex + i*3 ];
- i2 = drawIndexes[ dsurf->firstIndex + i*3 + 1 ];
- i3 = drawIndexes[ dsurf->firstIndex + i*3 + 2 ];
- v1 = &drawVerts[ dsurf->firstVert + i1 ];
- v2 = &drawVerts[ dsurf->firstVert + i2 ];
- v3 = &drawVerts[ dsurf->firstVert + i3 ];
- // try and make a quad out of two triangles
- if ( i != test->numFacets - 1 ) {
- i4 = drawIndexes[ dsurf->firstIndex + i*3 + 3 ];
- i5 = drawIndexes[ dsurf->firstIndex + i*3 + 4 ];
- i6 = drawIndexes[ dsurf->firstIndex + i*3 + 5 ];
- if ( i4 == i3 && i5 == i2 ) {
- v4 = &drawVerts[ dsurf->firstVert + i6 ];
- if ( VL_GenerateFacetFor4Points( dsurf, si, &test->facets[count], v1, v2, v4, v3 ) ) {
- count++;
- i++; // skip next tri
- continue;
- }
- }
- }
- if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v2, v3 )) {
- count++;
- }
- }
- // we may have turned some pairs into quads
- test->numFacets = count;
- }
- /*
- ====================
- VL_FacetsForPatch
- ====================
- */
- void VL_FacetsForPatch( dsurface_t *dsurf, int surfaceNum, shaderInfo_t *si, lsurfaceTest_t *test ) {
- int i, j, x, y;
- drawVert_t *v1, *v2, *v3, *v4;
- int count, ssize;
- mesh_t mesh;
- mesh_t *subdivided, *detailmesh, *newmesh;
- int widthtable[LIGHTMAP_SIZE], heighttable[LIGHTMAP_SIZE];
- mesh.width = dsurf->patchWidth;
- mesh.height = dsurf->patchHeight;
- mesh.verts = &drawVerts[ dsurf->firstVert ];
- newmesh = SubdivideMesh( mesh, 8, 999 );
- PutMeshOnCurve( *newmesh );
- MakeMeshNormals( *newmesh );
- subdivided = RemoveLinearMeshColumnsRows( newmesh );
- FreeMesh(newmesh);
- // DebugNet_RemoveAllPolys();
- // DebugNet_DrawMesh(subdivided);
- ssize = samplesize;
- if (si->lightmapSampleSize)
- ssize = si->lightmapSampleSize;
- if ( dsurf->lightmapNum >= 0 ) {
- detailmesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_SIZE, widthtable, heighttable);
- test->detailMesh = detailmesh;
- // DebugNet_RemoveAllPolys();
- // DebugNet_DrawMesh(detailmesh);
- if ( detailmesh->width != dsurf->lightmapWidth || detailmesh->height != dsurf->lightmapHeight ) {
- Error( "Mesh lightmap miscount");
- }
- }
- else {
- test->detailMesh = NULL;
- memset(widthtable, 0, sizeof(widthtable));
- memset(heighttable, 0, sizeof(heighttable));
- }
- test->patch = qtrue;
- test->trisoup = qfalse;
- test->numFacets = ( subdivided->width - 1 ) * ( subdivided->height - 1 ) * 2;
- test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
- test->shader = si;
- count = 0;
- x = 0;
- for ( i = 0 ; i < subdivided->width - 1 ; i++ ) {
- y = 0;
- for ( j = 0 ; j < subdivided->height - 1 ; j++ ) {
- v1 = subdivided->verts + j * subdivided->width + i;
- v2 = v1 + 1;
- v3 = v1 + subdivided->width + 1;
- v4 = v1 + subdivided->width;
- if ( VL_GenerateFacetFor4Points( dsurf, si, &test->facets[count], v1, v4, v3, v2 ) ) {
- test->facets[count].x = x;
- test->facets[count].y = y;
- test->facets[count].width = widthtable[i];
- test->facets[count].height = heighttable[j];
- count++;
- } else {
- if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v4, v3 )) {
- test->facets[count].x = x;
- test->facets[count].y = y;
- test->facets[count].width = widthtable[i];
- test->facets[count].height = heighttable[j];
- count++;
- }
- if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v3, v2 )) {
- test->facets[count].x = x;
- test->facets[count].y = y;
- test->facets[count].width = widthtable[i];
- test->facets[count].height = heighttable[j];
- count++;
- }
- }
- y += heighttable[j];
- }
- x += widthtable[i];
- }
- test->numFacets = count;
- FreeMesh(subdivided);
- }
- /*
- =====================
- VL_InitSurfacesForTesting
- =====================
- */
- void VL_InitSurfacesForTesting( void ) {
- int i, j, k;
- dsurface_t *dsurf;
- lsurfaceTest_t *test;
- shaderInfo_t *si;
- lFacet_t *facet;
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- // don't light the entity surfaces with vlight
- if ( entitySurface[i] )
- continue;
- //
- dsurf = &drawSurfaces[ i ];
- if ( !dsurf->numIndexes && !dsurf->patchWidth ) {
- continue;
- }
- si = ShaderInfoForShader( dshaders[ dsurf->shaderNum].shader );
- // if the surface is translucent and does not cast an alpha shadow
- if ( (si->contents & CONTENTS_TRANSLUCENT) && !(si->surfaceFlags & SURF_ALPHASHADOW) ) {
- // if the surface has no lightmap
- if ( dsurf->lightmapNum < 0 )
- continue;
- }
- test = malloc( sizeof( *test ) );
- memset(test, 0, sizeof( *test ));
- test->mutex = MutexAlloc();
- test->numvolumes = 0;
- if (si->forceTraceLight)
- test->always_tracelight = qtrue;
- else if (si->forceVLight)
- test->always_vlight = qtrue;
- lsurfaceTest[i] = test;
- if ( dsurf->surfaceType == MST_TRIANGLE_SOUP || dsurf->surfaceType == MST_PLANAR ) {
- VL_FacetsForTriangleSurface( dsurf, si, test );
- } else if ( dsurf->surfaceType == MST_PATCH ) {
- VL_FacetsForPatch( dsurf, i, si, test );
- }
- if (numfacets >= MAX_FACETS)
- Error("numfacets >= MAX_FACETS (%d)", MAX_FACETS);
- ClearBounds( test->mins, test->maxs );
- for (j = 0; j < test->numFacets; j++)
- {
- facet = &test->facets[j];
- for ( k = 0 ; k < facet->numpoints; k++) {
- AddPointToBounds( facet->points[k], test->mins, test->maxs );
- }
- }
- VL_SphereFromBounds( test->mins, test->maxs, test->origin, &test->radius );
- }
- _printf("%6d facets\n", numfacets);
- _printf("linking surfaces...\n");
- VL_LinkSurfaces();
- }
- /*
- =============
- VL_ChopWinding
- =============
- */
- int VL_ChopWinding (winding_t *in, plane_t *split, float epsilon)
- {
- vec_t dists[128];
- int sides[128];
- int counts[3];
- vec_t dot;
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
- winding_t out;
- winding_t *neww;
- counts[0] = counts[1] = counts[2] = 0;
- // determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
- if (!counts[SIDE_BACK])
- {
- if (!counts[SIDE_FRONT])
- return SIDE_ON;
- else
- return SIDE_FRONT;
- }
-
- if (!counts[SIDE_FRONT])
- {
- return SIDE_BACK;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- neww = &out;
- neww->numpoints = 0;
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->points[i];
- if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_ChopWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_ChopWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
- // generate a split point
- p2 = in->points[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
- memcpy(in, &out, sizeof(winding_t));
-
- return SIDE_CROSS;
- }
- /*
- =============
- VL_ChopWindingWithBrush
- returns all winding fragments outside the brush
- =============
- */
- int VL_ChopWindingWithBrush(winding_t *w, dbrush_t *brush, winding_t *outwindings, int maxout)
- {
- int i, res, numout;
- winding_t front, back;
- plane_t plane;
- numout = 0;
- memcpy(front.points, w->points, w->numpoints * sizeof(vec3_t));
- front.numpoints = w->numpoints;
- for (i = 0; i < brush->numSides; i++)
- {
- VectorCopy(dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].normal, plane.normal);
- VectorInverse(plane.normal);
- plane.dist = -dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].dist;
- res = VL_SplitWinding(&front, &back, &plane, 0.1);
- if (res == SIDE_BACK || res == SIDE_ON)
- {
- memcpy(outwindings[0].points, w->points, w->numpoints * sizeof(vec3_t));
- outwindings[0].numpoints = w->numpoints;
- return 1; //did not intersect
- }
- if (res != SIDE_FRONT)
- {
- if (numout >= maxout)
- {
- _printf("WARNING: VL_ChopWindingWithBrush: more than %d windings\n", maxout);
- return 0;
- }
- memcpy(outwindings[numout].points, back.points, back.numpoints * sizeof(vec3_t));
- outwindings[numout].numpoints = back.numpoints;
- numout++;
- }
- }
- return numout;
- }
- /*
- =============
- VL_WindingAreaOutsideBrushes
- =============
- */
- float VL_WindingAreaOutsideBrushes(winding_t *w, int *brushnums, int numbrushes)
- {
- int i, j, numwindings[2], n;
- winding_t windingsbuf[2][64];
- dbrush_t *brush;
- float area;
- memcpy(windingsbuf[0][0].points, w->points, w->numpoints * sizeof(vec3_t));
- windingsbuf[0][0].numpoints = w->numpoints;
- numwindings[0] = 1;
- for (i = 0; i < numbrushes; i++)
- {
- brush = &dbrushes[brushnums[i]];
- if (!(dshaders[brush->shaderNum].contentFlags & (
- CONTENTS_LAVA
- | CONTENTS_SLIME
- | CONTENTS_WATER
- | CONTENTS_FOG
- | CONTENTS_AREAPORTAL
- | CONTENTS_PLAYERCLIP
- | CONTENTS_MONSTERCLIP
- | CONTENTS_CLUSTERPORTAL
- | CONTENTS_DONOTENTER
- | CONTENTS_BODY
- | CONTENTS_CORPSE
- | CONTENTS_TRANSLUCENT
- | CONTENTS_TRIGGER
- | CONTENTS_NODROP) ) &&
- (dshaders[brush->shaderNum].contentFlags & CONTENTS_SOLID) )
- {
- numwindings[!(i & 1)] = 0;
- for (j = 0; j < numwindings[i&1]; j++)
- {
- n = VL_ChopWindingWithBrush(&windingsbuf[i&1][j], brush,
- &windingsbuf[!(i&1)][numwindings[!(i&1)]],
- 64 - numwindings[!(i&1)]);
- numwindings[!(i&1)] += n;
- }
- if (!numwindings[!(i&1)])
- return 0;
- }
- else
- {
- for (j = 0; j < numwindings[i&1]; j++)
- {
- windingsbuf[!(i&1)][j] = windingsbuf[i&1][j];
- }
- numwindings[!(i&1)] = numwindings[i&1];
- }
- }
- area = 0;
- for (j = 0; j < numwindings[i&1]; j++)
- {
- area += WindingArea(&windingsbuf[i&1][j]);
- }
- return area;
- }
- /*
- =============
- VL_R_WindingAreaOutsideSolid
- =============
- */
- float VL_R_WindingAreaOutsideSolid(winding_t *w, vec3_t normal, int nodenum)
- {
- int leafnum, res;
- float area;
- dnode_t *node;
- dleaf_t *leaf;
- dplane_t *plane;
- winding_t back;
- plane_t split;
- area = 0;
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VL_SplitWinding (w, &back, &split, 0.1);
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- if (DotProduct(normal, plane->normal) > 0)
- nodenum = node->children[0];
- else
- nodenum = node->children[1];
- }
- else
- {
- area += VL_R_WindingAreaOutsideSolid(&back, normal, node->children[1]);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- leaf = &dleafs[leafnum];
- if (leaf->cluster != -1)
- {
- area += VL_WindingAreaOutsideBrushes(w, &dleafbrushes[leaf->firstLeafBrush], leaf->numLeafBrushes);
- }
- return area;
- }
- /*
- =============
- VL_WindingAreaOutsideSolid
- =============
- */
- float VL_WindingAreaOutsideSolid(winding_t *w, vec3_t normal)
- {
- return VL_R_WindingAreaOutsideSolid(w, normal, 0);
- }
- /*
- =============
- VL_ChopWindingWithFacet
- =============
- */
- float VL_ChopWindingWithFacet(winding_t *w, lFacet_t *facet)
- {
- int i;
- for (i = 0; i < facet->numpoints; i++)
- {
- if (VL_ChopWinding(w, &facet->boundaries[i], 0) == SIDE_BACK)
- return 0;
- }
- if (nostitching)
- return WindingArea(w);
- else
- return VL_WindingAreaOutsideSolid(w, facet->plane.normal);
- }
- /*
- =============
- VL_CalcVisibleLightmapPixelArea
- nice brute force ;)
- =============
- */
- void VL_CalcVisibleLightmapPixelArea(void)
- {
- int i, j, x, y, k;
- dsurface_t *ds;
- lsurfaceTest_t *test;
- mesh_t *mesh;
- winding_t w, tmpw;
- float area;
- _printf("calculating visible lightmap pixel area...\n");
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- ds = &drawSurfaces[ i ];
- if ( ds->lightmapNum < 0 )
- continue;
- for (y = 0; y < ds->lightmapHeight; y++)
- {
- for (x = 0; x < ds->lightmapWidth; x++)
- {
- if (ds->surfaceType == MST_PATCH)
- {
- if (y == ds->lightmapHeight-1)
- continue;
- if (x == ds->lightmapWidth-1)
- continue;
- mesh = lsurfaceTest[i]->detailMesh;
- VectorCopy( mesh->verts[y*mesh->width+x].xyz, w.points[0]);
- VectorCopy( mesh->verts[(y+1)*mesh->width+x].xyz, w.points[1]);
- VectorCopy( mesh->verts[(y+1)*mesh->width+x+1].xyz, w.points[2]);
- VectorCopy( mesh->verts[y*mesh->width+x+1].xyz, w.points[3]);
- w.numpoints = 4;
- if (nostitching)
- area = WindingArea(&w);
- else
- area = VL_WindingAreaOutsideSolid(&w, mesh->verts[y*mesh->width+x].normal);
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[0], w.points[0]);
- VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[1], w.points[0]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[0], w.points[3]);
- VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[1], w.points[3]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[0], w.points[2]);
- VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[1], w.points[2]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[0], w.points[1]);
- VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[1], w.points[1]);
- w.numpoints = 4;
- area = 0;
- for (j = 0; j < test->numFacets; j++)
- {
- memcpy(&tmpw, &w, sizeof(winding_t));
- area += VL_ChopWindingWithFacet(&tmpw, &test->facets[j]);
- }
- }
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- lightmappixelarea[k] = area;
- }
- }
- }
- }
- /*
- =============
- VL_FindAdjacentSurface
- =============
- */
- int VL_FindAdjacentSurface(int surfaceNum, int facetNum, vec3_t p1, vec3_t p2, int *sNum, int *fNum, int *point)
- {
- int i, j, k;
- lsurfaceTest_t *test;
- lFacet_t *facet;
- dsurface_t *ds;
- float *fp1, *fp2;
- vec3_t dir;
- plane_t *facetplane;
- // winding_t w;
- facetplane = &lsurfaceTest[surfaceNum]->facets[facetNum].plane;
- // DebugNet_RemoveAllPolys();
- // memcpy(w.points, lsurfaceTest[surfaceNum]->facets[facetNum].points,
- // lsurfaceTest[surfaceNum]->facets[facetNum].numpoints * sizeof(vec3_t));
- // w.numpoints = lsurfaceTest[surfaceNum]->facets[facetNum].numpoints;
- // DebugNet_DrawWinding(&w, 2);
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- if (i == surfaceNum)
- continue;
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- if (test->trisoup)// || test->patch)
- continue;
- ds = &drawSurfaces[i];
- if ( ds->lightmapNum < 0 )
- continue;
- //if this surface is not even near the edge
- VectorSubtract(p1, test->origin, dir);
- if (fabs(dir[0]) > test->radius ||
- fabs(dir[1]) > test->radius ||
- fabs(dir[1]) > test->radius)
- {
- VectorSubtract(p2, test->origin, dir);
- if (fabs(dir[0]) > test->radius ||
- fabs(dir[1]) > test->radius ||
- fabs(dir[1]) > test->radius)
- {
- continue;
- }
- }
- //
- for (j = 0; j < test->numFacets; j++)
- {
- facet = &test->facets[j];
- //
- //if (!Plane_Equal(&facet->plane, facetplane, qfalse))
- if (DotProduct(facet->plane.normal, facetplane->normal) < 0.9)
- {
- if (!test->trisoup && !test->patch)
- break;
- continue;
- }
- //
- for (k = 0; k < facet->numpoints; k++)
- {
- fp1 = facet->points[k];
- if (fabs(p2[0] - fp1[0]) < 0.1 &&
- fabs(p2[1] - fp1[1]) < 0.1 &&
- fabs(p2[2] - fp1[2]) < 0.1)
- {
- fp2 = facet->points[(k+1) % facet->numpoints];
- if (fabs(p1[0] - fp2[0]) < 0.1 &&
- fabs(p1[1] - fp2[1]) < 0.1 &&
- fabs(p1[2] - fp2[2]) < 0.1)
- {
- // memcpy(w.points, facet->points, facet->numpoints * sizeof(vec3_t));
- // w.numpoints = facet->numpoints;
- // DebugNet_DrawWinding(&w, 1);
- *sNum = i;
- *fNum = j;
- *point = k;
- return qtrue;
- }
- }
- /*
- else if (fabs(p1[0] - fp1[0]) < 0.1 &&
- fabs(p1[1] - fp1[1]) < 0.1 &&
- fabs(p1[2] - fp1[2]) < 0.1)
- {
- fp2 = facet->points[(k+1) % facet->numpoints];
- if (fabs(p2[0] - fp2[0]) < 0.1 &&
- fabs(p2[1] - fp2[1]) < 0.1 &&
- fabs(p2[2] - fp2[2]) < 0.1)
- {
- // memcpy(w.points, facet->points, facet->numpoints * sizeof(vec3_t));
- // w.numpoints = facet->numpoints;
- // DebugNet_DrawWinding(&w, 1);
- *sNum = i;
- *fNum = j;
- *point = k;
- return qtrue;
- }
- }
- //*/
- }
- }
- }
- return qfalse;
- }
- /*
- =============
- VL_SmoothenLightmapEdges
- this code is used to smoothen lightmaps across surface edges
- =============
- */
- void VL_SmoothenLightmapEdges(void)
- {
- int i, j, k, coords1[2][2];
- float coords2[2][2];
- int x1, y1, xinc1, yinc1, k1, k2;
- float x2, y2, xinc2, yinc2, length;
- int surfaceNum, facetNum, point;
- lsurfaceTest_t *test;
- lFacet_t *facet1, *facet2;
- dsurface_t *ds1, *ds2;
- float *p[2], s, t, *color1, *color2;
- vec3_t dir, cross;
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- if (test->trisoup)// || test->patch)
- continue;
- ds1 = &drawSurfaces[i];
- if ( ds1->lightmapNum < 0 )
- continue;
- for (j = 0; j < test->numFacets; j++)
- {
- facet1 = &test->facets[j];
- //
- for (k = 0; k < facet1->numpoints; k++)
- {
- p[0] = facet1->points[k];
- p[1] = facet1->points[(k+1)%facet1->numpoints];
- //
- coords1[0][0] = facet1->lightmapCoords[k][0] * LIGHTMAP_SIZE;
- coords1[0][1] = facet1->lightmapCoords[k][1] * LIGHTMAP_SIZE;
- coords1[1][0] = facet1->lightmapCoords[(k+1)%facet1->numpoints][0] * LIGHTMAP_SIZE;
- coords1[1][1] = facet1->lightmapCoords[(k+1)%facet1->numpoints][1] * LIGHTMAP_SIZE;
- if (coords1[0][0] >= LIGHTMAP_SIZE)
- coords1[0][0] = LIGHTMAP_SIZE-1;
- if (coords1[0][1] >= LIGHTMAP_SIZE)
- coords1[0][1] = LIGHTMAP_SIZE-1;
- if (coords1[1][0] >= LIGHTMAP_SIZE)
- coords1[1][0] = LIGHTMAP_SIZE-1;
- if (coords1[1][1] >= LIGHTMAP_SIZE)
- coords1[1][1] = LIGHTMAP_SIZE-1;
- // try one row or column further because on flat faces the lightmap can
- // extend beyond the edge
- VectorSubtract(p[1], p[0], dir);
- VectorNormalize(dir, dir);
- CrossProduct(dir, facet1->plane.normal, cross);
- //
- if (coords1[0][0] - coords1[1][0] == 0)
- {
- s = DotProduct( cross, facet1->lightmapMatrix[0] );
- coords1[0][0] += s < 0 ? 1 : -1;
- coords1[1][0] += s < 0 ? 1 : -1;
- if (coords1[0][0] < ds1->lightmapX || coords1[0][0] >= ds1->lightmapX + ds1->lightmapWidth)
- {
- coords1[0][0] += s < 0 ? -1 : 1;
- coords1[1][0] += s < 0 ? -1 : 1;
- }
- length = fabs(coords1[1][1] - coords1[0][1]);
- }
- else if (coords1[0][1] - coords1[1][1] == 0)
- {
- t = DotProduct( cross, facet1->lightmapMatrix[1] );
- coords1[0][1] += t < 0 ? 1 : -1;
- coords1[1][1] += t < 0 ? 1 : -1;
- if (coords1[0][1] < ds1->lightmapY || coords1[0][1] >= ds1->lightmapY + ds1->lightmapHeight)
- {
- coords1[0][1] += t < 0 ? -1 : 1;
- coords1[1][1] += t < 0 ? -1 : 1;
- }
- length = fabs(coords1[1][0] - coords1[0][0]);
- }
- else
- {
- //the edge is not parallell to one of the lightmap axis
- continue;
- }
- //
- x1 = coords1[0][0];
- y1 = coords1[0][1];
- xinc1 = coords1[1][0] - coords1[0][0];
- if (xinc1 < 0) xinc1 = -1;
- if (xinc1 > 0) xinc1 = 1;
- yinc1 = coords1[1][1] - coords1[0][1];
- if (yinc1 < 0) yinc1 = -1;
- if (yinc1 > 0) yinc1 = 1;
- // the edge should be parallell to one of the lightmap axis
- if (xinc1 != 0 && yinc1 != 0)
- continue;
- //
- if (!VL_FindAdjacentSurface(i, j, p[0], p[1], &surfaceNum, &facetNum, &point))
- continue;
- //
- ds2 = &drawSurfaces[surfaceNum];
- facet2 = &lsurfaceTest[surfaceNum]->facets[facetNum];
- coords2[0][0] = facet2->lightmapCoords[(point+1)%facet2->numpoints][0] * LIGHTMAP_SIZE;
- coords2[0][1] = facet2->lightmapCoords[(point+1)%facet2->numpoints][1] * LIGHTMAP_SIZE;
- coords2[1][0] = facet2->lightmapCoords[point][0] * LIGHTMAP_SIZE;
- coords2[1][1] = facet2->lightmapCoords[point][1] * LIGHTMAP_SIZE;
- if (coords2[0][0] >= LIGHTMAP_SIZE)
- coords2[0][0] = LIGHTMAP_SIZE-1;
- if (coords2[0][1] >= LIGHTMAP_SIZE)
- coords2[0][1] = LIGHTMAP_SIZE-1;
- if (coords2[1][0] >= LIGHTMAP_SIZE)
- coords2[1][0] = LIGHTMAP_SIZE-1;
- if (coords2[1][1] >= LIGHTMAP_SIZE)
- coords2[1][1] = LIGHTMAP_SIZE-1;
- //
- x2 = coords2[0][0];
- y2 = coords2[0][1];
- xinc2 = coords2[1][0] - coords2[0][0];
- if (length)
- xinc2 = xinc2 / length;
- yinc2 = coords2[1][1] - coords2[0][1];
- if (length)
- yinc2 = yinc2 / length;
- // the edge should be parallell to one of the lightmap axis
- if ((int) xinc2 != 0 && (int) yinc2 != 0)
- continue;
- //
- while(1)
- {
- k1 = ( ds1->lightmapNum * LIGHTMAP_HEIGHT + y1) * LIGHTMAP_WIDTH + x1;
- k2 = ( ds2->lightmapNum * LIGHTMAP_HEIGHT + ((int) y2)) * LIGHTMAP_WIDTH + ((int) x2);
- color1 = lightFloats + k1*3;
- color2 = lightFloats + k2*3;
- if (lightmappixelarea[k1] < 0.01)
- {
- color1[0] = color2[0];
- color1[1] = color2[1];
- color1[2] = color2[2];
- }
- else
- {
- color1[0] = (float) color2[0] * 0.7 + (float) color1[0] * 0.3;
- color1[1] = (float) color2[1] * 0.7 + (float) color1[1] * 0.3;
- color1[2] = (float) color2[2] * 0.7 + (float) color1[2] * 0.3;
- }
- //
- if (x1 == coords1[1][0] &&
- y1 == coords1[1][1])
- break;
- x1 += xinc1;
- y1 += yinc1;
- x2 += xinc2;
- y2 += yinc2;
- if (x2 < ds2->lightmapX)
- x2 = ds2->lightmapX;
- if (x2 >= ds2->lightmapX + ds2->lightmapWidth)
- x2 = ds2->lightmapX + ds2->lightmapWidth-1;
- if (y2 < ds2->lightmapY)
- y2 = ds2->lightmapY;
- if (y2 >= ds2->lightmapY + ds2->lightmapHeight)
- y2 = ds2->lightmapY + ds2->lightmapHeight-1;
- }
- }
- }
- }
- }
- /*
- =============
- VL_FixLightmapEdges
- =============
- */
- void VL_FixLightmapEdges(void)
- {
- int i, j, x, y, k, foundvalue, height, width, index;
- int pos, top, bottom;
- dsurface_t *ds;
- lsurfaceTest_t *test;
- float color[3];
- float *ptr;
- byte filled[(LIGHTMAP_SIZE+1) * (LIGHTMAP_SIZE+1) / 8];
- float lightmap_edge_epsilon;
- lightmap_edge_epsilon = 0.1 * samplesize;
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- ds = &drawSurfaces[ i ];
- if ( ds->lightmapNum < 0 )
- continue;
- if (ds->surfaceType == MST_PATCH)
- {
- height = ds->lightmapHeight - 1;
- width = ds->lightmapWidth - 1;
- }
- else
- {
- height = ds->lightmapHeight;
- width = ds->lightmapWidth;
- }
- memset(filled, 0, sizeof(filled));
- // printf("\n");
- for (x = 0; x < width; x++)
- {
- for (y = 0; y < height; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (lightmappixelarea[k] > lightmap_edge_epsilon)
- {
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- filled[index >> 3] |= 1 << (index & 7);
- // printf("*");
- }
- // else
- // printf("_");
- }
- // printf("\n");
- }
- for (y = 0; y < height; y++)
- {
- pos = -2;
- for (x = 0; x < width; x++)
- {
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (pos == -2)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- pos = -1;
- }
- else if (pos == -1)
- {
- if (!(filled[index >> 3] & (1 << (index & 7))))
- pos = x - 1;
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- bottom = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + pos;
- top = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- for (j = 0; j < (x - pos + 1) / 2; j++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + pos + j + 1;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + pos + j + 1;
- filled[index >> 3] |= 1 << (index & 7);
- (lightFloats + k*3)[0] = (lightFloats + top*3)[0];
- (lightFloats + k*3)[1] = (lightFloats + top*3)[1];
- (lightFloats + k*3)[2] = (lightFloats + top*3)[2];
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x - j - 1;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x - j - 1;
- filled[index >> 3] |= 1 << (index & 7);
- (lightFloats + k*3)[0] = (lightFloats + bottom*3)[0];
- (lightFloats + k*3)[1] = (lightFloats + bottom*3)[1];
- (lightFloats + k*3)[2] = (lightFloats + bottom*3)[2];
- }
- pos = -1;
- }
- }
- }
- }
- for (x = 0; x < width; x++)
- {
- pos = -2;
- for (y = 0; y < height; y++)
- {
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (pos == -2)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- pos = -1;
- }
- else if (pos == -1)
- {
- if (!(filled[index >> 3] & (1 << (index & 7))))
- pos = y - 1;
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- bottom = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + pos)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- top = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- for (j = 0; j < (y - pos + 1) / 2; j++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + pos + j + 1)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + pos + j + 1) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- filled[index >> 3] |= 1 << (index & 7);
- (lightFloats + k*3)[0] = (lightFloats + top*3)[0];
- (lightFloats + k*3)[1] = (lightFloats + top*3)[1];
- (lightFloats + k*3)[2] = (lightFloats + top*3)[2];
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y - j - 1)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y - j - 1) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- filled[index >> 3] |= 1 << (index & 7);
- (lightFloats + k*3)[0] = (lightFloats + bottom*3)[0];
- (lightFloats + k*3)[1] = (lightFloats + bottom*3)[1];
- (lightFloats + k*3)[2] = (lightFloats + bottom*3)[2];
- }
- pos = -1;
- }
- }
- }
- }
- for (y = 0; y < height; y++)
- {
- foundvalue = qfalse;
- for (x = 0; x < width; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (foundvalue)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- }
- else
- {
- ptr = lightFloats + k*3;
- ptr[0] = color[0];
- ptr[1] = color[1];
- ptr[2] = color[2];
- filled[index >> 3] |= 1 << (index & 7);
- }
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- foundvalue = qtrue;
- }
- }
- }
- foundvalue = qfalse;
- for (x = width-1; x >= 0; x--)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (foundvalue)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- }
- else
- {
- ptr = lightFloats + k*3;
- ptr[0] = color[0];
- ptr[1] = color[1];
- ptr[2] = color[2];
- filled[index >> 3] |= 1 << (index & 7);
- }
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- foundvalue = qtrue;
- }
- }
- }
- }
- for (x = 0; x < width; x++)
- {
- foundvalue = qfalse;
- for (y = 0; y < height; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (foundvalue)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- }
- else
- {
- ptr = lightFloats + k*3;
- ptr[0] = color[0];
- ptr[1] = color[1];
- ptr[2] = color[2];
- filled[index >> 3] |= 1 << (index & 7);
- }
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- foundvalue = qtrue;
- }
- }
- }
- foundvalue = qfalse;
- for (y = height-1; y >= 0; y--)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (foundvalue)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- }
- else
- {
- ptr = lightFloats + k*3;
- ptr[0] = color[0];
- ptr[1] = color[1];
- ptr[2] = color[2];
- filled[index >> 3] |= 1 << (index & 7);
- }
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- foundvalue = qtrue;
- }
- }
- }
- }
- if (ds->surfaceType == MST_PATCH)
- {
- x = ds->lightmapWidth-1;
- for (y = 0; y < ds->lightmapHeight; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = (lightFloats + (k-1)*3)[0];
- ptr[1] = (lightFloats + (k-1)*3)[1];
- ptr[2] = (lightFloats + (k-1)*3)[2];
- }
- y = ds->lightmapHeight-1;
- for (x = 0; x < ds->lightmapWidth; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[0];
- ptr[1] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[1];
- ptr[2] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[2];
- }
- }
- /*
- //colored debug edges
- if (ds->surfaceType == MST_PATCH)
- {
- x = ds->lightmapWidth-1;
- for (y = 0; y < ds->lightmapHeight; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = 255;
- ptr[1] = 0;
- ptr[2] = 0;
- }
- y = ds->lightmapHeight-1;
- for (x = 0; x < ds->lightmapWidth; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = 0;
- ptr[1] = 255;
- ptr[2] = 0;
- }
- }
- //*/
- }
- //
- VL_SmoothenLightmapEdges();
- }
- /*
- =============
- VL_ShiftPatchLightmaps
- =============
- */
- void VL_ShiftPatchLightmaps(void)
- {
- int i, j, x, y, k;
- drawVert_t *verts;
- dsurface_t *ds;
- lsurfaceTest_t *test;
- float *ptr;
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- ds = &drawSurfaces[ i ];
- if ( ds->lightmapNum < 0 )
- continue;
- if (ds->surfaceType != MST_PATCH)
- continue;
- for (x = ds->lightmapWidth; x > 0; x--)
- {
- for (y = 0; y <= ds->lightmapHeight; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = (lightFloats + (k-1)*3)[0];
- ptr[1] = (lightFloats + (k-1)*3)[1];
- ptr[2] = (lightFloats + (k-1)*3)[2];
- }
- }
- for (y = ds->lightmapHeight; y > 0; y--)
- {
- for (x = 0; x <= ds->lightmapWidth; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[0];
- ptr[1] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[1];
- ptr[2] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[2];
- }
- }
- verts = &drawVerts[ ds->firstVert ];
- for ( j = 0 ; j < ds->patchHeight * ds->patchWidth; j++ )
- {
- verts[j].lightmap[0] += 0.5 / LIGHTMAP_WIDTH;
- verts[j].lightmap[1] += 0.5 / LIGHTMAP_HEIGHT;
- }
- ds->lightmapHeight++;
- ds->lightmapWidth++;
- }
- }
- /*
- =============
- VL_StoreLightmap
- =============
- */
- void VL_StoreLightmap(void)
- {
- int i, x, y, k;
- dsurface_t *ds;
- lsurfaceTest_t *test;
- float *src;
- byte *dst;
- _printf("storing lightmaps...\n");
- //fix lightmap edges before storing them
- VL_FixLightmapEdges();
- //
- #ifdef LIGHTMAP_PATCHSHIFT
- VL_ShiftPatchLightmaps();
- #endif
- //
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- ds = &drawSurfaces[ i ];
- if ( ds->lightmapNum < 0 )
- continue;
- for (y = 0; y < ds->lightmapHeight; y++)
- {
- for (x = 0; x < ds->lightmapWidth; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- VectorAdd((lightFloats + k*3), lightAmbientColor, (lightFloats + k*3));
- src = &lightFloats[k*3];
- dst = lightBytes + k*3;
- ColorToBytes(src, dst);
- }
- }
- }
- }
- /*
- =============
- PointInLeafnum
- =============
- */
- int PointInLeafnum(vec3_t point)
- {
- int nodenum;
- vec_t dist;
- dnode_t *node;
- dplane_t *plane;
- nodenum = 0;
- while (nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
- dist = DotProduct (point, plane->normal) - plane->dist;
- if (dist > 0)
- nodenum = node->children[0];
- else
- nodenum = node->children[1];
- }
- return -nodenum - 1;
- }
- /*
- =============
- VL_PointInLeafnum_r
- =============
- */
- int VL_PointInLeafnum_r(vec3_t point, int nodenum)
- {
- int leafnum;
- vec_t dist;
- dnode_t *node;
- dplane_t *plane;
- while (nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
- dist = DotProduct (point, plane->normal) - plane->dist;
- if (dist > 0.1)
- {
- nodenum = node->children[0];
- }
- else if (dist < -0.1)
- {
- nodenum = node->children[1];
- }
- else
- {
- leafnum = VL_PointInLeafnum_r(point, node->children[0]);
- if (dleafs[leafnum].cluster != -1)
- return leafnum;
- nodenum = node->children[1];
- }
- }
- leafnum = -nodenum - 1;
- return leafnum;
- }
- /*
- =============
- VL_PointInLeafnum
- =============
- */
- int VL_PointInLeafnum(vec3_t point)
- {
- return VL_PointInLeafnum_r(point, 0);
- }
- /*
- =============
- VL_LightLeafnum
- =============
- */
- int VL_LightLeafnum(vec3_t point)
- {
- /*
- int leafnum;
- dleaf_t *leaf;
- float x, y, z;
- vec3_t test;
- leafnum = VL_PointInLeafnum(point);
- leaf = &dleafs[leafnum];
- if (leaf->cluster != -1)
- return leafnum;
- for (z = 1; z >= -1; z -= 1)
- {
- for (x = 1; x >= -1; x -= 1)
- {
- for (y = 1; y >= -1; y -= 1)
- {
- VectorCopy(point, test);
- test[0] += x;
- test[1] += y;
- test[2] += z;
- leafnum = VL_PointInLeafnum(test);
- leaf = &dleafs[leafnum];
- if (leaf->cluster != -1)
- {
- VectorCopy(test, point);
- return leafnum;
- }
- }
- }
- }
- return leafnum;
- */
- return VL_PointInLeafnum(point);
- }
- //#define LIGHTPOLYS
- #ifdef LIGHTPOLYS
- winding_t *lightwindings[MAX_MAP_DRAW_SURFS];
- int numlightwindings;
- /*
- =============
- VL_DrawLightWindings
- =============
- */
- void VL_DrawLightWindings(void)
- {
- int i;
- for (i = 0; i < numlightwindings; i++)
- {
- #ifdef DEBUGNET
- DebugNet_DrawWinding(lightwindings[i], 1);
- #endif
- }
- }
- /*
- =============
- VL_LightSurfaceWithVolume
- =============
- */
- void VL_LightSurfaceWithVolume(int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume)
- {
- winding_t *w;
- lsurfaceTest_t *test;
- lFacet_t *facet;
- int i;
- test = lsurfaceTest[ surfaceNum ];
- facet = &test->facets[ facetNum ];
- //
- w = (winding_t *) malloc(sizeof(winding_t));
- memcpy(w->points, facet->points, sizeof(vec3_t) * facet->numpoints);
- w->numpoints = facet->numpoints;
- for (i = 0; i < volume->numplanes; i++)
- {
- //if totally on the back
- if (VL_ChopWinding(w, &volume->planes[i], 0.01) == SIDE_BACK)
- return;
- }
- lightwindings[numlightwindings] = w;
- numlightwindings++;
- if (numlightwindings >= MAX_MAP_DRAW_SURFS)
- Error("MAX_LIGHTWINDINGS");
- }
- #else
- /*
- =============
- VL_LightSurfaceWithVolume
- =============
- */
- /*
- int VL_PointInsideLightVolume(vec3_t point, lightvolume_t *volume)
- {
- int i;
- float d;
- for (i = 0; i < volume->numplanes; i++)
- {
- d = DotProduct(volume->planes[i].normal, point) - volume->planes[i].dist;
- if (d < 0) return qfalse;
- }
- return qtrue;
- }
- void VL_LightSurfaceWithVolume( int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume )
- {
- dsurface_t *ds;
- int i, j, k;
- int numPositions;
- vec3_t base, normal, color;
- int sampleWidth, sampleHeight;
- vec3_t lightmapOrigin, lightmapVecs[2], dir;
- unsigned char *ptr;
- float add, dist, angle;
- mesh_t * mesh;
- ds = &drawSurfaces[surfaceNum];
- // vertex-lit triangle model
- if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
- return;
- }
-
- if ( ds->lightmapNum < 0 ) {
- return; // doesn't need lighting
- }
- if ( ds->surfaceType == MST_PATCH ) {
- mesh = lsurfaceTest[surfaceNum]->detailMesh;
- } else {
- VectorCopy( ds->lightmapVecs[2], normal );
- VectorCopy( ds->lightmapOrigin, lightmapOrigin );
- VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] );
- VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] );
- }
- sampleWidth = ds->lightmapWidth;
- sampleHeight = ds->lightmapHeight;
- //calculate lightmap
- for ( i = 0 ; i < sampleWidth; i++ ) {
- for ( j = 0 ; j < sampleHeight; j++ ) {
- if ( ds->patchWidth ) {
- numPositions = 9;
- VectorCopy( mesh->verts[j*mesh->width+i].normal, normal );
- // VectorNormalize( normal, normal );
- // push off of the curve a bit
- VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base );
- // MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] );
- } else {
- numPositions = 9;
- for ( k = 0 ; k < 3 ; k++ ) {
- base[k] = lightmapOrigin[k] + normal[k]
- + ((float) i) * lightmapVecs[0][k]
- + ((float) j) * lightmapVecs[1][k];
- }
- }
- VectorAdd( base, surfaceOrigin[ surfaceNum ], base );
- VectorSubtract(base, light->origin, dir);
- dist = VectorNormalize(dir, dir);
- if ( dist < 16 ) {
- dist = 16;
- }
- angle = 1;//DotProduct( normal, dir ); //1;
- if (angle > 1)
- angle = 1;
- if ( light->atten_disttype == LDAT_LINEAR ) {
- add = angle * light->photons * lightLinearScale - dist;
- if ( add < 0 ) {
- add = 0;
- }
- } else {
- add = light->photons / ( dist * dist ) * angle;
- }
- if (add <= 1.0)
- continue;
- if (VL_PointInsideLightVolume(base, volume))
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j)
- * LIGHTMAP_WIDTH + ds->lightmapX + i;
- ptr = lightBytes + k*3;
- color[0] = (float) ptr[0] + add * light->color[0];
- color[1] = (float) ptr[1] + add * light->color[1];
- color[2] = (float) ptr[2] + add * light->color[2];
- ColorToBytes(color, ptr);
- }
- }
- }
- }
- */
- /*
- =============
- VL_GetFilter
- FIXME: don't use a lightmap pixel origin but use the four corner points
- to map part of a translucent surface onto the lightmap pixel
- =============
- */
- void VL_GetFilter(vlight_t *light, lightvolume_t *volume, vec3_t lmp, vec3_t filter)
- {
- lFacet_t *facet;
- lsurfaceTest_t *test;
- float d, d1, d2, frac, s, t, ns;
- int i, j, is, it, b;
- int x, y, u, v, numsamples, radius, color[4], largest;
- byte *image;
- vec3_t point, origin, total;
- VectorSet(filter, 1, 1, 1);
- if (noalphashading)
- return;
- if (volume->numtransFacets <= 0)
- return;
- if (light->type == LIGHT_SURFACEDIRECTED)
- {
- // project the light map pixel origin onto the area light source plane
- d = DotProduct(lmp, light->normal) - DotProduct(light->normal, light->w.points[0]);
- VectorMA(lmp, -d, light->normal, origin);
- }
- else
- {
- VectorCopy(light->origin, origin);
- }
- for (i = 0; i < volume->numtransFacets; i++)
- {
- test = lsurfaceTest[ volume->transSurfaces[i] ];
- facet = &test->facets[ volume->transFacets[i] ];
- // if this surface does not cast an alpha shadow
- if ( !(test->shader->surfaceFlags & SURF_ALPHASHADOW) )
- continue;
- // if there are no texture pixel available
- if ( !test->shader->pixels ) {
- continue;
- }
- //
- d1 = DotProduct( origin, facet->plane.normal) - facet->plane.dist;
- d2 = DotProduct( lmp, facet->plane.normal ) - facet->plane.dist;
- // this should never happen because the light volume went through the facet
- if ( ( d1 < 0 ) == ( d2 < 0 ) ) {
- continue;
- }
- // calculate the crossing point
- frac = d1 / ( d1 - d2 );
- for ( j = 0 ; j < 3 ; j++ ) {
- point[j] = origin[j] + frac * ( lmp[j] - origin[j] );
- }
- s = DotProduct( point, facet->textureMatrix[0] ) + facet->textureMatrix[0][3];
- t = DotProduct( point, facet->textureMatrix[1] ) + facet->textureMatrix[1][3];
- if (s < 0)
- s = 0;
- if (t < 0)
- t = 0;
- s = s - floor( s );
- t = t - floor( t );
- is = s * test->shader->width;
- it = t * test->shader->height;
- //if old style alpha shading
- if (nocolorshading) {
- image = test->shader->pixels + 4 * ( it * test->shader->width + is );
- // alpha filter
- b = image[3];
- // alpha test makes this a binary option
- b = b < 128 ? 0 : 255;
- filter[0] = filter[0] * (255-b) / 255;
- filter[1] = filter[1] * (255-b) / 255;
- filter[2] = filter[2] * (255-b) / 255;
- }
- else {
- VectorClear(total);
- numsamples = 0;
- radius = 2;
- for ( u = -radius; u <= radius; u++ )
- {
- x = is + u;
- if ( x < 0 || x >= test->shader->width)
- continue;
- for ( v = -radius; v <= radius; v++ )
- {
- y = it + v;
- if ( y < 0 || y >= test->shader->height)
- continue;
- image = test->shader->pixels + 4 * ( y * test->shader->width + x );
- color[0] = image[0];
- color[1] = image[1];
- color[2] = image[2];
- largest = 0;
- for (j = 0; j < 3; j++)
- if (image[j] > largest)
- largest = image[j];
- if (largest <= 0 || image[3] == 0) {
- color[0] = 255;
- color[1] = 255;
- color[2] = 255;
- largest = 255;
- }
- total[0] += ((float) color[0]/largest) * (255-image[3]) / 255.0;
- total[1] += ((float) color[1]/largest) * (255-image[3]) / 255.0;
- total[2] += ((float) color[2]/largest) * (255-image[3]) / 255.0;
- numsamples++;
- }
- }
- ns = numsamples;
- //
- filter[0] *= total[0] / ns;
- filter[1] *= total[1] / ns;
- filter[2] *= total[2] / ns;
- }
- }
- }
- /*
- =============
- VL_LightSurfaceWithVolume
- =============
- */
- void VL_LightSurfaceWithVolume( int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume )
- {
- int i;
- dsurface_t *ds;
- lFacet_t *facet;
- lsurfaceTest_t *test;
- winding_t w;
- vec3_t base, dir, delta, normal, filter, origin;
- int min_x[LIGHTMAP_SIZE+2], max_x[LIGHTMAP_SIZE+2];
- int min_y, max_y, k, x, y, n;
- float *color, distscale;
- float d, add, angle, dist, area, insidearea, coords[MAX_POINTS_ON_WINDING+1][2];
- mesh_t *mesh;
- byte polygonedges[(LIGHTMAP_SIZE+1) * (LIGHTMAP_SIZE+1) / 8];
- ds = &drawSurfaces[surfaceNum];
- // vertex-lit triangle model
- if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
- return;
- }
-
- if ( ds->lightmapNum < 0 ) {
- return; // doesn't need lighting
- }
- test = lsurfaceTest[ surfaceNum ];
- facet = &test->facets[ facetNum ];
- if (defaulttracelight && !test->always_vlight)
- return;
- if (test->always_tracelight)
- return;
- memcpy(w.points, facet->points, sizeof(vec3_t) * facet->numpoints);
- w.numpoints = facet->numpoints;
- for (i = 0; i < volume->numplanes; i++)
- {
- //if totally on the back
- if (VL_ChopWinding(&w, &volume->planes[i], 0.01) == SIDE_BACK)
- return;
- }
- // only one thread at a time may write to the lightmap of this surface
- MutexLock(test->mutex);
- test->numvolumes++;
- if (ds->surfaceType == MST_PATCH)
- {
- // FIXME: reduce size and don't mark all as edge
- min_y = ds->lightmapY + facet->y;
- max_y = ds->lightmapY + facet->y + facet->height - 1;
- for (y = min_y; y <= max_y; y++)
- {
- min_x[y] = ds->lightmapX + facet->x;
- max_x[y] = ds->lightmapX + facet->x + facet->width - 1;
- for (x = min_x[y]; x <= max_x[y]; x++)
- {
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- }
- }
- }
- else
- {
- for (i = 0; i < w.numpoints; i++)
- {
- float s, t;
- if (i >= MAX_POINTS_ON_WINDING)
- _printf("coords overflow\n");
- if (ds->surfaceType != MST_PATCH)
- {
- VectorSubtract(w.points[i], facet->mins, delta);
- s = DotProduct( delta, facet->lightmapMatrix[0] ) + ds->lightmapX + 0.5;
- t = DotProduct( delta, facet->lightmapMatrix[1] ) + ds->lightmapY + 0.5;
- if (s >= LIGHTMAP_SIZE)
- s = LIGHTMAP_SIZE - 0.5;
- if (s < 0)
- s = 0;
- if (t >= LIGHTMAP_SIZE)
- t = LIGHTMAP_SIZE - 0.5;
- if (t < 0)
- t = 0;
- coords[i][0] = s;
- coords[i][1] = t;
- }
- else
- {
- s = DotProduct( w.points[i], facet->lightmapMatrix[0] ) + facet->lightmapMatrix[0][3];
- t = DotProduct( w.points[i], facet->lightmapMatrix[1] ) + facet->lightmapMatrix[1][3];
- s = s - floor( s );
- t = t - floor( t );
- coords[i][0] = ds->lightmapX + s * LIGHTMAP_SIZE;// + 0.5;
- coords[i][1] = ds->lightmapY + t * LIGHTMAP_SIZE;// + 0.5;
- if (coords[i][0] >= LIGHTMAP_SIZE)
- coords[i][0] -= LIGHTMAP_SIZE;
- if (coords[i][1] >= LIGHTMAP_SIZE)
- coords[i][1] -= LIGHTMAP_SIZE;
- if (coords[i][0] < ds->lightmapX)
- coords[i][0] = ds->lightmapX;
- if (coords[i][1] < ds->lightmapY)
- coords[i][1] = ds->lightmapY;
- }
- x = coords[i][0];
- y = coords[i][1];
- if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
- _printf("VL_LightSurfaceWithVolume: x outside lightmap\n");
- if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
- _printf("VL_LightSurfaceWithVolume: y outside lightmap\n");
- }
- coords[i][0] = coords[0][0];
- coords[i][1] = coords[0][1];
- //
- min_y = LIGHTMAP_SIZE;
- max_y = 0;
- for (i = 0; i < LIGHTMAP_SIZE; i++)
- {
- min_x[i] = LIGHTMAP_SIZE;
- max_x[i] = 0;
- }
- memset(polygonedges, 0, sizeof(polygonedges));
- // scan convert the polygon onto the lightmap
- // for each edge it marks *every* lightmap pixel the edge goes through
- // so no brasenham and no scan conversion used for texture mapping but
- // more something like ray casting
- // this is necesary because we need all lightmap pixels totally or partly
- // inside the light volume. these lightmap pixels are only lit for the part
- // that they are inside the light volume.
- for (i = 0; i < w.numpoints; i++)
- {
- float xf, yf, dx, dy, xstep, ystep, xfrac, yfrac;
- int xinc, yinc;
- xf = coords[i][0];
- yf = coords[i][1];
- dx = coords[i+1][0] - xf;
- dy = coords[i+1][1] - yf;
- //
- x = (int) xf;
- y = (int) yf;
- //
- if (y < min_y)
- min_y = y;
- if (y > max_y)
- max_y = y;
- //
- if (fabs(dx) > fabs(dy))
- {
- if (dx > 0)
- {
- // y fraction at integer x below fractional x
- yfrac = yf + (floor(xf) - xf) * dy / dx;
- xinc = 1;
- }
- else if (dx < 0)
- {
- // y fraction at integer x above fractional x
- yfrac = yf + (floor(xf) + 1 - xf) * dy / dx;
- xinc = -1;
- }
- else
- {
- yfrac = yf;
- xinc = 0;
- }
- // step in y direction per 1 unit in x direction
- if (dx)
- ystep = dy / fabs(dx);
- else
- ystep = 0;
- while(1)
- {
- if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
- _printf("VL_LightSurfaceWithVolume: x outside lightmap\n");
- if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
- _printf("VL_LightSurfaceWithVolume: y outside lightmap\n");
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- if (x == (int) coords[i+1][0])
- break;
- yfrac += ystep;
- if (dy > 0)
- {
- if (yfrac > (float) y + 1)
- {
- y += 1;
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- }
- }
- else
- {
- if (yfrac < (float) y)
- {
- y -= 1;
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- }
- }
- x += xinc;
- }
- }
- else
- {
- if (dy > 0)
- {
- //x fraction at integer y below fractional y
- xfrac = xf + (floor(yf) - yf) * dx / dy;
- yinc = 1;
- }
- else if (dy < 0)
- {
- //x fraction at integer y above fractional y
- xfrac = xf + (floor(yf) + 1 - yf) * dx / dy;
- yinc = -1;
- }
- else
- {
- xfrac = xf;
- yinc = 0;
- }
- // step in x direction per 1 unit in y direction
- if (dy)
- xstep = dx / fabs(dy);
- else
- xstep = 0;
- while(1)
- {
- if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
- _printf("VL_LightSurfaceWithVolume: x outside lightmap\n");
- if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
- _printf("VL_LightSurfaceWithVolume: y outside lightmap\n");
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- if (y == (int) coords[i+1][1])
- break;
- xfrac += xstep;
- if (dx > 0)
- {
- if (xfrac > (float) x + 1)
- {
- x += 1;
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- }
- }
- else
- {
- if (xfrac < (float) x)
- {
- x -= 1;
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- }
- }
- y += yinc;
- }
- }
- }
- }
- // map light onto the lightmap
- for (y = min_y; y <= max_y; y++)
- {
- for (x = min_x[y]; x <= max_x[y]; x++)
- {
- if (ds->surfaceType == MST_PATCH)
- {
- mesh = test->detailMesh;
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, base);
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].normal, normal);
- //VectorCopy(facet->plane.normal, normal);
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x - ds->lightmapX, ds->lightmapVecs[0], base);
- VectorMA(base, (float) y - ds->lightmapY, ds->lightmapVecs[1], base);
- VectorCopy(facet->plane.normal, normal);
- }
- if (light->type == LIGHT_POINTSPOT)
- {
- float distByNormal;
- vec3_t pointAtDist;
- float radiusAtDist;
- float sampleRadius;
- vec3_t distToSample;
- float coneScale;
- VectorSubtract( light->origin, base, dir );
- distByNormal = -DotProduct( dir, light->normal );
- if ( distByNormal < 0 ) {
- continue;
- }
- VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
- radiusAtDist = light->radiusByDist * distByNormal;
- VectorSubtract( base, pointAtDist, distToSample );
- sampleRadius = VectorLength( distToSample );
- if ( sampleRadius >= radiusAtDist ) {
- continue; // outside the cone
- }
- if ( sampleRadius <= radiusAtDist - 32 ) {
- coneScale = 1.0; // fully inside
- } else {
- coneScale = ( radiusAtDist - sampleRadius ) / 32.0;
- }
-
- dist = VectorNormalize( dir, dir );
- // clamp the distance to prevent super hot spots
- if ( dist < 16 ) {
- dist = 16;
- }
- angle = DotProduct( normal, dir );
- if (angle > 1)
- angle = 1;
- if (angle > 0) {
- if ( light->atten_angletype == LAAT_QUADRATIC ) {
- angle = 1 - angle;
- angle *= angle;
- angle = 1 - angle;
- }
- else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
- angle = 1 - angle;
- angle *= angle * angle;
- angle = 1 - angle;
- }
- }
- if (light->atten_anglescale > 0) {
- angle /= light->atten_anglescale;
- if (angle > 1)
- angle = 1;
- }
- if (light->atten_distscale > 0) {
- distscale = light->atten_distscale;
- }
- else {
- distscale = 1;
- }
- //
- if ( light->atten_disttype == LDAT_NOSCALE ) {
- add = angle * coneScale;
- }
- else if ( light->atten_disttype == LDAT_LINEAR ) {
- add = angle * light->photons * lightLinearScale * coneScale - dist * distscale;
- if ( add < 0 ) {
- add = 0;
- }
- }
- else {
- add = light->photons / ( dist * dist * distscale) * angle * coneScale;
- }
- if (add <= 1.0)
- continue;
- }
- else if (light->type == LIGHT_POINTFAKESURFACE)
- {
- // calculate the contribution
- add = PointToPolygonFormFactor( base, normal, &light->w );
- if ( add <= 0 ) {
- if ( light->twosided ) {
- add = -add;
- } else {
- continue;
- }
- }
- }
- else if (light->type == LIGHT_SURFACEDIRECTED)
- {
- //VectorCopy(light->normal, dir);
- //VectorInverse(dir);
- // project the light map pixel origin onto the area light source plane
- d = DotProduct(base, light->normal) - DotProduct(light->normal, light->w.points[0]);
- VectorMA(base, -d, light->normal, origin);
- VectorSubtract(origin, base, dir);
- dist = VectorNormalize(dir, dir);
- if ( dist < 16 ) {
- dist = 16;
- }
- //
- angle = DotProduct( normal, dir );
- if (angle > 1)
- angle = 1;
- if (angle > 0) {
- if ( light->atten_angletype == LAAT_QUADRATIC ) {
- angle = 1 - angle;
- angle *= angle;
- angle = 1 - angle;
- }
- else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
- angle = 1 - angle;
- angle *= angle * angle;
- angle = 1 - angle;
- }
- }
- if (light->atten_anglescale > 0) {
- angle /= light->atten_anglescale;
- if (angle > 1)
- angle = 1;
- }
- if (light->atten_distscale > 0) {
- distscale = light->atten_distscale;
- }
- else {
- distscale = 1;
- }
- if ( light->atten_disttype == LDAT_NOSCALE ) {
- add = angle;
- }
- else if ( light->atten_disttype == LDAT_LINEAR ) {
- add = angle * light->photons * lightLinearScale - dist * distscale;
- if ( add < 0 ) {
- add = 0;
- }
- } else { //default quadratic
- add = light->photons / ( dist * dist * distscale) * angle;
- }
- if (add <= 0)
- continue;
- }
- else //normal radial point light
- {
- VectorSubtract(light->origin, base, dir);
- dist = VectorNormalize(dir, dir);
- if ( dist < 16 ) {
- dist = 16;
- }
- angle = DotProduct( normal, dir );
- if (angle > 1)
- angle = 1;
- if (angle > 0) {
- if ( light->atten_angletype == LAAT_QUADRATIC ) {
- angle = 1 - angle;
- angle *= angle;
- angle = 1 - angle;
- }
- else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
- angle = 1 - angle;
- angle *= angle * angle;
- angle = 1 - angle;
- }
- }
- if (light->atten_anglescale > 0) {
- angle /= light->atten_anglescale;
- if (angle > 1)
- angle = 1;
- }
- if (light->atten_distscale > 0) {
- distscale = light->atten_distscale;
- }
- else {
- distscale = 1;
- }
- if ( light->atten_disttype == LDAT_NOSCALE ) {
- add = angle;
- }
- else if ( light->atten_disttype == LDAT_LINEAR ) {
- add = angle * light->photons * lightLinearScale - dist * distscale;
- if ( add < 0 ) {
- add = 0;
- }
- } else {
- add = light->photons / ( dist * dist * distscale) * angle;
- }
- if (add <= 1.0)
- continue;
- }
- //
- k = (ds->lightmapNum * LIGHTMAP_HEIGHT + y) * LIGHTMAP_WIDTH + x;
- //if on one of the edges
- n = y * LIGHTMAP_SIZE + x;
- if ((polygonedges[n >> 3] & (1 << (n & 7)) ))
- {
- // multiply 'add' by the relative area being lit of the total visible lightmap pixel area
- //
- // first create a winding for the lightmap pixel
- if (ds->surfaceType == MST_PATCH)
- {
- mesh = test->detailMesh;
- if (y-ds->lightmapY >= mesh->height-1)
- _printf("y outside mesh\n");
- if (x-ds->lightmapX >= mesh->width-1)
- _printf("x outside mesh\n");
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[0]);
- VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[1]);
- VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[2]);
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[3]);
- w.numpoints = 4;
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[0]);
- VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[0]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[1]);
- VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[1]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[2]);
- VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[2]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[3]);
- VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[3]);
- w.numpoints = 4;
- }
- //
- // take the visible area of the lightmap pixel into account
- //
- //area = WindingArea(&w);
- area = lightmappixelarea[k];
- if (area <= 0)
- continue;
- // chop the lightmap pixel winding with the light volume
- for (i = 0; i < volume->numplanes; i++)
- {
- //if totally on the back
- if (VL_ChopWinding(&w, &volume->planes[i], 0) == SIDE_BACK)
- break;
- }
- // if the lightmap pixel is partly inside the light volume
- if (i >= volume->numplanes)
- {
- insidearea = WindingArea(&w);
- if (insidearea <= 0)
- i = 0;
- add = add * insidearea / area;
- }
- else
- {
- //DebugNet_DrawWinding(&w, 2);
- continue; // this shouldn't happen
- }
- }
- // get the light filter from all the translucent surfaces the light volume went through
- VL_GetFilter(light, volume, base, filter);
- //
- color = &lightFloats[k*3];
- color[0] += add * light->color[0] * filter[0];
- color[1] += add * light->color[1] * filter[1];
- color[2] += add * light->color[2] * filter[2];
- }
- }
- MutexUnlock(test->mutex);
- }
- #endif
- /*
- =============
- VL_SplitLightVolume
- =============
- */
- int VL_SplitLightVolume(lightvolume_t *volume, lightvolume_t *back, plane_t *split, float epsilon)
- {
- lightvolume_t f, b;
- vec_t dists[128];
- int sides[128];
- int counts[3];
- vec_t dot;
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
- counts[0] = counts[1] = counts[2] = 0;
- // determine sides for each point
- for (i = 0; i < volume->numplanes; i++)
- {
- dot = DotProduct (volume->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
- if (!counts[1])
- return 0; // completely on front side
-
- if (!counts[0])
- return 1; // completely on back side
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- f.numplanes = 0;
- b.numplanes = 0;
- for (i = 0; i < volume->numplanes; i++)
- {
- p1 = volume->points[i];
- if (f.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return 0; // can't chop -- fall back to original
- }
- if (b.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return 0; // can't chop -- fall back to original
- }
- if (sides[i] == SIDE_ON)
- {
- VectorCopy(p1, f.points[f.numplanes]);
- VectorCopy(p1, b.points[b.numplanes]);
- if (sides[i+1] == SIDE_BACK)
- {
- f.planes[f.numplanes] = *split;
- b.planes[b.numplanes] = volume->planes[i];
- }
- else if (sides[i+1] == SIDE_FRONT)
- {
- f.planes[f.numplanes] = volume->planes[i];
- b.planes[b.numplanes] = *split;
- VectorInverse(b.planes[b.numplanes].normal);
- b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
- }
- else //this shouldn't happen
- {
- f.planes[f.numplanes] = *split;
- b.planes[b.numplanes] = *split;
- VectorInverse(b.planes[b.numplanes].normal);
- b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
- }
- f.numplanes++;
- b.numplanes++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, f.points[f.numplanes]);
- f.planes[f.numplanes] = volume->planes[i];
- f.numplanes++;
- }
- if (sides[i] == SIDE_BACK)
- {
- VectorCopy (p1, b.points[b.numplanes]);
- b.planes[b.numplanes] = volume->planes[i];
- b.numplanes++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- if (f.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return 0; // can't chop -- fall back to original
- }
- if (b.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return 0; // can't chop -- fall back to original
- }
- // generate a split point
- p2 = volume->points[(i+1)%volume->numplanes];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
- VectorCopy (mid, f.points[f.numplanes]);
- VectorCopy(mid, b.points[b.numplanes]);
- if (sides[i+1] == SIDE_BACK)
- {
- f.planes[f.numplanes] = *split;
- b.planes[b.numplanes] = volume->planes[i];
- }
- else
- {
- f.planes[f.numplanes] = volume->planes[i];
- b.planes[b.numplanes] = *split;
- VectorInverse(b.planes[b.numplanes].normal);
- b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
- }
- f.numplanes++;
- b.numplanes++;
- }
- memcpy(volume->points, f.points, sizeof(vec3_t) * f.numplanes);
- memcpy(volume->planes, f.planes, sizeof(plane_t) * f.numplanes);
- volume->numplanes = f.numplanes;
- memcpy(back->points, b.points, sizeof(vec3_t) * b.numplanes);
- memcpy(back->planes, b.planes, sizeof(plane_t) * b.numplanes);
- back->numplanes = b.numplanes;
- return 2;
- }
- /*
- =============
- VL_PlaneForEdgeToWinding
- =============
- */
- void VL_PlaneForEdgeToWinding(vec3_t p1, vec3_t p2, winding_t *w, int windingonfront, plane_t *plane)
- {
- int i, j;
- float length, d;
- vec3_t v1, v2;
- VectorSubtract(p2, p1, v1);
- for (i = 0; i < w->numpoints; i++)
- {
- VectorSubtract (w->points[i], p1, v2);
- plane->normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
- plane->normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
- plane->normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
-
- // if points don't make a valid plane, skip it
- length = plane->normal[0] * plane->normal[0]
- + plane->normal[1] * plane->normal[1]
- + plane->normal[2] * plane->normal[2];
-
- if (length < ON_EPSILON)
- continue;
- length = 1/sqrt(length);
-
- plane->normal[0] *= length;
- plane->normal[1] *= length;
- plane->normal[2] *= length;
- plane->dist = DotProduct (w->points[i], plane->normal);
- //
- for (j = 0; j < w->numpoints; j++)
- {
- if (j == i)
- continue;
- d = DotProduct(w->points[j], plane->normal) - plane->dist;
- if (windingonfront)
- {
- if (d < -ON_EPSILON)
- break;
- }
- else
- {
- if (d > ON_EPSILON)
- break;
- }
- }
- if (j >= w->numpoints)
- return;
- }
- }
- /*
- =============
- VL_R_CastLightAtSurface
- =============
- */
- void VL_R_FloodLight(vlight_t *light, lightvolume_t *volume, int cluster, int firstportal);
- void VL_R_CastLightAtSurface(vlight_t *light, lightvolume_t *volume)
- {
- lsurfaceTest_t *test;
- int i, n;
- // light the surface with this volume
- VL_LightSurfaceWithVolume(volume->surfaceNum, volume->facetNum, light, volume);
- //
- test = lsurfaceTest[ volume->surfaceNum ];
- // if this is not a translucent surface
- if ( !(test->shader->surfaceFlags & SURF_ALPHASHADOW) && !(test->shader->contents & CONTENTS_TRANSLUCENT))
- return;
- //
- if (volume->numtransFacets >= MAX_TRANSLUCENTFACETS)
- Error("a light valume went through more than %d translucent facets", MAX_TRANSLUCENTFACETS);
- //add this translucent surface to the list
- volume->transSurfaces[volume->numtransFacets] = volume->surfaceNum;
- volume->transFacets[volume->numtransFacets] = volume->facetNum;
- volume->numtransFacets++;
- //clear the tested facets except the translucent ones
- memset(volume->facetTested, 0, sizeof(volume->facetTested));
- for (i = 0; i < volume->numtransFacets; i++)
- {
- test = lsurfaceTest[ volume->transSurfaces[i] ];
- n = test->facets[volume->transFacets[i]].num;
- volume->facetTested[n >> 3] |= 1 << (n & 7);
- }
- memset(volume->clusterTested, 0, sizeof(volume->clusterTested));
- volume->endplane = volume->farplane;
- volume->surfaceNum = -1;
- volume->facetNum = 0;
- VL_R_FloodLight(light, volume, volume->cluster, 0);
- if (volume->surfaceNum >= 0)
- {
- VL_R_CastLightAtSurface(light, volume);
- }
- }
- /*
- =============
- VL_R_SplitLightVolume
- =============
- */
- int numvolumes = 0;
- int VL_R_SplitLightVolume(vlight_t *light, lightvolume_t *volume, plane_t *split, int cluster, int firstportal)
- {
- lightvolume_t back;
- int res;
- //
- res = VL_SplitLightVolume(volume, &back, split, 0.1);
- // if the volume was split
- if (res == 2)
- {
- memcpy(back.clusterTested, volume->clusterTested, sizeof(back.clusterTested));
- memcpy(back.facetTested, volume->facetTested, sizeof(back.facetTested));
- back.num = numvolumes++;
- back.endplane = volume->endplane;
- back.surfaceNum = volume->surfaceNum;
- back.facetNum = volume->facetNum;
- back.type = volume->type;
- back.cluster = volume->cluster;
- back.farplane = volume->farplane;
- if (volume->numtransFacets > 0)
- {
- memcpy(back.transFacets, volume->transFacets, sizeof(back.transFacets));
- memcpy(back.transSurfaces, volume->transSurfaces, sizeof(back.transSurfaces));
- }
- back.numtransFacets = volume->numtransFacets;
- //
- // flood the volume at the back of the split plane
- VL_R_FloodLight(light, &back, cluster, firstportal);
- // if the back volume hit a surface
- if (back.surfaceNum >= 0)
- {
- VL_R_CastLightAtSurface(light, &back);
- }
- }
- return res;
- }
- /*
- =============
- VL_R_FloodLight
- =============
- */
- void VL_R_FloodLight(vlight_t *light, lightvolume_t *volume, int cluster, int firstportal)
- {
- int i, j, k, res, surfaceNum, backfaceculled, testculled;
- float d;
- winding_t winding, tmpwinding;
- lleaf_t *leaf;
- lportal_t *p;
- lsurfaceTest_t *test;
- lFacet_t *facet;
- vec3_t dir1, dir2;
- plane_t plane;
- // DebugNet_RemoveAllPolys();
- // VL_DrawLightVolume(light, volume);
- // if the first portal is not zero then we've checked all occluders in this leaf already
- if (firstportal == 0)
- {
- // check all potential occluders in this leaf
- for (i = 0; i < leafs[cluster].numSurfaces; i++)
- {
- surfaceNum = clustersurfaces[leafs[cluster].firstSurface + i];
- //
- test = lsurfaceTest[ surfaceNum ];
- if ( !test )
- continue;
- //
- testculled = qfalse;
- // use surface as an occluder
- for (j = 0; j < test->numFacets; j++)
- {
- // use each facet as an occluder
- facet = &test->facets[j];
- //
- // memcpy(winding.points, facet->points, sizeof(vec3_t) * facet->numpoints);
- // winding.numpoints = facet->numpoints;
- // DebugNet_DrawWinding(&winding, 5);
- //
- // if the facet was tested already
- if ( volume->facetTested[facet->num >> 3] & (1 << (facet->num & 7)) )
- continue;
- volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
- // backface culling for planar surfaces
- backfaceculled = qfalse;
- if (!test->patch && !test->trisoup)
- {
- if (volume->type == VOLUME_NORMAL)
- {
- // facet backface culling
- d = DotProduct(light->origin, facet->plane.normal) - facet->plane.dist;
- if (d < 0)
- {
- // NOTE: this doesn't work too great because of sometimes very bad tesselation
- // of surfaces that are supposed to be flat
- // FIXME: to work around this problem we should make sure that all facets
- // created from planar surfaces use the lightmapVecs normal vector
- /*
- if ( !test->shader->twoSided )
- {
- // skip all other facets of this surface as well because they are in the same plane
- for (k = 0; k < test->numFacets; k++)
- {
- facet = &test->facets[k];
- volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
- }
- }*/
- backfaceculled = qtrue;
- }
- }
- else
- {
- // FIXME: if all light source winding points are at the back of the facet
- // plane then backfaceculled = qtrue
- }
- }
- else // backface culling per facet for patches and triangle soups
- {
- if (volume->type == VOLUME_NORMAL)
- {
- // facet backface culling
- d = DotProduct(light->origin, facet->plane.normal) - facet->plane.dist;
- if (d < 0)
- backfaceculled = qtrue;
- }
- else
- {
- // FIXME: if all light source winding points are at the back of the facet
- // plane then backfaceculled = qtrue
- }
- }
- /* chopping does this already
- // check if this facet is totally or partly in front of the volume end plane
- for (k = 0; k < facet->numpoints; k++)
- {
- d = DotProduct(volume->endplane.normal, facet->points[k]) - volume->endplane.dist;
- if (d > ON_EPSILON)
- break;
- }
- // if this facet is outside the light volume
- if (k >= facet->numpoints)
- continue;
- */
- //
- if (backfaceculled)
- {
- // if the facet is not two sided
- if ( !nobackfaceculling && !test->shader->twoSided )
- continue;
- // flip the winding
- for (k = 0; k < facet->numpoints; k++)
- VectorCopy(facet->points[k], winding.points[facet->numpoints - k - 1]);
- winding.numpoints = facet->numpoints;
- }
- else
- {
- memcpy(winding.points, facet->points, sizeof(vec3_t) * facet->numpoints);
- winding.numpoints = facet->numpoints;
- }
- //
- if (!testculled)
- {
- testculled = qtrue;
- // fast check if the surface sphere is totally behind the volume end plane
- d = DotProduct(volume->endplane.normal, test->origin) - volume->endplane.dist;
- if (d < -test->radius)
- {
- for (k = 0; k < test->numFacets; k++)
- {
- facet = &test->facets[k];
- volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
- }
- break;
- }
- for (k = 0; k < volume->numplanes; k++)
- {
- d = DotProduct(volume->planes[k].normal, test->origin) - volume->planes[k].dist;
- if (d < - test->radius)
- {
- for (k = 0; k < test->numFacets; k++)
- {
- facet = &test->facets[k];
- volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
- }
- break;
- }
- }
- if (k < volume->numplanes)
- break;
- }
- //NOTE: we have to chop the facet winding with the volume end plane because
- // the faces in Q3 are not stitched together nicely
- res = VL_ChopWinding(&winding, &volume->endplane, 0.01);
- // if the facet is on or at the back of the volume end plane
- if (res == SIDE_BACK || res == SIDE_ON)
- continue;
- // check if the facet winding is totally or partly inside the light volume
- memcpy(&tmpwinding, &winding, sizeof(winding_t));
- for (k = 0; k < volume->numplanes; k++)
- {
- res = VL_ChopWinding(&tmpwinding, &volume->planes[k], 0.01);
- if (res == SIDE_BACK || res == SIDE_ON)
- break;
- }
- // if no part of the light volume is occluded by this facet
- if (k < volume->numplanes)
- continue;
- //
- for (k = 0; k < winding.numpoints; k++)
- {
- if (volume->type == VOLUME_DIRECTED)
- {
- VectorSubtract(winding.points[(k+1) % winding.numpoints], winding.points[k], dir1);
- CrossProduct(light->normal, dir1, plane.normal);
- VectorNormalize(plane.normal, plane.normal);
- plane.dist = DotProduct(plane.normal, winding.points[k]);
- }
- else
- {
- VectorSubtract(winding.points[(k+1) % winding.numpoints], winding.points[k], dir1);
- VectorSubtract(light->origin, winding.points[k], dir2);
- CrossProduct(dir1, dir2, plane.normal);
- VectorNormalize(plane.normal, plane.normal);
- plane.dist = DotProduct(plane.normal, winding.points[k]);
- }
- res = VL_R_SplitLightVolume(light, volume, &plane, cluster, 0);
- if (res == 1)
- break; //the facet wasn't really inside the volume
- }
- if (k >= winding.numpoints)
- {
- volume->endplane = facet->plane;
- if (backfaceculled)
- {
- VectorInverse(volume->endplane.normal);
- volume->endplane.dist = -volume->endplane.dist;
- }
- volume->surfaceNum = surfaceNum;
- volume->facetNum = j;
- }
- }
- }
- }
- // we've tested all occluders in this cluster
- volume->clusterTested[cluster >> 3] |= 1 << (cluster & 7);
- // flood light through the portals of the current leaf
- leaf = &leafs[cluster];
- for (i = firstportal; i < leaf->numportals; i++)
- {
- p = leaf->portals[i];
- //
- // memcpy(&winding, p->winding, sizeof(winding_t));
- // DebugNet_DrawWinding(&winding, 5);
- // if already flooded into the cluster this portal leads to
- if ( volume->clusterTested[p->leaf >> 3] & (1 << (p->leaf & 7)) )
- continue;
- //
- if (volume->type == VOLUME_NORMAL)
- {
- // portal backface culling
- d = DotProduct(light->origin, p->plane.normal) - p->plane.dist;
- if (d > 0) // portal plane normal points into neighbour cluster
- continue;
- }
- else
- {
- // FIXME: if all light source winding points are at the back of this portal
- // plane then there's no need to flood through
- }
- // check if this portal is totally or partly in front of the volume end plane
- // fast check with portal sphere
- d = DotProduct(volume->endplane.normal, p->origin) - volume->endplane.dist;
- if (d < -p->radius)
- continue;
- for (j = 0; j < p->winding->numpoints; j++)
- {
- d = DotProduct(volume->endplane.normal, p->winding->points[j]) - volume->endplane.dist;
- if (d > -0.01)
- break;
- }
- // if this portal is totally behind the light volume end plane
- if (j >= p->winding->numpoints)
- continue;
- //distance from point light to portal
- d = DotProduct(p->plane.normal, light->origin) - p->plane.dist;
- // only check if a point light is Not *on* the portal
- if (volume->type != VOLUME_NORMAL || fabs(d) > 0.1)
- {
- // check if the portal is partly or totally inside the light volume
- memcpy(&winding, p->winding, sizeof(winding_t));
- for (j = 0; j < volume->numplanes; j++)
- {
- res = VL_ChopWinding(&winding, &volume->planes[j], 0.01);
- if (res == SIDE_BACK || res == SIDE_ON)
- break;
- }
- // if the light volume does not go through this portal at all
- if (j < volume->numplanes)
- continue;
- }
- // chop the light volume with the portal
- for (k = 0; k < p->winding->numpoints; k++)
- {
- if (volume->type == VOLUME_DIRECTED)
- {
- VectorSubtract(p->winding->points[(k+1) % p->winding->numpoints], p->winding->points[k], dir1);
- CrossProduct(light->normal, dir1, plane.normal);
- VectorNormalize(plane.normal, plane.normal);
- plane.dist = DotProduct(plane.normal, p->winding->points[k]);
- }
- else
- {
- VectorSubtract(p->winding->points[(k+1) % p->winding->numpoints], p->winding->points[k], dir1);
- VectorSubtract(light->origin, p->winding->points[k], dir2);
- CrossProduct(dir1, dir2, plane.normal);
- VectorNormalize(plane.normal, plane.normal);
- plane.dist = DotProduct(plane.normal, p->winding->points[k]);
- }
- res = VL_R_SplitLightVolume(light, volume, &plane, cluster, i+1);
- if (res == 1)
- break; //volume didn't really go through the portal
- }
- // if the light volume went through the portal
- if (k >= p->winding->numpoints)
- {
- // flood through the portal
- VL_R_FloodLight(light, volume, p->leaf, 0);
- }
- }
- }
- /*
- =============
- VL_R_FloodAreaSpotLight
- =============
- */
- void VL_FloodAreaSpotLight(vlight_t *light, winding_t *w, int leafnum)
- {
- }
- /*
- =============
- VL_R_SubdivideAreaSpotLight
- =============
- */
- void VL_R_SubdivideAreaSpotLight(vlight_t *light, int nodenum, winding_t *w)
- {
- int leafnum, res;
- dnode_t *node;
- dplane_t *plane;
- winding_t back;
- plane_t split;
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VL_SplitWinding (w, &back, &split, 0.1);
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- memcpy(&back, w, sizeof(winding_t));
- VL_R_SubdivideAreaSpotLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- else
- {
- VL_R_SubdivideAreaSpotLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- if (dleafs[leafnum].cluster != -1)
- {
- VL_FloodAreaSpotLight(light, w, leafnum);
- }
- }
- /*
- =============
- VL_R_FloodRadialAreaLight
- =============
- */
- void VL_FloodRadialAreaLight(vlight_t *light, winding_t *w, int leafnum)
- {
- }
- /*
- =============
- VL_R_SubdivideRadialAreaLight
- =============
- */
- void VL_R_SubdivideRadialAreaLight(vlight_t *light, int nodenum, winding_t *w)
- {
- int leafnum, res;
- dnode_t *node;
- dplane_t *plane;
- winding_t back;
- plane_t split;
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VL_SplitWinding (w, &back, &split, 0.1);
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- memcpy(&back, w, sizeof(winding_t));
- VL_R_SubdivideRadialAreaLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- else
- {
- VL_R_SubdivideRadialAreaLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- if (dleafs[leafnum].cluster != -1)
- {
- VL_FloodRadialAreaLight(light, w, leafnum);
- }
- }
- /*
- =============
- VL_R_FloodDirectedLight
- =============
- */
- void VL_FloodDirectedLight(vlight_t *light, winding_t *w, int leafnum)
- {
- int i;
- float dist;
- lightvolume_t volume;
- vec3_t dir;
- if (light->atten_disttype == LDAT_NOSCALE)
- {
- // light travels without decrease in intensity over distance
- dist = MAX_WORLD_COORD;
- }
- else
- {
- if ( light->atten_disttype == LDAT_LINEAR )
- dist = light->photons * lightLinearScale;
- else
- dist = sqrt(light->photons);
- }
- memset(&volume, 0, sizeof(lightvolume_t));
- for (i = 0; i < w->numpoints; i++)
- {
- VectorMA(w->points[i], dist, light->normal, volume.points[i]);
- VectorSubtract(w->points[(i+1)%w->numpoints], w->points[i], dir);
- CrossProduct(light->normal, dir, volume.planes[i].normal);
- VectorNormalize(volume.planes[i].normal, volume.planes[i].normal);
- volume.planes[i].dist = DotProduct(volume.planes[i].normal, w->points[i]);
- }
- volume.numplanes = w->numpoints;
- VectorCopy(light->normal, volume.endplane.normal);
- VectorInverse(volume.endplane.normal);
- volume.endplane.dist = DotProduct(volume.endplane.normal, volume.points[0]);
- volume.farplane = volume.endplane;
- volume.surfaceNum = -1;
- volume.type = VOLUME_DIRECTED;
- volume.cluster = dleafs[leafnum].cluster;
- VL_R_FloodLight(light, &volume, volume.cluster, 0);
- if (volume.surfaceNum >= 0)
- {
- VL_R_CastLightAtSurface(light, &volume);
- }
- }
- /*
- =============
- VL_R_SubdivideDirectedAreaLight
- =============
- */
- void VL_R_SubdivideDirectedAreaLight(vlight_t *light, int nodenum, winding_t *w)
- {
- int leafnum, res;
- dnode_t *node;
- dplane_t *plane;
- winding_t back;
- plane_t split;
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VL_SplitWinding (w, &back, &split, 0.1);
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- memcpy(&back, w, sizeof(winding_t));
- VL_R_SubdivideDirectedAreaLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- else
- {
- VL_R_SubdivideDirectedAreaLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- if (dleafs[leafnum].cluster != -1)
- {
- VL_FloodDirectedLight(light, w, leafnum);
- }
- }
- /*
- =============
- VL_FloodLight
- =============
- */
- void VL_FloodLight(vlight_t *light)
- {
- lightvolume_t volume;
- dleaf_t *leaf;
- int leafnum, i, j, k, dir[2][4] = {{1, 1, -1, -1}, {1, -1, -1, 1}};
- float a, step, dist, radius, windingdist;
- vec3_t vec, r, p, temp;
- winding_t winding;
- switch(light->type)
- {
- case LIGHT_POINTRADIAL:
- {
- // source is a point
- // light radiates in all directions
- // creates sharp shadows
- //
- // create 6 volumes shining in the axis directions
- // what about: 4 tetrahedrons instead?
- //
- if ( light->atten_disttype == LDAT_LINEAR )
- dist = light->photons * lightLinearScale;
- else
- dist = sqrt(light->photons);
- //always put the winding at a large distance to avoid epsilon issues
- windingdist = MAX_WORLD_COORD;
- if (dist > windingdist)
- windingdist = dist;
- //
- leafnum = VL_LightLeafnum(light->origin);
- leaf = &dleafs[leafnum];
- if (leaf->cluster == -1)
- {
- light->insolid = qtrue;
- break;
- }
- // for each axis
- for (i = 0; i < 3; i++)
- {
- // for both directions on the axis
- for (j = -1; j <= 1; j += 2)
- {
- memset(&volume, 0, sizeof(lightvolume_t));
- volume.numplanes = 0;
- for (k = 0; k < 4; k ++)
- {
- volume.points[volume.numplanes][i] = light->origin[i] + j * windingdist;
- volume.points[volume.numplanes][(i+1)%3] = light->origin[(i+1)%3] + dir[0][k] * windingdist;
- volume.points[volume.numplanes][(i+2)%3] = light->origin[(i+2)%3] + dir[1][k] * windingdist;
- volume.numplanes++;
- }
- if (j >= 0)
- {
- VectorCopy(volume.points[0], temp);
- VectorCopy(volume.points[2], volume.points[0]);
- VectorCopy(temp, volume.points[2]);
- }
- for (k = 0; k < volume.numplanes; k++)
- {
- VL_PlaneFromPoints(&volume.planes[k], light->origin, volume.points[(k+1)%volume.numplanes], volume.points[k]);
- }
- VectorCopy(light->origin, temp);
- temp[i] += (float) j * dist;
- VectorClear(volume.endplane.normal);
- volume.endplane.normal[i] = -j;
- volume.endplane.dist = DotProduct(volume.endplane.normal, temp); //DotProduct(volume.endplane.normal, volume.points[0]);
- volume.farplane = volume.endplane;
- volume.cluster = leaf->cluster;
- volume.surfaceNum = -1;
- volume.type = VOLUME_NORMAL;
- //
- memset(volume.facetTested, 0, sizeof(volume.facetTested));
- memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
- VL_R_FloodLight(light, &volume, leaf->cluster, 0);
- if (volume.surfaceNum >= 0)
- {
- VL_R_CastLightAtSurface(light, &volume);
- }
- }
- }
- break;
- }
- case LIGHT_POINTSPOT:
- {
- // source is a point
- // light is targetted
- // creates sharp shadows
- //
- // what about using brushes to shape spot lights? that'd be pretty cool
- //
- if ( light->atten_disttype == LDAT_LINEAR )
- dist = light->photons * lightLinearScale;
- else
- dist = sqrt(light->photons);
- dist *= 2;
- //
- windingdist = 4096;
- if (dist > windingdist)
- windingdist = dist;
- //take 8 times the cone radius because the spotlight also lights outside the cone
- radius = 8 * windingdist * light->radiusByDist;
- //
- memset(&volume, 0, sizeof(lightvolume_t));
- leafnum = VL_LightLeafnum(light->origin);
- leaf = &dleafs[leafnum];
- if (leaf->cluster == -1)
- {
- light->insolid = qtrue;
- break;
- }
- //
- VectorClear(vec);
- for (i = 0; i < 3; i++)
- {
- if (light->normal[i] > -0.9 && light->normal[i] < 0.9)
- {
- vec[i] = 1;
- break;
- }
- }
- CrossProduct(light->normal, vec, r);
- VectorScale(r, radius, p);
- volume.numplanes = 0;
- step = 45;
- for (a = step / 2; a < 360 + step / 2; a += step)
- {
- RotatePointAroundVector(volume.points[volume.numplanes], light->normal, p, a);
- VectorAdd(light->origin, volume.points[volume.numplanes], volume.points[volume.numplanes]);
- VectorMA(volume.points[volume.numplanes], windingdist, light->normal, volume.points[volume.numplanes]);
- volume.numplanes++;
- }
- for (i = 0; i < volume.numplanes; i++)
- {
- VL_PlaneFromPoints(&volume.planes[i], light->origin, volume.points[(i+1)%volume.numplanes], volume.points[i]);
- }
- VectorMA(light->origin, dist, light->normal, temp);
- VectorCopy(light->normal, volume.endplane.normal);
- VectorInverse(volume.endplane.normal);
- volume.endplane.dist = DotProduct(volume.endplane.normal, temp);//DotProduct(volume.endplane.normal, volume.points[0]);
- volume.farplane = volume.endplane;
- volume.cluster = leaf->cluster;
- volume.surfaceNum = -1;
- volume.type = VOLUME_NORMAL;
- //
- memset(volume.facetTested, 0, sizeof(volume.facetTested));
- memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
- VL_R_FloodLight(light, &volume, leaf->cluster, 0);
- if (volume.surfaceNum >= 0)
- {
- VL_R_CastLightAtSurface(light, &volume);
- }
- break;
- }
- case LIGHT_POINTFAKESURFACE:
- {
- float value;
- int n, axis;
- vec3_t v, vecs[2];
- if ( light->atten_disttype == LDAT_LINEAR )
- dist = light->photons * lightLinearScale;
- else
- dist = sqrt(light->photons);
- //always put the winding at a large distance to avoid epsilon issues
- windingdist = 4096;
- if (dist > windingdist)
- windingdist = dist;
- //
- VectorMA(light->origin, 0.1, light->normal, light->origin);
- //
- leafnum = VL_LightLeafnum(light->origin);
- leaf = &dleafs[leafnum];
- if (leaf->cluster == -1)
- {
- light->insolid = qtrue;
- break;
- }
- value = 0;
- for (i = 0; i < 3; i++)
- {
- if (fabs(light->normal[i]) > value)
- {
- value = fabs(light->normal[i]);
- axis = i;
- }
- }
- for (i = 0; i < 2; i++)
- {
- VectorClear(v);
- v[(axis + 1 + i) % 3] = 1;
- CrossProduct(light->normal, v, vecs[i]);
- }
- //cast 4 volumes at the front of the surface
- for (i = -1; i <= 1; i += 2)
- {
- for (j = -1; j <= 1; j += 2)
- {
- for (n = 0; n < 2; n++)
- {
- memset(&volume, 0, sizeof(lightvolume_t));
- volume.numplanes = 3;
- VectorMA(light->origin, i * windingdist, vecs[0], volume.points[(i == j) == n]);
- VectorMA(light->origin, j * windingdist, vecs[1], volume.points[(i != j) == n]);
- VectorMA(light->origin, windingdist, light->normal, volume.points[2]);
- for (k = 0; k < volume.numplanes; k++)
- {
- VL_PlaneFromPoints(&volume.planes[k], light->origin, volume.points[(k+1)%volume.numplanes], volume.points[k]);
- }
- VL_PlaneFromPoints(&volume.endplane, volume.points[0], volume.points[1], volume.points[2]);
- VectorMA(light->origin, dist, light->normal, temp);
- volume.endplane.dist = DotProduct(volume.endplane.normal, temp);
- if (DotProduct(light->origin, volume.endplane.normal) - volume.endplane.dist > 0)
- break;
- }
- volume.farplane = volume.endplane;
- volume.cluster = leaf->cluster;
- volume.surfaceNum = -1;
- volume.type = VOLUME_NORMAL;
- //
- memset(volume.facetTested, 0, sizeof(volume.facetTested));
- memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
- VL_R_FloodLight(light, &volume, leaf->cluster, 0);
- if (volume.surfaceNum >= 0)
- {
- VL_R_CastLightAtSurface(light, &volume);
- }
- }
- }
- break;
- }
- case LIGHT_SURFACEDIRECTED:
- {
- // source is an area defined by a winding
- // the light is unidirectional
- // creates sharp shadows
- // for instance sun light or laser light
- //
- memcpy(&winding, &light->w, sizeof(winding_t));
- VL_R_SubdivideDirectedAreaLight(light, 0, &winding);
- break;
- }
- case LIGHT_SURFACERADIAL:
- {
- // source is an area defined by a winding
- // the light radiates in all directions at the front of the winding plane
- //
- memcpy(&winding, &light->w, sizeof(winding_t));
- VL_R_SubdivideRadialAreaLight(light, 0, &winding);
- break;
- }
- case LIGHT_SURFACESPOT:
- {
- // source is an area defined by a winding
- // light is targetted but not unidirectional
- //
- memcpy(&winding, &light->w, sizeof(winding_t));
- VL_R_SubdivideAreaSpotLight(light, 0, &winding);
- break;
- }
- }
- }
- /*
- =============
- VL_FloodLightThread
- =============
- */
- void VL_FloodLightThread(int num)
- {
- VL_FloodLight(vlights[num]);
- }
- /*
- =============
- VL_TestLightLeafs
- =============
- */
- void VL_TestLightLeafs(void)
- {
- int leafnum, i;
- vlight_t *light;
- dleaf_t *leaf;
- for (i = 0; i < numvlights; i++)
- {
- light = vlights[i];
- if (light->type != LIGHT_POINTRADIAL &&
- light->type != LIGHT_POINTSPOT)
- continue;
- leafnum = VL_LightLeafnum(light->origin);
- leaf = &dleafs[leafnum];
- if (leaf->cluster == -1)
- if (light->type == LIGHT_POINTRADIAL)
- qprintf("light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]);
- else if (light->type == LIGHT_POINTSPOT)
- qprintf("spot light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]);
- }
- }
- /*
- =============
- VL_DoForcedTraceLight
- =============
- */
- // from light.c
- void TraceLtm( int num );
- void VL_DoForcedTraceLight(int num)
- {
- dsurface_t *ds;
- shaderInfo_t *si;
- ds = &drawSurfaces[num];
- if ( ds->surfaceType == MST_TRIANGLE_SOUP )
- return;
- if ( ds->lightmapNum < 0 )
- return;
- // always light entity surfaces with the old light algorithm
- if ( !entitySurface[num] )
- {
- si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
- if (defaulttracelight)
- {
- if (si->forceVLight)
- return;
- }
- else
- {
- if (!si->forceTraceLight)
- return;
- }
- }
- TraceLtm(num);
- }
- /*
- =============
- VL_DoForcedTraceLightSurfaces
- =============
- */
- void VL_DoForcedTraceLightSurfaces(void)
- {
- _printf( "forced trace light\n" );
- RunThreadsOnIndividual( numDrawSurfaces, qtrue, VL_DoForcedTraceLight );
- }
- float *oldLightFloats;
- /*
- =============
- VL_SurfaceRadiosity
- =============
- */
- void VL_SurfaceRadiosity( int num ) {
- dsurface_t *ds;
- mesh_t *mesh;
- shaderInfo_t *si;
- lsurfaceTest_t *test;
- int x, y, k;
- vec3_t base, normal;
- float *color, area;
- vlight_t vlight;
- ds = &drawSurfaces[num];
- if ( ds->lightmapNum < 0 ) {
- return; // doesn't have a lightmap
- }
- // vertex-lit triangle model
- if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
- return;
- }
- si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
- test = lsurfaceTest[ num ];
- if (!test) {
- return;
- }
- for (x = 0; x < ds->lightmapWidth; x++) {
- for (y = 0; y < ds->lightmapHeight; y++) {
- //
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- area = lightmappixelarea[k];
- if (area <= 0)
- continue;
- //
- if (ds->surfaceType == MST_PATCH)
- {
- mesh = test->detailMesh;
- VectorCopy( mesh->verts[y*mesh->width+x].xyz, base);
- VectorCopy( mesh->verts[y*mesh->width+x].normal, normal);
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x, ds->lightmapVecs[0], base);
- VectorMA(base, (float) y, ds->lightmapVecs[1], base);
- VectorCopy(test->facets[0].plane.normal, normal);
- }
- // create ligth from base
- memset(&vlight, 0, sizeof(vlight_t));
- color = &oldLightFloats[k*3];
- // a few units away from the surface
- VectorMA(base, 5, normal, vlight.origin);
- ColorNormalize(color, vlight.color);
- // ok this is crap
- vlight.photons = VectorLength(color) * 0.05 * lightPointScale / (area * radiosity_scale);
- // what about using a front facing light only ?
- vlight.type = LIGHT_POINTRADIAL;
- // flood the light from this lightmap pixel
- VL_FloodLight(&vlight);
- // only one thread at a time may write to the lightmap of this surface
- MutexLock(test->mutex);
- // don't light the lightmap pixel itself
- lightFloats[k*3] = oldLightFloats[k*3];
- lightFloats[k*3+1] = oldLightFloats[k*3+1];
- lightFloats[k*3+2] = oldLightFloats[k*3+2];
- //
- MutexUnlock(test->mutex);
- }
- }
- }
- /*
- =============
- VL_Radiosity
- this aint working real well but it's fun to play with.
- =============
- */
- void VL_Radiosity(void) {
- oldLightFloats = lightFloats;
- lightFloats = (float *) malloc(numLightBytes * sizeof(float));
- memcpy(lightFloats, oldLightFloats, numLightBytes * sizeof(float));
- _printf("%7i surfaces\n", numDrawSurfaces);
- RunThreadsOnIndividual( numDrawSurfaces, qtrue, VL_SurfaceRadiosity );
- free(oldLightFloats);
- }
- /*
- =============
- VL_LightWorld
- =============
- */
- void VL_LightWorld(void)
- {
- int i, numcastedvolumes, numvlightsinsolid;
- float f;
- // find the optional world ambient
- GetVectorForKey( &entities[0], "_color", lightAmbientColor );
- f = FloatForKey( &entities[0], "ambient" );
- VectorScale( lightAmbientColor, f, lightAmbientColor );
- /*
- _printf("\r%6d lights out of %d", 0, numvlights);
- for (i = 0; i < numvlights; i++)
- {
- _printf("\r%6d", i);
- VL_FloodLight(vlights[i]);
- }
- _printf("\r%6d lights out of %d\n", i, numvlights);
- */
- _printf("%7i lights\n", numvlights);
- RunThreadsOnIndividual( numvlights, qtrue, VL_FloodLightThread );
- numcastedvolumes = 0;
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- if (lsurfaceTest[i])
- numcastedvolumes += lsurfaceTest[i]->numvolumes;
- }
- _printf("%7i light volumes casted\n", numcastedvolumes);
- numvlightsinsolid = 0;
- for (i = 0; i < numvlights; i++)
- {
- if (vlights[i]->insolid)
- numvlightsinsolid++;
- }
- _printf("%7i lights in solid\n", numvlightsinsolid);
- //
- radiosity_scale = 1;
- for (i = 0; i < radiosity; i++) {
- VL_Radiosity();
- radiosity_scale <<= 1;
- }
- //
- VL_StoreLightmap();
- // redo surfaces with the old light algorithm when needed
- VL_DoForcedTraceLightSurfaces();
- }
- /*
- =============
- VL_CreateEntityLights
- =============
- */
- entity_t *FindTargetEntity( const char *target );
- void VL_CreateEntityLights (void)
- {
- int i, c_entityLights;
- vlight_t *dl;
- entity_t *e, *e2;
- const char *name;
- const char *target;
- vec3_t dest;
- const char *_color;
- float intensity;
- int spawnflags;
- //
- c_entityLights = 0;
- _printf("Creating entity lights...\n");
- //
- for ( i = 0 ; i < num_entities ; i++ ) {
- e = &entities[i];
- name = ValueForKey (e, "classname");
- if (strncmp (name, "light", 5))
- continue;
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
- spawnflags = FloatForKey (e, "spawnflags");
- if ( spawnflags & 1 ) {
- dl->atten_disttype = LDAT_LINEAR;
- }
- if ( spawnflags & 2 ) {
- dl->atten_disttype = LDAT_NOSCALE;
- }
- if ( spawnflags & 4 ) {
- dl->atten_angletype = LAAT_QUADRATIC;
- }
- if ( spawnflags & 8 ) {
- dl->atten_angletype = LAAT_DOUBLEQUADRATIC;
- }
- dl->atten_distscale = FloatForKey(e, "atten_distscale");
- dl->atten_anglescale = FloatForKey(e, "atten_anglescale");
- GetVectorForKey (e, "origin", dl->origin);
- dl->style = FloatForKey (e, "_style");
- if (!dl->style)
- dl->style = FloatForKey (e, "style");
- if (dl->style < 0)
- dl->style = 0;
- intensity = FloatForKey (e, "light");
- if (!intensity)
- intensity = FloatForKey (e, "_light");
- if (!intensity)
- intensity = 300;
- _color = ValueForKey (e, "_color");
- if (_color && _color[0])
- {
- sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]);
- ColorNormalize (dl->color, dl->color);
- }
- else
- dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
- intensity = intensity * lightPointScale;
- dl->photons = intensity;
- dl->type = LIGHT_POINTRADIAL;
- // lights with a target will be spotlights
- target = ValueForKey (e, "target");
- if ( target[0] ) {
- float radius;
- float dist;
- e2 = FindTargetEntity (target);
- if (!e2) {
- _printf ("WARNING: light at (%i %i %i) has missing target\n",
- (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]);
- } else {
- GetVectorForKey (e2, "origin", dest);
- VectorSubtract (dest, dl->origin, dl->normal);
- dist = VectorNormalize (dl->normal, dl->normal);
- radius = FloatForKey (e, "radius");
- if ( !radius ) {
- radius = 64;
- }
- if ( !dist ) {
- dist = 64;
- }
- dl->radiusByDist = (radius + 16) / dist;
- dl->type = LIGHT_POINTSPOT;
- }
- }
- vlights[numvlights++] = dl;
- c_entityLights++;
- }
- _printf("%7i entity lights\n", c_entityLights);
- }
- /*
- ==================
- VL_SubdivideAreaLight
- ==================
- */
- void VL_SubdivideAreaLight( shaderInfo_t *ls, winding_t *w, vec3_t normal,
- float areaSubdivide, qboolean backsplash ) {
- float area, value, intensity;
- vlight_t *dl, *dl2;
- vec3_t mins, maxs;
- int axis;
- winding_t *front, *back;
- vec3_t planeNormal;
- float planeDist;
- if ( !w ) {
- return;
- }
- WindingBounds( w, mins, maxs );
- // check for subdivision
- for ( axis = 0 ; axis < 3 ; axis++ ) {
- if ( maxs[axis] - mins[axis] > areaSubdivide ) {
- VectorClear( planeNormal );
- planeNormal[axis] = 1;
- planeDist = ( maxs[axis] + mins[axis] ) * 0.5;
- ClipWindingEpsilon ( w, planeNormal, planeDist, ON_EPSILON, &front, &back );
- VL_SubdivideAreaLight( ls, front, normal, areaSubdivide, qfalse );
- VL_SubdivideAreaLight( ls, back, normal, areaSubdivide, qfalse );
- FreeWinding( w );
- return;
- }
- }
- // create a light from this
- area = WindingArea (w);
- if ( area <= 0 || area > 20000000 ) {
- return;
- }
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
- dl->type = LIGHT_POINTFAKESURFACE;
- WindingCenter( w, dl->origin );
- memcpy(dl->w.points, w->points, sizeof(vec3_t) * w->numpoints);
- dl->w.numpoints = w->numpoints;
- VectorCopy ( normal, dl->normal);
- VectorCopy ( normal, dl->plane);
- dl->plane[3] = DotProduct( dl->origin, normal );
- value = ls->value;
- intensity = value * area * lightAreaScale;
- VectorAdd( dl->origin, dl->normal, dl->origin );
- VectorCopy( ls->color, dl->color );
- dl->photons = intensity;
- // emitColor is irrespective of the area
- VectorScale( ls->color, value*lightFormFactorValueScale*lightAreaScale, dl->emitColor );
- //
- VectorCopy(dl->emitColor, dl->color);
- dl->si = ls;
- if ( ls->contents & CONTENTS_FOG ) {
- dl->twosided = qtrue;
- }
- vlights[numvlights++] = dl;
- // optionally create a point backsplash light
- if ( backsplash && ls->backsplashFraction > 0 ) {
- dl2 = malloc(sizeof(*dl));
- memset (dl2, 0, sizeof(*dl2));
- dl2->type = LIGHT_POINTRADIAL;
- VectorMA( dl->origin, ls->backsplashDistance, normal, dl2->origin );
- VectorCopy( ls->color, dl2->color );
- dl2->photons = dl->photons * ls->backsplashFraction;
- dl2->si = ls;
- vlights[numvlights++] = dl2;
- }
- }
- /*
- ==================
- VL_CreateFakeSurfaceLights
- ==================
- */
- void VL_CreateFakeSurfaceLights( void ) {
- int i, j, side;
- dsurface_t *ds;
- shaderInfo_t *ls;
- winding_t *w;
- lFacet_t *f;
- vlight_t *dl;
- vec3_t origin;
- drawVert_t *dv;
- int c_surfaceLights;
- float lightSubdivide;
- vec3_t normal;
- c_surfaceLights = 0;
- _printf ("Creating surface lights...\n");
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- // see if this surface is light emiting
- ds = &drawSurfaces[i];
- ls = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
- if ( ls->value == 0 ) {
- continue;
- }
- // determine how much we need to chop up the surface
- if ( ls->lightSubdivide ) {
- lightSubdivide = ls->lightSubdivide;
- } else {
- lightSubdivide = lightDefaultSubdivide;
- }
- c_surfaceLights++;
- // an autosprite shader will become
- // a point light instead of an area light
- if ( ls->autosprite ) {
- // autosprite geometry should only have four vertexes
- if ( lsurfaceTest[i] ) {
- // curve or misc_model
- f = lsurfaceTest[i]->facets;
- if ( lsurfaceTest[i]->numFacets != 1 || f->numpoints != 4 ) {
- _printf( "WARNING: surface at (%i %i %i) has autosprite shader but isn't a quad\n",
- (int)f->points[0], (int)f->points[1], (int)f->points[2] );
- }
- VectorAdd( f->points[0], f->points[1], origin );
- VectorAdd( f->points[2], origin, origin );
- VectorAdd( f->points[3], origin, origin );
- VectorScale( origin, 0.25, origin );
- } else {
- // normal polygon
- dv = &drawVerts[ ds->firstVert ];
- if ( ds->numVerts != 4 ) {
- _printf( "WARNING: surface at (%i %i %i) has autosprite shader but %i verts\n",
- (int)dv->xyz[0], (int)dv->xyz[1], (int)dv->xyz[2] );
- continue;
- }
- VectorAdd( dv[0].xyz, dv[1].xyz, origin );
- VectorAdd( dv[2].xyz, origin, origin );
- VectorAdd( dv[3].xyz, origin, origin );
- VectorScale( origin, 0.25, origin );
- }
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
- VectorCopy( origin, dl->origin );
- VectorCopy( ls->color, dl->color );
- dl->photons = ls->value * lightPointScale;
- dl->type = LIGHT_POINTRADIAL;
- vlights[numvlights++] = dl;
- continue;
- }
- // possibly create for both sides of the polygon
- for ( side = 0 ; side <= ls->twoSided ; side++ ) {
- // create area lights
- if ( lsurfaceTest[i] ) {
- // curve or misc_model
- for ( j = 0 ; j < lsurfaceTest[i]->numFacets ; j++ ) {
- f = lsurfaceTest[i]->facets + j;
- w = AllocWinding( f->numpoints );
- w->numpoints = f->numpoints;
- memcpy( w->points, f->points, f->numpoints * 12 );
- VectorCopy( f->plane.normal, normal );
- if ( side ) {
- winding_t *t;
- t = w;
- w = ReverseWinding( t );
- FreeWinding( t );
- VectorSubtract( vec3_origin, normal, normal );
- }
- VL_SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
- }
- } else {
- // normal polygon
- w = AllocWinding( ds->numVerts );
- w->numpoints = ds->numVerts;
- for ( j = 0 ; j < ds->numVerts ; j++ ) {
- VectorCopy( drawVerts[ds->firstVert+j].xyz, w->points[j] );
- }
- VectorCopy( ds->lightmapVecs[2], normal );
- if ( side ) {
- winding_t *t;
- t = w;
- w = ReverseWinding( t );
- FreeWinding( t );
- VectorSubtract( vec3_origin, normal, normal );
- }
- VL_SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
- }
- }
- }
- _printf( "%7i light emitting surfaces\n", c_surfaceLights );
- }
- /*
- ==================
- VL_WindingForBrushSide
- ==================
- */
- winding_t *VL_WindingForBrushSide(dbrush_t *brush, int side, winding_t *w)
- {
- int i, res;
- winding_t *tmpw;
- plane_t plane;
- VectorCopy(dplanes[ dbrushsides[ brush->firstSide + side ].planeNum ].normal, plane.normal);
- VectorInverse(plane.normal);
- plane.dist = -dplanes[ dbrushsides[ brush->firstSide + side ].planeNum ].dist;
- tmpw = BaseWindingForPlane( plane.normal, plane.dist );
- memcpy(w->points, tmpw->points, sizeof(vec3_t) * tmpw->numpoints);
- w->numpoints = tmpw->numpoints;
- for (i = 0; i < brush->numSides; i++)
- {
- if (i == side)
- continue;
- VectorCopy(dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].normal, plane.normal);
- VectorInverse(plane.normal);
- plane.dist = -dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].dist;
- res = VL_ChopWinding(w, &plane, 0.1);
- if (res == SIDE_BACK)
- return NULL;
- }
- return w;
- }
- /*
- ==================
- VL_CreateSkyLights
- ==================
- */
- void VL_CreateSkyLights(void)
- {
- int i, j, c_skyLights;
- dbrush_t *b;
- shaderInfo_t *si;
- dbrushside_t *s;
- vlight_t *dl;
- vec3_t sunColor, sunDir = { 0.45, 0.3, 0.9 };
- float d;
- VectorNormalize(sunDir, sunDir);
- VectorInverse(sunDir);
- c_skyLights = 0;
- _printf("Creating sky lights...\n");
- // find the sky shader
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- si = ShaderInfoForShader( dshaders[ drawSurfaces[i].shaderNum ].shader );
- if ( si->surfaceFlags & SURF_SKY ) {
- VectorCopy( si->sunLight, sunColor );
- VectorCopy( si->sunDirection, sunDir );
- VectorInverse(sunDir);
- break;
- }
- }
- // find the brushes
- for ( i = 0 ; i < numbrushes ; i++ ) {
- b = &dbrushes[i];
- for ( j = 0 ; j < b->numSides ; j++ ) {
- s = &dbrushsides[ b->firstSide + j ];
- if ( dshaders[ s->shaderNum ].surfaceFlags & SURF_SKY ) {
- //if this surface doesn't face in the same direction as the sun
- d = DotProduct(dplanes[ s->planeNum ].normal, sunDir);
- if (d <= 0)
- continue;
- //
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
- VectorCopy(sunColor, dl->color);
- VectorCopy(sunDir, dl->normal);
- VectorCopy(dplanes[ s->planeNum ].normal, dl->plane);
- dl->plane[3] = dplanes[ s->planeNum ].dist;
- dl->type = LIGHT_SURFACEDIRECTED;
- dl->atten_disttype = LDAT_NOSCALE;
- VL_WindingForBrushSide(b, j, &dl->w);
- // DebugNet_DrawWinding(&dl->w, 2);
- //
- vlights[numvlights++] = dl;
- c_skyLights++;
- }
- }
- }
- _printf("%7i light emitting sky surfaces\n", c_skyLights);
- }
- /*
- ==================
- VL_SetPortalSphere
- ==================
- */
- void VL_SetPortalSphere (lportal_t *p)
- {
- int i;
- vec3_t total, dist;
- winding_t *w;
- float r, bestr;
- w = p->winding;
- VectorCopy (vec3_origin, total);
- for (i=0 ; i<w->numpoints ; i++)
- {
- VectorAdd (total, w->points[i], total);
- }
-
- for (i=0 ; i<3 ; i++)
- total[i] /= w->numpoints;
- bestr = 0;
- for (i=0 ; i<w->numpoints ; i++)
- {
- VectorSubtract (w->points[i], total, dist);
- r = VectorLength (dist);
- if (r > bestr)
- bestr = r;
- }
- VectorCopy (total, p->origin);
- p->radius = bestr;
- }
- /*
- ==================
- VL_PlaneFromWinding
- ==================
- */
- void VL_PlaneFromWinding (winding_t *w, plane_t *plane)
- {
- vec3_t v1, v2;
- //calc plane
- VectorSubtract (w->points[2], w->points[1], v1);
- VectorSubtract (w->points[0], w->points[1], v2);
- CrossProduct (v2, v1, plane->normal);
- VectorNormalize (plane->normal, plane->normal);
- plane->dist = DotProduct (w->points[0], plane->normal);
- }
- /*
- ==================
- VL_AllocWinding
- ==================
- */
- winding_t *VL_AllocWinding (int points)
- {
- winding_t *w;
- int size;
-
- if (points > MAX_POINTS_ON_WINDING)
- Error ("NewWinding: %i points", points);
-
- size = (int)((winding_t *)0)->points[points];
- w = malloc (size);
- memset (w, 0, size);
-
- return w;
- }
- /*
- ============
- VL_LoadPortals
- ============
- */
- void VL_LoadPortals (char *name)
- {
- int i, j, hint;
- lportal_t *p;
- lleaf_t *l;
- char magic[80];
- FILE *f;
- int numpoints;
- winding_t *w;
- int leafnums[2];
- plane_t plane;
- //
-
- if (!strcmp(name,"-"))
- f = stdin;
- else
- {
- f = fopen(name, "r");
- if (!f)
- Error ("LoadPortals: couldn't read %s\n",name);
- }
- if (fscanf (f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces) != 4)
- Error ("LoadPortals: failed to read header");
- if (strcmp(magic, PORTALFILE))
- Error ("LoadPortals: not a portal file");
- _printf ("%6i portalclusters\n", portalclusters);
- _printf ("%6i numportals\n", numportals);
- _printf ("%6i numfaces\n", numfaces);
- if (portalclusters >= MAX_CLUSTERS)
- Error ("more than %d clusters in portal file\n", MAX_CLUSTERS);
- // each file portal is split into two memory portals
- portals = malloc(2*numportals*sizeof(lportal_t));
- memset (portals, 0, 2*numportals*sizeof(lportal_t));
-
- leafs = malloc(portalclusters*sizeof(lleaf_t));
- memset (leafs, 0, portalclusters*sizeof(lleaf_t));
- for (i=0, p=portals ; i<numportals ; i++)
- {
- if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) != 3)
- Error ("LoadPortals: reading portal %i", i);
- if (numpoints > MAX_POINTS_ON_WINDING)
- Error ("LoadPortals: portal %i has too many points", i);
- if ( (unsigned)leafnums[0] > portalclusters
- || (unsigned)leafnums[1] > portalclusters)
- Error ("LoadPortals: reading portal %i", i);
- if (fscanf (f, "%i ", &hint) != 1)
- Error ("LoadPortals: reading hint state");
-
- w = p->winding = VL_AllocWinding (numpoints);
- w->numpoints = numpoints;
-
- for (j=0 ; j<numpoints ; j++)
- {
- double v[3];
- int k;
- // scanf into double, then assign to vec_t
- // so we don't care what size vec_t is
- if (fscanf (f, "(%lf %lf %lf ) "
- , &v[0], &v[1], &v[2]) != 3)
- Error ("LoadPortals: reading portal %i", i);
- for (k=0 ; k<3 ; k++)
- w->points[j][k] = v[k];
- }
- fscanf (f, "\n");
-
- // calc plane
- VL_PlaneFromWinding (w, &plane);
- // create forward portal
- l = &leafs[leafnums[0]];
- if (l->numportals == MAX_PORTALS_ON_LEAF)
- Error ("Leaf with too many portals");
- l->portals[l->numportals] = p;
- l->numportals++;
-
- p->winding = w;
- VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
- p->plane.dist = -plane.dist;
- p->leaf = leafnums[1];
- VL_SetPortalSphere (p);
- p++;
-
- // create backwards portal
- l = &leafs[leafnums[1]];
- if (l->numportals == MAX_PORTALS_ON_LEAF)
- Error ("Leaf with too many portals");
- l->portals[l->numportals] = p;
- l->numportals++;
-
- p->winding = VL_AllocWinding(w->numpoints);
- p->winding->numpoints = w->numpoints;
- for (j=0 ; j<w->numpoints ; j++)
- {
- VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]);
- }
- p->plane = plane;
- p->leaf = leafnums[0];
- VL_SetPortalSphere (p);
- p++;
- }
-
- fclose (f);
- }
- /*
- ============
- VLightMain
- ============
- */
- int VLightMain (int argc, char **argv) {
- int i;
- double start, end;
- const char *value;
- _printf ("----- VLighting ----\n");
- for (i=1 ; i<argc ; i++) {
- if (!strcmp(argv[i],"-v")) {
- verbose = qtrue;
- } else if (!strcmp(argv[i],"-threads")) {
- numthreads = atoi (argv[i+1]);
- _printf("num threads = %d\n", numthreads);
- i++;
- } else if (!strcmp(argv[i],"-area")) {
- lightAreaScale *= atof(argv[i+1]);
- _printf ("area light scaling at %f\n", lightAreaScale);
- i++;
- } else if (!strcmp(argv[i],"-point")) {
- lightPointScale *= atof(argv[i+1]);
- _printf ("point light scaling at %f\n", lightPointScale);
- i++;
- } else if (!strcmp(argv[i], "-samplesize")) {
- samplesize = atoi(argv[i+1]);
- if (samplesize < 1) samplesize = 1;
- i++;
- _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize);
- } else if (!strcmp(argv[i], "-novertex")) {
- novertexlighting = qtrue;
- _printf("no vertex lighting = true\n");
- } else if (!strcmp(argv[i], "-nogrid")) {
- nogridlighting = qtrue;
- _printf("no grid lighting = true\n");
- } else if (!strcmp(argv[i], "-nostitching")) {
- nostitching = qtrue;
- _printf("no stitching = true\n");
- } else if (!strcmp(argv[i], "-noalphashading")) {
- noalphashading = qtrue;
- _printf("no alpha shading = true\n");
- } else if (!strcmp(argv[i], "-nocolorshading")) {
- nocolorshading = qtrue;
- _printf("old style alpha shading = true\n");
- } else if (!strcmp(argv[i], "-nobackfaceculling")) {
- nobackfaceculling = qtrue;
- _printf("no backface culling = true\n");
- } else if (!strcmp(argv[i], "-tracelight")) {
- defaulttracelight = qtrue;
- _printf("default trace light = true\n");
- } else if (!strcmp(argv[i], "-radiosity")) {
- radiosity = atoi(argv[i+1]);
- _printf("radiosity = %d\n", radiosity);
- i++;
- } else {
- break;
- }
- }
- ThreadSetDefault ();
- if (i != argc - 1) {
- _printf("usage: q3map -vlight [-<switch> [-<switch> ...]] <mapname>\n"
- "\n"
- "Switches:\n"
- " v = verbose output\n"
- " threads <X> = set number of threads to X\n"
- " area <V> = set the area light scale to V\n"
- " point <W> = set the point light scale to W\n"
- " novertex = don't calculate vertex lighting\n"
- " nogrid = don't calculate light grid for dynamic model lighting\n"
- " nostitching = no polygon stitching before lighting\n"
- " noalphashading = don't use alpha shading\n"
- " nocolorshading = don't use color alpha shading\n"
- " tracelight = use old light algorithm by default\n"
- " samplesize <N> = set the lightmap pixel size to NxN units\n");
- exit(0);
- }
- SetQdirFromPath (argv[i]);
- #ifdef _WIN32
- InitPakFile(gamedir, NULL);
- #endif
- strcpy (source, ExpandArg(argv[i]));
- StripExtension (source);
- DefaultExtension (source, ".bsp");
- LoadShaderInfo();
- _printf ("reading %s\n", source);
- LoadBSPFile (source);
- ParseEntities();
- value = ValueForKey( &entities[0], "gridsize" );
- if (strlen(value)) {
- sscanf( value, "%f %f %f", &gridSize[0], &gridSize[1], &gridSize[2] );
- _printf("grid size = {%1.1f, %1.1f, %1.1f}\n", gridSize[0], gridSize[1], gridSize[2]);
- }
- CountLightmaps();
- StripExtension (source);
- DefaultExtension (source, ".prt");
- VL_LoadPortals(source);
- // set surfaceOrigin
- SetEntityOrigins();
- // grid and vertex lighting
- GridAndVertexLighting();
- #ifdef DEBUGNET
- DebugNet_Setup();
- #endif
- start = clock();
- lightFloats = (float *) malloc(numLightBytes * sizeof(float));
- memset(lightFloats, 0, numLightBytes * sizeof(float));
- VL_InitSurfacesForTesting();
- VL_CalcVisibleLightmapPixelArea();
- numvlights = 0;
- VL_CreateEntityLights();
- VL_CreateFakeSurfaceLights();
- VL_CreateSkyLights();
- VL_TestLightLeafs();
- VL_LightWorld();
- #ifndef LIGHTPOLYS
- StripExtension (source);
- DefaultExtension (source, ".bsp");
- _printf ("writing %s\n", source);
- WriteBSPFile (source);
- #endif
- end = clock();
- _printf ("%5.2f seconds elapsed\n", (end-start) / CLK_TCK);
- #ifdef LIGHTPOLYS
- VL_DrawLightWindings();
- #endif
- #ifdef DEBUGNET
- DebugNet_Shutdown();
- #endif
- return 0;
- }
|