LevelEditor.py 225 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657
  1. from ShowBaseGlobal import *
  2. from PandaObject import *
  3. from PieMenu import *
  4. from GuiGlobals import *
  5. from Tkinter import *
  6. from DirectGeometry import *
  7. from SceneGraphExplorer import *
  8. from tkMessageBox import showinfo
  9. from tkFileDialog import *
  10. from whrandom import *
  11. import Pmw
  12. import Floater
  13. import EntryScale
  14. import VectorWidgets
  15. import string
  16. import os
  17. import getopt
  18. import sys
  19. import whrandom
  20. import __builtin__
  21. visualizeZones = base.config.GetBool("visualize-zones", 0)
  22. # Colors used by all color menus
  23. DEFAULT_COLORS = [
  24. Vec4(1,1,1,1),
  25. Vec4(0.75, 0.75, 0.75, 1.0 ),
  26. Vec4(0.5, 0.5, 0.5, 1.0),
  27. Vec4(0.25, 0.25, 0.25, 1.0)]
  28. # The list of items with color attributes
  29. COLOR_TYPES = ['wall_color', 'window_color',
  30. 'window_awning_color', 'sign_color', 'door_color',
  31. 'door_awning_color', 'cornice_color',
  32. 'prop_color']
  33. # The list of dna components maintained in the style attribute dictionary
  34. DNA_TYPES = ['wall', 'window', 'sign', 'door', 'cornice', 'toon_landmark',
  35. 'prop', 'street']
  36. BUILDING_TYPES = ['10_10', '20', '10_20', '20_10', '10_10_10',
  37. '4_21', '3_22', '4_13_8', '3_13_9', '10',
  38. '12_8', '13_9_8'
  39. ]
  40. BUILDING_HEIGHTS = [10, 20, 25, 30]
  41. NUM_WALLS = [1,2,3]
  42. OBJECT_SNAP_POINTS = {
  43. 'street_5x20': [(Vec3(5.0,0,0), Vec3(0)),
  44. (Vec3(0), Vec3(0))],
  45. 'street_10x20': [(Vec3(10.0,0,0), Vec3(0)),
  46. (Vec3(0), Vec3(0))],
  47. 'street_20x20': [(Vec3(20.0,0,0), Vec3(0)),
  48. (Vec3(0), Vec3(0))],
  49. 'street_30x20': [(Vec3(30.0,0,0), Vec3(0)),
  50. (Vec3(0), Vec3(0))],
  51. 'street_40x20': [(Vec3(40.0,0,0), Vec3(0)),
  52. (Vec3(0), Vec3(0))],
  53. 'street_80x20': [(Vec3(80.0,0,0), Vec3(0)),
  54. (Vec3(0), Vec3(0))],
  55. 'street_5x40': [(Vec3(5.0,0,0), Vec3(0)),
  56. (Vec3(0), Vec3(0))],
  57. 'street_10x40': [(Vec3(10.0,0,0), Vec3(0)),
  58. (Vec3(0), Vec3(0))],
  59. 'street_20x40': [(Vec3(20.0,0,0), Vec3(0)),
  60. (Vec3(0), Vec3(0))],
  61. 'street_20x40_15': [(Vec3(20.0,0,0), Vec3(0)),
  62. (Vec3(0), Vec3(0))],
  63. 'street_30x40': [(Vec3(30.0,0,0), Vec3(0)),
  64. (Vec3(0), Vec3(0))],
  65. 'street_40x40': [(Vec3(40.0,0,0), Vec3(0)),
  66. (Vec3(0), Vec3(0))],
  67. 'street_20x60': [(Vec3(20.0,0,0), Vec3(0)),
  68. (Vec3(0), Vec3(0))],
  69. 'street_40x60': [(Vec3(40.0,0,0), Vec3(0)),
  70. (Vec3(0), Vec3(0))],
  71. 'street_40x40_15': [(Vec3(40.0,0,0), Vec3(0)),
  72. (Vec3(0), Vec3(0))],
  73. 'street_80x40': [(Vec3(80.0,0,0), Vec3(0)),
  74. (Vec3(0), Vec3(0))],
  75. 'street_angle_30': [(Vec3(0), Vec3(-30,0,0)),
  76. (Vec3(0), Vec3(0))],
  77. 'street_angle_45': [(Vec3(0), Vec3(-45,0,0)),
  78. (Vec3(0), Vec3(0))],
  79. 'street_angle_60': [(Vec3(0), Vec3(-60,0,0)),
  80. (Vec3(0), Vec3(0))],
  81. 'street_inner_corner': [(Vec3(20.0,0,0), Vec3(0)),
  82. (Vec3(0), Vec3(0))],
  83. 'street_outer_corner': [(Vec3(20.0,0,0), Vec3(0)),
  84. (Vec3(0), Vec3(0))],
  85. 'street_full_corner': [(Vec3(40.0,0,0), Vec3(0)),
  86. (Vec3(0), Vec3(0))],
  87. 'street_tight_corner': [(Vec3(40.0,0,0), Vec3(0)),
  88. (Vec3(0), Vec3(0))],
  89. 'street_tight_corner_mirror': [(Vec3(40.0,0,0), Vec3(0)),
  90. (Vec3(0), Vec3(0))],
  91. 'street_double_corner': [(Vec3(40.0,0,0), Vec3(0)),
  92. (Vec3(0), Vec3(0))],
  93. 'street_curved_corner': [(Vec3(40.0,0,0), Vec3(0)),
  94. (Vec3(0), Vec3(0))],
  95. 'street_curved_corner_15': [(Vec3(40.0,0,0), Vec3(0)),
  96. (Vec3(0), Vec3(0))],
  97. 'street_t_intersection': [(Vec3(40.0,0,0), Vec3(0)),
  98. (Vec3(0), Vec3(0))],
  99. 'street_y_intersection': [(Vec3(30.0,0,0), Vec3(0)),
  100. (Vec3(0), Vec3(0))],
  101. 'street_street_20x20': [(Vec3(20.0,0,0), Vec3(0)),
  102. (Vec3(0), Vec3(0))],
  103. 'street_street_40x40': [(Vec3(40.0,0,0), Vec3(0)),
  104. (Vec3(0), Vec3(0))],
  105. 'street_sidewalk_20x20': [(Vec3(20.0,0,0), Vec3(0)),
  106. (Vec3(0), Vec3(0))],
  107. 'street_sidewalk_40x40': [(Vec3(40.0,0,0), Vec3(0)),
  108. (Vec3(0), Vec3(0))],
  109. 'street_divided_transition': [(Vec3(40.0,0,0), Vec3(0)),
  110. (Vec3(0), Vec3(0))],
  111. 'street_divided_40x70': [(Vec3(40.0,0,0), Vec3(0)),
  112. (Vec3(0), Vec3(0))],
  113. 'street_divided_transition_15': [(Vec3(40.0,0,0), Vec3(0)),
  114. (Vec3(0), Vec3(0))],
  115. 'street_divided_40x70_15': [(Vec3(40.0,0,0), Vec3(0)),
  116. (Vec3(0), Vec3(0))],
  117. 'street_stairs_40x10x5': [(Vec3(40.0,0,0), Vec3(0)),
  118. (Vec3(0), Vec3(0))],
  119. 'street_4way_intersection': [(Vec3(40.0,0,0), Vec3(0)),
  120. (Vec3(0), Vec3(0))],
  121. 'street_incline_40x40x5': [(Vec3(40.0,0,0), Vec3(0)),
  122. (Vec3(0), Vec3(0))],
  123. 'street_square_courtyard': [(Vec3(0.0,0,0), Vec3(0)),
  124. (Vec3(0), Vec3(0))],
  125. 'street_courtyard_70': [(Vec3(0.0,0,0), Vec3(0)),
  126. (Vec3(0), Vec3(0))],
  127. 'street_courtyard_70_exit': [(Vec3(0.0,0,0), Vec3(0)),
  128. (Vec3(0), Vec3(0))],
  129. 'street_courtyard_90': [(Vec3(0.0,0,0), Vec3(0)),
  130. (Vec3(0), Vec3(0))],
  131. 'street_courtyard_90_exit': [(Vec3(0.0,0,0), Vec3(0)),
  132. (Vec3(0), Vec3(0))],
  133. 'street_courtyard_70_15': [(Vec3(0.0,0,0), Vec3(0)),
  134. (Vec3(0), Vec3(0))],
  135. 'street_courtyard_70_15_exit': [(Vec3(0.0,0,0), Vec3(0)),
  136. (Vec3(0), Vec3(0))],
  137. 'street_courtyard_90_15': [(Vec3(0.0,0,0), Vec3(0)),
  138. (Vec3(0), Vec3(0))],
  139. 'street_courtyard_90_15_exit': [(Vec3(0.0,0,0), Vec3(0)),
  140. (Vec3(0), Vec3(0))],
  141. 'street_50_transition': [(Vec3(10.0,0,0), Vec3(0)),
  142. (Vec3(0), Vec3(0))],
  143. 'street_20x50': [(Vec3(20.0,0,0), Vec3(0)),
  144. (Vec3(0), Vec3(0))],
  145. 'street_40x50': [(Vec3(40.0,0,0), Vec3(0)),
  146. (Vec3(0), Vec3(0))],
  147. 'street_keyboard_10x40': [(Vec3(10.0,0,0), Vec3(0)),
  148. (Vec3(0), Vec3(0))],
  149. 'street_keyboard_20x40': [(Vec3(20.0,0,0), Vec3(0)),
  150. (Vec3(0), Vec3(0))],
  151. 'street_keyboard_40x40': [(Vec3(40.0,0,0), Vec3(0)),
  152. (Vec3(0), Vec3(0))],
  153. }
  154. # NEIGHBORHOOD DATA
  155. # If you run this from the command line you can pass in the hood codes
  156. # you want to load. For example:
  157. # ppython LevelEditor.py DD TT BR
  158. #
  159. if sys.argv[1:]:
  160. try:
  161. opts, pargs = getopt.getopt(sys.argv[1:], '')
  162. hoods = pargs
  163. except Exception, e:
  164. print e
  165. # If you do not run from the command line, we just load all of them
  166. # or you can hack this up for your own purposes.
  167. else:
  168. hoodString = base.config.GetString('level-editor-hoods',
  169. 'TT DD BR DG DL MM')
  170. hoods = string.split(hoodString)
  171. # The list of neighborhoods to edit
  172. hoodIds = {'TT' : 'toontown_central',
  173. 'DD' : 'donalds_dock',
  174. 'MM' : 'minnies_melody_land',
  175. 'BR' : 'the_burrrgh',
  176. 'DG' : 'daisys_garden',
  177. 'DL' : 'donalds_dreamland',
  178. }
  179. # Init neighborhood arrays
  180. NEIGHBORHOODS = []
  181. NEIGHBORHOOD_CODES = {}
  182. for hoodId in hoods:
  183. if hoodIds.has_key(hoodId):
  184. hoodName = hoodIds[hoodId]
  185. NEIGHBORHOOD_CODES[hoodName] = hoodId
  186. NEIGHBORHOODS.append(hoodName)
  187. else:
  188. print 'Error: no hood defined for: ', hoodId
  189. # Load DNA
  190. try:
  191. if dnaLoaded:
  192. pass
  193. except NameError:
  194. print "Loading LevelEditor for hoods: ", hoods
  195. # DNAStorage instance for storing level DNA info
  196. __builtin__.DNASTORE = DNASTORE = DNAStorage()
  197. # Load the generic storage files
  198. loadDNAFile(DNASTORE, 'phase_4/dna/storage.dna', CSDefault, 1)
  199. loadDNAFile(DNASTORE, 'phase_5/dna/storage_town.dna', CSDefault, 1)
  200. # Load all the neighborhood specific storage files
  201. if 'TT' in hoods:
  202. loadDNAFile(DNASTORE, 'phase_4/dna/storage_TT.dna', CSDefault, 1)
  203. loadDNAFile(DNASTORE, 'phase_4/dna/storage_TT_sz.dna', CSDefault, 1)
  204. loadDNAFile(DNASTORE, 'phase_5/dna/storage_TT_town.dna', CSDefault, 1)
  205. if 'DD' in hoods:
  206. loadDNAFile(DNASTORE, 'phase_6/dna/storage_DD.dna', CSDefault, 1)
  207. loadDNAFile(DNASTORE, 'phase_6/dna/storage_DD_sz.dna', CSDefault, 1)
  208. loadDNAFile(DNASTORE, 'phase_6/dna/storage_DD_town.dna', CSDefault, 1)
  209. if 'MM' in hoods:
  210. loadDNAFile(DNASTORE, 'phase_6/dna/storage_MM.dna', CSDefault, 1)
  211. loadDNAFile(DNASTORE, 'phase_6/dna/storage_MM_sz.dna', CSDefault, 1)
  212. loadDNAFile(DNASTORE, 'phase_6/dna/storage_MM_town.dna', CSDefault, 1)
  213. if 'BR' in hoods:
  214. loadDNAFile(DNASTORE, 'phase_8/dna/storage_BR.dna', CSDefault, 1)
  215. loadDNAFile(DNASTORE, 'phase_8/dna/storage_BR_sz.dna', CSDefault, 1)
  216. loadDNAFile(DNASTORE, 'phase_8/dna/storage_BR_town.dna', CSDefault, 1)
  217. if 'DG' in hoods:
  218. loadDNAFile(DNASTORE, 'phase_8/dna/storage_DG.dna', CSDefault, 1)
  219. loadDNAFile(DNASTORE, 'phase_8/dna/storage_DG_sz.dna', CSDefault, 1)
  220. loadDNAFile(DNASTORE, 'phase_8/dna/storage_DG_town.dna', CSDefault, 1)
  221. if 'DL' in hoods:
  222. loadDNAFile(DNASTORE, 'phase_8/dna/storage_DL.dna', CSDefault, 1)
  223. loadDNAFile(DNASTORE, 'phase_8/dna/storage_DL_sz.dna', CSDefault, 1)
  224. loadDNAFile(DNASTORE, 'phase_8/dna/storage_DL_town.dna', CSDefault, 1)
  225. __builtin__.dnaLoaded = 1
  226. # Precompute class types for type comparisons
  227. DNA_CORNICE = DNACornice.getClassType()
  228. DNA_DOOR = DNADoor.getClassType()
  229. DNA_FLAT_BUILDING = DNAFlatBuilding.getClassType()
  230. DNA_NODE = DNANode.getClassType()
  231. DNA_GROUP = DNAGroup.getClassType()
  232. DNA_VIS_GROUP = DNAVisGroup.getClassType()
  233. DNA_LANDMARK_BUILDING = DNALandmarkBuilding.getClassType()
  234. DNA_NODE = DNANode.getClassType()
  235. DNA_PROP = DNAProp.getClassType()
  236. DNA_SIGN = DNASign.getClassType()
  237. DNA_SIGN_BASELINE = DNASignBaseline.getClassType()
  238. DNA_SIGN_TEXT = DNASignText.getClassType()
  239. DNA_SIGN_GRAPHIC = DNASignGraphic.getClassType()
  240. DNA_STREET = DNAStreet.getClassType()
  241. DNA_WALL = DNAWall.getClassType()
  242. DNA_WINDOWS = DNAWindows.getClassType()
  243. # DNA Utility functions (possible class extensions?)
  244. def DNARemoveChildren(dnaObject):
  245. """ Utility function to delete all the children of a DNANode """
  246. children = []
  247. for i in range(dnaObject.getNumChildren()):
  248. children.append(dnaObject.at(i))
  249. for child in children:
  250. dnaObject.remove(child)
  251. DNASTORE.removeDNAGroup(child)
  252. def DNARemoveChildOfClass(dnaNode, classType, childNum = 0):
  253. """ Remove the nth object of that type you come across """
  254. childCount = 0
  255. for i in range(dnaNode.getNumChildren()):
  256. child = dnaNode.at(i)
  257. if DNAClassEqual(child, classType):
  258. if childCount == childNum:
  259. dnaNode.remove(child)
  260. DNASTORE.removeDNAGroup(child)
  261. return 1
  262. childCount = childCount + 1
  263. # None found
  264. return 0
  265. def DNARemoveAllChildrenOfClass(dnaNode, classType):
  266. """ Remove the objects of that type """
  267. children = []
  268. for i in range(dnaNode.getNumChildren()):
  269. child=dnaNode.at(i)
  270. if DNAClassEqual(child, classType):
  271. children.append(child)
  272. for child in children:
  273. dnaNode.remove(child)
  274. DNASTORE.removeDNAGroup(child)
  275. def DNAGetChildren(dnaNode, classType=None):
  276. """ Return the objects of that type """
  277. children = []
  278. for i in range(dnaNode.getNumChildren()):
  279. child=dnaNode.at(i)
  280. if ((not classType)
  281. or DNAClassEqual(child, classType)):
  282. children.append(child)
  283. return children
  284. def DNAGetChild(dnaObject, type = DNA_NODE, childNum = 0):
  285. childCount = 0
  286. for i in range(dnaObject.getNumChildren()):
  287. child = dnaObject.at(i)
  288. if DNAClassEqual(child, type):
  289. if childCount == childNum:
  290. return child
  291. childCount = childCount + 1
  292. # Not found
  293. return None
  294. def DNAGetChildRecursive(dnaObject, type = DNA_NODE, childNum = 0):
  295. childCount = 0
  296. for i in range(dnaObject.getNumChildren()):
  297. child = dnaObject.at(i)
  298. if DNAClassEqual(child, type):
  299. if childCount == childNum:
  300. return child
  301. childCount = childCount + 1
  302. else:
  303. child = DNAGetChildRecursive(child, type, childNum-childCount)
  304. if child:
  305. return child
  306. # Not found
  307. return None
  308. def DNAGetChildOfClass(dnaNode, classType):
  309. for i in range(dnaNode.getNumChildren()):
  310. child = dnaNode.at(i)
  311. if DNAClassEqual(child, classType):
  312. return child
  313. # Not found
  314. return None
  315. def DNAGetClassType(dnaObject):
  316. return dnaObject.__class__.getClassType()
  317. def DNAClassEqual(dnaObject, classType):
  318. return DNAGetClassType(dnaObject).eq(classType)
  319. def DNAIsDerivedFrom(dnaObject, classType):
  320. return DNAGetClassType(dnaObject).isDerivedFrom(classType)
  321. def DNAGetWallHeights(aDNAFlatBuilding):
  322. """ Get a list of wall heights for a given flat building """
  323. # Init variables
  324. heightList = []
  325. offsetList = []
  326. offset = 0.0
  327. # Compute wall heights
  328. for i in range(aDNAFlatBuilding.getNumChildren()):
  329. child = aDNAFlatBuilding.at(i)
  330. if DNAClassEqual(child, DNA_WALL):
  331. height = child.getHeight()
  332. heightList.append(height)
  333. offsetList.append(offset)
  334. offset = offset + height
  335. return heightList, offsetList
  336. def DNAGetBaselineString(baseline):
  337. s=""
  338. for i in range(baseline.getNumChildren()):
  339. child = baseline.at(i)
  340. if DNAClassEqual(child, DNA_SIGN_TEXT):
  341. s=s+child.getLetters()
  342. elif DNAClassEqual(child, DNA_SIGN_GRAPHIC):
  343. s=s+'['+child.getCode()+']'
  344. return s
  345. def DNASetBaselineString(baseline, text):
  346. # TODO: Instead of removing all the text and replacing it,
  347. # replace each text item and then add or remove at the end.
  348. # This should allow inlined graphics to stay in place.
  349. # end of todo.
  350. DNARemoveAllChildrenOfClass(baseline, DNA_SIGN_TEXT);
  351. for i in text:
  352. text=DNASignText("text")
  353. text.setLetters(i)
  354. baseline.add(text)
  355. class LevelEditor(NodePath, PandaObject):
  356. """Class used to create a Toontown LevelEditor object"""
  357. # Init the list of callbacks:
  358. selectedNodePathHookHooks=[]
  359. deselectedNodePathHookHooks=[]
  360. # Primary variables:
  361. # DNAData: DNA object holding DNA info about level
  362. # DNAToplevel: Top level DNA Node, all DNA objects descend from this node
  363. # NPToplevel: Corresponding Node Path
  364. # DNAParent: Current DNA Node that new objects get added to
  365. # NPParent: Corresponding Node Path
  366. # DNAVisGroup: Current DNAVisGroup that new objects get added to
  367. # NPVisGroup: Corresponding Node Path
  368. # selectedDNARoot: DNA Node of currently selected object
  369. # selectedNPRoot: Corresponding Node Path
  370. # DNATarget: Subcomponent being modified by Pie Menu
  371. def __init__(self, hoods = hoods):
  372. # Make the level editor a node path so that you can show/hide
  373. # The level editor separately from loading/saving the top level node
  374. # Initialize superclass
  375. NodePath.__init__(self)
  376. # Become the new node path
  377. self.assign(hidden.attachNewNode('LevelEditor'))
  378. # Enable replaceSelected by default:
  379. self.replaceSelectedEnabled=1
  380. self.removeHookList=[self.landmarkBlockRemove]
  381. # Start block ID at 0 (it will be incremented before use (to 1)):
  382. self.landmarkBlock=0
  383. # Create ancillary objects
  384. # Style manager for keeping track of styles/colors
  385. self.styleManager = LevelStyleManager()
  386. # Load neighborhood maps
  387. self.createLevelMaps()
  388. # Marker for showing next insertion point
  389. self.createInsertionMarker()
  390. # Create level Editor Panel
  391. self.panel = LevelEditorPanel(self)
  392. # Used to store whatever edges and points are loaded in the level
  393. self.edgeDict = {}
  394. self.pointDict = {}
  395. self.point2edgeDict = {}
  396. self.cellDict = {}
  397. self.visitedPoints = []
  398. self.visitedEdges = []
  399. # Initialize LevelEditor variables DNAData, DNAToplevel, NPToplevel
  400. # DNAParent, NPParent, groupNum, lastAngle
  401. # Pass in the new toplevel group and don't clear out the old
  402. # toplevel group (since it doesn't exist yet)
  403. self.reset(fDeleteToplevel = 0, fCreateToplevel = 1)
  404. # The list of events the level editor responds to
  405. self.actionEvents = [
  406. # Node path events
  407. ('preRemoveNodePath', self.removeNodePathHook),
  408. # Actions in response to DIRECT operations
  409. ('DIRECT_selectedNodePath', self.selectedNodePathHook),
  410. ('DIRECT_deselectedNodePath', self.deselectedNodePathHook),
  411. ('DIRECT_manipulateObjectCleanup', self.updateSelectedPose),
  412. ('DIRECT_nodePathSetName', self.setName),
  413. ('DIRECT_activeParent', self.setActiveParent),
  414. ('DIRECT_reparent', self.reparent),
  415. ('RGBPanel_setColor', self.setColor),
  416. # Actions in response to Level Editor Panel operations
  417. ('SGE_Add Group', self.addGroup),
  418. ('SGE_Add Vis Group', self.addVisGroup),
  419. # Actions in response to Pie Menu interaction
  420. ('select_building_style_all', self.setBuildingStyle),
  421. ('select_building_type', self.setBuildingType),
  422. ('select_building_width', self.setBuildingWidth),
  423. ('select_cornice_color', self.setDNATargetColor),
  424. ('select_cornice_orientation', self.setDNATargetOrientation),
  425. ('select_cornice_texture', self.setDNATargetCode, ['cornice']),
  426. ('select_sign_color', self.setDNATargetColor),
  427. ('select_sign_orientation', self.setDNATargetOrientation),
  428. ('select_sign_texture', self.setDNATargetCode, ['sign']),
  429. ('select_baseline_style', self.panel.setSignBaselineStyle),
  430. ('select_door_color', self.setDNATargetColor),
  431. ('select_door_orientation', self.setDNATargetOrientation),
  432. ('select_door_texture', self.setDNATargetCode, ['door']),
  433. ('select_door_awning_texture', self.setDNATargetCode,
  434. ['door_awning']),
  435. ('select_door_awning_color', self.setDNATargetColor),
  436. ('select_window_color', self.setDNATargetColor),
  437. ('select_window_count', self.setWindowCount),
  438. ('select_window_orientation', self.setDNATargetOrientation),
  439. ('select_window_texture', self.setDNATargetCode, ['windows']),
  440. ('select_window_awning_texture', self.setDNATargetCode,
  441. ['window_awning']),
  442. ('select_window_awning_color', self.setDNATargetColor),
  443. ('select_wall_style', self.setWallStyle),
  444. ('select_wall_color', self.setDNATargetColor),
  445. ('select_wall_orientation', self.setDNATargetOrientation),
  446. ('select_wall_texture', self.setDNATargetCode, ['wall']),
  447. ('select_toon_landmark_texture', self.setDNATargetCode,
  448. ['landmark']),
  449. ('select_toon_landmark_door_color', self.setDNATargetColor),
  450. ('select_toon_landmark_door_orientation',
  451. self.setDNATargetOrientation),
  452. ('select_landmark_door_texture', self.setDNATargetCode,
  453. ['landmark_door']),
  454. ('select_street_texture', self.setDNATargetCode, ['street']),
  455. ('select_prop_texture', self.setDNATargetCode, ['prop']),
  456. ('select_prop_color', self.setDNATargetColor),
  457. # Hot key actions
  458. ('a', self.autoPositionGrid),
  459. ('j', self.jumpToInsertionPoint),
  460. ('left', self.keyboardXformSelected, ['left']),
  461. ('right', self.keyboardXformSelected, ['right']),
  462. ('up', self.keyboardXformSelected, ['up']),
  463. ('down', self.keyboardXformSelected, ['down']),
  464. ('S', self.placeSuitPoint),
  465. ('C', self.placeBattleCell),
  466. ('o', self.addToLandmarkBlock),
  467. ('O', self.toggleShowLandmarkBlock),
  468. ('%', self.pdbBreak),
  469. ]
  470. # Initialize state
  471. # Make sure direct is running
  472. direct.enable()
  473. # And only the appropriate handles are showing
  474. direct.widget.disableHandles(['x-ring', 'x-disc',
  475. 'y-ring', 'y-disc',
  476. 'z-post'])
  477. # Initialize camera
  478. base.cam.node().setNear(1.0)
  479. base.cam.node().setFar(3000)
  480. direct.camera.setPos(0,-10,10)
  481. # Initialize drive mode
  482. self.configureDriveModeCollisionData()
  483. # Init visibility variables
  484. self.__zoneId = None
  485. # Hide (disable) grid initially
  486. self.showGrid(0)
  487. # Create variable for vis groups panel
  488. self.vgpanel = None
  489. # Start off enabled
  490. self.enable()
  491. # SUIT POINTS
  492. # Create a sphere model to show suit points
  493. self.suitPointMarker = loader.loadModel('models/misc/sphere')
  494. self.suitPointMarker.setScale(0.25)
  495. # Initialize the suit points
  496. self.startSuitPoint = None
  497. self.endSuitPoint = None
  498. self.currentSuitPointType = DNASuitPoint.STREETPOINT
  499. # BATTLE CELLS
  500. self.battleCellMarker = loader.loadModel('models/misc/sphere')
  501. self.battleCellMarker.setName('battleCellMarker')
  502. self.battleCellMarker.setScale(1)
  503. self.currentBattleCellType = "20w 20l"
  504. # Update panel
  505. # Editing the first hood id on the list
  506. self.setEditMode(NEIGHBORHOODS[0])
  507. # Start of with first item in lists
  508. self.panel.streetSelector.selectitem(0)
  509. self.panel.streetSelector.invoke()
  510. self.panel.toonBuildingSelector.selectitem(0)
  511. self.panel.toonBuildingSelector.invoke()
  512. self.panel.landmarkBuildingSelector.selectitem(0)
  513. self.panel.landmarkBuildingSelector.invoke()
  514. self.panel.propSelector.selectitem(0)
  515. self.panel.propSelector.invoke()
  516. # Start off with 20 foot buildings
  517. self.panel.twentyFootButton.invoke()
  518. # Update scene graph explorer
  519. self.panel.sceneGraphExplorer.update()
  520. # ENABLE/DISABLE
  521. def enable(self):
  522. """ Enable level editing and show level """
  523. # Make sure level is visible
  524. self.reparentTo(direct.group)
  525. self.show()
  526. # Add all the action events
  527. for event in self.actionEvents:
  528. if len(event) == 3:
  529. self.accept(event[0], event[1], event[2])
  530. else:
  531. self.accept(event[0], event[1])
  532. # Enable mouse interaction (pie menus)
  533. self.enableMouse()
  534. # Spawn task to keep insertion marker aligned with grid
  535. self.spawnInsertionMarkerTask()
  536. def disable(self):
  537. """ Disable level editing and hide level """
  538. # Deselect everything as a precaution
  539. direct.deselectAll()
  540. # Hide the level
  541. self.reparentTo(hidden)
  542. # Ignore the hooks
  543. for eventPair in self.actionEvents:
  544. self.ignore(eventPair[0])
  545. # These are added outside of actionEvents list
  546. self.ignore('insert')
  547. self.ignore('space')
  548. # Disable Pie Menu mouse interaction
  549. self.disableMouse()
  550. # Remove insertion marker task
  551. taskMgr.removeTasksNamed('insertionMarkerTask')
  552. def reset(self, fDeleteToplevel = 1, fCreateToplevel = 1,
  553. fUpdateExplorer = 1):
  554. """
  555. Reset level and re-initialize main class variables
  556. Pass in the new top level group
  557. """
  558. # Reset path markers
  559. self.resetPathMarkers()
  560. # Reset battle cell markers
  561. self.resetBattleCellMarkers()
  562. if fDeleteToplevel:
  563. # First destroy existing scene-graph/DNA hierarchy
  564. self.deleteToplevel()
  565. # Clear DNASTORE
  566. DNASTORE.resetDNAGroups()
  567. # Reset DNA VIS Groups
  568. DNASTORE.resetDNAVisGroups()
  569. DNASTORE.resetSuitPoints()
  570. DNASTORE.resetBattleCells()
  571. # Create fresh DNA DATA
  572. self.DNAData = DNAData('level_data')
  573. # Create new toplevel node path and DNA
  574. if fCreateToplevel:
  575. self.createToplevel(DNANode('level'))
  576. # Initialize variables
  577. # Reset grid
  578. direct.grid.setPosHprScale(0,0,0,0,0,0,1,1,1)
  579. # The selected DNA Object/NodePath
  580. self.selectedDNARoot = None
  581. self.selectedNPRoot = None
  582. self.selectedSuitPoint = None
  583. self.lastLandmarkBuildingDNA = None
  584. self.showLandmarkBlockToggleGroup = None
  585. # Set active target (the subcomponent being modified)
  586. self.DNATarget = None
  587. self.DNATargetParent = None
  588. # Set count of groups added to level
  589. self.setGroupNum(0)
  590. # Heading angle of last object added to level
  591. self.setLastAngle(0.0)
  592. # Last wall and building modified using pie menus
  593. self.lastSign = None
  594. self.lastWall = None
  595. self.lastBuilding = None
  596. # Code of last selected object (for autopositionGrid)
  597. self.snapList = []
  598. # Last menu used
  599. self.activeMenu = None
  600. # For highlighting suit paths
  601. self.visitedPoints = []
  602. self.visitedEdges = []
  603. # Update scene graph explorer
  604. if fUpdateExplorer:
  605. self.panel.sceneGraphExplorer.update()
  606. def deleteToplevel(self):
  607. # Destory old toplevel node path and DNA
  608. # First the toplevel DNA
  609. self.DNAData.remove(self.DNAToplevel)
  610. if self.NPToplevel.hasArcs():
  611. # Then the toplevel Node Path
  612. self.NPToplevel.reparentTo(hidden)
  613. self.NPToplevel.removeNode()
  614. def createToplevel(self, dnaNode, nodePath = None):
  615. # When you create a new level, data is added to this node
  616. # When you load a DNA file, you replace this node with the new data
  617. self.DNAToplevel = dnaNode
  618. self.DNAData.add(self.DNAToplevel)
  619. if nodePath:
  620. # Node path given, use it
  621. self.NPToplevel = nodePath
  622. self.NPToplevel.reparentTo(self)
  623. else:
  624. # No node path given, traverse
  625. self.NPToplevel = self.DNAToplevel.traverse(self, DNASTORE, 1)
  626. # Update parent pointers
  627. self.DNAParent = self.DNAToplevel
  628. self.NPParent = self.NPToplevel
  629. self.VGParent = None
  630. # Add toplevel node path for suit points
  631. self.suitPointToplevel = self.NPToplevel.attachNewNode('suitPoints')
  632. def destroy(self):
  633. """ Disable level editor and destroy node path """
  634. self.disable()
  635. self.removeNode()
  636. self.panel.destroy()
  637. if self.vgpanel:
  638. self.vgpanel.destroy()
  639. def useDirectFly(self):
  640. """ Disable player camera controls/enable direct camera control """
  641. # Turn off collision traversal
  642. self.traversalOff()
  643. # Turn on collisions
  644. self.collisionsOff()
  645. # Turn on visiblity
  646. self.visibilityOff()
  647. # Reset cam
  648. base.camera.iPos(base.cam)
  649. base.cam.iPosHpr()
  650. # Renable mouse
  651. self.enableMouse()
  652. direct.enable()
  653. def useDriveMode(self):
  654. """ Lerp down to eye level then switch to Drive mode """
  655. pos = direct.camera.getPos()
  656. pos.setZ(4.0)
  657. hpr = direct.camera.getHpr()
  658. hpr.set(hpr[0], 0.0, 0.0)
  659. t = direct.camera.lerpPosHpr(pos, hpr, 1.0, blendType = 'easeInOut',
  660. task = 'manipulateCamera')
  661. # Note, if this dies an unatural death, this could screw things up
  662. t.uponDeath = self.switchToDriveMode
  663. def switchToDriveMode(self,state):
  664. """ Disable direct camera manipulation and enable player drive mode """
  665. direct.minimumConfiguration()
  666. direct.manipulationControl.disableManipulation()
  667. # Update vis data
  668. self.initVisibilityData()
  669. # Switch to drive mode
  670. base.useDrive()
  671. # Move cam up and back
  672. base.cam.setPos(0,-5,4)
  673. # And move down and forward to compensate
  674. base.camera.setPos(base.camera, 0, 5, -4)
  675. # Make sure we're where we want to be
  676. pos = direct.camera.getPos()
  677. pos.setZ(0.0)
  678. hpr = direct.camera.getHpr()
  679. hpr.set(hpr[0], 0.0, 0.0)
  680. # Fine tune the drive mode
  681. base.mouseInterface.node().setPos(pos)
  682. base.mouseInterface.node().setHpr(hpr)
  683. base.mouseInterface.node().setForwardSpeed(20.0)
  684. base.mouseInterface.node().setReverseSpeed(20.0)
  685. # Turn on collisions
  686. if self.panel.fColl.get():
  687. self.collisionsOn()
  688. # Turn on visiblity
  689. if self.panel.fVis.get():
  690. self.visibilityOn()
  691. # Turn on collision traversal
  692. if self.panel.fColl.get() or self.panel.fVis.get():
  693. self.traversalOn()
  694. def configureDriveModeCollisionData(self):
  695. """initializeCollisions(self)
  696. Set up the local avatar for collisions
  697. """
  698. # Set up the collision sphere
  699. # This is a sphere on the ground to detect barrier collisions
  700. self.cSphere = CollisionSphere(0.0, 0.0, 0.0, 1.5)
  701. self.cSphereNode = CollisionNode('cSphereNode')
  702. self.cSphereNode.addSolid(self.cSphere)
  703. self.cSphereNodePath = camera.attachNewNode(self.cSphereNode)
  704. self.cSphereNodePath.hide()
  705. self.cSphereBitMask = BitMask32.bit(0)
  706. self.cSphereNode.setFromCollideMask(self.cSphereBitMask)
  707. self.cSphereNode.setIntoCollideMask(BitMask32.allOff())
  708. # Set up the collison ray
  709. # This is a ray cast from your head down to detect floor polygons
  710. self.cRay = CollisionRay(0.0, 0.0, 6.0, 0.0, 0.0, -1.0)
  711. self.cRayNode = CollisionNode('cRayNode')
  712. self.cRayNode.addSolid(self.cRay)
  713. self.cRayNodePath = camera.attachNewNode(self.cRayNode)
  714. self.cRayNodePath.hide()
  715. self.cRayBitMask = BitMask32.bit(1)
  716. self.cRayNode.setFromCollideMask(self.cRayBitMask)
  717. self.cRayNode.setIntoCollideMask(BitMask32.allOff())
  718. # set up wall collision mechanism
  719. self.pusher = CollisionHandlerPusher()
  720. self.pusher.setInPattern("enter%in")
  721. self.pusher.setOutPattern("exit%in")
  722. # set up floor collision mechanism
  723. self.lifter = CollisionHandlerFloor()
  724. self.lifter.setInPattern("on-floor")
  725. self.lifter.setOutPattern("off-floor")
  726. self.floorOffset = 0.1
  727. self.lifter.setOffset(self.floorOffset)
  728. # Limit our rate-of-fall with the lifter.
  729. # If this is too low, we actually "fall" off steep stairs
  730. # and float above them as we go down. I increased this
  731. # from 8.0 to 16.0 to prevent this
  732. self.lifter.setMaxVelocity(16.0)
  733. # set up the collision traverser
  734. self.cTrav = CollisionTraverser()
  735. # activate the collider with the traverser and pusher
  736. self.pusher.addCollider(self.cSphereNode, base.drive.node())
  737. self.lifter.addCollider(self.cRayNode, base.drive.node())
  738. # A map of zone ID's to a list of nodes that are visible from
  739. # that zone.
  740. self.nodeDict = {}
  741. # A map of zone ID's to the particular node that corresponds
  742. # to that zone.
  743. self.zoneDict = {}
  744. # A list of all visible nodes
  745. self.nodeList = []
  746. # Flag for bootstrapping visibility
  747. self.fVisInit = 0
  748. def traversalOn(self):
  749. base.cTrav = self.cTrav
  750. def traversalOff(self):
  751. base.cTrav = 0
  752. def collisionsOff(self):
  753. self.cTrav.removeCollider(self.cSphereNode)
  754. def collisionsOn(self):
  755. self.collisionsOff()
  756. self.cTrav.addCollider(self.cSphereNode, self.pusher)
  757. def toggleCollisions(self):
  758. if self.panel.fColl.get():
  759. print 'ON'
  760. self.collisionsOn()
  761. self.traversalOn()
  762. else:
  763. self.collisionsOff()
  764. if (not (self.panel.fColl.get() or self.panel.fVis.get())):
  765. self.traversalOff()
  766. def initVisibilityData(self):
  767. # First make sure everything is shown
  768. self.showAllVisibles()
  769. # A map of zone ID's to a list of nodes that are visible from
  770. # that zone.
  771. self.nodeDict = {}
  772. # A map of zone ID's to the particular node that corresponds
  773. # to that zone.
  774. self.zoneDict = {}
  775. # A list of all visible nodes
  776. self.nodeList = []
  777. # NOTE: this should change to find the groupnodes in
  778. # the dna storage instead of searching through the tree
  779. for i in range(DNASTORE.getNumDNAVisGroups()):
  780. groupFullName = DNASTORE.getDNAVisGroupName(i)
  781. groupName = self.extractGroupName(groupFullName)
  782. zoneId = int(groupName)
  783. self.nodeDict[zoneId] = []
  784. self.zoneDict[zoneId] = self.NPToplevel.find("**/" + groupName)
  785. # TODO: we only need to look from the top of the hood
  786. # down one level to find the vis groups as an optimization
  787. groupNode = self.NPToplevel.find("**/" + groupFullName)
  788. if groupNode.isEmpty():
  789. print "Could not find visgroup"
  790. self.nodeList.append(groupNode)
  791. for j in range(DNASTORE.getNumVisiblesInDNAVisGroup(i)):
  792. visName = DNASTORE.getVisibleName(i, j)
  793. visNode = self.NPToplevel.find("**/" + visName)
  794. self.nodeDict[zoneId].append(visNode)
  795. # Rename the floor polys to have the same name as the
  796. # visgroup they are in... This makes visibility possible.
  797. self.renameFloorPolys(self.nodeList)
  798. # Init vis flag
  799. self.fVisInit = 1
  800. def extractGroupName(self, groupFullName):
  801. # The Idea here is that group names may have extra flags associated
  802. # with them that tell more information about what is special about
  803. # the particular vis zone. A normal vis zone might just be "13001",
  804. # but a special one might be "14356:safe_zone" or
  805. # "345:safe_zone:exit_zone"... These are hypotheticals. The main
  806. # idea is that there are colon separated flags after the initial
  807. # zone name.
  808. return(string.split(groupFullName, ":", 1)[0])
  809. def renameFloorPolys(self, nodeList):
  810. for i in nodeList:
  811. # Get all the collision nodes in the vis group
  812. collNodePaths = i.findAllMatches("**/+CollisionNode")
  813. numCollNodePaths = collNodePaths.getNumPaths()
  814. visGroupName = i.node().getName()
  815. for j in range(numCollNodePaths):
  816. collNodePath = collNodePaths.getPath(j)
  817. bitMask = collNodePath.node().getIntoCollideMask()
  818. if bitMask.getBit(1):
  819. # Bit 1 is the floor collision bit. This renames
  820. # all floor collision polys to the same name as their
  821. # visgroup.
  822. collNodePath.node().setName(visGroupName)
  823. def hideAllVisibles(self):
  824. for i in self.nodeList:
  825. i.hide()
  826. def showAllVisibles(self):
  827. for i in self.nodeList:
  828. i.show()
  829. i.clearColor()
  830. def visibilityOn(self):
  831. self.visibilityOff()
  832. # Accept event
  833. self.accept("on-floor", self.enterZone)
  834. # Add collider
  835. self.cTrav.addCollider(self.cRayNode, self.lifter)
  836. # Reset lifter
  837. self.lifter.clear()
  838. # Reset flag
  839. self.fVisInit = 1
  840. def visibilityOff(self):
  841. self.ignore("on-floor")
  842. self.cTrav.removeCollider(self.cRayNode)
  843. self.showAllVisibles()
  844. def toggleVisibility(self):
  845. if self.panel.fVis.get():
  846. self.visibilityOn()
  847. self.traversalOn()
  848. else:
  849. self.visibilityOff()
  850. if (not (self.panel.fColl.get() or self.panel.fVis.get())):
  851. self.traversalOff()
  852. def enterZone(self, newZone):
  853. """
  854. Puts the toon in the indicated zone. newZone may either be a
  855. CollisionEntry object as determined by a floor polygon, or an
  856. integer zone id. It may also be None, to indicate no zone.
  857. """
  858. # First entry into a zone, hide everything
  859. if self.fVisInit:
  860. self.hideAllVisibles()
  861. self.fVisInit = 0
  862. # Get zone id
  863. if isinstance(newZone, CollisionEntry):
  864. # Get the name of the collide node
  865. newZoneId = int(newZone.getIntoNode().getName())
  866. else:
  867. newZoneId = newZone
  868. # Ensure we have vis data
  869. assert(self.nodeDict)
  870. # Hide the old zone (if there is one)
  871. if self.__zoneId != None:
  872. for i in self.nodeDict[self.__zoneId]:
  873. i.hide()
  874. # Show the new zone
  875. if newZoneId != None:
  876. for i in self.nodeDict[newZoneId]:
  877. i.show()
  878. # Make sure we changed zones
  879. if newZoneId != self.__zoneId:
  880. if self.panel.fVisZones.get():
  881. # Set a color override on our zone to make it obvious what
  882. # zone we're in.
  883. if self.__zoneId != None:
  884. self.zoneDict[self.__zoneId].clearColor()
  885. if newZoneId != None:
  886. self.zoneDict[newZoneId].setColor(0, 0, 1, 1, 100)
  887. # The new zone is now old
  888. self.__zoneId = newZoneId
  889. def enableMouse(self):
  890. """ Enable Pie Menu interaction (and disable player camera control) """
  891. # Turn off player camera control
  892. base.disableMouse()
  893. # Handle mouse events for pie menus
  894. self.accept('DIRECT_mouse3',self.levelHandleMouse3)
  895. self.accept('DIRECT_mouse3Up',self.levelHandleMouse3Up)
  896. def disableMouse(self):
  897. """ Disable Pie Menu interaction """
  898. # Disable handling of mouse events
  899. self.ignore('DIRECT_mouse3')
  900. self.ignore('DIRECT_mouse3Up')
  901. # LEVEL OBJECT MANAGEMENT FUNCTIONS
  902. def findDNANode(self, nodePath):
  903. """ Find node path's DNA Object in DNAStorage (if any) """
  904. if nodePath:
  905. return DNASTORE.findDNAGroup(nodePath.id())
  906. else:
  907. return None
  908. def replaceSelected(self):
  909. if self.replaceSelectedEnabled:
  910. # Update visible geometry using new DNA
  911. newRoot = self.replace(self.selectedNPRoot, self.selectedDNARoot)
  912. # Reselect node path and respawn followSelectedNodePathTask
  913. direct.select(newRoot)
  914. def replace(self, nodePath, dnaNode):
  915. """ Replace a node path with the results of a DNANode traversal """
  916. # Find node path's parent
  917. parent = nodePath.getParent()
  918. dnaParent = dnaNode.getParent()
  919. # Get rid of the old node path and remove its DNA and
  920. # node relations from the DNA Store
  921. self.remove(dnaNode, nodePath)
  922. # Traverse the old (modified) dna to create the new node path
  923. newNodePath = dnaNode.traverse(parent, DNASTORE, 1)
  924. # Add it back to the dna parent
  925. dnaParent.add(dnaNode)
  926. # Update scene graph explorer
  927. # self.panel.sceneGraphExplorer.update()
  928. # Return new node path
  929. return newNodePath
  930. def remove(self, dnaNode, nodePath):
  931. """
  932. Delete DNA and Node relation from DNA Store and remove the node
  933. path from the scene graph.
  934. """
  935. # First delete DNA and node relation from the DNA Store
  936. if dnaNode:
  937. # Get DNANode's parent
  938. parentDNANode = dnaNode.getParent()
  939. if parentDNANode:
  940. # Remove DNANode from its parent
  941. parentDNANode.remove(dnaNode)
  942. # Delete DNA and associated Node Relations from DNA Store
  943. DNASTORE.removeDNAGroup(dnaNode)
  944. if nodePath:
  945. # Next deselect nodePath to avoid having bad node paths in the dict
  946. direct.deselect(nodePath)
  947. # Now you can get rid of the node path
  948. nodePath.removeNode()
  949. def removeNodePathHook(self, nodePath):
  950. dnaNode = self.findDNANode(nodePath)
  951. # Does the node path correspond to a DNA Object
  952. if dnaNode:
  953. for hook in self.removeHookList:
  954. hook(dnaNode, nodePath)
  955. # Get DNANode's parent
  956. parentDNANode = dnaNode.getParent()
  957. if parentDNANode:
  958. # Remove DNANode from its parent
  959. parentDNANode.remove(dnaNode)
  960. # Delete DNA and associated Node Relations from DNA Store
  961. DNASTORE.removeDNAGroup(dnaNode)
  962. else:
  963. pointOrCell, type = self.findPointOrCell(nodePath)
  964. if pointOrCell and type:
  965. if (type == 'suitPointMarker'):
  966. print 'Suit Point:', pointOrCell
  967. if DNASTORE.removeSuitPoint(pointOrCell):
  968. print "Removed from DNASTORE"
  969. else:
  970. print "Not found in DNASTORE"
  971. # Remove point from pointDict
  972. del(self.pointDict[pointOrCell])
  973. # Remove point from visitedPoints list
  974. if pointOrCell in self.visitedPoints:
  975. self.visitedPoints.remove(pointOrCell)
  976. # Update edge related dictionaries
  977. for edge in self.point2edgeDict[pointOrCell]:
  978. # Is it still in edge dict?
  979. oldEdgeLine = self.edgeDict.get(edge, None)
  980. if oldEdgeLine:
  981. del self.edgeDict[edge]
  982. oldEdgeLine.reset()
  983. del oldEdgeLine
  984. # Find other endpoints of edge and clear out
  985. # corresponding point2edgeDict entry
  986. startPoint = edge.getStartPoint()
  987. endPoint = edge.getEndPoint()
  988. if pointOrCell == startPoint:
  989. self.point2edgeDict[endPoint].remove(edge)
  990. elif pointOrCell == endPoint:
  991. self.point2edgeDict[startPoint].remove(edge)
  992. # Is it in the visited edges list?
  993. if edge in self.visitedEdges:
  994. self.visitedEdges.remove(edge)
  995. # Now delete point2edgeDict entry for this point
  996. del(self.point2edgeDict[pointOrCell])
  997. elif (type == 'battleCellMarker'):
  998. # Get parent vis group
  999. visGroupNP, visGroupDNA = self.findParentVisGroup(nodePath)
  1000. print 'Battle Cell:', pointOrCell
  1001. # Remove cell from vis group
  1002. if visGroupNP and visGroupDNA:
  1003. if visGroupDNA.removeBattleCell(pointOrCell):
  1004. print "Removed from Vis Group"
  1005. else:
  1006. print "Not found in Vis Group"
  1007. else:
  1008. print "Parent Vis Group not found"
  1009. # Remove cell from DNASTORE
  1010. if DNASTORE.removeBattleCell(pointOrCell):
  1011. print "Removed from DNASTORE"
  1012. else:
  1013. print "Not found in DNASTORE"
  1014. # Remove cell from cellDict
  1015. del(self.cellDict[pointOrCell])
  1016. def reparent(self, nodePath, oldParent, newParent):
  1017. """ Move node path (and its DNA) to active parent """
  1018. # Does the node path correspond to a DNA Object
  1019. dnaNode = self.findDNANode(nodePath)
  1020. if dnaNode:
  1021. # Find old parent DNA
  1022. oldParentDNANode = self.findDNANode(oldParent)
  1023. # Remove DNA from old parent
  1024. if oldParentDNANode:
  1025. oldParentDNANode.remove(dnaNode)
  1026. if newParent:
  1027. # Update active parent just to be safe
  1028. self.setActiveParent(newParent)
  1029. # Move DNA to new parent (if active parent set)
  1030. if self.DNAParent != None:
  1031. self.DNAParent.add(dnaNode)
  1032. # It is, is it a DNA_NODE (i.e. it has pos/hpr/scale)?
  1033. # Update pose to reflect new relationship
  1034. if DNAIsDerivedFrom(dnaNode, DNA_NODE):
  1035. # Update DNA
  1036. self.updatePose(dnaNode, nodePath)
  1037. def setActiveParent(self, nodePath = None):
  1038. """ Set NPParent and DNAParent to node path and its DNA """
  1039. # If we've got a valid node path
  1040. if nodePath:
  1041. # See if this is in the DNA database
  1042. newDNAParent = self.findDNANode(nodePath)
  1043. if newDNAParent:
  1044. self.DNAParent = newDNAParent
  1045. self.NPParent = nodePath
  1046. else:
  1047. print 'LevelEditor.setActiveParent: nodePath not found'
  1048. else:
  1049. print 'LevelEditor.setActiveParent: nodePath == None'
  1050. def setName(self, nodePath, newName):
  1051. """ Set name of nodePath's DNA (if it exists) """
  1052. # Find the DNA that corresponds to this node path
  1053. dnaNode = self.findDNANode(nodePath)
  1054. if dnaNode:
  1055. # If it exists, set the name of the DNA Node
  1056. dnaNode.setName(newName)
  1057. def updateSelectedPose(self):
  1058. """
  1059. Update the DNA database to reflect selected objects current positions
  1060. """
  1061. for selectedNode in direct.selected:
  1062. # Is this a DNA Object in the DNASTORE database?
  1063. dnaObject = self.findDNANode(selectedNode)
  1064. if dnaObject:
  1065. # It is, is it a DNA_NODE (i.e. does it have pos/hpr/scale)?
  1066. if DNAIsDerivedFrom(dnaObject, DNA_NODE):
  1067. # First snap selected node path to grid
  1068. pos = selectedNode.getPos(direct.grid)
  1069. snapPos = direct.grid.computeSnapPoint(pos)
  1070. if self.panel.fPlaneSnap.get():
  1071. zheight = 0
  1072. else:
  1073. zheight = snapPos[2]
  1074. selectedNode.setPos(direct.grid,
  1075. snapPos[0], snapPos[1], zheight)
  1076. # Angle snap
  1077. h = direct.grid.computeSnapAngle(selectedNode.getH())
  1078. selectedNode.setH(h)
  1079. if selectedNode == direct.selected.last:
  1080. self.setLastAngle(h)
  1081. # Update DNA
  1082. self.updatePose(dnaObject, selectedNode)
  1083. else:
  1084. pointOrCell, type = self.findPointOrCell(selectedNode)
  1085. if pointOrCell and type:
  1086. # First snap selected node path to grid
  1087. pos = selectedNode.getPos(direct.grid)
  1088. snapPos = direct.grid.computeSnapPoint(pos)
  1089. if self.panel.fPlaneSnap.get():
  1090. zheight = 0
  1091. else:
  1092. zheight = snapPos[2]
  1093. selectedNode.setPos(
  1094. direct.grid,
  1095. snapPos[0], snapPos[1], zheight)
  1096. newPos = selectedNode.getPos(self.NPToplevel)
  1097. # Update DNA
  1098. pointOrCell.setPos(newPos)
  1099. if (type == 'suitPointMarker'):
  1100. print "Found suit point!", pointOrCell
  1101. # Ok, now update all the lines into that node
  1102. for edge in self.point2edgeDict[pointOrCell]:
  1103. # Is it still in edge dict?
  1104. oldEdgeLine = self.edgeDict.get(edge, None)
  1105. if oldEdgeLine:
  1106. del self.edgeDict[edge]
  1107. oldEdgeLine.reset()
  1108. del oldEdgeLine
  1109. newEdgeLine = self.drawSuitEdge(
  1110. edge, self.NPParent)
  1111. self.edgeDict[edge] = newEdgeLine
  1112. elif (type == 'battleCellMarker'):
  1113. print "Found battle cell!", pointOrCell
  1114. def updatePose(self, dnaObject, nodePath):
  1115. """
  1116. Update a DNA Object's pos, hpr, and scale based upon
  1117. node path's current pose
  1118. """
  1119. # Set DNA's pos, hpr, and scale
  1120. dnaObject.setPos(nodePath.getPos())
  1121. dnaObject.setHpr(nodePath.getHpr())
  1122. dnaObject.setScale(nodePath.getScale())
  1123. # LEVEL OBJECT CREATION FUNCTIONS
  1124. def initDNANode(self, dnaNode):
  1125. """
  1126. This method adds a new DNA object to the scene and adds hooks that
  1127. allow duplicate copies of this DNA node to be added using the
  1128. space bar. For DNAFlatBuildings, a new copy with random style is
  1129. generated by hitting the insert key.
  1130. """
  1131. # First create the visible geometry for this DNA Node
  1132. self.initNodePath(dnaNode)
  1133. # And add hooks to insert copies of dnaNode
  1134. self.addReplicationHooks(dnaNode)
  1135. def addReplicationHooks(self, dnaNode):
  1136. # Now add hook to allow placement of a new dna Node of this type
  1137. # by simply hitting the space bar or insert key. Note, extra paramter
  1138. # indicates new dnaNode should be a copy
  1139. self.accept('space', self.initNodePath, [dnaNode, 'space'])
  1140. self.accept('insert', self.initNodePath, [dnaNode, 'insert'])
  1141. def setRandomBuildingStyle(self, dnaNode, name = 'building'):
  1142. """ Initialize a new DNA Flat building to a random building style """
  1143. # What is the current building type?
  1144. buildingType = self.getCurrent('building_type')
  1145. # If random
  1146. if buildingType == 'random':
  1147. # Generate height list based on current building height
  1148. buildingHeight = self.getCurrent('building_height')
  1149. heightList = self.getRandomHeightList(buildingHeight)
  1150. # Convert height list to building type
  1151. buildingType = createHeightCode(heightList)
  1152. else:
  1153. # Use specified height list
  1154. heightList = map(string.atof, string.split(buildingType, '_'))
  1155. height = calcHeight(heightList)
  1156. # Is this a never before seen height list? If so, record it.
  1157. try:
  1158. attr = self.getAttribute(`height` + '_ft_wall_heights')
  1159. if heightList not in attr.getList():
  1160. print 'Adding new height list entry'
  1161. attr.add(heightList)
  1162. except KeyError:
  1163. print 'Non standard height building'
  1164. # See if this building type corresponds to existing style dict
  1165. try:
  1166. dict = self.getDict(buildingType + '_styles')
  1167. except KeyError:
  1168. # Nope
  1169. dict = {}
  1170. # No specific dict or empty dict, try to pick a dict
  1171. # based on number of walls
  1172. if not dict:
  1173. # How many walls?
  1174. numWalls = len(heightList)
  1175. # Get the building_style attribute dictionary for
  1176. # this number of walls
  1177. dict = self.getDict(`numWalls` + '_wall_styles')
  1178. if not dict:
  1179. # Still no dict, create new random style using height list
  1180. styleList = []
  1181. # Build up wall styles
  1182. for height in heightList:
  1183. wallStyle = self.getRandomDictionaryEntry(
  1184. self.getDict('wall_style'))
  1185. styleList.append((wallStyle, height))
  1186. # Create new random flat building style
  1187. style = DNAFlatBuildingStyle(styleList = styleList)
  1188. else:
  1189. # Pick a style
  1190. style = self.getRandomDictionaryEntry(dict)
  1191. # Set style....finally
  1192. self.styleManager.setDNAFlatBuildingStyle(
  1193. dnaNode, style, width = self.getRandomWallWidth(),
  1194. heightList = heightList, name = name)
  1195. def getRandomHeightList(self, buildingHeight):
  1196. # Select a list of wall heights
  1197. heightLists = self.getList(`buildingHeight` + '_ft_wall_heights')
  1198. l = len(heightLists)
  1199. if l > 0:
  1200. # If a list exists for this building height, pick randomly
  1201. return heightLists[randint(0,l - 1)]
  1202. else:
  1203. # No height lists exists for this building height, generate
  1204. chance = randint(0,100)
  1205. if buildingHeight <= 10:
  1206. return [buildingHeight]
  1207. elif buildingHeight <= 20:
  1208. if chance <= 30:
  1209. return [20]
  1210. elif chance <= 80:
  1211. return [10, 10]
  1212. else:
  1213. return [12, 8]
  1214. elif buildingHeight <= 25:
  1215. if chance <= 25:
  1216. return [3, 22]
  1217. elif chance <= 50:
  1218. return [4, 21]
  1219. elif chance <= 75:
  1220. return [3, 13, 9]
  1221. else:
  1222. return [4, 13, 8]
  1223. else:
  1224. if chance <= 20:
  1225. return [10, 20]
  1226. elif chance <= 35:
  1227. return [20, 10]
  1228. elif chance <= 75:
  1229. return [10, 10, 10]
  1230. else:
  1231. return [13, 9, 8]
  1232. def getRandomWallWidth(self):
  1233. chance = randint(0,100)
  1234. if chance <= 15:
  1235. return 5.0
  1236. elif chance <= 30:
  1237. return 10.0
  1238. elif chance <= 65:
  1239. return 15.0
  1240. elif chance <= 85:
  1241. return 20.0
  1242. else:
  1243. return 25.0
  1244. def initNodePath(self, dnaNode, hotKey = None):
  1245. """
  1246. Update DNA to reflect latest style choices and then generate
  1247. new node path and add it to the scene graph
  1248. """
  1249. # Determine dnaNode Class Type
  1250. nodeClass = DNAGetClassType(dnaNode)
  1251. # Did the user hit insert or space?
  1252. if hotKey:
  1253. # Yes, make a new copy of the dnaNode
  1254. dnaNode = dnaNode.__class__(dnaNode)
  1255. # And determine dnaNode type and perform any type specific updates
  1256. if nodeClass.eq(DNA_PROP):
  1257. dnaNode.setCode(self.getCurrent('prop_texture'))
  1258. elif nodeClass.eq(DNA_STREET):
  1259. dnaNode.setCode(self.getCurrent('street_texture'))
  1260. elif nodeClass.eq(DNA_FLAT_BUILDING):
  1261. # If insert, pick a new random style
  1262. if hotKey == 'insert':
  1263. self.setRandomBuildingStyle(dnaNode, dnaNode.getName())
  1264. # Get a new building width
  1265. self.setCurrent('building_width',
  1266. self.getRandomWallWidth())
  1267. dnaNode.setWidth(self.getCurrent('building_width'))
  1268. # Position it
  1269. # First kill autoposition task so grid can jump to its final
  1270. # destination (part of cleanup
  1271. taskMgr.removeTasksNamed('autoPositionGrid')
  1272. # Now find where to put node path
  1273. if (hotKey is not None) and nodeClass.eq(DNA_PROP):
  1274. # If its a prop and a copy, place it based upon current
  1275. # mouse position
  1276. hitPt = self.getGridIntersectionPoint()
  1277. # Attach a node, so we can set pos with respect to:
  1278. tempNode = hidden.attachNewNode('tempNode')
  1279. # Place it:
  1280. tempNode.setPos(direct.grid, hitPt)
  1281. # Copy the pos to where we really want it:
  1282. dnaNode.setPos(tempNode.getPos())
  1283. # Clean up:
  1284. tempNode.removeNode()
  1285. else:
  1286. # Place the new node path at the current grid origin
  1287. dnaNode.setPos(direct.grid.getPos())
  1288. # Initialize angle to match last object
  1289. dnaNode.setHpr(Vec3(self.getLastAngle(), 0, 0))
  1290. # Add the DNA to the active parent
  1291. self.DNAParent.add(dnaNode)
  1292. # And create the geometry
  1293. newNodePath = dnaNode.traverse(self.NPParent, DNASTORE, 1)
  1294. # Update scene graph explorer
  1295. # self.panel.sceneGraphExplorer.update()
  1296. # Reset last Code (for autoPositionGrid)
  1297. if DNAClassEqual(dnaNode, DNA_STREET):
  1298. self.snapList = OBJECT_SNAP_POINTS[dnaNode.getCode()]
  1299. # Select the instance
  1300. direct.select(newNodePath)
  1301. # Update grid to get ready for the next object
  1302. self.autoPositionGrid()
  1303. def addGroup(self, nodePath):
  1304. """ Add a new DNA Node Group to the specified Node Path """
  1305. # Set the node path as the current parent
  1306. direct.setActiveParent(nodePath)
  1307. # Add a new group to the selected parent
  1308. self.createNewGroup()
  1309. def addVisGroup(self, nodePath):
  1310. """ Add a new DNA Group to the specified Node Path """
  1311. # Set the node path as the current parent
  1312. direct.setActiveParent(nodePath)
  1313. # Add a new group to the selected parent
  1314. self.createNewGroup(type = 'vis')
  1315. def createNewGroup(self, type = 'dna'):
  1316. """ Create a new DNA Node group under the active parent """
  1317. # Create a new DNA Node group
  1318. if type == 'dna':
  1319. newDNANode = DNANode('group_' + `self.getGroupNum()`)
  1320. else:
  1321. newDNANode = DNAVisGroup('VisGroup_' + `self.getGroupNum()`)
  1322. # Increment group counter
  1323. self.setGroupNum(self.getGroupNum() + 1)
  1324. # Add new DNA Node group to the current parent DNA Object
  1325. self.DNAParent.add(newDNANode)
  1326. # The new Node group becomes the active parent
  1327. self.DNAParent = newDNANode
  1328. # Traverse it to generate the new node path as a child of NPParent
  1329. newNodePath = self.DNAParent.traverse(self.NPParent, DNASTORE, 1)
  1330. # Update NPParent to point to the new node path
  1331. self.NPParent = newNodePath
  1332. # Update scene graph explorer
  1333. # self.panel.sceneGraphExplorer.update()
  1334. def addFlatBuilding(self, buildingType):
  1335. # Create new building
  1336. newDNAFlatBuilding = DNAFlatBuilding()
  1337. self.setRandomBuildingStyle(newDNAFlatBuilding,
  1338. name = 'tb0:'+ buildingType + '_DNARoot')
  1339. # Now place new building in the world
  1340. self.initDNANode(newDNAFlatBuilding)
  1341. def getNextLandmarkBlock(self):
  1342. self.landmarkBlock=self.landmarkBlock+1
  1343. return str(self.landmarkBlock)
  1344. def addLandmark(self, landmarkType):
  1345. # Record new landmark type
  1346. self.setCurrent('toon_landmark_texture', landmarkType)
  1347. # And create new landmark building
  1348. block=self.getNextLandmarkBlock()
  1349. newDNALandmarkBuilding = DNALandmarkBuilding(
  1350. 'tb'+block+':'+landmarkType + '_DNARoot')
  1351. newDNALandmarkBuilding.setCode(landmarkType)
  1352. newDNALandmarkBuilding.setPos(VBase3(0))
  1353. newDNALandmarkBuilding.setHpr(VBase3(0))
  1354. newDNADoor = self.createDoor()
  1355. newDNALandmarkBuilding.add(newDNADoor)
  1356. # Now place new landmark building in the world
  1357. self.initDNANode(newDNALandmarkBuilding)
  1358. def addProp(self, propType):
  1359. # Record new prop type
  1360. self.setCurrent('prop_texture', propType)
  1361. # And create new prop
  1362. newDNAProp = DNAProp(propType + '_DNARoot')
  1363. newDNAProp.setCode(propType)
  1364. newDNAProp.setPos(VBase3(0))
  1365. newDNAProp.setHpr(VBase3(0))
  1366. # Now place new prop in the world
  1367. self.initDNANode(newDNAProp)
  1368. def addStreet(self, streetType):
  1369. # Record new street type
  1370. self.setCurrent('street_texture', streetType)
  1371. # And create new street
  1372. newDNAStreet = DNAStreet(streetType + '_DNARoot')
  1373. newDNAStreet.setCode(streetType)
  1374. newDNAStreet.setPos(VBase3(0))
  1375. newDNAStreet.setHpr(VBase3(0))
  1376. # Set street texture to neighborhood dependant texture
  1377. newDNAStreet.setStreetTexture(
  1378. 'street_street_' + self.neighborhoodCode + '_tex')
  1379. newDNAStreet.setSidewalkTexture(
  1380. 'street_sidewalk_' + self.neighborhoodCode + '_tex')
  1381. # Now place new street in the world
  1382. self.initDNANode(newDNAStreet)
  1383. def createCornice(self):
  1384. newDNACornice = DNACornice('cornice')
  1385. newDNACornice.setCode(self.getCurrent('cornice_texture'))
  1386. newDNACornice.setColor(self.getCurrent('cornice_color'))
  1387. return newDNACornice
  1388. def createDoor(self):
  1389. if not (self.getCurrent('door_texture')):
  1390. doorStyles = self.styleManager.attributeDictionary['door_texture'].getList()[:-1]
  1391. defaultDoorStyle = doorStyles[randint(0, len(doorStyles) - 1)]
  1392. self.setCurrent('door_texture', defaultDoorStyle)
  1393. newDNADoor = DNADoor('door')
  1394. newDNADoor.setCode(self.getCurrent('door_texture'))
  1395. newDNADoor.setColor(self.getCurrent('door_color'))
  1396. return newDNADoor
  1397. def createSign(self):
  1398. if not (self.getCurrent('sign_texture')):
  1399. defaultSignStyle = self.styleManager.attributeDictionary['sign_texture'].getList()[0]
  1400. self.setCurrent('sign_texture', defaultSignStyle)
  1401. newDNASign = DNASign('sign')
  1402. newDNASign.setCode(self.getCurrent('sign_texture'))
  1403. newDNASign.setColor(self.getCurrent('sign_color'))
  1404. #newDNASign.setColor(VBase4(0.0, 1.0, 0.0, 1.0))
  1405. #newDNASign.setScale(VBase3(2.0, 1.0, 2.0))
  1406. baseline = DNASignBaseline('baseline')
  1407. baseline.setCode("comic")
  1408. baseline.setColor(VBase4(0.0, 0.0, 0.0, 1.0))
  1409. #baseline.setKern(1.0);
  1410. #baseline.setWiggle(30.0);
  1411. #baseline.setStumble(1.0);
  1412. #baseline.setStomp(10.0);
  1413. #baseline.setWidth(16.0)
  1414. #baseline.setHeight(16.0)
  1415. baseline.setScale(VBase3(0.7, 1.0, 0.7))
  1416. newDNASign.add(baseline)
  1417. #graphic = DNASignGraphic('graphic')
  1418. #graphic.setCode("sign_general1")
  1419. #graphic.setColor(VBase4(1.0, 1.0, 0.0, 0.5))
  1420. #graphic.setScale(VBase3(.2, 1.0, .2))
  1421. #graphic.setHpr(VBase3(0.0, 0.0, 90.0))
  1422. #baseline.add(graphic)
  1423. DNASetBaselineString(baseline, "Toon Shop")
  1424. return newDNASign
  1425. def createWindows(self):
  1426. newDNAWindows = DNAWindows()
  1427. newDNAWindows.setCode(self.getCurrent('window_texture'))
  1428. newDNAWindows.setWindowCount(self.getCurrent('window_count'))
  1429. newDNAWindows.setColor(self.getCurrent('window_color'))
  1430. return newDNAWindows
  1431. def removeCornice(self, cornice, parent):
  1432. self.setCurrent('cornice_color', cornice.getColor())
  1433. DNARemoveChildOfClass(parent, DNA_CORNICE)
  1434. def removeLandmarkDoor(self, door, parent):
  1435. self.setCurrent('door_color', door.getColor())
  1436. DNARemoveChildOfClass(parent, DNA_DOOR)
  1437. def removeSign(self, sign, parent):
  1438. self.setCurrent('sign_color', sign.getColor())
  1439. DNARemoveChildOfClass(parent, DNA_SIGN)
  1440. def removeDoor(self, door, parent):
  1441. self.setCurrent('door_color', door.getColor())
  1442. DNARemoveChildOfClass(parent, DNA_DOOR)
  1443. def removeWindows(self, windows, parent):
  1444. # And record number of windows
  1445. self.setCurrent('window_color', windows.getColor())
  1446. self.setCurrent('window_count', windows.getWindowCount())
  1447. DNARemoveChildOfClass(parent, DNA_WINDOWS)
  1448. # LEVEL-OBJECT MODIFICATION FUNCTIONS
  1449. def levelHandleMouse3(self):
  1450. # Initialize dna target
  1451. self.DNATarget = None
  1452. # If nothing selected, just return
  1453. if not self.selectedNPRoot:
  1454. return
  1455. # Next check to see if the selected object is a DNA object
  1456. dnaObject = self.findDNANode(self.selectedNPRoot)
  1457. # Nope, not a DNA object, just return
  1458. if not dnaObject:
  1459. return
  1460. # Pick a menu based upon object type
  1461. if DNAClassEqual(dnaObject, DNA_FLAT_BUILDING):
  1462. # FLAT BUILDING OPERATIONS
  1463. menuMode, wallNum = self.getFlatBuildingMode(dnaObject)
  1464. # Check menuMode
  1465. if menuMode == None:
  1466. return
  1467. # Find appropriate target
  1468. wall = self.getWall(dnaObject, wallNum)
  1469. # Record bldg/wall
  1470. self.lastBuilding = dnaObject
  1471. self.lastWall = wall
  1472. if string.find(menuMode,'wall') >= 0:
  1473. self.DNATarget = wall
  1474. self.DNATargetParent = dnaObject
  1475. elif string.find(menuMode,'door') >= 0:
  1476. self.DNATarget = DNAGetChildOfClass(wall, DNA_DOOR)
  1477. self.DNATargetParent = wall
  1478. elif string.find(menuMode, 'window') >= 0:
  1479. self.DNATarget = DNAGetChildOfClass(wall, DNA_WINDOWS)
  1480. self.DNATargetParent = wall
  1481. elif string.find(menuMode,'cornice') >= 0:
  1482. self.DNATarget = DNAGetChildOfClass(wall, DNA_CORNICE)
  1483. self.DNATargetParent = wall
  1484. else:
  1485. self.DNATarget = dnaObject
  1486. elif DNAClassEqual(dnaObject, DNA_PROP):
  1487. # PROP OPERATIONS
  1488. self.DNATarget = dnaObject
  1489. if direct.fControl:
  1490. menuMode = 'prop_color'
  1491. elif direct.fShift:
  1492. menuMode = 'sign_texture'
  1493. self.DNATarget = DNAGetChildOfClass(dnaObject, DNA_SIGN)
  1494. self.DNATargetParent = dnaObject
  1495. else:
  1496. menuMode = 'prop_texture'
  1497. elif DNAClassEqual(dnaObject, DNA_LANDMARK_BUILDING):
  1498. # INSERT HERE
  1499. # LANDMARK BUILDING OPERATIONS
  1500. menuMode = self.getLandmarkBuildingMode(dnaObject)
  1501. if string.find(menuMode, 'door') >= 0:
  1502. self.DNATarget = DNAGetChildOfClass(dnaObject, DNA_DOOR)
  1503. self.DNATargetParent = dnaObject
  1504. elif string.find(menuMode, 'sign') >= 0:
  1505. self.DNATarget = DNAGetChildOfClass(dnaObject, DNA_SIGN)
  1506. self.DNATargetParent = dnaObject
  1507. else:
  1508. self.DNATarget = dnaObject
  1509. elif DNAClassEqual(dnaObject, DNA_STREET):
  1510. # STREET OPERATIONS
  1511. self.DNATarget = dnaObject
  1512. menuMode = 'street_texture'
  1513. # No valid menu mode, get the hell out of here!
  1514. if menuMode == None:
  1515. return
  1516. # Now spawn apropriate menu task if menu selected
  1517. self.activeMenu = self.getMenu(menuMode)
  1518. # Set initial state
  1519. state = None
  1520. if self.DNATarget:
  1521. if string.find(menuMode,'texture') >= 0:
  1522. state = self.DNATarget.getCode()
  1523. elif string.find(menuMode, 'color') >= 0:
  1524. state = self.DNATarget.getColor()
  1525. self.panel.setCurrentColor(state)
  1526. self.panel.setResetColor(state)
  1527. elif string.find(menuMode, 'orientation') >= 0:
  1528. state = self.DNATarget.getCode()[-2:]
  1529. elif menuMode == 'building_width':
  1530. state = self.DNATarget.getWidth()
  1531. elif menuMode == 'window_count':
  1532. state = self.DNATarget.getWindowCount()
  1533. elif menuMode == 'building_style_all':
  1534. # Extract the building style from the current building
  1535. state = DNAFlatBuildingStyle(building = self.DNATarget)
  1536. elif menuMode == 'baseline_style':
  1537. # Extract the baseline style
  1538. state = DNABaselineStyle(
  1539. baseline = self.panel.currentBaselineDNA)
  1540. elif menuMode == 'wall_style':
  1541. # Extract the wall style from the current wall
  1542. state = DNAWallStyle(wall = self.DNATarget)
  1543. self.activeMenu.setInitialState(state)
  1544. # Spawn active menu's task
  1545. self.activeMenu.spawnPieMenuTask()
  1546. def getLandmarkBuildingMode(self, dnaObject):
  1547. # Where are we hitting the building?
  1548. hitPt = self.getWallIntersectionPoint(self.selectedNPRoot)
  1549. if hitPt[2] < 10.0:
  1550. # Do door operations
  1551. if direct.fControl:
  1552. menuMode = 'door_color'
  1553. elif direct.fAlt:
  1554. menuMode = 'door_orientation'
  1555. else:
  1556. menuMode = 'door_texture'
  1557. else:
  1558. # Do sign operations
  1559. if direct.fControl:
  1560. menuMode = 'sign_color'
  1561. elif direct.fAlt:
  1562. menuMode = 'sign_orientation'
  1563. elif direct.fShift:
  1564. menuMode = 'baseline_style'
  1565. else:
  1566. menuMode = 'sign_texture'
  1567. return menuMode
  1568. def getFlatBuildingMode(self, dnaObject):
  1569. # Where are we hitting the building?
  1570. hitPt = self.getWallIntersectionPoint(self.selectedNPRoot)
  1571. wallNum = self.computeWallNum(dnaObject, hitPt)
  1572. if wallNum < 0:
  1573. # Do building related operations
  1574. """
  1575. if direct.fShift:
  1576. menuMode = 'building_type'
  1577. elif direct.fAlt:
  1578. """
  1579. if direct.fAlt:
  1580. menuMode = 'building_width'
  1581. else:
  1582. menuMode = 'building_style_all'
  1583. else:
  1584. # Otherwise, do wall specific operations
  1585. # Figure out where you are hitting on the wall
  1586. wallHeights, offsetList = DNAGetWallHeights(dnaObject)
  1587. # Find a normalized X and Z coordinate
  1588. xPt = hitPt[0]/dnaObject.getWidth()
  1589. # Adjust zPt depending on what wall you are pointing at
  1590. wallHeight = wallHeights[wallNum]
  1591. zPt = (hitPt[2] - offsetList[wallNum])/wallHeight
  1592. # Record current wall height
  1593. self.setCurrent('wall_height', wallHeight)
  1594. # Determine which zone you are pointing at
  1595. if (zPt > 0.8):
  1596. # Do cornice operations
  1597. if direct.fControl:
  1598. menuMode = 'cornice_color'
  1599. elif direct.fAlt:
  1600. menuMode = 'cornice_orientation'
  1601. else:
  1602. menuMode = 'cornice_texture'
  1603. elif ((xPt < 0.3) or (xPt > 0.7)):
  1604. # Do wall operations
  1605. if direct.fControl:
  1606. menuMode = 'wall_color'
  1607. elif direct.fAlt:
  1608. menuMode = 'wall_orientation'
  1609. elif direct.fShift:
  1610. menuMode = 'wall_texture'
  1611. else:
  1612. menuMode = 'wall_style'
  1613. elif (zPt < 0.4):
  1614. # Do door operations
  1615. if direct.fControl:
  1616. menuMode = 'door_color'
  1617. elif direct.fAlt:
  1618. menuMode = 'door_orientation'
  1619. else:
  1620. menuMode = 'door_texture'
  1621. # MRM: Temp for now
  1622. menuMode = 'window_texture'
  1623. else:
  1624. # Do window operations
  1625. if direct.fControl:
  1626. menuMode = 'window_color'
  1627. elif direct.fAlt:
  1628. menuMode = 'window_orientation'
  1629. elif direct.fShift:
  1630. menuMode = 'window_count'
  1631. else:
  1632. menuMode = 'window_texture'
  1633. return menuMode, wallNum
  1634. def levelHandleMouse3Up(self):
  1635. if self.activeMenu:
  1636. self.activeMenu.removePieMenuTask()
  1637. # Update panel color if appropriate
  1638. if self.DNATarget:
  1639. objClass = DNAGetClassType(self.DNATarget)
  1640. if ((objClass.eq(DNA_WALL)) or
  1641. (objClass.eq(DNA_WINDOWS)) or
  1642. (objClass.eq(DNA_DOOR)) or
  1643. (objClass.eq(DNA_CORNICE)) or
  1644. (objClass.eq(DNA_PROP))
  1645. ):
  1646. self.panel.setCurrentColor(self.DNATarget.getColor())
  1647. def setDNATargetColor(self, color):
  1648. if self.DNATarget:
  1649. self.DNATarget.setColor(color)
  1650. self.replaceSelected()
  1651. def setDNATargetCode(self, type, code):
  1652. if (self.DNATarget != None) and (code != None):
  1653. # Update code
  1654. self.DNATarget.setCode(code)
  1655. elif (self.DNATarget != None) and (code == None):
  1656. # Delete object, record pertinant properties before
  1657. # you delete the object so you can restore them later
  1658. # Remove object
  1659. if (type == 'cornice'):
  1660. self.removeCornice(self.DNATarget, self.DNATargetParent)
  1661. elif (type == 'sign'):
  1662. self.removeSign(self.DNATarget, self.DNATargetParent)
  1663. elif (type == 'landmark_door'):
  1664. self.removeLandmarkDoor(self.DNATarget, self.DNATargetParent)
  1665. elif (type == 'door'):
  1666. self.removeDoor(self.DNATarget, self.DNATargetParent)
  1667. elif (type == 'windows'):
  1668. self.removeWindows(self.DNATarget, self.DNATargetParent)
  1669. # Clear out DNATarget
  1670. self.DNATarget = None
  1671. elif (self.DNATarget == None) and (code != None):
  1672. # Add new object
  1673. if (type == 'cornice'):
  1674. self.DNATarget = self.createCornice()
  1675. elif (type == 'sign'):
  1676. self.DNATarget = self.createSign()
  1677. elif (type == 'landmark_door'):
  1678. self.DNATarget = self.createDoor()
  1679. elif (type == 'door'):
  1680. self.DNATarget = self.createDoor()
  1681. elif (type == 'windows'):
  1682. # Make sure window_count n.e. 0
  1683. if self.getCurrent('window_count') == 0:
  1684. self.setCurrent(
  1685. 'window_count',
  1686. self.getRandomWindowCount())
  1687. # Now create the windows
  1688. self.DNATarget = self.createWindows()
  1689. if self.DNATarget:
  1690. self.DNATargetParent.add(self.DNATarget)
  1691. # Update visible representation
  1692. self.replaceSelected()
  1693. def setDNATargetOrientation(self, orientation):
  1694. if (self.DNATarget != None) and (orientation != None):
  1695. oldCode = self.DNATarget.getCode()[:-2]
  1696. self.DNATarget.setCode(oldCode+orientation)
  1697. self.replaceSelected()
  1698. def setBuildingStyle(self, style):
  1699. if (self.DNATarget != None) and (style != None):
  1700. self.styleManager.setDNAFlatBuildingStyle(
  1701. self.DNATarget, style,
  1702. width = self.DNATarget.getWidth(),
  1703. name = self.DNATarget.getName())
  1704. # MRM: Need to disable dna store warning
  1705. self.replaceSelected()
  1706. # Re-add replication hooks so we get right kind of copy
  1707. self.addReplicationHooks(self.DNATarget)
  1708. def setBuildingType(self, type):
  1709. print 'setBuildingType: ', `type`
  1710. def setBuildingWidth(self, width):
  1711. if self.DNATarget:
  1712. self.DNATarget.setWidth(width)
  1713. self.replaceSelected()
  1714. def setWindowCount(self, count):
  1715. if (self.DNATarget != None) and (count != 0):
  1716. self.DNATarget.setWindowCount(count)
  1717. elif (self.DNATarget != None) and (count == 0):
  1718. # Remove windows and clear out DNATarget
  1719. self.removeWindows(self.DNATarget, self.DNATargetParent)
  1720. self.DNATarget = None
  1721. elif (self.DNATarget == None) and (count != 0):
  1722. self.DNATarget = self.createWindows()
  1723. self.DNATargetParent.add(self.DNATarget)
  1724. self.replaceSelected()
  1725. def setWallStyle(self, style):
  1726. if (self.DNATarget != None) and (style != None):
  1727. self.styleManager.setDNAWallStyle(
  1728. self.DNATarget, style,
  1729. self.DNATarget.getHeight())
  1730. self.replaceSelected()
  1731. def setColor(self, nodePath, r,g,b,a):
  1732. """ This is used to set color of dnaNode subparts """
  1733. dnaNode = self.findDNANode(nodePath)
  1734. if dnaNode:
  1735. objClass = DNAGetClassType(dnaNode)
  1736. if ((objClass.eq(DNA_WALL)) or
  1737. (objClass.eq(DNA_WINDOWS)) or
  1738. (objClass.eq(DNA_DOOR)) or
  1739. (objClass.eq(DNA_CORNICE)) or
  1740. (objClass.eq(DNA_PROP)) or
  1741. (objClass.eq(DNA_SIGN)) or
  1742. (objClass.eq(DNA_SIGN_BASELINE)) or
  1743. (objClass.eq(DNA_SIGN_TEXT)) or
  1744. (objClass.eq(DNA_SIGN_GRAPHIC))
  1745. ):
  1746. # Update dna information
  1747. dnaNode.setColor(VBase4(r/255.0, g/255.0, b/255.0, a/255.0))
  1748. # SELECTION FUNCTIONS
  1749. def selectedNodePathHook(self, nodePath):
  1750. """
  1751. Hook called upon selection of a node path used to restrict
  1752. selection to DNA Objects. Press control to select any type of
  1753. DNA Object, with no control key pressed, hook selects only
  1754. DNA Root objects
  1755. """
  1756. # Clear out old root variables
  1757. self.selectedDNARoot = None
  1758. self.selectedNPRoot = None
  1759. self.selectedSuitPoint = None
  1760. # Now process newly selected node path
  1761. dnaParent = None
  1762. dnaNode = self.findDNANode(nodePath)
  1763. if direct.fControl:
  1764. # Is the current node a DNA Object?
  1765. if not dnaNode:
  1766. # No it isn't, look for a parent DNA object
  1767. dnaParent = self.findDNAParent(nodePath.getParent())
  1768. else:
  1769. # Is the current node a DNA Root object?
  1770. if nodePath.getName()[-8:] != '_DNARoot':
  1771. # No it isn't, look for a parent DNA Root object
  1772. dnaParent = self.findDNARoot(nodePath.getParent())
  1773. # Do we need to switch selection to a parent object?
  1774. if dnaParent:
  1775. # Yes, deselect currently selected node path
  1776. direct.deselect(nodePath)
  1777. # And select parent
  1778. direct.select(dnaParent, direct.fShift)
  1779. elif dnaNode:
  1780. # We got a valid node path/DNA object, continue
  1781. self.selectedNPRoot = nodePath
  1782. self.selectedDNARoot = dnaNode
  1783. # Reset last landmark
  1784. if DNAClassEqual(dnaNode, DNA_LANDMARK_BUILDING):
  1785. self.lastLandmarkBuildingDNA=dnaNode
  1786. if self.showLandmarkBlockToggleGroup:
  1787. # Toggle old highlighting off:
  1788. self.toggleShowLandmarkBlock()
  1789. # Toggle on the the new highlighting:
  1790. self.toggleShowLandmarkBlock()
  1791. # Reset last Code (for autoPositionGrid)
  1792. if DNAClassEqual(dnaNode, DNA_STREET):
  1793. self.snapList = OBJECT_SNAP_POINTS[dnaNode.getCode()]
  1794. else:
  1795. pointOrCell, type = self.findPointOrCell(nodePath)
  1796. if pointOrCell and (type == 'suitPointMarker'):
  1797. print "Found suit point!", pointOrCell
  1798. self.selectedSuitPoint = pointOrCell
  1799. if pointOrCell and (type == 'battleCellMarker'):
  1800. print "Found battle cell!", pointOrCell
  1801. # Let others know that something new may be selected:
  1802. for i in self.selectedNodePathHookHooks:
  1803. i()
  1804. def deselectedNodePathHook(self, nodePath):
  1805. # Clear out old root variables
  1806. self.selectedDNARoot = None
  1807. self.selectedNPRoot = None
  1808. self.selectedSuitPoint = None
  1809. # Let others know:
  1810. for i in self.deselectedNodePathHookHooks:
  1811. i()
  1812. def findDNAParent(self, nodePath):
  1813. """ Walk up a node path's ancestry looking for its DNA Root """
  1814. # Check to see if current node is a dna object
  1815. if self.findDNANode(nodePath):
  1816. # Its a root!
  1817. return nodePath
  1818. else:
  1819. # If reached the top: fail
  1820. if not nodePath.hasParent():
  1821. return 0
  1822. else:
  1823. # Try parent
  1824. return self.findDNAParent(nodePath.getParent())
  1825. def findDNARoot(self, nodePath):
  1826. """ Walk up a node path's ancestry looking for its DNA Root """
  1827. # Check current node's name for root marker
  1828. if (nodePath.getName()[-8:] == '_DNARoot'):
  1829. # Its a root!
  1830. return nodePath
  1831. else:
  1832. # If reached the top: fail
  1833. if not nodePath.hasParent():
  1834. return None
  1835. else:
  1836. # Try parent
  1837. return self.findDNARoot(nodePath.getParent())
  1838. def findPointOrCell(self, nodePath):
  1839. """
  1840. Walk up a node path's ancestry to see if its a suit point marker
  1841. or a battle cell marker
  1842. """
  1843. # Check current node's name for root marker
  1844. if (nodePath.getName() == 'suitPointMarker'):
  1845. # Its a suit point marker!
  1846. # See if point is in pointDict
  1847. point = self.getSuitPointFromNodePath(nodePath)
  1848. return point, 'suitPointMarker'
  1849. elif (nodePath.getName() == 'battleCellMarker'):
  1850. # Its a battle cell marker
  1851. # See if cell is in cell Dict
  1852. cell = self.getBattleCellFromNodePath(nodePath)
  1853. return cell, 'battleCellMarker'
  1854. else:
  1855. # If reached the top: fail
  1856. if not nodePath.hasParent():
  1857. return None, None
  1858. else:
  1859. # Try parent
  1860. return self.findPointOrCell(nodePath.getParent())
  1861. # MANIPULATION FUNCTIONS
  1862. def keyboardRotateSelected(self, arrowDirection):
  1863. """ Rotate selected objects using arrow keys """
  1864. # Get snap angle
  1865. if direct.fShift:
  1866. oldSnapAngle = direct.grid.snapAngle
  1867. direct.grid.setSnapAngle(1.0)
  1868. snapAngle = direct.grid.snapAngle
  1869. print direct.fShift, snapAngle
  1870. # Compute new angle
  1871. if ((arrowDirection == 'left') or (arrowDirection == 'up')):
  1872. self.setLastAngle(self.getLastAngle() + snapAngle)
  1873. else:
  1874. self.setLastAngle(self.getLastAngle() - snapAngle)
  1875. if (self.getLastAngle() < -180.0):
  1876. self.setLastAngle(self.getLastAngle() + 360.0)
  1877. elif (self.getLastAngle() > 180.0):
  1878. self.setLastAngle(self.getLastAngle() - 360.0)
  1879. # Move selected objects
  1880. for selectedNode in direct.selected:
  1881. selectedNode.setHpr(self.getLastAngle(), 0, 0)
  1882. # Snap objects to grid and update DNA if necessary
  1883. self.updateSelectedPose()
  1884. if direct.fShift:
  1885. direct.grid.setSnapAngle(oldSnapAngle)
  1886. def keyboardTranslateSelected(self, arrowDirection):
  1887. gridToCamera = direct.grid.getMat(direct.camera)
  1888. camXAxis = gridToCamera.xformVec(X_AXIS)
  1889. xxDot = camXAxis.dot(X_AXIS)
  1890. xzDot = camXAxis.dot(Z_AXIS)
  1891. # what is the current grid spacing?
  1892. if direct.fShift:
  1893. # If shift, divide grid spacing by 10.0
  1894. oldGridSpacing = direct.grid.gridSpacing
  1895. # Use back door to set grid spacing to avoid grid update
  1896. direct.grid.gridSpacing = direct.grid.gridSpacing/10.0
  1897. deltaMove = direct.grid.gridSpacing
  1898. # Compute the specified delta
  1899. deltaPos = Vec3(0)
  1900. if (abs(xxDot) > abs(xzDot)):
  1901. if (xxDot < 0.0):
  1902. deltaMove = -deltaMove
  1903. # Compute delta
  1904. if (arrowDirection == 'right'):
  1905. deltaPos.setX(deltaPos[0] + deltaMove)
  1906. elif (arrowDirection == 'left'):
  1907. deltaPos.setX(deltaPos[0] - deltaMove)
  1908. elif (arrowDirection == 'up'):
  1909. deltaPos.setY(deltaPos[1] + deltaMove)
  1910. elif (arrowDirection == 'down'):
  1911. deltaPos.setY(deltaPos[1] - deltaMove)
  1912. else:
  1913. if (xzDot < 0.0):
  1914. deltaMove = -deltaMove
  1915. # Compute delta
  1916. if (arrowDirection == 'right'):
  1917. deltaPos.setY(deltaPos[1] - deltaMove)
  1918. elif (arrowDirection == 'left'):
  1919. deltaPos.setY(deltaPos[1] + deltaMove)
  1920. elif (arrowDirection == 'up'):
  1921. deltaPos.setX(deltaPos[0] + deltaMove)
  1922. elif (arrowDirection == 'down'):
  1923. deltaPos.setX(deltaPos[0] - deltaMove)
  1924. # Move selected objects
  1925. for selectedNode in direct.selected:
  1926. # Move it
  1927. selectedNode.setPos(direct.grid,
  1928. selectedNode.getPos(direct.grid) + deltaPos)
  1929. # Snap objects to grid and update DNA if necessary
  1930. self.updateSelectedPose()
  1931. # Restore grid spacing
  1932. if direct.fShift:
  1933. # Use back door to set grid spacing to avoid grid update
  1934. direct.grid.gridSpacing = oldGridSpacing
  1935. def keyboardXformSelected(self, arrowDirection):
  1936. if direct.fControl:
  1937. self.keyboardRotateSelected(arrowDirection)
  1938. else:
  1939. self.keyboardTranslateSelected(arrowDirection)
  1940. # VISIBILITY FUNCTIONS
  1941. def editDNAVisGroups(self):
  1942. visGroups = self.getDNAVisGroups(self.NPToplevel)
  1943. if visGroups:
  1944. self.vgpanel = VisGroupsEditor(self, visGroups)
  1945. else:
  1946. showinfo('Vis Groups Editor','No DNA Vis Groups Found!')
  1947. def getDNAVisGroups(self, nodePath):
  1948. """ Find the highest level vis groups in the scene graph """
  1949. dnaNode = self.findDNANode(nodePath)
  1950. if dnaNode:
  1951. if DNAClassEqual(dnaNode, DNA_VIS_GROUP):
  1952. return [[nodePath, dnaNode]]
  1953. childVisGroups = []
  1954. children = nodePath.getChildrenAsList()
  1955. for child in children:
  1956. childVisGroups = (childVisGroups + self.getDNAVisGroups(child))
  1957. return childVisGroups
  1958. def findParentVisGroup(self, nodePath):
  1959. """ Find the containing vis group """
  1960. dnaNode = self.findDNANode(nodePath)
  1961. if dnaNode:
  1962. if DNAClassEqual(dnaNode, DNA_VIS_GROUP):
  1963. return nodePath, dnaNode
  1964. elif nodePath.hasParent():
  1965. return self.findParentVisGroup(nodePath.getParent())
  1966. else:
  1967. return None
  1968. def showGrid(self,flag):
  1969. """ toggle direct grid """
  1970. if flag:
  1971. direct.grid.enable()
  1972. else:
  1973. direct.grid.disable()
  1974. # LEVEL MAP/MARKER FUNCTIONS
  1975. def createLevelMaps(self):
  1976. """
  1977. Load up the various neighborhood maps
  1978. """
  1979. # For neighborhood maps
  1980. self.levelMap = hidden.attachNewNode('level-map')
  1981. self.activeMap = None
  1982. self.mapDictionary = {}
  1983. """
  1984. for neighborhood in NEIGHBORHOODS:
  1985. self.createMap(neighborhood)
  1986. """
  1987. def createMap(self, neighborhood):
  1988. map = loader.loadModel('models/level_editor/' + neighborhood +
  1989. '_layout')
  1990. if map:
  1991. map.arc().setTransition(TransparencyTransition(1))
  1992. map.setColor(Vec4(1,1,1,.4))
  1993. self.mapDictionary[neighborhood] = map
  1994. # Make sure this item isn't pickable
  1995. direct.addUnpickable(neighborhood + '_layout')
  1996. def selectMap(self, neighborhood):
  1997. if self.activeMap:
  1998. self.activeMap.reparentTo(hidden)
  1999. if self.mapDictionary.has_key(neighborhood):
  2000. self.activeMap = self.mapDictionary[neighborhood]
  2001. self.activeMap.reparentTo(self.levelMap)
  2002. def toggleMapVis(self, flag):
  2003. if flag:
  2004. self.levelMap.reparentTo(direct.group)
  2005. else:
  2006. self.levelMap.reparentTo(hidden)
  2007. def createInsertionMarker(self):
  2008. self.insertionMarker = LineNodePath(self)
  2009. self.insertionMarker.lineNode.setName('insertionMarker')
  2010. self.insertionMarker.setColor(VBase4(0.785, 0.785, 0.5,1))
  2011. self.insertionMarker.setThickness(1)
  2012. self.insertionMarker.reset()
  2013. self.insertionMarker.moveTo(-75,0,0)
  2014. self.insertionMarker.drawTo(75,0,0)
  2015. self.insertionMarker.moveTo(0,-75,0)
  2016. self.insertionMarker.drawTo(0,75,0)
  2017. self.insertionMarker.moveTo(0,0,-75)
  2018. self.insertionMarker.drawTo(0,0,75)
  2019. self.insertionMarker.create()
  2020. def spawnInsertionMarkerTask(self):
  2021. t = Task.Task(self.insertionMarkerTask)
  2022. taskMgr.spawnTaskNamed(t, 'insertionMarkerTask')
  2023. def insertionMarkerTask(self, state):
  2024. self.insertionMarker.setPosHpr(direct.grid, 0,0,0, 0,0,0)
  2025. # MRM: Why is this necessary?
  2026. self.insertionMarker.setScale(1,1,1)
  2027. return Task.cont
  2028. # UTILITY FUNCTIONS
  2029. def getRandomDictionaryEntry(self,dict):
  2030. numKeys = len(dict)
  2031. if numKeys > 0:
  2032. keys = dict.keys()
  2033. key = keys[randint(0,numKeys - 1)]
  2034. return dict[key]
  2035. else:
  2036. return None
  2037. def getRandomWindowCount(self):
  2038. if ((self.lastWall != None) and (self.lastBuilding != None)):
  2039. h = ROUND_INT(self.lastWall.getHeight())
  2040. w = ROUND_INT(self.lastBuilding.getWidth())
  2041. # Otherwise....
  2042. if w == 5:
  2043. # 5 ft walls can have 1 window
  2044. return 1
  2045. elif h == 10:
  2046. # All other 10 ft high bldgs can have 1 or 2
  2047. return randint(1,2)
  2048. else:
  2049. # All others can have 1 - 4
  2050. return randint(1,4)
  2051. else:
  2052. return 1
  2053. def autoPositionGrid(self):
  2054. taskMgr.removeTasksNamed('autoPositionGrid')
  2055. # Move grid to prepare for placement of next object
  2056. selectedNode = direct.selected.last
  2057. if selectedNode:
  2058. dnaNode = self.findDNANode(selectedNode)
  2059. if dnaNode == None:
  2060. return
  2061. nodeClass = DNAGetClassType(dnaNode)
  2062. deltaPos = Point3(20,0,0)
  2063. deltaHpr = VBase3(0)
  2064. if nodeClass.eq(DNA_FLAT_BUILDING):
  2065. deltaPos.setX(dnaNode.getWidth())
  2066. elif nodeClass.eq(DNA_STREET):
  2067. objectCode = dnaNode.getCode()
  2068. deltas = self.getNextSnapPoint()
  2069. deltaPos.assign(deltas[0])
  2070. deltaHpr.assign(deltas[1])
  2071. elif nodeClass.eq(DNA_LANDMARK_BUILDING):
  2072. objectCode = dnaNode.getCode()
  2073. if objectCode[-2:-1] == 'A':
  2074. deltaPos.setX(25.0)
  2075. elif objectCode[-2:-1] == 'B':
  2076. deltaPos.setX(15.0)
  2077. elif objectCode[-2:-1] == 'C':
  2078. deltaPos.setX(20.0)
  2079. # Position grid for placing next object
  2080. # Eventually we need to setHpr too
  2081. t = direct.grid.lerpPosHpr(
  2082. deltaPos, deltaHpr, 0.25,
  2083. other = selectedNode,
  2084. blendType = 'easeInOut',
  2085. task = 'autoPositionGrid')
  2086. t.deltaPos = deltaPos
  2087. t.deltaHpr = deltaHpr
  2088. t.selectedNode = selectedNode
  2089. t.uponDeath = self.autoPositionCleanup
  2090. # Also move the camera
  2091. taskMgr.removeTasksNamed('autoMoveDelay')
  2092. handlesToCam = direct.widget.getPos(direct.camera)
  2093. handlesToCam = handlesToCam * ( direct.dr.near/handlesToCam[1])
  2094. if ((abs(handlesToCam[0]) > (direct.dr.nearWidth * 0.4)) or
  2095. (abs(handlesToCam[2]) > (direct.dr.nearHeight * 0.4))):
  2096. taskMgr.removeTasksNamed('manipulateCamera')
  2097. direct.cameraControl.centerCamIn(0.5)
  2098. def autoPositionCleanup(self,state):
  2099. direct.grid.setPosHpr(state.selectedNode, state.deltaPos,
  2100. state.deltaHpr)
  2101. if direct.grid.getHprSnap():
  2102. # Clean up grid angle
  2103. direct.grid.setH(ROUND_TO(direct.grid.getH(),
  2104. direct.grid.snapAngle))
  2105. def getNextSnapPoint(self):
  2106. """ Pull next pos hpr deltas off of snap list then rotate list """
  2107. if self.snapList:
  2108. deltas = self.snapList[0]
  2109. # Rotate list by one
  2110. self.snapList = self.snapList[1:] + self.snapList[:1]
  2111. return deltas
  2112. else:
  2113. return (ZERO_VEC, ZERO_VEC)
  2114. def getWallIntersectionPoint(self, selectedNode):
  2115. """
  2116. Return point of intersection between building's wall and line from cam
  2117. through mouse.
  2118. """
  2119. # Find mouse point on near plane
  2120. mouseX = direct.dr.mouseX
  2121. mouseY = direct.dr.mouseY
  2122. nearX = (math.tan(deg2Rad(direct.dr.fovH)/2.0) *
  2123. mouseX * direct.dr.near)
  2124. nearZ = (math.tan(deg2Rad(direct.dr.fovV)/2.0) *
  2125. mouseY * direct.dr.near)
  2126. # Initialize points
  2127. mCam2Wall = direct.camera.getMat(selectedNode)
  2128. mouseOrigin = Point3(0)
  2129. mouseOrigin.assign(mCam2Wall.getRow3(3))
  2130. mouseDir = Vec3(0)
  2131. mouseDir.set(nearX, direct.dr.near, nearZ)
  2132. mouseDir.assign(mCam2Wall.xformVec(mouseDir))
  2133. # Calc intersection point
  2134. return planeIntersect(mouseOrigin, mouseDir, ZERO_POINT, NEG_Y_AXIS)
  2135. def getGridSnapIntersectionPoint(self):
  2136. """
  2137. Return point of intersection between ground plane and line from cam
  2138. through mouse. Return false, if nothing selected. Snap to grid.
  2139. """
  2140. return direct.grid.computeSnapPoint(self.getGridIntersectionPoint())
  2141. def getGridIntersectionPoint(self):
  2142. """
  2143. Return point of intersection between ground plane and line from cam
  2144. through mouse. Return false, if nothing selected
  2145. """
  2146. # Find mouse point on near plane
  2147. mouseX = direct.dr.mouseX
  2148. mouseY = direct.dr.mouseY
  2149. nearX = (math.tan(deg2Rad(direct.dr.fovH)/2.0) *
  2150. mouseX * direct.dr.near)
  2151. nearZ = (math.tan(deg2Rad(direct.dr.fovV)/2.0) *
  2152. mouseY * direct.dr.near)
  2153. # Initialize points
  2154. mCam2Grid = direct.camera.getMat(direct.grid)
  2155. mouseOrigin = Point3(0)
  2156. mouseOrigin.assign(mCam2Grid.getRow3(3))
  2157. mouseDir = Vec3(0)
  2158. mouseDir.set(nearX, direct.dr.near, nearZ)
  2159. mouseDir.assign(mCam2Grid.xformVec(mouseDir))
  2160. # Calc intersection point
  2161. return planeIntersect(mouseOrigin, mouseDir, ZERO_POINT, Z_AXIS)
  2162. def jumpToInsertionPoint(self):
  2163. """ Move selected object to insertion point """
  2164. selectedNode = direct.selected.last
  2165. if selectedNode:
  2166. # Check if its a dna node
  2167. dnaNode = self.findDNANode(selectedNode)
  2168. if dnaNode:
  2169. # Place the new node path at the current grid origin
  2170. selectedNode.setPos(direct.grid,0,0,0)
  2171. # Initialize angle to match last object
  2172. selectedNode.setHpr(self.getLastAngle(), 0, 0)
  2173. # Now update DNA pos and hpr to reflect final pose
  2174. dnaNode.setPos(selectedNode.getPos())
  2175. dnaNode.setHpr(selectedNode.getHpr())
  2176. # Update grid to get ready for the next object
  2177. self.autoPositionGrid()
  2178. # STYLE/DNA FILE FUNCTIONS
  2179. def loadSpecifiedDNAFile(self):
  2180. f = Filename(self.styleManager.stylePathPrefix +
  2181. '/alpha/DIRECT/LevelEditor/DNAFiles')
  2182. path = os.path.join(f.toOsSpecific(), self.outputDir)
  2183. if not os.path.isdir(path):
  2184. print 'LevelEditor Warning: Invalid default DNA directory!'
  2185. print 'Using current directory'
  2186. path = '.'
  2187. dnaFilename = askopenfilename(
  2188. defaultextension = '.dna',
  2189. filetypes = (('DNA Files', '*.dna'),('All files', '*')),
  2190. initialdir = path,
  2191. title = 'Load DNA File',
  2192. parent = self.panel.component('hull'))
  2193. if dnaFilename:
  2194. self.loadDNAFromFile(dnaFilename)
  2195. def saveToSpecifiedDNAFile(self):
  2196. f = Filename(self.styleManager.stylePathPrefix +
  2197. '/alpha/DIRECT/LevelEditor/DNAFiles')
  2198. path = os.path.join(f.toOsSpecific(), self.outputDir)
  2199. if not os.path.isdir(path):
  2200. print 'LevelEditor Warning: Invalid DNA save directory!'
  2201. print 'Using current directory'
  2202. path = '.'
  2203. dnaFilename = asksaveasfilename(
  2204. defaultextension = '.dna',
  2205. filetypes = (('DNA Files', '*.dna'),('All files', '*')),
  2206. initialdir = path,
  2207. title = 'Save DNA File as',
  2208. parent = self.panel.component('hull'))
  2209. if dnaFilename:
  2210. self.outputDNA(dnaFilename)
  2211. def loadDNAFromFile(self, filename):
  2212. # Reset level, destroying existing scene/DNA hierarcy
  2213. self.reset(fDeleteToplevel = 1, fCreateToplevel = 0,
  2214. fUpdateExplorer = 0)
  2215. # Now load in new file
  2216. node = loadDNAFile(DNASTORE, filename, CSDefault, 1)
  2217. if node.getNumParents(RenderRelation.getClassType()) == 1:
  2218. # If the node already has a parent arc when it's loaded, we must
  2219. # be using the level editor and we want to preserve that arc.
  2220. newNPToplevel = NodePath()
  2221. newNPToplevel.extendBy(node.getParent(
  2222. RenderRelation.getClassType(), 0))
  2223. newNPToplevel.reparentTo(hidden)
  2224. else:
  2225. # Otherwise, we should create a new arc for the node.
  2226. newNPToplevel = hidden.attachNewNode(node)
  2227. # Make sure the topmost file DNA object gets put under DNARoot
  2228. newDNAToplevel = self.findDNANode(newNPToplevel)
  2229. # reset the landmark block number:
  2230. (self.landmarkBlock, needTraverse)=self.findHighestLandmarkBlock(
  2231. newDNAToplevel, newNPToplevel)
  2232. # Update toplevel variables
  2233. if needTraverse:
  2234. self.createToplevel(newDNAToplevel)
  2235. else:
  2236. self.createToplevel(newDNAToplevel, newNPToplevel)
  2237. # Create visible representations of all the paths and battle cells
  2238. self.createSuitPaths()
  2239. self.hideSuitPaths()
  2240. self.createBattleCells()
  2241. self.hideBattleCells()
  2242. # Set the title bar to have the filename to make it easier
  2243. # to remember what file you are working on
  2244. self.panel["title"] = 'Level Editor: ' + os.path.basename(filename)
  2245. self.panel.sceneGraphExplorer.update()
  2246. def outputDNADefaultFile(self):
  2247. f = Filename(self.styleManager.stylePathPrefix +
  2248. '/alpha/DIRECT/LevelEditor/DNAFiles')
  2249. file = os.path.join(f.toOsSpecific(), self.outputDir, self.outputFile)
  2250. self.outputDNA(file)
  2251. def outputDNA(self,filename):
  2252. print 'Saving DNA to: ', filename
  2253. binaryFilename = Filename(filename)
  2254. binaryFilename.setBinary()
  2255. self.DNAData.writeDna(binaryFilename, Notify.out(),DNASTORE)
  2256. def saveColor(self):
  2257. self.appendColorToColorPaletteFile(self.panel.colorEntry.get())
  2258. def appendColorToColorPaletteFile(self, color):
  2259. obj = self.DNATarget
  2260. if obj:
  2261. classType = DNAGetClassType(obj)
  2262. if classType.eq(DNA_WALL):
  2263. tag = 'wall_color:'
  2264. elif classType.eq(DNA_WINDOWS):
  2265. tag = 'window_color:'
  2266. elif classType.eq(DNA_DOOR):
  2267. tag = 'door_color:'
  2268. elif classType.eq(DNA_CORNICE):
  2269. tag = 'cornice_color:'
  2270. elif classType.eq(DNA_PROP):
  2271. tag = 'prop_color:'
  2272. else:
  2273. return
  2274. # Valid type, add color to file
  2275. filename = self.neighborhood + '_colors.txt'
  2276. fname = Filename(self.styleManager.stylePathPrefix +
  2277. '/alpha/DIRECT/LevelEditor/StyleFiles/' +
  2278. filename)
  2279. f = open(fname.toOsSpecific(), 'a')
  2280. f.write('%s Vec4(%.2f, %.2f, %.2f, 1.0)\n' %
  2281. (tag,
  2282. color[0]/255.0,
  2283. color[1]/255.0,
  2284. color[2]/255.0))
  2285. f.close()
  2286. def saveBaselineStyle(self):
  2287. if self.panel.currentBaselineDNA:
  2288. # Valid baseline, add style to file
  2289. filename = self.neighborhood + '_baseline_styles.txt'
  2290. fname = Filename(self.styleManager.stylePathPrefix +
  2291. '/alpha/DIRECT/LevelEditor/StyleFiles/' +
  2292. filename)
  2293. f = open(fname.toOsSpecific(), 'a')
  2294. # Add a blank line
  2295. f.write('\n')
  2296. # Now output style details to file
  2297. style = DNABaselineStyle(baseline = self.panel.currentBaselineDNA)
  2298. style.output(f)
  2299. # Close the file
  2300. f.close()
  2301. def saveWallStyle(self):
  2302. if self.lastWall:
  2303. # Valid wall, add style to file
  2304. filename = self.neighborhood + '_wall_styles.txt'
  2305. fname = Filename(self.styleManager.stylePathPrefix +
  2306. '/alpha/DIRECT/LevelEditor/StyleFiles/' +
  2307. filename)
  2308. f = open(fname.toOsSpecific(), 'a')
  2309. # Add a blank line
  2310. f.write('\n')
  2311. # Now output style details to file
  2312. style = DNAWallStyle(wall = self.lastWall)
  2313. style.output(f)
  2314. # Close the file
  2315. f.close()
  2316. def saveBuildingStyle(self):
  2317. dnaObject = self.selectedDNARoot
  2318. if dnaObject:
  2319. if DNAClassEqual(dnaObject, DNA_FLAT_BUILDING):
  2320. # Valid wall, add style to file
  2321. filename = self.neighborhood + '_building_styles.txt'
  2322. fname = Filename(self.styleManager.stylePathPrefix +
  2323. '/alpha/DIRECT/LevelEditor/StyleFiles/' +
  2324. filename)
  2325. f = open(fname.toOsSpecific(), 'a')
  2326. # Add a blank line
  2327. f.write('\n')
  2328. # Now output style details to file
  2329. style = DNAFlatBuildingStyle(building = dnaObject)
  2330. style.output(f)
  2331. # Close the file
  2332. f.close()
  2333. return
  2334. print 'Must select building before saving building style'
  2335. # GET/SET
  2336. # DNA Object elements
  2337. def getWall(self, dnaFlatBuilding, wallNum):
  2338. wallCount = 0
  2339. for i in range(dnaFlatBuilding.getNumChildren()):
  2340. child = dnaFlatBuilding.at(i)
  2341. if DNAClassEqual(child, DNA_WALL):
  2342. if wallCount == wallNum:
  2343. return child
  2344. wallCount = wallCount + 1
  2345. # Not found
  2346. return None
  2347. def computeWallNum(self, aDNAFlatBuilding, hitPt):
  2348. """
  2349. Given a hitPt, return wall number if cursor is over building
  2350. Return -1 if cursor is outside of building
  2351. """
  2352. xPt = hitPt[0]
  2353. zPt = hitPt[2]
  2354. # Left or right of building
  2355. if ((xPt < 0) or (xPt > aDNAFlatBuilding.getWidth())):
  2356. return -1
  2357. # Below the building
  2358. if zPt < 0:
  2359. return -1
  2360. # Above z = 0 and within wall width, check height of walls
  2361. heightList, offsetList = DNAGetWallHeights(aDNAFlatBuilding)
  2362. wallNum = 0
  2363. for i in range(len(heightList)):
  2364. # Compute top of wall segment
  2365. top = offsetList[i] + heightList[i]
  2366. if zPt < top:
  2367. return wallNum
  2368. wallNum = wallNum + 1
  2369. return -1
  2370. def getWindowCount(self, dnaWall):
  2371. windowCount = 0
  2372. for i in range(dnaWall.getNumChildren()):
  2373. child = dnaWall.at(i)
  2374. if DNAClassEqual(child, DNA_WINDOWS):
  2375. windowCount = windowCount + 1
  2376. # Not found
  2377. return windowCount
  2378. # Style manager edit mode
  2379. def setEditMode(self, neighborhood):
  2380. self.neighborhood = neighborhood
  2381. self.neighborhoodCode = NEIGHBORHOOD_CODES[self.neighborhood]
  2382. self.outputFile = neighborhood + '_working.dna'
  2383. if neighborhood == 'toontown_central':
  2384. self.outputDir = 'ToontownCentral'
  2385. elif neighborhood == 'donalds_dock':
  2386. self.outputDir = 'DonaldsDock'
  2387. elif neighborhood == 'minnies_melody_land':
  2388. self.outputDir = 'MinniesMelodyLand'
  2389. elif neighborhood == 'the_burrrgh':
  2390. self.outputDir = 'TheBurrrgh'
  2391. elif neighborhood == 'daisys_garden':
  2392. self.outputDir = 'DaisysGarden'
  2393. elif neighborhood == 'donalds_dreamland':
  2394. self.outputDir = 'DonaldsDreamland'
  2395. self.panel.editMenu.selectitem(neighborhood)
  2396. self.styleManager.setEditMode(neighborhood)
  2397. self.panel.updateHeightList(self.getCurrent('building_height'))
  2398. self.selectMap(neighborhood)
  2399. def getEditMode(self):
  2400. return self.styleManager.getEditMode()
  2401. # Level Style Attributes
  2402. def __getitem__(self,attribute):
  2403. """ Return top level entry in attribute dictionary """
  2404. return self.styleManager.attributeDictionary[attribute]
  2405. def getAttribute(self, attribute):
  2406. """ Return specified attribute for current neighborhood """
  2407. return self.styleManager.getAttribute(attribute)
  2408. def hasAttribute(self, attribute):
  2409. """ Return specified attribute for current neighborhood """
  2410. return self.styleManager.hasAttribute(attribute)
  2411. def getCurrent(self, attribute):
  2412. """ Return neighborhood's current selection for specified attribute """
  2413. return self.getAttribute(attribute).getCurrent()
  2414. def setCurrent(self, attribute, newCurrent):
  2415. """ Set neighborhood's current selection for specified attribute """
  2416. self.getAttribute(attribute).setCurrent(newCurrent, fEvent = 0)
  2417. def getMenu(self, attribute):
  2418. """ Return neighborhood's Pie Menu object for specified attribute """
  2419. return self.getAttribute(attribute).getMenu()
  2420. def getDict(self, attribute):
  2421. """ Return neighborhood's Dictionary for specified attribute """
  2422. return self.getAttribute(attribute).getDict()
  2423. def getList(self, attribute):
  2424. """ Return neighborhood's List for specified attribute """
  2425. return self.getAttribute(attribute).getList()
  2426. # DNA variables
  2427. def getDNAData(self):
  2428. return self.DNAData
  2429. def getDNAToplevel(self):
  2430. return self.DNAToplevel
  2431. def getDNAParent(self):
  2432. return self.DNAParent
  2433. def getDNATarget(self):
  2434. return self.DNATarget
  2435. # Node Path variables
  2436. def getNPToplevel(self):
  2437. return self.NPToplevel
  2438. def getNPParent(self):
  2439. return self.NPParent
  2440. # Count of groups added to level
  2441. def setGroupNum(self,num):
  2442. self.groupNum = num
  2443. def getGroupNum(self):
  2444. return self.groupNum
  2445. # Angle of last object added to level
  2446. def setLastAngle(self, angle):
  2447. self.lastAngle = angle
  2448. def getLastAngle(self):
  2449. return self.lastAngle
  2450. def drawSuitEdge(self, edge, parent):
  2451. # Draw a line from start to end
  2452. edgeLine = LineNodePath(parent)
  2453. edgeLine.lineNode.setName('suitEdge')
  2454. edgeLine.setColor(VBase4(0.0, 0.0, 0.5 ,1))
  2455. edgeLine.setThickness(1)
  2456. edgeLine.reset()
  2457. # We need to draw the arrow relative to the parent, but the
  2458. # point positions are relative to the NPToplevel. So get the
  2459. # start and end positions relative to the parent, then draw
  2460. # the arrow using those points
  2461. tempNode = self.NPToplevel.attachNewNode('tempNode')
  2462. mat = self.NPToplevel.getMat(parent)
  2463. relStartPos = Point3(mat.xformPoint(edge.getStartPoint().getPos()))
  2464. relEndPos = Point3(mat.xformPoint(edge.getEndPoint().getPos()))
  2465. # Compute offset: a vector rotated 90 degrees clockwise
  2466. offset = Vec3(relEndPos - relStartPos)
  2467. offset.normalize()
  2468. offset *= 0.1
  2469. a = offset[0]
  2470. offset.setX(offset[1])
  2471. offset.setY(-1 * a)
  2472. # Just to get it above the street
  2473. offset.setZ(0.05)
  2474. # Add offset to start and end to help differentiate lines
  2475. relStartPos += offset
  2476. relEndPos += offset
  2477. # Draw arrow
  2478. edgeLine.drawArrow(relStartPos,
  2479. relEndPos,
  2480. 15, # arrow angle
  2481. 1) # arrow length
  2482. edgeLine.create()
  2483. # Adjust color of highlighted lines
  2484. if edge in self.visitedEdges:
  2485. NodePath.setColor(edgeLine,1,0,0,1)
  2486. # Clean up:
  2487. tempNode.removeNode()
  2488. return edgeLine
  2489. def drawSuitPoint(self, suitPoint, pos, type, parent):
  2490. marker = self.suitPointMarker.copyTo(parent)
  2491. marker.setName("suitPointMarker")
  2492. marker.setPos(pos)
  2493. if (type == DNASuitPoint.STREETPOINT):
  2494. marker.setColor(0,0,0.6)
  2495. marker.setScale(0.4)
  2496. elif (type == DNASuitPoint.FRONTDOORPOINT):
  2497. marker.setColor(0,0,1)
  2498. marker.setScale(0.5)
  2499. elif (type == DNASuitPoint.SIDEDOORPOINT):
  2500. marker.setColor(0,0.2,0.4)
  2501. marker.setScale(0.5)
  2502. # Highlight if necessary
  2503. if suitPoint in self.visitedPoints:
  2504. marker.setColor(1,0,0,1)
  2505. return marker
  2506. def placeSuitPoint(self):
  2507. v = self.getGridSnapIntersectionPoint()
  2508. # get the absolute pos relative to the top level.
  2509. # That is what gets stored in the point
  2510. mat = direct.grid.getMat(self.NPToplevel)
  2511. absPos = Point3(mat.xformPoint(v))
  2512. print 'Suit point: ' + `absPos`
  2513. # Store the point in the DNA. If this point is already in there,
  2514. # it returns the existing point
  2515. suitPoint = DNASTORE.storeSuitPoint(self.currentSuitPointType, absPos)
  2516. if not self.pointDict.has_key(suitPoint):
  2517. marker = self.drawSuitPoint(suitPoint,
  2518. absPos, self.currentSuitPointType,
  2519. self.suitPointToplevel)
  2520. self.pointDict[suitPoint] = marker
  2521. self.currentSuitPointIndex = suitPoint.getIndex()
  2522. if self.startSuitPoint:
  2523. self.endSuitPoint = suitPoint
  2524. # Make a new dna edge
  2525. if DNAClassEqual(self.DNAParent, DNA_VIS_GROUP):
  2526. zoneId = self.DNAParent.getName()
  2527. suitEdge = DNASuitEdge(
  2528. self.startSuitPoint, self.endSuitPoint, zoneId)
  2529. DNASTORE.storeSuitEdge(suitEdge)
  2530. # Add edge to the current vis group so it can be written out
  2531. self.DNAParent.addSuitEdge(suitEdge)
  2532. # Draw a line to represent the edge
  2533. edgeLine = self.drawSuitEdge(suitEdge, self.NPParent)
  2534. # Store the line in a dict so we can hide/show them
  2535. self.edgeDict[suitEdge] = edgeLine
  2536. # Store the edge on each point in case we move the point
  2537. # we can update the edge
  2538. for point in [self.startSuitPoint, self.endSuitPoint]:
  2539. if self.point2edgeDict.has_key(point):
  2540. self.point2edgeDict[point].append(suitEdge)
  2541. else:
  2542. self.point2edgeDict[point] = [suitEdge]
  2543. print 'Added dnaSuitEdge to zone: ' + zoneId
  2544. else:
  2545. print 'Error: DNAParent is not a dnaVisGroup. Did not add edge'
  2546. # Reset
  2547. self.startSuitPoint = None
  2548. self.endSuitPoint = None
  2549. else:
  2550. # First point, store it
  2551. self.startSuitPoint = suitPoint
  2552. def highlightConnected(self, nodePath = None, fReversePath = 0):
  2553. if nodePath == None:
  2554. nodePath = direct.selected.last
  2555. if nodePath:
  2556. suitPoint = self.findPointOrCell(nodePath)[0]
  2557. if suitPoint:
  2558. self.clearPathHighlights()
  2559. self.highlightConnectedRec(suitPoint, fReversePath)
  2560. def highlightConnectedRec(self, suitPoint, fReversePath):
  2561. nodePath = self.pointDict.get(suitPoint, None)
  2562. if nodePath:
  2563. # highlight marker
  2564. nodePath.setColor(1,0,0,1)
  2565. # Add point to visited points
  2566. self.visitedPoints.append(suitPoint)
  2567. # highlight connected edges
  2568. for edge in self.point2edgeDict[suitPoint]:
  2569. if ((fReversePath or (suitPoint == edge.getStartPoint())) and
  2570. (edge not in self.visitedEdges)):
  2571. edgeLine = self.edgeDict[edge]
  2572. # Call node path not LineNodePath setColor
  2573. NodePath.setColor(edgeLine,1,0,0,1)
  2574. # Add edge to visited edges
  2575. self.visitedEdges.append(edge)
  2576. # Color components connected to the edge
  2577. if fReversePath:
  2578. startPoint = edge.getStartPoint()
  2579. if startPoint not in self.visitedPoints:
  2580. self.highlightConnectedRec(startPoint,
  2581. fReversePath)
  2582. endPoint = edge.getEndPoint()
  2583. type = endPoint.getPointType()
  2584. if ((endPoint not in self.visitedPoints) and
  2585. (fReversePath or (type == DNASuitPoint.STREETPOINT))):
  2586. self.highlightConnectedRec(endPoint,
  2587. fReversePath)
  2588. def clearPathHighlights(self):
  2589. for point in self.pointDict.keys():
  2590. type = point.getPointType()
  2591. marker = self.pointDict[point]
  2592. if (type == DNASuitPoint.STREETPOINT):
  2593. marker.setColor(0,0,0.6)
  2594. elif (type == DNASuitPoint.FRONTDOORPOINT):
  2595. marker.setColor(0,0,1)
  2596. elif (type == DNASuitPoint.SIDEDOORPOINT):
  2597. marker.setColor(0,0.2,0.4)
  2598. for edge in self.edgeDict.values():
  2599. edge.clearColor()
  2600. self.visitedPoints = []
  2601. self.visitedEdges = []
  2602. def drawBattleCell(self, cell, parent):
  2603. marker = self.battleCellMarker.copyTo(parent)
  2604. # Greenish
  2605. marker.setColor(0.25,0.75,0.25,0.5)
  2606. marker.setTransparency(1)
  2607. marker.setPos(cell.getPos())
  2608. # scale to radius which is width/2
  2609. marker.setScale(cell.getWidth()/2.0,
  2610. cell.getHeight()/2.0,
  2611. 1)
  2612. return marker
  2613. def placeBattleCell(self):
  2614. # Store the battle cell in the current vis group
  2615. if not DNAClassEqual(self.DNAParent, DNA_VIS_GROUP):
  2616. print 'Error: DNAParent is not a dnaVisGroup. Did not add battle cell'
  2617. return
  2618. v = self.getGridSnapIntersectionPoint()
  2619. mat = direct.grid.getMat(self.NPParent)
  2620. absPos = Point3(mat.xformPoint(v))
  2621. if (self.currentBattleCellType == '20w 20l'):
  2622. cell = DNABattleCell(20, 20, absPos)
  2623. elif (self.currentBattleCellType == '20w 30l'):
  2624. cell = DNABattleCell(20, 30, absPos)
  2625. elif (self.currentBattleCellType == '30w 20l'):
  2626. cell = DNABattleCell(30, 20, absPos)
  2627. elif (self.currentBattleCellType == '30w 30l'):
  2628. cell = DNABattleCell(30, 30, absPos)
  2629. # Store the battle cell in the storage
  2630. DNASTORE.storeBattleCell(cell)
  2631. # Draw the battle cell
  2632. marker = self.drawBattleCell(cell, self.NPParent)
  2633. # Keep a handy dict of the visible markers
  2634. self.cellDict[cell] = marker
  2635. # Store the battle cell in the current vis group
  2636. self.DNAParent.addBattleCell(cell)
  2637. def createSuitPaths(self):
  2638. # Points
  2639. numPoints = DNASTORE.getNumSuitPoints()
  2640. for i in range(numPoints):
  2641. point = DNASTORE.getSuitPointAtIndex(i)
  2642. marker = self.drawSuitPoint(point,
  2643. point.getPos(), point.getPointType(),
  2644. self.suitPointToplevel)
  2645. self.pointDict[point] = marker
  2646. # Edges
  2647. visGroups = self.getDNAVisGroups(self.NPToplevel)
  2648. for visGroup in visGroups:
  2649. np = visGroup[0]
  2650. dnaVisGroup = visGroup[1]
  2651. numSuitEdges = dnaVisGroup.getNumSuitEdges()
  2652. for i in range(numSuitEdges):
  2653. edge = dnaVisGroup.getSuitEdge(i)
  2654. edgeLine = self.drawSuitEdge(edge, np)
  2655. self.edgeDict[edge] = edgeLine
  2656. # Store the edge on each point in case we move the point
  2657. # we can update the edge
  2658. for point in [edge.getStartPoint(), edge.getEndPoint()]:
  2659. if self.point2edgeDict.has_key(point):
  2660. self.point2edgeDict[point].append(edge)
  2661. else:
  2662. self.point2edgeDict[point] = [edge]
  2663. def getSuitPointFromNodePath(self, nodePath):
  2664. """
  2665. Given a node path, attempt to find the point,nodePath pair
  2666. in the pointDict. If it is there, return the point. If we
  2667. cannot find it, return None.
  2668. TODO: a reverse lookup pointDict would speed this up quite a bit
  2669. """
  2670. for point, marker in self.pointDict.items():
  2671. if marker.eq(nodePath):
  2672. return point
  2673. return None
  2674. def resetPathMarkers(self):
  2675. for edge, edgeLine in self.edgeDict.items():
  2676. if not edgeLine.isEmpty():
  2677. edgeLine.reset()
  2678. edgeLine.removeNode()
  2679. self.edgeDict = {}
  2680. for point, marker in self.pointDict.items():
  2681. if not marker.isEmpty():
  2682. marker.removeNode()
  2683. self.pointDict = {}
  2684. def hideSuitPaths(self):
  2685. for edge, edgeLine in self.edgeDict.items():
  2686. edgeLine.hide()
  2687. for point, marker in self.pointDict.items():
  2688. marker.hide()
  2689. def showSuitPaths(self):
  2690. for edge, edgeLine in self.edgeDict.items():
  2691. edgeLine.show()
  2692. for point, marker in self.pointDict.items():
  2693. marker.show()
  2694. def createBattleCells(self):
  2695. # Edges
  2696. visGroups = self.getDNAVisGroups(self.NPToplevel)
  2697. for visGroup in visGroups:
  2698. np = visGroup[0]
  2699. dnaVisGroup = visGroup[1]
  2700. numCells = dnaVisGroup.getNumBattleCells()
  2701. for i in range(numCells):
  2702. cell = dnaVisGroup.getBattleCell(i)
  2703. marker = self.drawBattleCell(cell, np)
  2704. self.cellDict[cell] = marker
  2705. def resetBattleCellMarkers(self):
  2706. for cell, marker in self.cellDict.items():
  2707. if not marker.isEmpty():
  2708. marker.remove()
  2709. self.cellDict = {}
  2710. def hideBattleCells(self):
  2711. for cell, marker in self.cellDict.items():
  2712. marker.hide()
  2713. def showBattleCells(self):
  2714. for cell, marker in self.cellDict.items():
  2715. marker.show()
  2716. def getBattleCellFromNodePath(self, nodePath):
  2717. """
  2718. Given a node path, attempt to find the battle cell, nodePath pair
  2719. in the cellDict. If it is there, return the cell. If we
  2720. cannot find it, return None.
  2721. TODO: a reverse lookup cellDict would speed this up quite a bit
  2722. """
  2723. for cell, marker in self.cellDict.items():
  2724. if marker.eq(nodePath):
  2725. return cell
  2726. return None
  2727. def toggleZoneColors(self):
  2728. if self.panel.zoneColor.get():
  2729. self.colorZones()
  2730. else:
  2731. self.clearZoneColors()
  2732. def colorZones(self):
  2733. # Give each zone a random color to see them better
  2734. visGroups = self.getDNAVisGroups(self.NPToplevel)
  2735. for visGroup in visGroups:
  2736. np = visGroup[0]
  2737. np.setColor(0.5 + random()/2.0,
  2738. 0.5 + random()/2.0,
  2739. 0.5 + random()/2.0)
  2740. def clearZoneColors(self):
  2741. # Clear random colors
  2742. visGroups = self.getDNAVisGroups(self.NPToplevel)
  2743. for visGroup in visGroups:
  2744. np = visGroup[0]
  2745. np.clearColor()
  2746. def getBlockFromName(self, name):
  2747. block=name[2:name.find(':')]
  2748. return block
  2749. def addToLandmarkBlock(self):
  2750. dnaRoot=self.selectedDNARoot
  2751. if dnaRoot and self.lastLandmarkBuildingDNA:
  2752. if DNAClassEqual(dnaRoot, DNA_FLAT_BUILDING):
  2753. n=dnaRoot.getName()
  2754. n=n[n.find(':'):]
  2755. block=self.lastLandmarkBuildingDNA.getName()
  2756. block=block[2:block.find(':')]
  2757. dnaRoot.setName('tb'+block+n)
  2758. self.replaceSelected()
  2759. # If we're highlighting the landmark blocks:
  2760. if self.showLandmarkBlockToggleGroup:
  2761. # then highlight this one:
  2762. np=self.selectedNPRoot
  2763. self.showLandmarkBlockToggleGroup.append(np)
  2764. np.setColor(1,0,0,1)
  2765. elif self.selectedSuitPoint and self.lastLandmarkBuildingDNA:
  2766. block=self.lastLandmarkBuildingDNA.getName()
  2767. block=block[2:block.find(':')]
  2768. print ("associate point with building: " + str(block))
  2769. self.selectedSuitPoint.setLandmarkBuildingIndex(int(block))
  2770. def findHighestLandmarkBlock(self, dnaRoot, npRoot):
  2771. npc=npRoot.findAllMatches("**/*:toon_landmark_*")
  2772. highest=0
  2773. for i in range(npc.getNumPaths()):
  2774. path=npc.getPath(i)
  2775. block=path.getName()
  2776. block=int(block[2:block.find(':')])
  2777. if (block > highest):
  2778. highest=block
  2779. # Make a list of flat building names, outside of the
  2780. # recursive function:
  2781. self.flatNames=['random'] + BUILDING_TYPES
  2782. self.flatNames=map(lambda n: n+'_DNARoot', self.flatNames)
  2783. # Search/recurse the dna:
  2784. newHighest=self.convertToLandmarkBlocks(highest, dnaRoot)
  2785. # Get rid of the list of flat building names:
  2786. del self.flatNames
  2787. needToTraverse = (highest!=newHighest)
  2788. return (newHighest, needToTraverse)
  2789. def convertToLandmarkBlocks(self, block, dnaRoot):
  2790. """
  2791. Find all the buildings without landmark blocks and
  2792. assign them one.
  2793. """
  2794. for i in range(dnaRoot.getNumChildren()):
  2795. child = dnaRoot.at(i)
  2796. if DNAClassEqual(child, DNA_LANDMARK_BUILDING):
  2797. # Landmark buildings:
  2798. name=child.getName()
  2799. if name.find('toon_landmark_')==0:
  2800. block=block+1
  2801. child.setName('tb'+str(block)+':'+name)
  2802. elif DNAClassEqual(child, DNA_FLAT_BUILDING):
  2803. # Flat buildings:
  2804. name=child.getName()
  2805. if (name in self.flatNames):
  2806. child.setName('tb0:'+name)
  2807. else:
  2808. block = self.convertToLandmarkBlocks(block, child)
  2809. return block
  2810. def revertLandmarkBlock(self, block):
  2811. """
  2812. un-block flat buildings (set them to block zero).
  2813. """
  2814. npc=self.NPToplevel.findAllMatches("**/tb"+block+":*_DNARoot")
  2815. for i in range(npc.getNumPaths()):
  2816. nodePath=npc.getPath(i)
  2817. name=nodePath.getName()
  2818. if name[name.find(':'):][:15] != ':toon_landmark_':
  2819. name='tb0'+name[name.find(':'):]
  2820. dna=self.findDNANode(nodePath)
  2821. dna.setName(name)
  2822. nodePath=self.replace(nodePath, dna)
  2823. # If we're highlighting the landmark blocks:
  2824. if self.showLandmarkBlockToggleGroup:
  2825. # then highlight this one:
  2826. self.showLandmarkBlockToggleGroup.append(nodePath)
  2827. nodePath.setColor(0,1,0,1)
  2828. def landmarkBlockRemove(self, dna, nodePath):
  2829. if dna:
  2830. name=dna.getName()
  2831. # Get the underscore index within the name:
  2832. usIndex=name.find(':')
  2833. if name[usIndex:][:15] == ':toon_landmark_':
  2834. block=name[2:usIndex]
  2835. self.lastLandmarkBuildingDNA=None
  2836. self.revertLandmarkBlock(block)
  2837. def toggleShowLandmarkBlock(self):
  2838. dna=self.lastLandmarkBuildingDNA
  2839. if dna:
  2840. if not self.showLandmarkBlockToggleGroup:
  2841. group=[]
  2842. block=dna.getName()
  2843. block=block[2:block.find(':')]
  2844. # Get current landmark buildings:
  2845. npc=self.NPToplevel.findAllMatches("**/tb"+block+":*_DNARoot")
  2846. for i in range(npc.getNumPaths()):
  2847. nodePath=npc.getPath(i)
  2848. group.append(nodePath)
  2849. nodePath.setColor(1,0,0,1)
  2850. # Get block zero buildings (i.e. non-blocked):
  2851. npc=self.NPToplevel.findAllMatches("**/tb0:*_DNARoot")
  2852. for i in range(npc.getNumPaths()):
  2853. nodePath=npc.getPath(i)
  2854. group.append(nodePath)
  2855. nodePath.setColor(0,1,0,1)
  2856. # Get the suit point for this lb
  2857. for point, marker in self.pointDict.items():
  2858. if (point.getPointType() == DNASuitPoint.FRONTDOORPOINT):
  2859. lbIndex = point.getLandmarkBuildingIndex()
  2860. if (lbIndex == int(block)):
  2861. marker.setColor(1,0,0,1)
  2862. marker.setScale(1.0)
  2863. # There should only be one, so break now
  2864. elif (lbIndex == -1):
  2865. # This point belongs to no block
  2866. marker.setColor(0,1,0,1)
  2867. self.showLandmarkBlockToggleGroup=group
  2868. else:
  2869. for i in self.showLandmarkBlockToggleGroup:
  2870. i.clearColor()
  2871. for point, marker in self.pointDict.items():
  2872. if (point.getPointType() == DNASuitPoint.FRONTDOORPOINT):
  2873. marker.setColor(0,0,1,1)
  2874. marker.setScale(0.5)
  2875. self.showLandmarkBlockToggleGroup=None
  2876. def pdbBreak(self):
  2877. pdb.set_trace()
  2878. class LevelStyleManager:
  2879. """Class which reads in style files and manages class variables"""
  2880. def __init__(self):
  2881. # Used to locate the alpha mount on windows (i.e. on what drive)
  2882. self.stylePathPrefix = base.config.GetString('style-path-prefix', '')
  2883. # The main dictionary holding all attribute objects
  2884. self.attributeDictionary = {}
  2885. # Create the style samples
  2886. self.createBaselineStyleAttributes()
  2887. self.createWallStyleAttributes()
  2888. self.createBuildingStyleAttributes()
  2889. self.createColorAttributes()
  2890. self.createDNAAttributes()
  2891. self.createMiscAttributes()
  2892. # BASELINE STYLE FUNCTIONS
  2893. def createBaselineStyleAttributes(self):
  2894. """
  2895. Create a baselineStyle entry in the attribute dictionary
  2896. This will be a dictionary of style attributes, one per neighborhood
  2897. """
  2898. # First create an empty dictionary
  2899. dict = self.attributeDictionary['baseline_style'] = {}
  2900. # Create a attribute object for each neighborhood
  2901. for neighborhood in NEIGHBORHOODS:
  2902. attribute = LevelAttribute('baseline_style')
  2903. attribute.setDict(
  2904. # Create a baseline style dictionary for each neighborhood
  2905. self.createBaselineStyleDictionary(neighborhood))
  2906. # Using this dictionary, create style pie menus
  2907. attribute.setMenu(
  2908. self.createBaselineStyleMenu(neighborhood, attribute.getDict()))
  2909. dict[neighborhood] = attribute
  2910. def createBaselineStyleDictionary(self, neighborhood):
  2911. """
  2912. Create a dictionary of baseline styles for a neighborhood
  2913. """
  2914. filename = neighborhood + '_baseline_styles.txt'
  2915. print 'Loading baseline styles from: ' + filename
  2916. styleData = self.getStyleFileData(filename)
  2917. return self.initializeBaselineStyleDictionary(styleData, neighborhood)
  2918. def initializeBaselineStyleDictionary(self, styleData, neighborhood):
  2919. """
  2920. Fill in the baseline style dictionary with data from the style file
  2921. """
  2922. styleDictionary = {}
  2923. styleCount = 0
  2924. code = NEIGHBORHOOD_CODES[neighborhood]
  2925. while styleData:
  2926. l = styleData[0]
  2927. if l == 'baselineStyle':
  2928. # Start of new style, strip off first line then extract style
  2929. style, styleData = self.extractBaselineStyle(styleData)
  2930. style.name = code + '_baseline_style_' + `styleCount`
  2931. # Store style in dictionary
  2932. styleDictionary[style.name] = style
  2933. styleCount = styleCount + 1
  2934. # Move to next line
  2935. styleData = styleData[1:]
  2936. return styleDictionary
  2937. def extractBaselineStyle(self, styleData):
  2938. """
  2939. Pull out one style from a list of style data. Will keep
  2940. processing data until endBaselineStyle of end of data is reached.
  2941. Returns a baseline style and remaining styleData.
  2942. """
  2943. # Create default style
  2944. style = DNABaselineStyle()
  2945. # Strip off first line
  2946. styleData = styleData[1:]
  2947. while styleData:
  2948. l = styleData[0]
  2949. if l == 'endBaselineStyle':
  2950. # End of style found, break out of while loop
  2951. # Note, endBaselineStyle line is *not* stripped off
  2952. return style, styleData
  2953. else:
  2954. pair = map(string.strip, l.split(':'))
  2955. if style.__dict__.has_key(pair[0]):
  2956. pair_0 = pair[0]
  2957. # Convert some numerical values
  2958. if (pair_0 == 'color'
  2959. or pair_0 == 'kern'
  2960. or pair_0 == 'wiggle'
  2961. or pair_0 == 'stumble'
  2962. or pair_0 == 'stomp'
  2963. or pair_0 == 'curve'
  2964. or pair_0 == 'x'
  2965. or pair_0 == 'z'
  2966. or pair_0 == 'scaleX'
  2967. or pair_0 == 'scaleZ'
  2968. or pair_0 == 'roll'):
  2969. style[pair_0] = eval(pair[1])
  2970. else:
  2971. style[pair_0] = pair[1]
  2972. else:
  2973. print 'extractBaselineStyle: Invalid Key'
  2974. print pair[0]
  2975. styleData = styleData[1:]
  2976. # No end of style found, return style data as is
  2977. return style, None
  2978. def createBaselineStyleMenu(self, neighborhood, dictionary):
  2979. """
  2980. Create a baseline style pie menu
  2981. """
  2982. numItems = len(dictionary)
  2983. newStyleMenu = hidden.attachNewNode(neighborhood + '_style_menu')
  2984. radius = 0.7
  2985. angle = deg2Rad(360.0/numItems)
  2986. keys = dictionary.keys()
  2987. keys.sort()
  2988. styles = map(lambda x, d = dictionary: d[x], keys)
  2989. sf = 0.1
  2990. aspectRatio = (direct.dr.width/float(direct.dr.height))
  2991. for i in range(numItems):
  2992. # Get the node
  2993. node = self.createBaselineStyleSample(styles[i])
  2994. bounds = node.getBounds()
  2995. center = bounds.getCenter()
  2996. center = center * sf
  2997. # Reposition it
  2998. node.setPos((radius * math.cos(i * angle)) - center[0],
  2999. 0.0,
  3000. ((radius * aspectRatio * math.sin(i * angle)) -
  3001. center[2]))
  3002. # Scale it
  3003. node.setScale(sf)
  3004. # Add it to the styleMenu
  3005. node.reparentTo(newStyleMenu)
  3006. # Scale the whole shebang down by 0.5
  3007. newStyleMenu.setScale(0.5)
  3008. # Create and return a pie menu
  3009. return PieMenu(newStyleMenu, styles)
  3010. def createBaselineStyleSample(self, baselineStyle):
  3011. """
  3012. Create a style sample using the DNA info in the style
  3013. """
  3014. baseline = DNASignBaseline()
  3015. # Set some example text:
  3016. DNASetBaselineString(baseline, "Example Text")
  3017. baselineStyle.copyTo(baseline)
  3018. return baseline.traverse(hidden, DNASTORE, 1)
  3019. # WALL STYLE FUNCTIONS
  3020. def createWallStyleAttributes(self):
  3021. """
  3022. Create a wallStyle entry in the attribute dictionary
  3023. This will be a dictionary of style attributes, one per neighborhood
  3024. """
  3025. # First create an empty dictionary
  3026. dict = self.attributeDictionary['wall_style'] = {}
  3027. # Create a attribute object for each neighborhood
  3028. for neighborhood in NEIGHBORHOODS:
  3029. attribute = LevelAttribute('wall_style')
  3030. attribute.setDict(
  3031. # Create a wall style dictionary for each neighborhood
  3032. self.createWallStyleDictionary(neighborhood))
  3033. # Using this dictionary, create color pie menus
  3034. attribute.setMenu(
  3035. self.createWallStyleMenu(neighborhood, attribute.getDict()))
  3036. dict[neighborhood] = attribute
  3037. def createWallStyleDictionary(self, neighborhood):
  3038. """
  3039. Create a dictionary of wall styles for a neighborhood
  3040. """
  3041. filename = neighborhood + '_wall_styles.txt'
  3042. print 'Loading wall styles from: ' + filename
  3043. styleData = self.getStyleFileData(filename)
  3044. return self.initializeWallStyleDictionary(styleData, neighborhood)
  3045. def initializeWallStyleDictionary(self, styleData, neighborhood):
  3046. """
  3047. Fill in the wall style dictionary with data from the style file
  3048. """
  3049. styleDictionary = {}
  3050. styleCount = 0
  3051. code = NEIGHBORHOOD_CODES[neighborhood]
  3052. while styleData:
  3053. l = styleData[0]
  3054. if l == 'wallStyle':
  3055. # Start of new style, strip off first line then extract style
  3056. style, styleData = self.extractWallStyle(styleData)
  3057. style.name = code + '_wall_style_' + `styleCount`
  3058. # Store style in dictionary
  3059. styleDictionary[style.name] = style
  3060. styleCount = styleCount + 1
  3061. # Move to next line
  3062. styleData = styleData[1:]
  3063. return styleDictionary
  3064. def extractWallStyle(self, styleData):
  3065. """
  3066. Pull out one style from a list of style data. Will keep
  3067. processing data until endWallStyle of end of data is reached.
  3068. Returns a wall style and remaining styleData.
  3069. """
  3070. # Create default style
  3071. style = DNAWallStyle()
  3072. # Strip off first line
  3073. styleData = styleData[1:]
  3074. while styleData:
  3075. l = styleData[0]
  3076. if l == 'endWallStyle':
  3077. # End of style found, break out of while loop
  3078. # Note, endWallStyle line is *not* stripped off
  3079. return style, styleData
  3080. else:
  3081. pair = map(string.strip, l.split(':'))
  3082. if style.__dict__.has_key(pair[0]):
  3083. # Convert colors and count strings to numerical values
  3084. if ((string.find(pair[0],'_color') >= 0) or
  3085. (string.find(pair[0],'_count') >= 0)):
  3086. style[pair[0]] = eval(pair[1])
  3087. else:
  3088. style[pair[0]] = pair[1]
  3089. else:
  3090. print 'getStyleDictionaryFromStyleData: Invalid Key'
  3091. print pair[0]
  3092. styleData = styleData[1:]
  3093. # No end of style found, return style data as is
  3094. return style, None
  3095. def createWallStyleMenu(self, neighborhood, dictionary):
  3096. """
  3097. Create a wall style pie menu
  3098. """
  3099. numItems = len(dictionary)
  3100. newStyleMenu = hidden.attachNewNode(neighborhood + '_style_menu')
  3101. radius = 0.7
  3102. angle = deg2Rad(360.0/numItems)
  3103. keys = dictionary.keys()
  3104. keys.sort()
  3105. styles = map(lambda x, d = dictionary: d[x], keys)
  3106. sf = 0.03
  3107. aspectRatio = (direct.dr.width/float(direct.dr.height))
  3108. for i in range(numItems):
  3109. # Get the node
  3110. node = self.createWallStyleSample(styles[i])
  3111. bounds = node.getBounds()
  3112. center = bounds.getCenter()
  3113. center = center * sf
  3114. # Reposition it
  3115. node.setPos((radius * math.cos(i * angle)) - center[0],
  3116. 0.0,
  3117. ((radius * aspectRatio * math.sin(i * angle)) -
  3118. center[2]))
  3119. # Scale it
  3120. node.setScale(sf)
  3121. # Add it to the styleMenu
  3122. node.reparentTo(newStyleMenu)
  3123. # Scale the whole shebang down by 0.5
  3124. newStyleMenu.setScale(0.5)
  3125. # Create and return a pie menu
  3126. return PieMenu(newStyleMenu, styles)
  3127. def createWallStyleSample(self, wallStyle):
  3128. """
  3129. Create a style sample using the DNA info in the style
  3130. """
  3131. bldg = DNAFlatBuilding()
  3132. bldgStyle = DNAFlatBuildingStyle(styleList = [(wallStyle, 10.0)])
  3133. self.setDNAFlatBuildingStyle(bldg, bldgStyle, width = 12.0,
  3134. name = 'wall_style_sample')
  3135. return bldg.traverse(hidden, DNASTORE, 1)
  3136. # BUILDING STYLE FUNCTIONS
  3137. def createBuildingStyleAttributes(self):
  3138. """
  3139. Create a buildingStyle entry in the attribute dictionary
  3140. This will be a dictionary of style attributes, one per neighborhood
  3141. This information is sorted and stored by num walls, building height,
  3142. and building type (e.g. 10_20, or 10_10_10).
  3143. """
  3144. # First create an attribute which holds one dictionary per
  3145. # neighborhood which stores all of the styles for each neighborhood.
  3146. styleDict = self.attributeDictionary['building_style_all'] = {}
  3147. # Keep track of all building types
  3148. typeDict = {}
  3149. masterTypeList = []
  3150. for neighborhood in NEIGHBORHOODS:
  3151. attribute = LevelAttribute('building_style_all')
  3152. # Create a building style dictionary for each neighborhood
  3153. attribute.setDict(
  3154. self.createBuildingStyleDictionary(neighborhood))
  3155. # Using this dictionary, create building style pie menus
  3156. attribute.setMenu(
  3157. self.createBuildingStyleMenu(neighborhood,
  3158. attribute.getDict()))
  3159. # Store attribute in dictionary keyed by neighborhood
  3160. styleDict[neighborhood] = attribute
  3161. # Generate a list of building types for this neighborhood
  3162. # and a list of building types for all neighborhoods,
  3163. # to be used in creating attribute dicts below
  3164. typeList = typeDict[neighborhood] = []
  3165. for style in attribute.getList():
  3166. heightType = string.strip(string.split(style.name, ':')[1])
  3167. if heightType not in typeList:
  3168. typeList.append(heightType)
  3169. if heightType not in masterTypeList:
  3170. masterTypeList.append(heightType)
  3171. # Now sort styles according to the building type and number of walls
  3172. # in the building style. Each of these attributes is also sorted by
  3173. # neighborhood
  3174. for i in masterTypeList:
  3175. typeKey = i + '_styles'
  3176. self.attributeDictionary[typeKey] = {}
  3177. for i in NUM_WALLS:
  3178. numWallKey = `i` + '_wall_styles'
  3179. self.attributeDictionary[numWallKey] = {}
  3180. # Also sort height lists according to total height of the building
  3181. for i in BUILDING_HEIGHTS:
  3182. heightKey = `i` + '_ft_wall_heights'
  3183. self.attributeDictionary[heightKey] = {}
  3184. # Now distribute data for each neighborhood
  3185. for neighborhood in NEIGHBORHOODS:
  3186. # Create temp dicts to accumulate styles and heights for that
  3187. # neighborhood
  3188. typeAttributes = {}
  3189. numWallsAttributes = {}
  3190. heightAttributes = {}
  3191. # Store atributes for the different categories
  3192. # Building type
  3193. for i in typeDict[neighborhood]:
  3194. typeAttrName = neighborhood + '_' + i + '_styles'
  3195. typeAttributes[i] = LevelAttribute(typeAttrName)
  3196. # Number of walls
  3197. for i in NUM_WALLS:
  3198. styleAttrName = neighborhood + '_' + `i` + '_wall_styles'
  3199. numWallsAttributes[i] = LevelAttribute(styleAttrName)
  3200. # Building height
  3201. for i in BUILDING_HEIGHTS:
  3202. heightAttrName = neighborhood + '_' + `i` + '_ft_wall_heights'
  3203. heightAttributes[i] = LevelAttribute(heightAttrName)
  3204. # Sort through the styles and store in separate lists
  3205. for style in styleDict[neighborhood].getList():
  3206. # Put in code for number of walls into building styles
  3207. heightType = string.strip(string.split(style.name, ':')[1])
  3208. heightList = map(string.atof, string.split(heightType, '_'))
  3209. numWalls = len(heightList)
  3210. # This one stores styles sorted by type
  3211. typeAttributes[heightType].add(style)
  3212. # This one stores styles sorted by number of walls
  3213. numWallsAttributes[numWalls].add(style)
  3214. # A record of all the unique height lists
  3215. height = calcHeight(heightList)
  3216. if heightList not in heightAttributes[height].getList():
  3217. heightAttributes[height].add(heightList)
  3218. # Now store these sorted style and height attributes
  3219. # in the appropriate top-level attribute dictionary
  3220. for i in typeDict[neighborhood]:
  3221. # Styles
  3222. typeKey = i + '_styles'
  3223. self.attributeDictionary[typeKey][neighborhood] = (
  3224. typeAttributes[i])
  3225. for i in NUM_WALLS:
  3226. # Styles
  3227. numWallKey = `i` + '_wall_styles'
  3228. self.attributeDictionary[numWallKey][neighborhood] = (
  3229. numWallsAttributes[i])
  3230. for i in BUILDING_HEIGHTS:
  3231. # Heights
  3232. heightKey = `i` + '_ft_wall_heights'
  3233. self.attributeDictionary[heightKey][neighborhood] = (
  3234. heightAttributes[i])
  3235. def createBuildingStyleDictionary(self, neighborhood):
  3236. """
  3237. Create a dictionary of wall styles for a neighborhood
  3238. """
  3239. filename = neighborhood + '_building_styles.txt'
  3240. print 'Loading building styles from: ' + filename
  3241. styleData = self.getStyleFileData(filename)
  3242. return self.initializeBuildingStyleDictionary(styleData, neighborhood)
  3243. def initializeBuildingStyleDictionary(self, styleData, neighborhood):
  3244. """
  3245. Fill in the building style dictionary with data from the style file
  3246. """
  3247. # Create a dictionary of all building styles, this will later be
  3248. # split out into a separate dictionary for each building type
  3249. # e.g. 20, 10-10, 10-20....
  3250. bldgStyleDictionary = {}
  3251. styleCount = 0
  3252. code = NEIGHBORHOOD_CODES[neighborhood]
  3253. while styleData:
  3254. # Pull out first line
  3255. l = styleData[0]
  3256. if l[:13] == 'buildingStyle':
  3257. # Start with empty style list
  3258. bldgStyle = DNAFlatBuildingStyle(styleList = [])
  3259. # Extract height information found at end of line
  3260. heightCode = string.strip(string.split(l, ':')[1])
  3261. heightList = map(string.atof, string.split(heightCode, '_'))
  3262. # Construct name for building style. Tack on height code
  3263. # to be used later to split styles by heightCode
  3264. bldgStyle.name = (
  3265. code + '_building_style_' + `styleCount` +
  3266. ':' + heightCode)
  3267. # Increment counter
  3268. styleCount = styleCount + 1
  3269. # Reset wall counter to zero
  3270. wallCount = 0
  3271. elif l == 'endBuildingStyle':
  3272. # Done, add new style to dictionary
  3273. bldgStyleDictionary[bldgStyle.name] = bldgStyle
  3274. elif l[:9] == 'wallStyle':
  3275. # Beginning of next wall style
  3276. wallStyle, styleData = self.extractWallStyle(styleData)
  3277. wallStyle.name = bldgStyle.name + '_wall_' + `wallCount`
  3278. try:
  3279. height = heightList[wallCount]
  3280. except IndexError:
  3281. height = 10.0
  3282. # Add wall style to building style
  3283. bldgStyle.add(wallStyle, height)
  3284. # Increment wall counter
  3285. wallCount = wallCount + 1
  3286. # Move to next line
  3287. styleData = styleData[1:]
  3288. return bldgStyleDictionary
  3289. def createBuildingStyleMenu(self, neighborhood, dictionary):
  3290. """
  3291. Create a wall style pie menu
  3292. """
  3293. numItems = len(dictionary)
  3294. newStyleMenu = hidden.attachNewNode(neighborhood + '_style_menu')
  3295. radius = 0.7
  3296. angle = deg2Rad(360.0/numItems)
  3297. keys = dictionary.keys()
  3298. keys.sort()
  3299. styles = map(lambda x, d = dictionary: d[x], keys)
  3300. sf = 0.02
  3301. aspectRatio = (direct.dr.width/float(direct.dr.height))
  3302. for i in range(numItems):
  3303. # Get the node
  3304. node = self.createBuildingStyleSample(styles[i])
  3305. bounds = node.getBounds()
  3306. center = bounds.getCenter()
  3307. center = center * sf
  3308. # Reposition it
  3309. node.setPos((radius * math.cos(i * angle)) - center[0],
  3310. 0.0,
  3311. ((radius * aspectRatio * math.sin(i * angle)) -
  3312. center[2]))
  3313. # Scale it
  3314. node.setScale(sf)
  3315. # Add it to the styleMenu
  3316. node.reparentTo(newStyleMenu)
  3317. # Scale the whole shebang down by 0.5
  3318. newStyleMenu.setScale(0.5)
  3319. # Create and return a pie menu
  3320. return PieMenu(newStyleMenu, styles)
  3321. def createBuildingStyleSample(self, bldgStyle):
  3322. """
  3323. Create a style sample using the DNA info in the style
  3324. """
  3325. bldg = DNAFlatBuilding()
  3326. self.setDNAFlatBuildingStyle(bldg, bldgStyle, width = 10.0,
  3327. name = 'building_style_sample')
  3328. return bldg.traverse(hidden, DNASTORE, 1)
  3329. def setDNAFlatBuildingStyle(self, fb, bldgStyle, width = 10.0,
  3330. heightList = None, name = 'building'):
  3331. """ Set DNAFlatBuilding style. """
  3332. # Remove flat building's children
  3333. DNARemoveChildren(fb)
  3334. # Update the name
  3335. fb.setName(name)
  3336. # Create the walls
  3337. styleList = bldgStyle.styleList
  3338. # Height list not specified, use styles default heights
  3339. if not heightList:
  3340. heightList = bldgStyle.heightList
  3341. for i in range(len(styleList)):
  3342. wallStyle = styleList[i]
  3343. # Get Style
  3344. if not wallStyle:
  3345. # If set to None use default style
  3346. wallStyle = DNAWallStyle()
  3347. # Try to get height
  3348. try:
  3349. wallHeight = heightList[i]
  3350. except IndexError:
  3351. wallHeight = 10.0
  3352. # Create wall accordingly
  3353. wall = DNAWall()
  3354. self.setDNAWallStyle(wall, wallStyle, wallHeight,
  3355. width = width)
  3356. # Add it to building DNA
  3357. fb.add(wall)
  3358. # Set the buildings width
  3359. fb.setWidth(width)
  3360. def setDNAWallStyle(self, wall, style, height = 10.0, width = None):
  3361. """ Set DNAWall to input style. """
  3362. # Remove wall's children
  3363. DNARemoveChildren(wall)
  3364. # Update wall attributes
  3365. wall.setCode(style['wall_texture'])
  3366. wall.setColor(style['wall_color'])
  3367. wall.setHeight(height)
  3368. # Add windows if necessary
  3369. if style['window_texture']:
  3370. windows = DNAWindows()
  3371. windowCount = style['window_count']
  3372. if width:
  3373. if (width < 15.0):
  3374. windowCount = min(1, windowCount)
  3375. windows.setWindowCount(windowCount)
  3376. # Set window's attributes
  3377. windows.setCode(style['window_texture'])
  3378. windows.setColor(style['window_color'])
  3379. # Add windows to the wall
  3380. wall.add(windows)
  3381. # Add a window awning if necessary
  3382. if style['window_awning_texture']:
  3383. awning = DNAProp()
  3384. # Update awning's attributes
  3385. awning.setCode(style['window_awning_texture'])
  3386. awning.setColor(style['window_awning_color'])
  3387. # Add awning to window
  3388. windows.add(awning)
  3389. # Add a door if necessary
  3390. if style['door_texture']:
  3391. door = DNADoor()
  3392. # Set the door's attributes
  3393. door.setCode(style['door_texture'])
  3394. door.setColor(style['door_color'])
  3395. # Add door to wall
  3396. wall.add(door)
  3397. # Add a door awning if necessary
  3398. if style['door_awning_texture']:
  3399. awning = DNAProp()
  3400. awning.setCode(style['door_awning_texture'])
  3401. awning.setColor(style['door_awning_color'])
  3402. door.add(awning)
  3403. # And a cornice if necessary
  3404. if style['cornice_texture']:
  3405. cornice = DNACornice()
  3406. # Set the cornice's attributes
  3407. cornice.setCode(style['cornice_texture'])
  3408. cornice.setColor(style['cornice_color'])
  3409. # Add cornice to wall
  3410. wall.add(cornice)
  3411. def printFlatBuildingStyle(self, building):
  3412. for i in range(building.getNumChildren()):
  3413. child = building.at(i)
  3414. if DNAClassEqual(child, DNA_WALL):
  3415. self.printWallStyle(child)
  3416. def printWallStyle(self, wall):
  3417. print 'wall_texture: ' + wall.getCode()
  3418. color = wall.getColor()
  3419. print ('wall_color: Vec4(%.3f, %.3f, %.3f, 1.0)' %
  3420. (color[0], color[1], color[2]))
  3421. for i in range(wall.getNumChildren()):
  3422. child = wall.at(i)
  3423. if DNAClassEqual(child, DNA_WINDOWS):
  3424. print 'window_texture: ' + child.getCode()
  3425. color = child.getColor()
  3426. print ('window_color: Vec4(%.3f, %.3f, %.3f, 1.0)' %
  3427. (color[0], color[1], color[2]))
  3428. # MRM: Check for awnings here
  3429. elif DNAClassEqual(child, DNA_DOOR):
  3430. print 'door_texture: ' + child.getCode()
  3431. color = child.getColor()
  3432. print ('door_color: Vec4(%.3f, %.3f, %.3f, 1.0)' %
  3433. (color[0], color[1], color[2]))
  3434. # MRM: Check for awnings here
  3435. elif DNAClassEqual(child, DNA_CORNICE):
  3436. print 'cornice_texture: ' + child.getCode()
  3437. color = child.getColor()
  3438. print ('cornice_color: Vec4(%.3f, %.3f, %.3f, 1.0)' %
  3439. (color[0], color[1], color[2]))
  3440. # COLOR PALETTE FUNCTIONS
  3441. def createColorAttributes(self):
  3442. # First compile color information for each neighborhood
  3443. colorDictionary = {}
  3444. colorMenuDictionary = {}
  3445. for neighborhood in NEIGHBORHOODS:
  3446. colorDictionary[neighborhood] = (
  3447. # Create a wall style dictionary for each neighborhood
  3448. self.createColorDictionary(neighborhood))
  3449. # Using this dictionary, create color pie menus
  3450. colorMenuDictionary[neighborhood] = (
  3451. self.createColorMenus(
  3452. neighborhood, colorDictionary[neighborhood]))
  3453. # Now store this info in the appropriate place in the attribute dict
  3454. for colorType in COLOR_TYPES:
  3455. neighborhoodDict = self.attributeDictionary[colorType] = {}
  3456. for neighborhood in NEIGHBORHOODS:
  3457. attribute = LevelAttribute(colorType)
  3458. dict = {}
  3459. # Add colors to attribute dictionary
  3460. colorList = colorDictionary[neighborhood][colorType]
  3461. for i in range(len(colorList)):
  3462. dict[i] = colorList[i]
  3463. attribute.setDict(dict)
  3464. attribute.setMenu(
  3465. colorMenuDictionary[neighborhood][colorType])
  3466. neighborhoodDict[neighborhood] = attribute
  3467. def createColorDictionary(self, neighborhood):
  3468. filename = neighborhood + '_colors.txt'
  3469. print 'Loading Color Palettes from: ' + filename
  3470. colorData = self.getStyleFileData(filename)
  3471. return self.getColorDictionary(colorData)
  3472. def getColorDictionary(self, colorData):
  3473. # Initialze neighborhod color dictionary
  3474. dict = {}
  3475. for colorType in COLOR_TYPES:
  3476. dict[colorType] = DEFAULT_COLORS[:]
  3477. # Add color information to appropriate sub-list
  3478. for line in colorData:
  3479. pair = map(string.strip, line.split(':'))
  3480. key = pair[0]
  3481. if dict.has_key(key):
  3482. dict[key].append(eval(pair[1]))
  3483. else:
  3484. print 'LevelStyleManager.getColorDictionary key not found'
  3485. return dict
  3486. def createColorMenus(self, neighborhood, dictionary):
  3487. menuDict = {}
  3488. keys = dictionary.keys()
  3489. for key in keys:
  3490. menuDict[key] = (
  3491. self.createColorMenu(neighborhood + key, dictionary[key]))
  3492. return menuDict
  3493. def createColorMenu(self, menuName, colorList, radius = 0.7, sf = 2.0):
  3494. # Create color chips for each color
  3495. numItems = len(colorList)
  3496. # Attach it to hidden for now
  3497. newColorMenu = hidden.attachNewNode(menuName + 'Menu')
  3498. # Compute the angle per item
  3499. angle = deg2Rad(360.0/float(numItems))
  3500. aspectRatio = (direct.dr.width / float(direct.dr.height))
  3501. # Attach the color chips to the new menu and adjust sizes
  3502. for i in range (numItems):
  3503. # Create a text node--just a card, really--of the right color.
  3504. tn = TextNode()
  3505. tn.freeze()
  3506. tn.setFont(getDefaultFont())
  3507. tn.setTransform(Mat4.scaleMat(0.07, 0.07, 0.07 * aspectRatio))
  3508. tn.setCardColor(colorList[i])
  3509. tn.setCardActual(0, 1.1111, 0, 0.8333)
  3510. tn.setText(' ')
  3511. tn.thaw()
  3512. # Reposition it
  3513. card = tn.getCardTransformed()
  3514. center = (card[1] - card[0], card[3] - card[2])
  3515. node = newColorMenu.attachNewNode(tn)
  3516. node.setScale(sf)
  3517. node.setPos(radius * math.cos(i * angle) - center[0], 0.0,
  3518. ((radius * aspectRatio * math.sin(i * angle)) -
  3519. center[1]))
  3520. # Scale the whole shebang down by 0.5
  3521. newColorMenu.setScale(0.5)
  3522. # Create and return resulting pie menu
  3523. return PieMenu(newColorMenu, colorList)
  3524. # DNA ATTRIBUTES
  3525. def createDNAAttributes(self):
  3526. # Create the DNA Attribute entries
  3527. # Most objects are oriented with graphical menu items
  3528. # Street and props aren't oiented and use text menus
  3529. for dnaType in DNA_TYPES:
  3530. # Create a dictionary of dna types
  3531. dict = {}
  3532. if ((dnaType == 'street') or (dnaType == 'prop') or
  3533. (dnaType == 'toon_landmark')):
  3534. dnaList = self.getCatalogCodes(dnaType)
  3535. elif (dnaType == 'sign'):
  3536. dnaList = [''] + self.getCatalogCodes(dnaType)
  3537. else:
  3538. dnaList = [None] + self.getCatalogCodesSuffix(dnaType, '_ur')
  3539. # Add dnaCodes to attribute dictionary
  3540. for i in range(len(dnaList)):
  3541. dict[i] = dnaList[i]
  3542. # Create a LevelAttribute
  3543. attribute = LevelAttribute(dnaType + '_texture')
  3544. attribute.setDict(dict)
  3545. # Prepend None to allow option of no item
  3546. if ((dnaType == 'street') or (dnaType == 'prop') or
  3547. (dnaType == 'toon_landmark')):
  3548. attribute.setMenu(self.createTextPieMenu(dnaType, dnaList))
  3549. elif (dnaType == 'wall'):
  3550. attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
  3551. sf = 0.25))
  3552. elif (dnaType == 'sign'):
  3553. attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
  3554. sf = 0.05))
  3555. elif (dnaType == 'door'):
  3556. attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
  3557. sf = 0.035))
  3558. elif (dnaType == 'cornice'):
  3559. attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
  3560. sf = 0.5))
  3561. elif (dnaType == 'window'):
  3562. attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
  3563. sf = 0.125))
  3564. else:
  3565. print 'unknown attribute'
  3566. # Add it to the attributeDictionary
  3567. self.attributeDictionary[dnaType + '_texture'] = attribute
  3568. def createDNAPieMenu(self, dnaType, dnaList, radius = 0.7, sf = 1.0):
  3569. # Get the currently available window options
  3570. numItems = len(dnaList)
  3571. # Create a top level node to hold the menu
  3572. newMenu = hidden.attachNewNode(dnaType + 'Menu')
  3573. # Compute angle increment per item
  3574. angle = deg2Rad(360.0/numItems)
  3575. aspectRatio = direct.dr.width /float(direct.dr.height)
  3576. # Add items
  3577. for i in range(0, numItems):
  3578. if dnaList[i]:
  3579. # Get the node
  3580. node = DNASTORE.findNode(dnaList[i])
  3581. else:
  3582. node = None
  3583. if node:
  3584. # Add it to the window menu
  3585. path = node.instanceTo(newMenu)
  3586. # Place menu nodes in a circle, offset each in X and Z
  3587. # by half node width/height
  3588. bounds = path.getBounds()
  3589. center = bounds.getCenter()
  3590. center = center * sf
  3591. path.setPos((radius * math.cos(i * angle)) - center[0],
  3592. 0.0,
  3593. ((radius * aspectRatio * math.sin(i * angle)) -
  3594. center[2]))
  3595. path.setScale(sf)
  3596. # Scale the whole shebang down by 0.5
  3597. newMenu.setScale(0.5)
  3598. # Create and return a pie menu
  3599. return PieMenu(newMenu, dnaList)
  3600. def createTextPieMenu(self, dnaType, textList, radius = 0.7, sf = 1.0):
  3601. numItems = len(textList)
  3602. # Create top level node for new menu
  3603. newMenu = hidden.attachNewNode(dnaType + 'Menu')
  3604. # Compute angle per item
  3605. angle = deg2Rad(360.0/numItems)
  3606. aspectRatio = direct.dr.width/float(direct.dr.height)
  3607. # Add items
  3608. for i in range (numItems):
  3609. # Create text node for each item
  3610. if (textList[i] != None):
  3611. tn = TextNode()
  3612. tn.freeze()
  3613. tn.setFont(getDefaultFont())
  3614. tn.setTransform(Mat4.scaleMat(0.07, 0.07, 0.07 * aspectRatio))
  3615. tn.setTextColor(0, 0, 0, 1)
  3616. tn.setCardColor(1, 1, 1, 1)
  3617. tn.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
  3618. tn.setText(str(textList[i]))
  3619. tn.thaw()
  3620. # Reposition it
  3621. card = tn.getCardTransformed()
  3622. center = (card[1] - card[0], card[3] - card[2])
  3623. node = newMenu.attachNewNode(tn)
  3624. node.setScale(sf)
  3625. node.setPos(radius * math.cos(i * angle) - center[0], 0.0,
  3626. ((radius * aspectRatio * math.sin(i * angle)) -
  3627. center[1]))
  3628. # Scale the whole shebang down by 0.5
  3629. newMenu.setScale(0.5)
  3630. # Create and return a pie menu
  3631. return PieMenu(newMenu, textList)
  3632. # MISCELLANEOUS MENUS
  3633. def createMiscAttributes(self):
  3634. # Num windows menu
  3635. self.createMiscAttribute('window_count',[0,1,2,3,4])
  3636. # Building width menu
  3637. self.createMiscAttribute('building_width',[5,10,15,15.6,20,20.7,25])
  3638. # Building types
  3639. self.createMiscAttribute('building_type', BUILDING_TYPES)
  3640. # Building heights
  3641. self.createMiscAttribute('building_height', [10,20,25,30])
  3642. # MRM: Need offset on these menus
  3643. # Wall orientation menu
  3644. self.createMiscAttribute('wall_orientation', ['ur','ul','dl','dr'])
  3645. # Wall height menu
  3646. self.createMiscAttribute('wall_height', [10, 20])
  3647. # Window orientation menu
  3648. self.createMiscAttribute('window_orientation', ['ur','ul',None,None])
  3649. # Sign orientation menu
  3650. self.createMiscAttribute('sign_orientation', ['ur','ul',None,None])
  3651. # Door orientation menu
  3652. self.createMiscAttribute('door_orientation', ['ur','ul',None,None])
  3653. # Cornice orientation menu
  3654. self.createMiscAttribute('cornice_orientation', ['ur','ul',None,None])
  3655. def createMiscAttribute(self, miscType, miscList, sf = 3.0):
  3656. # Create a dictionary from miscList
  3657. dict = {}
  3658. # Add items to attribute dictionary
  3659. for i in range(len(miscList)):
  3660. dict[i] = miscList[i]
  3661. # Create the miscellaneous Attribute entries
  3662. attribute = LevelAttribute(miscType)
  3663. attribute.setDict(dict)
  3664. # Now create a pie menu
  3665. attribute.setMenu(self.createTextPieMenu(miscType, miscList,
  3666. sf = sf))
  3667. # Add it to the attributeDictionary
  3668. self.attributeDictionary[miscType] = attribute
  3669. # GENERAL FUNCTIONS
  3670. def getStyleFileData(self, filename):
  3671. """
  3672. Open the specified file and strip out unwanted whitespace and
  3673. empty lines. Return file as list, one file line per element.
  3674. """
  3675. fname = Filename(self.stylePathPrefix +
  3676. '/alpha/DIRECT/LevelEditor/StyleFiles/' +
  3677. filename)
  3678. f = open(fname.toOsSpecific(), 'r')
  3679. rawData = f.readlines()
  3680. f.close()
  3681. styleData = []
  3682. for line in rawData:
  3683. l = string.strip(line)
  3684. if l:
  3685. styleData.append(l)
  3686. return styleData
  3687. # UTILITY FUNCTIONS
  3688. def getAttribute(self, attribute):
  3689. """ Return specified attribute for current neighborhood """
  3690. levelAttribute = self.attributeDictionary[attribute]
  3691. # Get attribute for current neighborhood
  3692. if (type(levelAttribute) == types.DictionaryType):
  3693. levelAttribute = levelAttribute[self.getEditMode()]
  3694. return levelAttribute
  3695. # UTILITY FUNCTIONS
  3696. def hasAttribute(self, attribute):
  3697. """ Return specified attribute for current neighborhood """
  3698. if not self.attributeDictionary.has_key(attribute):
  3699. return 0
  3700. else:
  3701. levelAttribute = self.attributeDictionary[attribute]
  3702. # Get attribute for current neighborhood
  3703. if (type(levelAttribute) == types.DictionaryType):
  3704. editMode = self.getEditMode()
  3705. return levelAttribute.has_key(editMode)
  3706. else:
  3707. return 1
  3708. def getCatalogCode(self, category, i):
  3709. return DNASTORE.getCatalogCode(category, i)
  3710. def getCatalogCodes(self, category):
  3711. numCodes = DNASTORE.getNumCatalogCodes(category)
  3712. codes = []
  3713. for i in range(numCodes):
  3714. codes.append(DNASTORE.getCatalogCode(category, i))
  3715. return codes
  3716. def getCatalogCodesSuffix(self, category, suffix):
  3717. codes = self.getCatalogCodes(category)
  3718. orientedCodes = []
  3719. for code in codes:
  3720. if code[-3:] == suffix:
  3721. orientedCodes.append(code)
  3722. return orientedCodes
  3723. def setEditMode(self, mode):
  3724. """Set current neighborhood editing mode"""
  3725. self._editMode = mode
  3726. def getEditMode(self):
  3727. """Get current neighborhood editing mode"""
  3728. return self._editMode
  3729. class LevelAttribute:
  3730. """Class which encapsulates a pie menu and a set of items"""
  3731. def __init__(self, name):
  3732. # Record name
  3733. self.name = name
  3734. # Pie menu used to pick an option
  3735. self._menu = None
  3736. # Dictionary of available options
  3737. self._dict = {}
  3738. self._list = []
  3739. self.count = 0
  3740. # Currently selected option
  3741. self._current = None
  3742. def setCurrent(self, newValue, fEvent = 1):
  3743. self._current = newValue
  3744. # Send event if specified
  3745. if fEvent:
  3746. messenger.send('select_' + self.name, [self._current])
  3747. def setMenu(self,menu):
  3748. self._menu = menu
  3749. self._menu.action = self.setCurrent
  3750. def setDict(self,dict):
  3751. self._dict = dict
  3752. # Create a list from the dictionary
  3753. self._list = dict.values()
  3754. # Update count
  3755. self.count = len(self._list)
  3756. # Initialize current to first item
  3757. if (len(self._list) > 0):
  3758. self._current = self._list[0]
  3759. def setList(self,list):
  3760. self._list = list
  3761. # Create a dictionary from the list
  3762. self._dict = {}
  3763. self.count = 0
  3764. for item in list:
  3765. self._dict[self.count] = item
  3766. self.count += 1
  3767. # Initialize current to first item
  3768. if (self.count > 0):
  3769. self._current = self._list[0]
  3770. def add(self,item):
  3771. self._dict[self.count] = item
  3772. self._list.append(item)
  3773. self.count += 1
  3774. def getCurrent(self):
  3775. return self._current
  3776. def getMenu(self):
  3777. return self._menu
  3778. def getDict(self):
  3779. return self._dict
  3780. def getList(self):
  3781. return self._list
  3782. def getCount(self):
  3783. return self.count
  3784. class DNAFlatBuildingStyle:
  3785. """Class to hold attributes of a building style"""
  3786. def __init__(self, building = None, styleList = None, name = 'bldg_style'):
  3787. self.name = name
  3788. if building:
  3789. # Passed in a building
  3790. self.copy(building)
  3791. elif styleList != None:
  3792. # Passed in a list of style-height pairs
  3793. self.styleList = []
  3794. self.heightList = []
  3795. self.numWalls = 0
  3796. for pair in styleList:
  3797. self.add(pair[0], pair[1])
  3798. else:
  3799. # Use default style/height
  3800. self.styleList = [DNAWallStyle()]
  3801. self.heightList = [10]
  3802. self.numWalls = 1
  3803. def add(self, style, height):
  3804. self.styleList.append(style)
  3805. self.heightList.append(height)
  3806. self.numWalls += 1
  3807. def copy(self, building):
  3808. self.styleList = []
  3809. self.heightList = DNAGetWallHeights(building)[0]
  3810. self.numWalls = 0
  3811. for i in range(building.getNumChildren()):
  3812. child = building.at(i)
  3813. if DNAClassEqual(child, DNA_WALL):
  3814. wallStyle = DNAWallStyle(wall = child)
  3815. self.styleList.append(wallStyle)
  3816. self.numWalls += 1
  3817. def output(self, file = sys.stdout):
  3818. file.write('buildingStyle: %s\n' % createHeightCode(self.heightList))
  3819. for style in self.styleList:
  3820. style.output(file)
  3821. file.write('endBuildingStyle\n')
  3822. def createHeightCode(heightList):
  3823. def joinHeights(h1,h2):
  3824. return '%s_%s' % (h1, h2)
  3825. hl = map(ROUND_INT, heightList)
  3826. if len(hl) == 1:
  3827. return `hl[0]`
  3828. return reduce(joinHeights, hl)
  3829. def calcHeight(heightList):
  3830. height = 0
  3831. for h in heightList:
  3832. height = height + h
  3833. return int(height)
  3834. class DNABaselineStyle:
  3835. """Class to hold attributes of a baseline style (wiggle, colors, etc)"""
  3836. def __init__(self, baseline = None, name = 'baseline_style'):
  3837. # First initialize everything
  3838. self.name = name
  3839. self.code = None # i.e. font
  3840. self.kern = None
  3841. self.wiggle = None
  3842. self.stumble = None
  3843. self.stomp = None
  3844. self.curve = None
  3845. self.x = None
  3846. self.z = None
  3847. self.scaleX = 1.0
  3848. self.scaleZ = 1.0
  3849. self.roll = None
  3850. self.flags = None
  3851. self.color = Vec4(1.0)
  3852. # Then copy the specifics for the baseline if input
  3853. if baseline:
  3854. self.copy(baseline)
  3855. def copy(self, baseline):
  3856. self.code = baseline.getCode()
  3857. self.kern = baseline.getKern()
  3858. self.wiggle = baseline.getWiggle()
  3859. self.stumble = baseline.getStumble()
  3860. self.stomp = baseline.getStomp()
  3861. width=baseline.getWidth()
  3862. if width:
  3863. self.curve = 1.0/width
  3864. else:
  3865. self.curve = 0.0
  3866. pos = baseline.getPos()
  3867. self.x = pos[0]
  3868. self.z = pos[2]
  3869. scale = baseline.getScale()
  3870. self.scaleX = scale[0]
  3871. self.scaleZ = scale[2]
  3872. hpr = baseline.getHpr()
  3873. self.roll = hpr[2]
  3874. self.flags = baseline.getFlags()
  3875. self.color = baseline.getColor()
  3876. def copyTo(self, baseline):
  3877. if self.code != None:
  3878. baseline.setCode(self.code)
  3879. if self.kern != None:
  3880. baseline.setKern(self.kern)
  3881. if self.wiggle != None:
  3882. baseline.setWiggle(self.wiggle)
  3883. if self.stumble != None:
  3884. baseline.setStumble(self.stumble)
  3885. if self.stomp != None:
  3886. baseline.setStomp(self.stomp)
  3887. if self.curve != None:
  3888. diameter=0.0
  3889. if self.curve:
  3890. diameter=1.0/self.curve
  3891. baseline.setWidth(diameter)
  3892. baseline.setHeight(diameter)
  3893. if (self.x != None) or (self.z != None):
  3894. pos=baseline.getPos()
  3895. if self.x != None:
  3896. pos=Vec3(self.x, pos[1], pos[2])
  3897. if self.z != None:
  3898. pos=Vec3(pos[0], pos[1], self.z)
  3899. baseline.setPos(pos)
  3900. if self.roll != None:
  3901. baseline.setHpr(Vec3(0.0, 0.0, self.roll))
  3902. if (self.scaleX != None) or (self.scaleZ != None):
  3903. scale=baseline.getScale()
  3904. if self.scaleX != None:
  3905. scale=Vec3(self.scaleX, scale[1], scale[2])
  3906. if self.scaleZ != None:
  3907. scale=Vec3(scale[0], scale[1], self.scaleZ)
  3908. baseline.setScale(scale)
  3909. if self.flags != None:
  3910. baseline.setFlags(self.flags)
  3911. if self.color != None:
  3912. baseline.setColor(self.color)
  3913. def output(self, file = sys.stdout):
  3914. """ Output style description to a file """
  3915. file.write('baselineStyle\n')
  3916. if self.name != None:
  3917. file.write('name: %s\n' % self.name)
  3918. if self.code != None:
  3919. file.write('code: %s\n' % self.code)
  3920. if self.kern != None:
  3921. file.write('kern: %s\n' % self.kern)
  3922. if self.wiggle != None:
  3923. file.write('wiggle: %s\n' % self.wiggle)
  3924. if self.stumble != None:
  3925. file.write('stumble: %s\n' % self.stumble)
  3926. if self.stomp != None:
  3927. file.write('stomp: %s\n' % self.stomp)
  3928. if self.curve != None:
  3929. file.write('curve: %s\n' % self.curve)
  3930. if self.x != None:
  3931. file.write('x: %s\n' % self.x)
  3932. if self.z != None:
  3933. file.write('z: %s\n' % self.z)
  3934. if self.scaleX != None:
  3935. file.write('scaleX: %s\n' % self.scaleX)
  3936. if self.scaleZ != None:
  3937. file.write('scaleZ: %s\n' % self.scaleZ)
  3938. if self.roll != None:
  3939. file.write('roll: %s\n' % self.roll)
  3940. if self.flags != None:
  3941. file.write('flags: %s\n' % self.flags)
  3942. if self.color != None:
  3943. file.write('color: Vec4(%.2f, %.2f, %.2f, 1.0)\n'
  3944. % (self.color[0], self.color[1], self.color[2]))
  3945. file.write('endBaselineStyle\n')
  3946. # Convience functions to facilitate class use
  3947. def __setitem__(self, index, item):
  3948. self.__dict__[index] = item
  3949. def __getitem__(self, index):
  3950. return self.__dict__[index]
  3951. def __repr__(self):
  3952. return(
  3953. 'name: %s\n' % self.name +
  3954. 'code: %s\n' % self.code +
  3955. 'kern: %s\n' % self.kern +
  3956. 'wiggle: %s\n' % self.wiggle +
  3957. 'stumble: %s\n' % self.stumble +
  3958. 'stomp: %s\n' % self.stomp +
  3959. 'curve: %s\n' % self.curve +
  3960. 'x: %s\n' % self.x +
  3961. 'z: %s\n' % self.z +
  3962. 'scaleX: %s\n' % self.scaleX +
  3963. 'scaleZ: %s\n' % self.scaleZ +
  3964. 'roll: %s\n' % self.roll +
  3965. 'flags: %s\n' % self.flags +
  3966. 'color: %s\n' % self.color
  3967. )
  3968. class DNAWallStyle:
  3969. """Class to hold attributes of a wall style (textures, colors, etc)"""
  3970. def __init__(self, wall = None, name = 'wall_style'):
  3971. # First initialize everything
  3972. self.name = name
  3973. self.wall_texture = 'wall_md_blank_ur'
  3974. self.wall_color = Vec4(1.0)
  3975. self.window_count = 2
  3976. self.window_texture = None
  3977. self.window_color = Vec4(1.0)
  3978. self.window_awning_texture = None
  3979. self.window_awning_color = Vec4(1.0)
  3980. self.door_texture = None
  3981. self.door_color = Vec4(1.0)
  3982. self.door_awning_texture = None
  3983. self.door_awning_color = Vec4(1.0)
  3984. self.cornice_texture = None
  3985. self.cornice_color = Vec4(1.0)
  3986. # Then copy the specifics for the wall if input
  3987. if wall:
  3988. self.copy(wall)
  3989. def copy(self, wall):
  3990. self.wall_texture = wall.getCode()
  3991. self.wall_color = wall.getColor()
  3992. for i in range(wall.getNumChildren()):
  3993. child = wall.at(i)
  3994. if DNAClassEqual(child, DNA_WINDOWS):
  3995. self.window_count = child.getWindowCount()
  3996. self.window_texture = child.getCode()
  3997. self.window_color = child.getColor()
  3998. # MRM: Check for awnings here
  3999. elif DNAClassEqual(child, DNA_DOOR):
  4000. self.door_texture = child.getCode()
  4001. self.door_color = child.getColor()
  4002. # MRM: Check for awnings here
  4003. elif DNAClassEqual(child, DNA_CORNICE):
  4004. self.cornice_texture = child.getCode()
  4005. self.cornice_color = child.getColor()
  4006. def output(self, file = sys.stdout):
  4007. """ Output style description to a file """
  4008. def writeAttributes(f, type, s = self):
  4009. color = s[type + '_color']
  4010. f.write('%s_texture: %s\n' % (type, s[type + '_texture']))
  4011. f.write('%s_color: Vec4(%.2f, %.2f, %.2f, 1.0)\n' %
  4012. (type, color[0], color[1], color[2]))
  4013. file.write('wallStyle\n')
  4014. writeAttributes(file, 'wall')
  4015. if self['window_texture']:
  4016. writeAttributes(file, 'window')
  4017. file.write('window_count: %s\n' % self['window_count'])
  4018. if self['window_awning_texture']:
  4019. writeAttributes(file, 'window_awning')
  4020. if self['door_texture']:
  4021. writeAttributes(file, 'door')
  4022. if self['door_awning_texture']:
  4023. writeAttributes(file, 'door_awning')
  4024. if self['cornice_texture']:
  4025. writeAttributes(file, 'cornice')
  4026. file.write('endWallStyle\n')
  4027. # Convience functions to facilitate class use
  4028. def __setitem__(self, index, item):
  4029. self.__dict__[index] = item
  4030. def __getitem__(self, index):
  4031. return self.__dict__[index]
  4032. def __repr__(self):
  4033. return(
  4034. 'Name: %s\n' % self.name +
  4035. 'Wall Texture: %s\n' % self.wall_texture +
  4036. 'Wall Color: %s\n' % self.wall_color +
  4037. 'Window Texture: %s\n' % self.window_texture +
  4038. 'Window Color: %s\n' % self.window_color +
  4039. 'Window Awning Texture: %s\n' % self.window_awning_texture +
  4040. 'Window Awning Color: %s\n' % self.window_awning_color +
  4041. 'Door Texture: %s\n' % self.door_texture +
  4042. 'Door Color: %s\n' % self.door_color +
  4043. 'Door Awning Texture: %s\n' % self.door_awning_texture +
  4044. 'Door Awning Color: %s\n' % self.door_awning_color +
  4045. 'Cornice Texture: %s\n' % self.cornice_texture +
  4046. 'Cornice Color: %s\n' % self.cornice_color
  4047. )
  4048. class OldLevelEditor(NodePath, PandaObject):
  4049. pass
  4050. class LevelEditorPanel(Pmw.MegaToplevel):
  4051. def __init__(self, levelEditor, parent = None, **kw):
  4052. INITOPT = Pmw.INITOPT
  4053. optiondefs = (
  4054. ('title', 'Toontown Level Editor', None),
  4055. )
  4056. self.defineoptions(kw, optiondefs)
  4057. Pmw.MegaToplevel.__init__(self, parent, title = self['title'])
  4058. self.levelEditor = levelEditor
  4059. self.styleManager = self.levelEditor.styleManager
  4060. self.fUpdateSelected = 1
  4061. # Handle to the toplevels hull
  4062. hull = self.component('hull')
  4063. hull.geometry('400x550')
  4064. balloon = self.balloon = Pmw.Balloon(hull)
  4065. # Start with balloon help disabled
  4066. self.balloon.configure(state = 'none')
  4067. menuFrame = Frame(hull, relief = GROOVE, bd = 2)
  4068. menuFrame.pack(fill = X)
  4069. menuBar = Pmw.MenuBar(menuFrame, hotkeys = 1, balloon = balloon)
  4070. menuBar.pack(side = LEFT, expand = 1, fill = X)
  4071. menuBar.addmenu('Level Editor', 'Level Editor Operations')
  4072. menuBar.addmenuitem('Level Editor', 'command',
  4073. 'Load DNA from specified file',
  4074. label = 'Load DNA...',
  4075. command = self.levelEditor.loadSpecifiedDNAFile)
  4076. menuBar.addmenuitem('Level Editor', 'command',
  4077. 'Save DNA data to specified file',
  4078. label = 'Save DNA As...',
  4079. command = self.levelEditor.saveToSpecifiedDNAFile)
  4080. menuBar.addmenuitem('Level Editor', 'command',
  4081. 'Save DNA File',
  4082. label = 'Save DNA',
  4083. command = self.levelEditor.outputDNADefaultFile)
  4084. menuBar.addmenuitem('Level Editor', 'command',
  4085. 'Edit Visibility Groups',
  4086. label = 'Edit Vis Groups',
  4087. command = self.levelEditor.editDNAVisGroups)
  4088. menuBar.addmenuitem('Level Editor', 'command',
  4089. 'Reset level',
  4090. label = 'Reset level',
  4091. command = self.levelEditor.reset)
  4092. menuBar.addmenuitem('Level Editor', 'command',
  4093. 'Exit Level Editor Panel',
  4094. label = 'Exit',
  4095. command = self.levelEditor.destroy)
  4096. menuBar.addmenu('Style', 'Style Operations')
  4097. menuBar.addmenuitem('Style', 'command',
  4098. "Save Selected Object's Color",
  4099. label = 'Save Color',
  4100. command = self.levelEditor.saveColor)
  4101. menuBar.addmenuitem('Style', 'command',
  4102. "Save Selected Baseline's Style",
  4103. label = 'Save Baseline Style',
  4104. command = self.levelEditor.saveBaselineStyle)
  4105. menuBar.addmenuitem('Style', 'command',
  4106. "Save Selected Wall's Style",
  4107. label = 'Save Wall Style',
  4108. command = self.levelEditor.saveWallStyle)
  4109. menuBar.addmenuitem('Style', 'command',
  4110. "Save Selected Buildings's Style",
  4111. label = 'Save Bldg Style',
  4112. command = self.levelEditor.saveBuildingStyle)
  4113. menuBar.addmenuitem('Style', 'command',
  4114. 'Reload Color Palettes',
  4115. label = 'Reload Colors',
  4116. command = self.styleManager.createColorAttributes)
  4117. menuBar.addmenuitem('Style', 'command',
  4118. 'Reload Baseline Style Palettes',
  4119. label = 'Reload Baseline Styles',
  4120. command = self.styleManager.createBaselineStyleAttributes)
  4121. menuBar.addmenuitem('Style', 'command',
  4122. 'Reload Wall Style Palettes',
  4123. label = 'Reload Wall Styles',
  4124. command = self.styleManager.createWallStyleAttributes)
  4125. menuBar.addmenuitem('Style', 'command',
  4126. 'Reload Building Style Palettes',
  4127. label = 'Reload Bldg Styles',
  4128. command = self.styleManager.createBuildingStyleAttributes)
  4129. menuBar.addmenu('Help', 'Level Editor Help Operations')
  4130. self.toggleBalloonVar = IntVar()
  4131. self.toggleBalloonVar.set(0)
  4132. menuBar.addmenuitem('Help', 'checkbutton',
  4133. 'Toggle balloon help',
  4134. label = 'Balloon Help',
  4135. variable = self.toggleBalloonVar,
  4136. command = self.toggleBalloon)
  4137. self.editMenu = Pmw.ComboBox(
  4138. menuFrame, labelpos = W,
  4139. label_text = 'Edit Mode:', entry_width = 18,
  4140. selectioncommand = self.levelEditor.setEditMode, history = 0,
  4141. scrolledlist_items = NEIGHBORHOODS)
  4142. self.editMenu.selectitem(NEIGHBORHOODS[0])
  4143. self.editMenu.pack(side = LEFT, expand = 0)
  4144. # Create the notebook pages
  4145. self.notebook = Pmw.NoteBook(hull)
  4146. self.notebook.pack(fill = BOTH, expand = 1)
  4147. streetsPage = self.notebook.add('Streets')
  4148. toonBuildingsPage = self.notebook.add('Toon Bldgs')
  4149. landmarkBuildingsPage = self.notebook.add('Landmark Bldgs')
  4150. # suitBuildingsPage = self.notebook.add('Suit Buildings')
  4151. propsPage = self.notebook.add('Props')
  4152. signPage = self.notebook.add('Signs')
  4153. suitPathPage = self.notebook.add('Paths')
  4154. battleCellPage = self.notebook.add('Cells')
  4155. sceneGraphPage = self.notebook.add('SceneGraph')
  4156. self.notebook['raisecommand'] = self.updateInfo
  4157. # STREETS
  4158. Label(streetsPage, text = 'Streets',
  4159. font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
  4160. self.addStreetButton = Button(
  4161. streetsPage,
  4162. text = 'ADD STREET',
  4163. command = self.addStreet)
  4164. self.addStreetButton.pack(fill = X, padx = 20, pady = 10)
  4165. self.streetSelector = Pmw.ComboBox(
  4166. streetsPage,
  4167. dropdown = 0,
  4168. listheight = 200,
  4169. labelpos = W,
  4170. label_text = 'Street type:',
  4171. label_width = 12,
  4172. label_anchor = W,
  4173. entry_width = 30,
  4174. selectioncommand = self.setStreetModuleType,
  4175. scrolledlist_items = map(lambda s: s[7:],
  4176. self.styleManager.getCatalogCodes(
  4177. 'street'))
  4178. )
  4179. self.streetModuleType = self.styleManager.getCatalogCode('street',0)
  4180. self.streetSelector.selectitem(self.streetModuleType[7:])
  4181. self.streetSelector.pack(expand = 1, fill = BOTH)
  4182. # TOON BUILDINGS
  4183. Label(toonBuildingsPage, text = 'Toon Buildings',
  4184. font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
  4185. self.addToonBuildingButton = Button(
  4186. toonBuildingsPage,
  4187. text = 'ADD TOON BUILDING',
  4188. command = self.addFlatBuilding)
  4189. self.addToonBuildingButton.pack(fill = X, padx = 20, pady = 10)
  4190. self.toonBuildingSelector = Pmw.ComboBox(
  4191. toonBuildingsPage,
  4192. dropdown = 0,
  4193. listheight = 200,
  4194. labelpos = W,
  4195. label_width = 12,
  4196. label_anchor = W,
  4197. label_text = 'Bldg type:',
  4198. entry_width = 30,
  4199. selectioncommand = self.setFlatBuildingType,
  4200. scrolledlist_items = (['random'] + BUILDING_TYPES)
  4201. )
  4202. bf = Frame(toonBuildingsPage)
  4203. Label(bf, text = 'Building Height:').pack(side = LEFT, expand = 0)
  4204. self.heightMode = IntVar()
  4205. self.heightMode.set(20)
  4206. self.tenFootButton = Radiobutton(
  4207. bf,
  4208. text = '10 ft',
  4209. value = 10,
  4210. variable = self.heightMode,
  4211. command = self.setFlatBuildingHeight)
  4212. self.tenFootButton.pack(side = LEFT, expand = 1, fill = X)
  4213. self.twentyFootButton = Radiobutton(
  4214. bf,
  4215. text = '20 ft',
  4216. value = 20,
  4217. variable = self.heightMode,
  4218. command = self.setFlatBuildingHeight)
  4219. self.twentyFootButton.pack(side = LEFT, expand = 1, fill = X)
  4220. self.twentyFiveFootButton = Radiobutton(
  4221. bf,
  4222. text = '25 ft',
  4223. value = 25,
  4224. variable = self.heightMode,
  4225. command = self.setFlatBuildingHeight)
  4226. self.twentyFiveFootButton.pack(side = LEFT, expand = 1, fill = X)
  4227. self.thirtyFootButton = Radiobutton(
  4228. bf,
  4229. text = '30 ft',
  4230. value = 30,
  4231. variable = self.heightMode,
  4232. command = self.setFlatBuildingHeight)
  4233. self.thirtyFootButton.pack(side = LEFT, expand = 1, fill = X)
  4234. bf.pack(fill = X)
  4235. self.toonBuildingType = 'random'
  4236. self.toonBuildingSelector.selectitem(self.toonBuildingType)
  4237. self.toonBuildingSelector.pack(expand = 1, fill = BOTH)
  4238. # LANDMARK BUILDINGS
  4239. Label(landmarkBuildingsPage, text = 'Landmark Buildings',
  4240. font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
  4241. self.addLandmarkBuildingButton = Button(
  4242. landmarkBuildingsPage,
  4243. text = 'ADD LANDMARK BUILDING',
  4244. command = self.addLandmark)
  4245. self.addLandmarkBuildingButton.pack(fill = X, padx = 20, pady = 10)
  4246. self.landmarkBuildingSelector = Pmw.ComboBox(
  4247. landmarkBuildingsPage,
  4248. dropdown = 0,
  4249. listheight = 200,
  4250. labelpos = W,
  4251. label_width = 12,
  4252. label_anchor = W,
  4253. label_text = 'Bldg type:',
  4254. entry_width = 30,
  4255. selectioncommand = self.setLandmarkType,
  4256. scrolledlist_items = map(lambda s: s[14:],
  4257. self.styleManager.getCatalogCodes(
  4258. 'toon_landmark'))
  4259. )
  4260. self.landmarkType = self.styleManager.getCatalogCode(
  4261. 'toon_landmark',0)
  4262. self.landmarkBuildingSelector.selectitem(
  4263. self.styleManager.getCatalogCode('toon_landmark',0)[14:])
  4264. self.landmarkBuildingSelector.pack(expand = 1, fill = BOTH)
  4265. # SIGNS
  4266. Label(signPage, text = 'Signs',
  4267. font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
  4268. self.currentSignDNA=None
  4269. self.currentBaselineDNA=None
  4270. self.levelEditor.selectedNodePathHookHooks.append(self.updateSignPage)
  4271. gridFrame = Frame(signPage)
  4272. signSelectedFrame = Frame(gridFrame)
  4273. self.currentBaselineIndex=0
  4274. self.baselineMenu = Pmw.ComboBox(
  4275. signSelectedFrame,
  4276. labelpos = W,
  4277. label_text = 'Selected:', entry_width = 24,
  4278. selectioncommand = self.selectSignBaseline,
  4279. history = 0, # unique = 0,
  4280. scrolledlist_items = ['<the sign>'])
  4281. self.baselineMenu.selectitem(self.currentBaselineIndex)
  4282. self.baselineMenu.pack(side = LEFT, expand = 1, fill = X)
  4283. self.baselineAddButton = Button(
  4284. signSelectedFrame,
  4285. text="Add Baseline", command=self.addBaseline)
  4286. self.baselineAddButton.pack(side = LEFT, expand = 1, fill = X)
  4287. self.baselineDeleteButton = Button(
  4288. signSelectedFrame,
  4289. text="Del", command=self.deleteSignItem)
  4290. self.baselineDeleteButton.pack(side = LEFT, expand = 1, fill = X)
  4291. signSelectedFrame.grid(row=0, column=0, columnspan=6)
  4292. self.baselineString=StringVar()
  4293. self.baselineString.trace("wu", self.signBaselineTrace)
  4294. self.baselineTextBox = Entry(
  4295. gridFrame, width = 24,
  4296. textvariable=self.baselineString)
  4297. self.baselineTextBox.grid(row=1, column=0, columnspan=3)
  4298. fontList = [""]+self.styleManager.getCatalogCodes('font')
  4299. self.fontMenu = Pmw.ComboBox(
  4300. gridFrame, labelpos = W,
  4301. label_text = 'Font:', entry_width = 12,
  4302. selectioncommand = self.setSignBaslineFont, history = 0,
  4303. scrolledlist_items = fontList)
  4304. self.fontMenu.selectitem(0)
  4305. self.fontMenu.grid(row=1, column=3, columnspan=3)
  4306. graphicList = self.styleManager.getCatalogCodes('graphic')
  4307. self.graphicMenu = Pmw.ComboBox(
  4308. gridFrame, labelpos = W,
  4309. label_text = 'Add Graphic:', entry_width = 24,
  4310. selectioncommand = self.addSignGraphic, history = 0,
  4311. scrolledlist_items = graphicList)
  4312. self.graphicMenu.selectitem(0)
  4313. self.graphicMenu.grid(row=2, column=0, columnspan=4)
  4314. signButtonFrame = Frame(gridFrame)
  4315. self.bigFirstLetterIntVar = IntVar()
  4316. self.bigFirstLetterCheckbutton = Checkbutton(
  4317. signButtonFrame,
  4318. text = 'Big First Letter',
  4319. variable=self.bigFirstLetterIntVar, command=self.setBigFirstLetter)
  4320. self.bigFirstLetterCheckbutton.pack(
  4321. side = LEFT, expand = 1, fill = X)
  4322. self.allCapsIntVar = IntVar()
  4323. self.allCapsCheckbutton = Checkbutton(
  4324. signButtonFrame,
  4325. text = 'All Caps',
  4326. variable=self.allCapsIntVar, command=self.setAllCaps)
  4327. self.allCapsCheckbutton.pack(side = LEFT, expand = 1, fill = X)
  4328. self.dropShadowIntVar = IntVar()
  4329. self.dropShadowCheckbutton = Checkbutton(
  4330. signButtonFrame,
  4331. text = 'Drop Shadow',
  4332. variable=self.dropShadowIntVar, command=self.setDropShadow)
  4333. self.dropShadowCheckbutton.pack(side = LEFT, expand = 1, fill = X)
  4334. signButtonFrame.grid(row=3, column=0, columnspan=6)
  4335. self.addKernFloater = Floater.Floater(
  4336. gridFrame,
  4337. text='Kern',
  4338. maxVelocity=1.0,
  4339. command=self.setSignBaselineKern)
  4340. self.addKernFloater.grid(row=4, column=0, rowspan=2, columnspan=3)
  4341. self.addWiggleFloater = Floater.Floater(
  4342. gridFrame,
  4343. text='Wiggle',
  4344. maxVelocity=10.0,
  4345. command=self.setSignBaselineWiggle)
  4346. self.addWiggleFloater.grid(row=6, column=0, rowspan=2, columnspan=3)
  4347. self.addStumbleFloater = Floater.Floater(
  4348. gridFrame,
  4349. text='Stumble',
  4350. maxVelocity=1.0,
  4351. command=self.setSignBaselineStumble)
  4352. self.addStumbleFloater.grid(row=8, column=0, rowspan=2, columnspan=3)
  4353. self.addStompFloater = Floater.Floater(
  4354. gridFrame,
  4355. text='Stomp',
  4356. maxVelocity=1.0,
  4357. command=self.setSignBaselineStomp)
  4358. self.addStompFloater.grid(row=10, column=0, rowspan=2, columnspan=3)
  4359. self.addCurveFloater = Floater.Floater(
  4360. gridFrame,
  4361. text='Curve',
  4362. maxVelocity = 1.0,
  4363. command=self.setSignBaselineCurve)
  4364. self.addCurveFloater.grid(row=12, column=0, rowspan=2, columnspan=3)
  4365. self.addXFloater = Floater.Floater(
  4366. gridFrame,
  4367. text='X',
  4368. maxVelocity=1.0,
  4369. command=self.setDNATargetX)
  4370. self.addXFloater.grid(row=4, column=3, rowspan=2, columnspan=3)
  4371. self.addZFloater = Floater.Floater(
  4372. gridFrame,
  4373. text='Z',
  4374. maxVelocity=1.0,
  4375. command=self.setDNATargetZ)
  4376. self.addZFloater.grid(row=6, column=3, rowspan=2, columnspan=3)
  4377. self.addScaleXFloater = Floater.Floater(
  4378. gridFrame,
  4379. text='Scale X',
  4380. maxVelocity=1.0,
  4381. command=self.setDNATargetScaleX)
  4382. self.addScaleXFloater.grid(row=8, column=3, rowspan=2, columnspan=3)
  4383. self.addScaleZFloater = Floater.Floater(
  4384. gridFrame,
  4385. text='Scale Z',
  4386. maxVelocity=1.0,
  4387. command=self.setDNATargetScaleZ)
  4388. self.addScaleZFloater.grid(row=10, column=3, rowspan=2, columnspan=3)
  4389. self.addRollFloater = Floater.Floater(
  4390. gridFrame,
  4391. text='Roll',
  4392. maxVelocity=10.0,
  4393. command=self.setDNATargetRoll)
  4394. self.addRollFloater.grid(row=12, column=3, rowspan=2, columnspan=3)
  4395. gridFrame.pack(fill=BOTH)
  4396. # PROPS
  4397. Label(propsPage, text = 'Props',
  4398. font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
  4399. self.addPropsButton = Button(
  4400. propsPage,
  4401. text = 'ADD PROP',
  4402. command = self.addProp)
  4403. self.addPropsButton.pack(fill = X, padx = 20, pady = 10)
  4404. self.propSelector = Pmw.ComboBox(
  4405. propsPage,
  4406. dropdown = 0,
  4407. listheight = 200,
  4408. labelpos = W,
  4409. label_width = 12,
  4410. label_anchor = W,
  4411. label_text = 'Prop type:',
  4412. entry_width = 30,
  4413. selectioncommand = self.setPropType,
  4414. scrolledlist_items = self.styleManager.getCatalogCodes('prop')
  4415. )
  4416. self.propType = self.styleManager.getCatalogCode('prop',0)
  4417. self.propSelector.selectitem(
  4418. self.styleManager.getCatalogCode('prop',0))
  4419. self.propSelector.pack(expand = 1, fill = BOTH)
  4420. # SUIT PATHS
  4421. Label(suitPathPage, text = 'Suit Paths',
  4422. font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
  4423. spButtons = Frame(suitPathPage)
  4424. self.fPaths = IntVar()
  4425. self.fPaths.set(0)
  4426. self.pathButton = Checkbutton(spButtons,
  4427. text = 'Show Paths',
  4428. width = 6,
  4429. variable = self.fPaths,
  4430. command = self.toggleSuitPaths)
  4431. self.pathButton.pack(side = LEFT, expand = 1, fill = X)
  4432. self.zoneColor = IntVar()
  4433. self.zoneColor.set(0)
  4434. self.colorZoneButton1 = Checkbutton(
  4435. spButtons,
  4436. text = 'Color Zones', width = 6,
  4437. variable = self.zoneColor,
  4438. command = self.levelEditor.toggleZoneColors)
  4439. self.colorZoneButton1.pack(side = LEFT, expand = 1, fill = X)
  4440. spButtons.pack(fill = X)
  4441. spButtons = Frame(suitPathPage)
  4442. Label(spButtons, text = 'Highlight:').pack(side = LEFT, fill = X)
  4443. self.highlightConnectedButton = Button(
  4444. spButtons,
  4445. text = 'Forward',
  4446. width = 6,
  4447. command = self.levelEditor.highlightConnected)
  4448. self.highlightConnectedButton.pack(side = LEFT, expand = 1, fill = X)
  4449. self.highlightConnectedButton2 = Button(
  4450. spButtons,
  4451. text = 'Connected',
  4452. width = 6,
  4453. command = lambda s = self: s.levelEditor.highlightConnected(fReversePath = 1))
  4454. self.highlightConnectedButton2.pack(side = LEFT, expand = 1, fill = X)
  4455. self.clearHighlightButton = Button(
  4456. spButtons,
  4457. text = 'Clear',
  4458. width = 6,
  4459. command = self.levelEditor.clearPathHighlights)
  4460. self.clearHighlightButton.pack(side = LEFT, expand = 1, fill = X)
  4461. spButtons.pack(fill = X, pady = 4)
  4462. self.suitPointSelector = Pmw.ComboBox(
  4463. suitPathPage,
  4464. dropdown = 0,
  4465. listheight = 200,
  4466. labelpos = W,
  4467. label_text = 'Point type:',
  4468. label_width = 12,
  4469. label_anchor = W,
  4470. entry_width = 30,
  4471. selectioncommand = self.setSuitPointType,
  4472. scrolledlist_items = ['street', 'front door', 'side door']
  4473. )
  4474. self.suitPointSelector.selectitem('street')
  4475. self.suitPointSelector.pack(expand = 1, fill = BOTH)
  4476. # BATTLE CELLS
  4477. Label(battleCellPage, text = 'Battle Cells',
  4478. font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
  4479. bcButtons = Frame(battleCellPage)
  4480. self.fCells = IntVar()
  4481. self.fCells.set(0)
  4482. self.cellButton = Checkbutton(bcButtons,
  4483. text = 'Show Cells',
  4484. width = 6,
  4485. variable = self.fCells,
  4486. command = self.toggleBattleCells)
  4487. self.cellButton.pack(side = LEFT, expand = 1, fill = X)
  4488. self.colorZoneButton2 = Checkbutton(
  4489. bcButtons,
  4490. text = 'Color Zones', width = 6,
  4491. variable = self.zoneColor,
  4492. command = self.levelEditor.toggleZoneColors)
  4493. self.colorZoneButton2.pack(side = LEFT, expand = 1, fill = X)
  4494. bcButtons.pack(fill = X)
  4495. self.battleCellSelector = Pmw.ComboBox(
  4496. battleCellPage,
  4497. dropdown = 0,
  4498. listheight = 200,
  4499. labelpos = W,
  4500. label_text = 'Cell type:',
  4501. label_width = 12,
  4502. label_anchor = W,
  4503. entry_width = 30,
  4504. selectioncommand = self.setBattleCellType,
  4505. scrolledlist_items = ['20w 20l', '20w 30l', '30w 20l', '30w 30l']
  4506. )
  4507. self.battleCellSelector.selectitem('20w 20l')
  4508. self.battleCellSelector.pack(expand = 1, fill = BOTH)
  4509. # SCENE GRAPH EXPLORER
  4510. Label(sceneGraphPage, text = 'Level Scene Graph',
  4511. font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
  4512. self.sceneGraphExplorer = SceneGraphExplorer(
  4513. parent = sceneGraphPage,
  4514. nodePath = self.levelEditor,
  4515. menuItems = ['Add Group', 'Add Vis Group'])
  4516. self.sceneGraphExplorer.pack(expand = 1, fill = BOTH)
  4517. # Compact down notebook
  4518. self.notebook.setnaturalsize()
  4519. self.colorEntry = VectorWidgets.ColorEntry(
  4520. hull, text = 'Select Color',
  4521. command = self.updateSelectedObjColor)
  4522. self.colorEntry.menu.add_command(
  4523. label = 'Save Color', command = self.levelEditor.saveColor)
  4524. self.colorEntry.pack(fill = X)
  4525. buttonFrame = Frame(hull)
  4526. self.fMapVis = IntVar()
  4527. self.fMapVis.set(0)
  4528. self.mapSnapButton = Checkbutton(buttonFrame,
  4529. text = 'Map Vis',
  4530. width = 6,
  4531. variable = self.fMapVis,
  4532. command = self.toggleMapVis)
  4533. #self.mapSnapButton.pack(side = LEFT, expand = 1, fill = X)
  4534. self.fXyzSnap = IntVar()
  4535. self.fXyzSnap.set(1)
  4536. self.xyzSnapButton = Checkbutton(buttonFrame,
  4537. text = 'XyzSnap',
  4538. width = 6,
  4539. variable = self.fXyzSnap,
  4540. command = self.toggleXyzSnap)
  4541. self.xyzSnapButton.pack(side = LEFT, expand = 1, fill = X)
  4542. self.fHprSnap = IntVar()
  4543. self.fHprSnap.set(1)
  4544. self.hprSnapButton = Checkbutton(buttonFrame,
  4545. text = 'HprSnap',
  4546. width = 6,
  4547. variable = self.fHprSnap,
  4548. command = self.toggleHprSnap)
  4549. self.hprSnapButton.pack(side = LEFT, expand = 1, fill = X)
  4550. def toggleWidgetHandles(s = self):
  4551. if s.fPlaneSnap.get():
  4552. direct.widget.disableHandles(['x-ring', 'x-disc',
  4553. 'y-ring', 'y-disc',
  4554. 'z-post'])
  4555. else:
  4556. direct.widget.enableHandles('all')
  4557. self.fPlaneSnap = IntVar()
  4558. self.fPlaneSnap.set(1)
  4559. self.planeSnapButton = Checkbutton(buttonFrame,
  4560. text = 'PlaneSnap',
  4561. width = 6,
  4562. variable = self.fPlaneSnap,
  4563. command = toggleWidgetHandles)
  4564. self.planeSnapButton.pack(side = LEFT, expand = 1, fill = X)
  4565. self.fGrid = IntVar()
  4566. self.fGrid.set(0)
  4567. direct.gridButton = Checkbutton(buttonFrame,
  4568. text = 'Show Grid',
  4569. width = 6,
  4570. variable = self.fGrid,
  4571. command = self.toggleGrid)
  4572. direct.gridButton.pack(side = LEFT, expand = 1, fill = X)
  4573. buttonFrame.pack(fill = X)
  4574. buttonFrame4 = Frame(hull)
  4575. self.driveMode = IntVar()
  4576. self.driveMode.set(1)
  4577. self.directModeButton = Radiobutton(
  4578. buttonFrame4,
  4579. text = 'DIRECT Fly',
  4580. value = 1,
  4581. variable = self.driveMode,
  4582. command = self.levelEditor.useDirectFly)
  4583. self.directModeButton.pack(side = LEFT, fill = X, expand = 1)
  4584. self.driveModeButton = Radiobutton(
  4585. buttonFrame4,
  4586. text = 'Drive',
  4587. value = 0,
  4588. variable = self.driveMode,
  4589. command = self.levelEditor.useDriveMode)
  4590. self.driveModeButton.pack(side = LEFT, fill = X, expand = 1)
  4591. self.fColl = IntVar()
  4592. self.fColl.set(1)
  4593. direct.collButton = Checkbutton(
  4594. buttonFrame4,
  4595. text = 'Collide',
  4596. variable = self.fColl,
  4597. command = self.levelEditor.toggleCollisions)
  4598. direct.collButton.pack(side = LEFT, expand = 1, fill = X)
  4599. self.fVis = IntVar()
  4600. self.fVis.set(1)
  4601. direct.visButton = Checkbutton(
  4602. buttonFrame4,
  4603. text = 'Visibility',
  4604. variable = self.fVis,
  4605. command = self.levelEditor.toggleVisibility)
  4606. direct.visButton.pack(side = LEFT, expand = 1, fill = X)
  4607. self.fVisZones = IntVar()
  4608. self.fVisZones.set(visualizeZones)
  4609. direct.visZonesButton = Checkbutton(
  4610. buttonFrame4,
  4611. text = 'Show Zones',
  4612. variable = self.fVisZones)
  4613. direct.visZonesButton.pack(side = LEFT, expand = 1, fill = X)
  4614. buttonFrame4.pack(fill = X, padx = 5)
  4615. # Make sure input variables processed
  4616. self.initialiseoptions(LevelEditorPanel)
  4617. def updateInfo(self, page):
  4618. if page == 'Signs':
  4619. self.updateSignPage()
  4620. def toggleGrid(self):
  4621. if self.fGrid.get():
  4622. direct.grid.enable()
  4623. else:
  4624. direct.grid.disable()
  4625. def toggleSuitPaths(self):
  4626. if self.fPaths.get():
  4627. self.levelEditor.showSuitPaths()
  4628. else:
  4629. self.levelEditor.hideSuitPaths()
  4630. def toggleBattleCells(self):
  4631. if self.fCells.get():
  4632. self.levelEditor.showBattleCells()
  4633. else:
  4634. self.levelEditor.hideBattleCells()
  4635. def toggleXyzSnap(self):
  4636. direct.grid.setXyzSnap(self.fXyzSnap.get())
  4637. def toggleHprSnap(self):
  4638. direct.grid.setHprSnap(self.fXyzSnap.get())
  4639. def toggleMapVis(self):
  4640. self.levelEditor.toggleMapVis(self.fMapVis.get())
  4641. def setStreetModuleType(self,name):
  4642. self.streetModuleType = 'street_' + name
  4643. self.levelEditor.setCurrent('street_texture', self.streetModuleType)
  4644. def addStreet(self):
  4645. self.levelEditor.addStreet(self.streetModuleType)
  4646. def setFlatBuildingType(self,name):
  4647. self.toonBuildingType = name
  4648. self.levelEditor.setCurrent('building_type', self.toonBuildingType)
  4649. def setFlatBuildingHeight(self):
  4650. height = self.heightMode.get()
  4651. self.levelEditor.setCurrent('building_height', height)
  4652. self.updateHeightList(height)
  4653. def updateHeightList(self, height):
  4654. # Update combo box
  4655. heightList = self.levelEditor.getList(`height` + '_ft_wall_heights')
  4656. self.toonBuildingSelector.setlist(
  4657. ['random'] + map(createHeightCode,heightList))
  4658. self.toonBuildingSelector.selectitem(0)
  4659. self.toonBuildingSelector.invoke()
  4660. def addFlatBuilding(self):
  4661. self.levelEditor.addFlatBuilding(self.toonBuildingType)
  4662. def setLandmarkType(self,name):
  4663. self.landmarkType = 'toon_landmark_' + name
  4664. self.levelEditor.setCurrent('toon_landmark_texture', self.landmarkType)
  4665. def signPanelSync(self):
  4666. self.baselineMenu.delete(1, END)
  4667. sign=self.findSignFromDNARoot()
  4668. if not sign:
  4669. return
  4670. baselineList = DNAGetChildren(sign, DNA_SIGN_BASELINE)
  4671. for baseline in baselineList:
  4672. s=DNAGetBaselineString(baseline)
  4673. self.baselineMenu.insert(END, s)
  4674. self.baselineMenu.selectitem(0)
  4675. self.selectSignBaseline(0)
  4676. def updateSignPage(self):
  4677. if (self.notebook.getcurselection() == 'Signs'):
  4678. sign=self.findSignFromDNARoot()
  4679. # Only update if it's not the current sign:
  4680. if (self.currentSignDNA != sign):
  4681. self.currentSignDNA = sign
  4682. self.signPanelSync()
  4683. def findSignFromDNARoot(self):
  4684. dnaRoot=self.levelEditor.selectedDNARoot
  4685. if not dnaRoot:
  4686. return
  4687. objClass=DNAGetClassType(dnaRoot)
  4688. if (objClass.eq(DNA_LANDMARK_BUILDING)
  4689. or objClass.eq(DNA_PROP)):
  4690. target=DNAGetChildRecursive(dnaRoot, DNA_SIGN)
  4691. return target
  4692. def selectSignBaseline(self, val):
  4693. if not self.currentSignDNA:
  4694. return
  4695. # Temporarily undefine DNATarget (this will speed
  4696. # up setting the values, because the callbacks won't
  4697. # call self.levelEditor.replaceSelected() with each
  4698. # setting):
  4699. self.levelEditor.DNATarget=None
  4700. self.currentBaselineDNA=None
  4701. target=None
  4702. index=self.currentBaselineIndex=int((self.baselineMenu.curselection())[0])
  4703. if (index==0):
  4704. target=self.currentSignDNA
  4705. # Unset some ui elements:
  4706. self.baselineString.set('')
  4707. self.fontMenu.selectitem(0)
  4708. self.addCurveFloater.set(0)
  4709. self.addKernFloater.set(0)
  4710. self.addWiggleFloater.set(0)
  4711. self.addStumbleFloater.set(0)
  4712. self.addStompFloater.set(0)
  4713. self.bigFirstLetterIntVar.set(0)
  4714. self.allCapsIntVar.set(0)
  4715. self.dropShadowIntVar.set(0)
  4716. else:
  4717. target=DNAGetChild(self.currentSignDNA, DNA_SIGN_BASELINE, index-1)
  4718. if target:
  4719. # Update panel info:
  4720. self.baselineString.set(DNAGetBaselineString(target))
  4721. self.fontMenu.selectitem(target.getCode())
  4722. self.addCurveFloater.set(target.getWidth())
  4723. self.addKernFloater.set(target.getKern())
  4724. self.addWiggleFloater.set(target.getWiggle())
  4725. self.addStumbleFloater.set(target.getStumble())
  4726. self.addStompFloater.set(target.getStomp())
  4727. flags=target.getFlags()
  4728. self.bigFirstLetterIntVar.set('b' in flags)
  4729. self.allCapsIntVar.set('c' in flags)
  4730. self.dropShadowIntVar.set('d' in flags)
  4731. self.currentBaselineDNA=target
  4732. if target:
  4733. pos=target.getPos()
  4734. self.addXFloater.set(pos[0])
  4735. self.addZFloater.set(pos[2])
  4736. scale=target.getScale()
  4737. self.addScaleXFloater.set(scale[0])
  4738. self.addScaleZFloater.set(scale[2])
  4739. hpr=target.getHpr()
  4740. self.addRollFloater.set(hpr[2])
  4741. self.levelEditor.DNATarget=target
  4742. def deleteSignItem(self):
  4743. """Delete the selected sign or sign baseline"""
  4744. if (self.currentBaselineDNA):
  4745. # Remove the baseline:
  4746. assert(int((self.baselineMenu.curselection())[0]) == self.currentBaselineIndex)
  4747. DNARemoveChildOfClass(self.currentSignDNA, DNA_SIGN_BASELINE,
  4748. self.currentBaselineIndex-1)
  4749. self.baselineMenu.delete(self.currentBaselineIndex)
  4750. self.baselineMenu.selectitem(0)
  4751. self.currentBaselineIndex=0
  4752. self.currentBaselineDNA=None
  4753. self.selectSignBaseline(0)
  4754. self.levelEditor.replaceSelected()
  4755. elif (self.currentSignDNA):
  4756. # Remove the sign:
  4757. assert(int((self.baselineMenu.curselection())[0]) == 0)
  4758. le = self.levelEditor
  4759. le.removeSign(le.DNATarget, le.DNATargetParent)
  4760. self.currentBaselineDNA=None
  4761. self.currentSignDNA=None
  4762. self.levelEditor.replaceSelected()
  4763. def signBaselineTrace(self, a, b, mode):
  4764. #print self, a, b, mode, self.baselineString.get()
  4765. baseline=self.currentBaselineDNA
  4766. if baseline:
  4767. s=self.baselineString.get()
  4768. self.setBaselineString(s)
  4769. def addSignGraphic(self, code):
  4770. """
  4771. Create a new baseline with a graphic and
  4772. add it to the current sign
  4773. """
  4774. sign=self.findSignFromDNARoot()
  4775. if sign:
  4776. graphic=DNASignGraphic()
  4777. graphic.setCode(code)
  4778. baseline=DNASignBaseline()
  4779. baseline.add(graphic)
  4780. sign.add(baseline)
  4781. # Show the UI to the new baseline:
  4782. self.levelEditor.DNATarget=baseline
  4783. self.baselineMenu.insert(END, '['+code+']')
  4784. current=self.baselineMenu.size()-1
  4785. self.baselineMenu.selectitem(current)
  4786. self.selectSignBaseline(current)
  4787. self.levelEditor.replaceSelected()
  4788. def addBaseline(self):
  4789. sign=self.findSignFromDNARoot()
  4790. if sign:
  4791. baseline=DNASignBaseline()
  4792. text="Zoo"
  4793. DNASetBaselineString(baseline, text)
  4794. sign.add(baseline)
  4795. # Show the UI to the new baseline:
  4796. self.levelEditor.DNATarget=baseline
  4797. self.baselineMenu.insert(END, text)
  4798. current=self.baselineMenu.size()-1
  4799. self.baselineMenu.selectitem(current)
  4800. self.selectSignBaseline(current)
  4801. self.levelEditor.replaceSelected()
  4802. def addBaselineItem(self):
  4803. pass
  4804. def selectSignBaselineItem(self, val):
  4805. baseline=self.currentBaselineDNA
  4806. if baseline:
  4807. baseline.setCode(val)
  4808. self.levelEditor.replaceSelected()
  4809. def setSignBaselineStyle(self, val):
  4810. baseline=self.currentBaselineDNA
  4811. if baseline == None:
  4812. print "\n\nbaseline == None"
  4813. return #skyler: This isn't working yet.
  4814. # As a workaround, select the baseline from the tk panel.
  4815. # Try to find the first baseline in the sign:
  4816. sign=self.findSignFromDNARoot()
  4817. if sign:
  4818. self.currentSignDNA = sign
  4819. baseline=DNAGetChild(sign, DNA_SIGN_BASELINE)
  4820. if baseline and val:
  4821. self.levelEditor.DNATarget=baseline
  4822. self.currentBaselineDNA=baseline
  4823. settings=val
  4824. self.levelEditor.replaceSelectedEnabled=0
  4825. # Don't set string: self.baselineString.set('')
  4826. if settings['curve'] != None:
  4827. self.addCurveFloater.set(settings['curve'])
  4828. if settings['kern'] != None:
  4829. self.addKernFloater.set(settings['kern'])
  4830. if settings['wiggle'] != None:
  4831. self.addWiggleFloater.set(settings['wiggle'])
  4832. if settings['stumble'] != None:
  4833. self.addStumbleFloater.set(settings['stumble'])
  4834. if settings['stomp'] != None:
  4835. self.addStompFloater.set(settings['stomp'])
  4836. flags=settings['flags']
  4837. if flags != None:
  4838. self.bigFirstLetterIntVar.set('b' in flags)
  4839. self.setBigFirstLetter();
  4840. self.allCapsIntVar.set('c' in flags)
  4841. self.setAllCaps()
  4842. self.dropShadowIntVar.set('d' in flags)
  4843. self.setDropShadow()
  4844. code = settings['code']
  4845. if code != None:
  4846. self.fontMenu.selectitem(code)
  4847. self.setSignBaslineFont(code)
  4848. if settings['x'] != None:
  4849. self.addXFloater.set(settings['x'])
  4850. if settings['z'] != None:
  4851. self.addZFloater.set(settings['z'])
  4852. if settings['scaleX'] != None:
  4853. self.addScaleXFloater.set(settings['scaleX'])
  4854. if settings['scaleZ'] != None:
  4855. self.addScaleZFloater.set(settings['scaleZ'])
  4856. if settings['roll'] != None:
  4857. self.addRollFloater.set(settings['roll'])
  4858. color = settings['color']
  4859. if color != None:
  4860. #self.updateSelectedObjColor(settings['color'])
  4861. self.setCurrentColor(color)
  4862. self.setResetColor(color)
  4863. baseline.setColor(color)
  4864. self.levelEditor.replaceSelectedEnabled=1
  4865. self.levelEditor.replaceSelected()
  4866. def setBaselineString(self, val):
  4867. baseline=self.currentBaselineDNA
  4868. if baseline:
  4869. DNASetBaselineString(baseline, val);
  4870. self.baselineMenu.delete(self.currentBaselineIndex)
  4871. self.baselineMenu.insert(self.currentBaselineIndex, val)
  4872. self.baselineMenu.selectitem(self.currentBaselineIndex)
  4873. self.levelEditor.replaceSelected()
  4874. def adjustBaselineFlag(self, newValue, flagChar):
  4875. baseline=self.currentBaselineDNA
  4876. if baseline:
  4877. flags=baseline.getFlags()
  4878. if newValue:
  4879. if not flagChar in flags:
  4880. # Add the flag:
  4881. baseline.setFlags(flags+flagChar)
  4882. elif flagChar in flags:
  4883. # Remove the flag:
  4884. flags=string.join(flags.split(flagChar), '')
  4885. baseline.setFlags(flags)
  4886. self.levelEditor.replaceSelected()
  4887. def setBigFirstLetter(self):
  4888. self.adjustBaselineFlag(self.bigFirstLetterIntVar.get(), 'b')
  4889. def setAllCaps(self):
  4890. self.adjustBaselineFlag(self.allCapsIntVar.get(), 'c')
  4891. def setDropShadow(self):
  4892. self.adjustBaselineFlag(self.dropShadowIntVar.get(), 'd')
  4893. def setSignBaslineFont(self, val):
  4894. target=self.levelEditor.DNATarget
  4895. if target and (DNAGetClassType(target).eq(DNA_SIGN_BASELINE)
  4896. or DNAGetClassType(target).eq(DNA_SIGN_TEXT)):
  4897. target.setCode(val)
  4898. self.levelEditor.replaceSelected()
  4899. def setSignBaselineCurve(self, val):
  4900. baseline=self.currentBaselineDNA
  4901. if baseline:
  4902. try:
  4903. val=1.0/val
  4904. except ZeroDivisionError:
  4905. val=0
  4906. baseline.setWidth(val)
  4907. baseline.setHeight(val)
  4908. self.levelEditor.replaceSelected()
  4909. def setSignBaselineKern(self, val):
  4910. baseline=self.currentBaselineDNA
  4911. if baseline:
  4912. baseline.setKern(val)
  4913. self.levelEditor.replaceSelected()
  4914. def setSignBaselineWiggle(self, val):
  4915. baseline=self.currentBaselineDNA
  4916. if baseline:
  4917. baseline.setWiggle(val)
  4918. self.levelEditor.replaceSelected()
  4919. def setSignBaselineStumble(self, val):
  4920. baseline=self.currentBaselineDNA
  4921. if baseline:
  4922. baseline.setStumble(val)
  4923. self.levelEditor.replaceSelected()
  4924. def setSignBaselineStomp(self, val):
  4925. baseline=self.currentBaselineDNA
  4926. if baseline:
  4927. baseline.setStomp(val)
  4928. self.levelEditor.replaceSelected()
  4929. def setDNATargetX(self, val):
  4930. target=self.levelEditor.DNATarget
  4931. if target:
  4932. pos=target.getPos()
  4933. pos=VBase3(val, pos[1], pos[2])
  4934. target.setPos(pos)
  4935. self.levelEditor.replaceSelected()
  4936. def setDNATargetZ(self, val):
  4937. target=self.levelEditor.DNATarget
  4938. if target:
  4939. pos=target.getPos()
  4940. pos=VBase3(pos[0], pos[1], val)
  4941. target.setPos(pos)
  4942. self.levelEditor.replaceSelected()
  4943. def setDNATargetScaleX(self, val):
  4944. target=self.levelEditor.DNATarget
  4945. if target:
  4946. scale=target.getScale()
  4947. scale=VBase3(val, scale[1], scale[2])
  4948. target.setScale(scale)
  4949. self.levelEditor.replaceSelected()
  4950. def setDNATargetScaleZ(self, val):
  4951. target=self.levelEditor.DNATarget
  4952. if target:
  4953. scale=target.getScale()
  4954. scale=VBase3(scale[0], scale[1], val)
  4955. target.setScale(scale)
  4956. self.levelEditor.replaceSelected()
  4957. def setDNATargetRoll(self, val):
  4958. target=self.levelEditor.DNATarget
  4959. if target:
  4960. hpr=target.getHpr()
  4961. hpr=VBase3(hpr[0], hpr[1], val)
  4962. target.setHpr(hpr)
  4963. self.levelEditor.replaceSelected()
  4964. def addLandmark(self):
  4965. self.levelEditor.addLandmark(self.landmarkType)
  4966. def setPropType(self,name):
  4967. self.propType = name
  4968. self.levelEditor.setCurrent('prop_texture', self.propType)
  4969. def addProp(self):
  4970. self.levelEditor.addProp(self.propType)
  4971. def updateSelectedWallWidth(self, strVal):
  4972. self.levelEditor.updateSelectedWallWidth(string.atof(strVal))
  4973. def setCurrentColor(self, colorVec, fUpdate = 0):
  4974. # Turn on/off update of selected before updating entry
  4975. self.fUpdateSelected = fUpdate
  4976. self.colorEntry.set([int(colorVec[0] * 255.0),
  4977. int(colorVec[1] * 255.0),
  4978. int(colorVec[2] * 255.0),
  4979. 255])
  4980. def setResetColor(self, colorVec):
  4981. self.colorEntry['resetValue'] = (
  4982. [int(colorVec[0] * 255.0),
  4983. int(colorVec[1] * 255.0),
  4984. int(colorVec[2] * 255.0),
  4985. 255])
  4986. def setSuitPointType(self,name):
  4987. if (name == "street"):
  4988. self.levelEditor.currentSuitPointType = DNASuitPoint.STREETPOINT
  4989. elif (name == "front door"):
  4990. self.levelEditor.currentSuitPointType = DNASuitPoint.FRONTDOORPOINT
  4991. elif (name == "side door"):
  4992. self.levelEditor.currentSuitPointType = DNASuitPoint.SIDEDOORPOINT
  4993. print self.levelEditor.currentSuitPointType
  4994. def setBattleCellType(self,name):
  4995. self.levelEditor.currentBattleCellType = name
  4996. def updateSelectedObjColor(self, color):
  4997. try:
  4998. obj = self.levelEditor.DNATarget
  4999. if self.fUpdateSelected and (obj != None):
  5000. objClass = DNAGetClassType(obj)
  5001. if ((objClass.eq(DNA_WALL)) or
  5002. (objClass.eq(DNA_WINDOWS)) or
  5003. (objClass.eq(DNA_DOOR)) or
  5004. (objClass.eq(DNA_CORNICE)) or
  5005. (objClass.eq(DNA_PROP)) or
  5006. (objClass.eq(DNA_SIGN)) or
  5007. (objClass.eq(DNA_SIGN_BASELINE)) or
  5008. (objClass.eq(DNA_SIGN_TEXT)) or
  5009. (objClass.eq(DNA_SIGN_GRAPHIC))
  5010. ):
  5011. self.levelEditor.setDNATargetColor(
  5012. VBase4((color[0]/255.0),
  5013. (color[1]/255.0),
  5014. (color[2]/255.0),
  5015. 1.0))
  5016. except AttributeError:
  5017. pass
  5018. # Default is to update selected
  5019. self.fUpdateSelected = 1
  5020. def toggleBalloon(self):
  5021. if self.toggleBalloonVar.get():
  5022. self.balloon.configure(state = 'balloon')
  5023. else:
  5024. self.balloon.configure(state = 'none')
  5025. class VisGroupsEditor(Pmw.MegaToplevel):
  5026. def __init__(self, levelEditor, visGroups = ['None'],
  5027. parent = None, **kw):
  5028. INITOPT = Pmw.INITOPT
  5029. optiondefs = (
  5030. ('title', 'Visability Groups Editor', None),
  5031. )
  5032. self.defineoptions(kw, optiondefs)
  5033. Pmw.MegaToplevel.__init__(self, parent, title = self['title'])
  5034. self.levelEditor = levelEditor
  5035. self.visGroups = visGroups
  5036. self.visGroupNames = map(lambda pair: pair[1].getName(),
  5037. self.visGroups)
  5038. # Initialize dictionary of visibility relationships
  5039. self.visDict = {}
  5040. # Group we are currently setting visGroups for
  5041. self.target = None
  5042. # Flag to enable/disable toggleVisGroup command
  5043. self.fCommand = 1
  5044. # Handle to the toplevels hull
  5045. hull = self.component('hull')
  5046. balloon = self.balloon = Pmw.Balloon(hull)
  5047. # Start with balloon help disabled
  5048. self.balloon.configure(state = 'none')
  5049. menuFrame = Frame(hull, relief = GROOVE, bd = 2)
  5050. menuFrame.pack(fill = X, expand = 1)
  5051. menuBar = Pmw.MenuBar(menuFrame, hotkeys = 1, balloon = balloon)
  5052. menuBar.pack(side = LEFT, expand = 1, fill = X)
  5053. menuBar.addmenu('Vis Groups Editor',
  5054. 'Visability Groups Editor Operations')
  5055. menuBar.addmenuitem('Vis Groups Editor', 'command',
  5056. 'Exit Visability Groups Editor',
  5057. label = 'Exit',
  5058. command = self.preDestroy)
  5059. menuBar.addmenu('Help', 'Visability Groups Editor Help Operations')
  5060. self.toggleBalloonVar = IntVar()
  5061. self.toggleBalloonVar.set(0)
  5062. menuBar.addmenuitem('Help', 'checkbutton',
  5063. 'Toggle balloon help',
  5064. label = 'Balloon Help',
  5065. variable = self.toggleBalloonVar,
  5066. command = self.toggleBalloon)
  5067. # Create a combo box to choose target vis group
  5068. self.targetSelector = Pmw.ComboBox(
  5069. hull, labelpos = W, label_text = 'Target Vis Group:',
  5070. entry_width = 12, selectioncommand = self.selectVisGroup,
  5071. scrolledlist_items = self.visGroupNames)
  5072. self.targetSelector.selectitem(self.visGroupNames[0])
  5073. self.targetSelector.pack(expand = 1, fill = X)
  5074. # Scrolled frame to hold radio selector
  5075. sf = Pmw.ScrolledFrame(hull, horizflex = 'elastic',
  5076. usehullsize = 1, hull_width = 200,
  5077. hull_height = 400)
  5078. frame = sf.interior()
  5079. sf.pack(padx=5, pady=3, fill = BOTH, expand = 1)
  5080. # Add vis groups selector
  5081. self.selected = Pmw.RadioSelect(frame, selectmode=MULTIPLE,
  5082. orient = VERTICAL,
  5083. pady = 0,
  5084. command = self.toggleVisGroup)
  5085. for groupInfo in self.visGroups:
  5086. nodePath = groupInfo[0]
  5087. group = groupInfo[1]
  5088. name = group.getName()
  5089. self.selected.add(name, width = 12)
  5090. # Assemble list of groups visible from this group
  5091. visible = []
  5092. for i in range(group.getNumVisibles()):
  5093. visible.append(group.getVisibleName(i))
  5094. visible.sort()
  5095. self.visDict[name] = [nodePath, group, visible]
  5096. # Pack the widget
  5097. self.selected.pack(expand = 1, fill = X)
  5098. # And make sure scrolled frame is happy
  5099. sf.reposition()
  5100. buttonFrame = Frame(hull)
  5101. buttonFrame.pack(fill=X, expand = 1)
  5102. self.showMode = IntVar()
  5103. self.showMode.set(0)
  5104. self.showAllButton = Radiobutton(buttonFrame, text = 'Show All',
  5105. value = 0, indicatoron = 1,
  5106. variable = self.showMode,
  5107. command = self.refreshVisibility)
  5108. self.showAllButton.pack(side = LEFT, fill = X, expand = 1)
  5109. self.showActiveButton = Radiobutton(buttonFrame, text = 'Show Target',
  5110. value = 1, indicatoron = 1,
  5111. variable = self.showMode,
  5112. command = self.refreshVisibility)
  5113. self.showActiveButton.pack(side = LEFT, fill = X, expand = 1)
  5114. # Make sure input variables processed
  5115. self.initialiseoptions(VisGroupsEditor)
  5116. # Switch to current target's list
  5117. self.selectVisGroup(self.visGroupNames[0])
  5118. def selectVisGroup(self, target):
  5119. print 'Setting vis options for group:', target
  5120. # Record current target
  5121. oldTarget = self.target
  5122. # Record new target
  5123. self.target = target
  5124. # Deselect buttons from old target (first deactivating command)
  5125. self.fCommand = 0
  5126. if oldTarget:
  5127. visList = self.visDict[oldTarget][2]
  5128. for group in visList:
  5129. self.selected.invoke(self.selected.index(group))
  5130. # Now set buttons to reflect state of new target
  5131. visList = self.visDict[target][2]
  5132. for group in visList:
  5133. self.selected.invoke(self.selected.index(group))
  5134. # Reactivate command
  5135. self.fCommand = 1
  5136. # Update scene
  5137. self.refreshVisibility()
  5138. def toggleVisGroup(self, groupName, state):
  5139. if self.fCommand:
  5140. targetInfo = self.visDict[self.target]
  5141. target = targetInfo[1]
  5142. visList = targetInfo[2]
  5143. groupNP = self.visDict[groupName][0]
  5144. group = self.visDict[groupName][1]
  5145. # MRM: Add change in visibility here
  5146. # Show all vs. show active
  5147. if state == 1:
  5148. print 'Vis Group:', self.target, 'adding group:', groupName
  5149. if groupName not in visList:
  5150. visList.append(groupName)
  5151. target.addVisible(groupName)
  5152. # Update vis and color
  5153. groupNP.show()
  5154. groupNP.setColor(1,0,0,1)
  5155. else:
  5156. print 'Vis Group:', self.target, 'removing group:', groupName
  5157. if groupName in visList:
  5158. visList.remove(groupName)
  5159. target.removeVisible(groupName)
  5160. # Update vis and color
  5161. if self.showMode.get() == 1:
  5162. groupNP.hide()
  5163. groupNP.clearColor()
  5164. def refreshVisibility(self):
  5165. # Get current visibility list for target
  5166. targetInfo = self.visDict[self.target]
  5167. visList = targetInfo[2]
  5168. for key in self.visDict.keys():
  5169. groupNP = self.visDict[key][0]
  5170. if key in visList:
  5171. groupNP.show()
  5172. if key == self.target:
  5173. groupNP.setColor(0,1,0,1)
  5174. else:
  5175. groupNP.setColor(1,0,0,1)
  5176. else:
  5177. if self.showMode.get() == 0:
  5178. groupNP.show()
  5179. else:
  5180. groupNP.hide()
  5181. groupNP.clearColor()
  5182. def preDestroy(self):
  5183. # First clear level editor variable
  5184. self.levelEditor.vgpanel = None
  5185. self.destroy()
  5186. def toggleBalloon(self):
  5187. if self.toggleBalloonVar.get():
  5188. self.balloon.configure(state = 'balloon')
  5189. else:
  5190. self.balloon.configure(state = 'none')
  5191. l = LevelEditor()
  5192. run()