WorldEditorDoc.cpp 179 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. // WorldEditorDoc.cpp : implementation of the CWorldEditorDoc class
  13. //
  14. #include "stdafx.h"
  15. #include "WorldEditor.h"
  16. #include "WorldEditorDoc.h"
  17. #include <Engine/Base/Profiling.h>
  18. #include <Engine/Build.h>
  19. #include <direct.h>
  20. #ifdef _DEBUG
  21. #undef new
  22. #define new DEBUG_NEW
  23. #undef THIS_FILE
  24. static char THIS_FILE[] = __FILE__;
  25. #endif
  26. #pragma optimize("p", on) // this is in effect for entire file!
  27. extern COLOR acol_ColorizePallete[];
  28. /////////////////////////////////////////////////////////////////////////////
  29. // CWorldEditorDoc
  30. IMPLEMENT_DYNCREATE(CWorldEditorDoc, CDocument)
  31. BEGIN_MESSAGE_MAP(CWorldEditorDoc, CDocument)
  32. //{{AFX_MSG_MAP(CWorldEditorDoc)
  33. ON_COMMAND(ID_CSG_SPLIT_SECTORS, OnCsgSplitSectors)
  34. ON_UPDATE_COMMAND_UI(ID_CSG_SPLIT_SECTORS, OnUpdateCsgSplitSectors)
  35. ON_COMMAND(ID_CSG_CANCEL, OnCsgCancel)
  36. ON_COMMAND(ID_SHOW_ORIENTATION, OnShowOrientation)
  37. ON_UPDATE_COMMAND_UI(ID_SHOW_ORIENTATION, OnUpdateShowOrientation)
  38. ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
  39. ON_COMMAND(ID_EDIT_REDO, OnEditRedo)
  40. ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
  41. ON_UPDATE_COMMAND_UI(ID_EDIT_REDO, OnUpdateEditRedo)
  42. ON_COMMAND(ID_WORLD_SETTINGS, OnWorldSettings)
  43. ON_COMMAND(ID_CSG_JOIN_SECTORS, OnCsgJoinSectors)
  44. ON_UPDATE_COMMAND_UI(ID_CSG_JOIN_SECTORS, OnUpdateCsgJoinSectors)
  45. ON_COMMAND(ID_AUTO_SNAP, OnAutoSnap)
  46. ON_COMMAND(ID_CSG_ADD, OnCsgAdd)
  47. ON_UPDATE_COMMAND_UI(ID_CSG_ADD, OnUpdateCsgAdd)
  48. ON_COMMAND(ID_CSG_REMOVE, OnCsgRemove)
  49. ON_UPDATE_COMMAND_UI(ID_CSG_REMOVE, OnUpdateCsgRemove)
  50. ON_COMMAND(ID_CSG_SPLIT_POLYGONS, OnCsgSplitPolygons)
  51. ON_UPDATE_COMMAND_UI(ID_CSG_SPLIT_POLYGONS, OnUpdateCsgSplitPolygons)
  52. ON_COMMAND(ID_CSG_JOIN_POLYGONS, OnCsgJoinPolygons)
  53. ON_UPDATE_COMMAND_UI(ID_CSG_JOIN_POLYGONS, OnUpdateCsgJoinPolygons)
  54. ON_COMMAND(ID_CALCULATESHADOWS, OnCalculateShadows)
  55. ON_COMMAND(ID_BROWSE_ENTITIES_MODE, OnBrowseEntitiesMode)
  56. ON_UPDATE_COMMAND_UI(ID_BROWSE_ENTITIES_MODE, OnUpdateBrowseEntitiesMode)
  57. ON_COMMAND(ID_PREVIOUS_SELECTED_ENTITY, OnPreviousSelectedEntity)
  58. ON_UPDATE_COMMAND_UI(ID_PREVIOUS_SELECTED_ENTITY, OnUpdatePreviousSelectedEntity)
  59. ON_COMMAND(ID_NEXT_SELECTED_ENTITY, OnNextSelectedEntity)
  60. ON_UPDATE_COMMAND_UI(ID_NEXT_SELECTED_ENTITY, OnUpdateNextSelectedEntity)
  61. ON_COMMAND(ID_JOIN_LAYERS, OnJoinLayers)
  62. ON_UPDATE_COMMAND_UI(ID_AUTO_SNAP, OnUpdateAutoSnap)
  63. ON_COMMAND(ID_SELECT_BY_CLASS, OnSelectByClass)
  64. ON_UPDATE_COMMAND_UI(ID_SELECT_BY_CLASS, OnUpdateSelectByClass)
  65. ON_COMMAND(ID_CSG_JOIN_ALL_POLYGONS, OnCsgJoinAllPolygons)
  66. ON_UPDATE_COMMAND_UI(ID_CSG_JOIN_ALL_POLYGONS, OnUpdateCsgJoinAllPolygons)
  67. ON_COMMAND(ID_TEXTURE_1, OnTexture1)
  68. ON_UPDATE_COMMAND_UI(ID_TEXTURE_1, OnUpdateTexture1)
  69. ON_COMMAND(ID_TEXTURE_2, OnTexture2)
  70. ON_UPDATE_COMMAND_UI(ID_TEXTURE_2, OnUpdateTexture2)
  71. ON_COMMAND(ID_TEXTURE_3, OnTexture3)
  72. ON_UPDATE_COMMAND_UI(ID_TEXTURE_3, OnUpdateTexture3)
  73. ON_COMMAND(ID_TEXTURE_MODE_1, OnTextureMode1)
  74. ON_COMMAND(ID_TEXTURE_MODE_2, OnTextureMode2)
  75. ON_COMMAND(ID_TEXTURE_MODE_3, OnTextureMode3)
  76. ON_COMMAND(ID_SAVE_THUMBNAIL, OnSaveThumbnail)
  77. ON_COMMAND(ID_UPDATE_LINKS, OnUpdateLinks)
  78. ON_COMMAND(ID_SNAPSHOT, OnSnapshot)
  79. ON_COMMAND(ID_MIRROR_AND_STRETCH, OnMirrorAndStretch)
  80. ON_COMMAND(ID_FLIP_LAYER, OnFlipLayer)
  81. ON_UPDATE_COMMAND_UI(ID_FLIP_LAYER, OnUpdateFlipLayer)
  82. ON_COMMAND(ID_FILTER_SELECTION, OnFilterSelection)
  83. ON_COMMAND(ID_UPDATE_CLONES, OnUpdateClones)
  84. ON_UPDATE_COMMAND_UI(ID_UPDATE_CLONES, OnUpdateUpdateClones)
  85. ON_COMMAND(ID_HIDE_SELECTED, OnHideSelected)
  86. ON_UPDATE_COMMAND_UI(ID_HIDE_SELECTED, OnUpdateHideSelected)
  87. ON_COMMAND(ID_HIDE_UNSELECTED, OnHideUnselected)
  88. ON_COMMAND(ID_SHOW_ALL, OnShowAll)
  89. ON_COMMAND(ID_CHECK_EDIT, OnCheckEdit)
  90. ON_COMMAND(ID_CHECK_ADD, OnCheckAdd)
  91. ON_COMMAND(ID_CHECK_DELETE, OnCheckDelete)
  92. ON_UPDATE_COMMAND_UI(ID_CHECK_EDIT, OnUpdateCheckEdit)
  93. ON_UPDATE_COMMAND_UI(ID_CHECK_ADD, OnUpdateCheckAdd)
  94. ON_UPDATE_COMMAND_UI(ID_CHECK_DELETE, OnUpdateCheckDelete)
  95. ON_COMMAND(ID_UPDATE_BRUSHES, OnUpdateBrushes)
  96. ON_COMMAND(ID_SELECT_BY_CLASS_IMPORTANT, OnSelectByClassImportant)
  97. ON_COMMAND(ID_INSERT_3D_OBJECT, OnInsert3dObject)
  98. ON_COMMAND(ID_EXPORT_3D_OBJECT, OnExport3dObject)
  99. ON_UPDATE_COMMAND_UI(ID_EXPORT_3D_OBJECT, OnUpdateExport3dObject)
  100. ON_COMMAND(ID_CROSSROAD_FOR_N, OnCrossroadForN)
  101. ON_COMMAND(ID_POPUP_VTX_ALLIGN, OnPopupVtxAllign)
  102. ON_COMMAND(ID_POPUP_VTX_FILTER, OnPopupVtxFilter)
  103. ON_COMMAND(ID_POPUP_VTX_NUMERIC, OnPopupVtxNumeric)
  104. ON_COMMAND(ID_HIDE_SELECTED_SECTORS, OnHideSelectedSectors)
  105. ON_COMMAND(ID_HIDE_UNSELECTED_SECTORS, OnHideUnselectedSectors)
  106. ON_COMMAND(ID_SHOW_ALL_SECTORS, OnShowAllSectors)
  107. ON_COMMAND(ID_TEXTURE_MODE_4, OnTextureMode4)
  108. ON_COMMAND(ID_TEXTURE_MODE_5, OnTextureMode5)
  109. ON_COMMAND(ID_TEXTURE_MODE_6, OnTextureMode6)
  110. ON_COMMAND(ID_TEXTURE_MODE_7, OnTextureMode7)
  111. ON_COMMAND(ID_TEXTURE_MODE_8, OnTextureMode8)
  112. ON_COMMAND(ID_TEXTURE_MODE_9, OnTextureMode9)
  113. ON_COMMAND(ID_TEXTURE_MODE_10, OnTextureMode10)
  114. //}}AFX_MSG_MAP
  115. ON_COMMAND(ID_EXPORT_PLACEMENTS, OnExportPlacements)
  116. ON_COMMAND(ID_EXPORT_ENTITIES, OnExportEntities)
  117. END_MESSAGE_MAP()
  118. /////////////////////////////////////////////////////////////////////////////
  119. // CWorldEditorDoc construction/destruction
  120. CWorldEditorDoc::CWorldEditorDoc()
  121. {
  122. m_iCurrentTerrainUndo=-1;
  123. m_ptrSelectedTerrain=NULL;
  124. m_slDisplaceTexTime=0;
  125. m_bAskedToCheckOut = FALSE;
  126. m_pCutLineView = NULL;
  127. m_iMirror = 0;
  128. m_bWasEverSaved = FALSE;
  129. m_iSelectedEntityInVolume = 0;
  130. m_iTexture = 0;
  131. m_ctLastPrimitiveVertices = -1;
  132. m_bPrimitiveCreatedFirstTime = TRUE;
  133. m_fLastPrimitiveWidth = 0.0;
  134. m_fLastPrimitiveLenght = 0.0;
  135. m_bLastIfOuter = FALSE;
  136. m_ttLastTriangularisationType = theApp.m_vfpCurrent.vfp_ttTriangularisationType;
  137. m_bAutoSnap = TRUE;
  138. m_bPrimitiveMode = FALSE;
  139. m_pwoSecondLayer = NULL;
  140. m_penPrimitive = NULL;
  141. m_bOrientationIcons=AfxGetApp()->GetProfileInt( L"World editor", L"Orientation icons", FALSE);
  142. m_bBrowseEntitiesMode = FALSE;
  143. m_bReadOnly = FALSE;
  144. m_csgtLastUsedCSGOperation = CSG_ILLEGAL;
  145. m_csgtPreLastUsedCSGOperation = CSG_ILLEGAL;
  146. m_bPreLastUsedPrimitiveMode = TRUE;
  147. m_bLastUsedPrimitiveMode = TRUE;
  148. m_fnLastDroppedTemplate = CTString("");
  149. // initialize grid placement
  150. m_plGrid.pl_PositionVector = FLOAT3D(0.0f,0.0f,0.0f);
  151. m_plGrid.pl_OrientationAngle = ANGLE3D(0,0,0);
  152. // initialize delta placement
  153. m_plDeltaPlacement.pl_PositionVector = FLOAT3D(0.0f,0.0f,0.0f);
  154. m_plDeltaPlacement.pl_OrientationAngle = ANGLE3D(0,0,0);
  155. // initialize last placement
  156. m_plLastPlacement.pl_PositionVector = FLOAT3D(0.0f,0.0f,0.0f);
  157. m_plLastPlacement.pl_OrientationAngle = ANGLE3D(0,0,0);
  158. // initialize create box vertices
  159. char strIni[ 128];
  160. strcpy( strIni, CStringA(theApp.GetProfileString( L"World editor", L"Volume box min", L"0.0 0.0 0.0")));
  161. sscanf( strIni, "%f %f %f",
  162. &m_vCreateBoxVertice0(1), &m_vCreateBoxVertice0(2), &m_vCreateBoxVertice0(3));
  163. strcpy( strIni, CStringA(theApp.GetProfileString( L"World editor", L"Volume box max", L"1.0 1.0 1.0")));
  164. sscanf( strIni, "%f %f %f",
  165. &m_vCreateBoxVertice1(1), &m_vCreateBoxVertice1(2), &m_vCreateBoxVertice1(3));
  166. // set default editing mode - polygon mode
  167. INDEX iMode=AfxGetApp()->GetProfileInt( L"World editor", L"Last editing mode", POLYGON_MODE);
  168. if(iMode==POLYGON_MODE || iMode==VERTEX_MODE || iMode==SECTOR_MODE || iMode==ENTITY_MODE || iMode==TERRAIN_MODE)
  169. {
  170. SetEditingMode( iMode);
  171. }
  172. else
  173. {
  174. SetEditingMode( POLYGON_MODE);
  175. }
  176. }
  177. CWorldEditorDoc::~CWorldEditorDoc()
  178. {
  179. DeleteTerrainUndo(this);
  180. if(m_iMode==POLYGON_MODE || m_iMode==VERTEX_MODE || m_iMode==SECTOR_MODE || m_iMode==ENTITY_MODE || m_iMode==TERRAIN_MODE)
  181. {
  182. theApp.WriteProfileInt(L"World editor", L"Last editing mode", m_iMode);
  183. }
  184. else
  185. {
  186. theApp.WriteProfileInt(L"World editor", L"Last editing mode", POLYGON_MODE);
  187. }
  188. if( m_pwoSecondLayer != NULL)
  189. delete m_pwoSecondLayer;
  190. // delete stored undo members
  191. FORDELETELIST(CUndo, m_lnListNode, m_lhUndo, itUndo)
  192. {
  193. delete &itUndo.Current();
  194. }
  195. // delete redo
  196. FORDELETELIST(CUndo, m_lnListNode, m_lhRedo, itRedo)
  197. {
  198. delete &itRedo.Current();
  199. }
  200. }
  201. void CWorldEditorDoc::ClearSelections(ESelectionType stExcept /*=ST_NONE*/)
  202. {
  203. if( stExcept != ST_VERTEX) { m_selVertexSelection.Clear(); m_chSelections.MarkChanged();}
  204. if( stExcept != ST_ENTITY) { m_selEntitySelection.Clear(); m_chSelections.MarkChanged();}
  205. if( stExcept != ST_VOLUME) { m_cenEntitiesSelectedByVolume.Clear(); m_chSelections.MarkChanged();}
  206. if( stExcept != ST_SECTOR) { m_selSectorSelection.Clear(); m_chSelections.MarkChanged();}
  207. if( stExcept != ST_POLYGON) { m_selPolygonSelection.Clear(); m_chSelections.MarkChanged();}
  208. }
  209. /*
  210. * Sets message about current mode and selected members
  211. */
  212. void CWorldEditorDoc::SetStatusLineModeInfoMessage( void)
  213. {
  214. BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
  215. BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
  216. // initialy, we are in polygon edit mode
  217. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  218. HICON hIcon;
  219. char strModeName[ 32];
  220. // write mode change on status line
  221. switch( m_iMode)
  222. {
  223. case POLYGON_MODE:
  224. {
  225. sprintf( strModeName, "%d polys, layer %d", m_selPolygonSelection.Count(), m_iTexture+1);
  226. hIcon = theApp.LoadIcon( IDR_ICON_PANE_POLYGON);
  227. break;
  228. };
  229. case SECTOR_MODE:
  230. {
  231. sprintf( strModeName, "%d sectors", m_selSectorSelection.Count());
  232. hIcon = theApp.LoadIcon( IDR_ICON_PANE_SECTOR);
  233. break;
  234. };
  235. case ENTITY_MODE:
  236. {
  237. if( m_bBrowseEntitiesMode)
  238. {
  239. sprintf( strModeName, "%d in volume", m_cenEntitiesSelectedByVolume.Count());
  240. }
  241. else
  242. {
  243. sprintf( strModeName, "%d entities", m_selEntitySelection.Count());
  244. };
  245. hIcon = theApp.LoadIcon( IDR_ICON_PANE_ENTITY);
  246. break;
  247. }
  248. case CSG_MODE:
  249. {
  250. sprintf( strModeName, "CSG mode");
  251. hIcon = theApp.LoadIcon( IDR_ICON_PANE_CSG);
  252. break;
  253. };
  254. case VERTEX_MODE:
  255. {
  256. sprintf( strModeName, "%d vertices", m_selVertexSelection.Count());
  257. hIcon = theApp.LoadIcon( IDR_ICON_PANE_VERTEX);
  258. break;
  259. };
  260. case TERRAIN_MODE:
  261. {
  262. if(bCtrl&&bAlt)
  263. {
  264. if(theApp.m_iTerrainEditMode==TEM_HEIGHTMAP)
  265. {
  266. sprintf( strModeName, "%s", "Pick altitude");
  267. }
  268. else
  269. {
  270. sprintf( strModeName, "%s", "Pick layer");
  271. }
  272. }
  273. else if(theApp.m_iTerrainEditMode==TEM_HEIGHTMAP)
  274. {
  275. INDEX iIcon;
  276. CTString strText;
  277. if(theApp.m_iTerrainBrushMode==TBM_FILTER)
  278. {
  279. sprintf( strModeName, "%s", GetFilterName(theApp.m_iFilter));
  280. }
  281. else
  282. {
  283. GetBrushModeInfo(INDEX(theApp.m_iTerrainBrushMode), iIcon, strText);
  284. sprintf( strModeName, "%s", strText);
  285. }
  286. }
  287. else
  288. {
  289. sprintf( strModeName, "Layer %d", GetLayerIndex());
  290. }
  291. hIcon = theApp.LoadIcon( IDR_ICON_PANE_TERRAIN);
  292. break;
  293. };
  294. default: { FatalError("Unknown editing mode."); break;};
  295. }
  296. pMainFrame->m_wndStatusBar.GetStatusBarCtrl().SetIcon( EDITING_MODE_ICON_PANE, hIcon);
  297. pMainFrame->m_wndStatusBar.SetPaneText( EDITING_MODE_PANE, CString(strModeName), TRUE);
  298. }
  299. /*
  300. * Changes editing mode
  301. */
  302. void CWorldEditorDoc::SetEditingMode( INDEX iNewMode)
  303. {
  304. #if !ALLOW_TERRAINS
  305. if(iNewMode==TERRAIN_MODE)
  306. {
  307. return;
  308. }
  309. #endif
  310. // exit cut mode
  311. theApp.m_bCutModeOn = FALSE;
  312. // cancel browse entities mode
  313. if( m_bBrowseEntitiesMode)
  314. {
  315. OnBrowseEntitiesMode();
  316. }
  317. // set new mode
  318. m_iMode = iNewMode;
  319. SetStatusLineModeInfoMessage();
  320. UpdateAllViews( NULL);
  321. // send message for mode change
  322. PostThreadMessage( GetCurrentThreadId(), WM_CHANGE_EDITING_MODE, TRUE, 0);
  323. }
  324. BOOL CWorldEditorDoc::OnNewDocument()
  325. {
  326. if (!CDocument::OnNewDocument())
  327. return FALSE;
  328. // create the World entity
  329. CPlacement3D plWorld;
  330. plWorld.pl_PositionVector = FLOAT3D(0.0f,0.0f,0.0f);
  331. plWorld.pl_OrientationAngle = ANGLE3D(0,0,0);
  332. CEntity *penWorldBase;
  333. try
  334. {
  335. penWorldBase = m_woWorld.CreateEntity_t(plWorld, CTFILENAME("Classes\\WorldBase.ecl"));
  336. }
  337. catch( char *err_str)
  338. {
  339. AfxMessageBox( CString(err_str));
  340. return FALSE;
  341. }
  342. // prepare the entity
  343. penWorldBase->Initialize();
  344. EFirstWorldBase eFirstWorldBase;
  345. penWorldBase->SendEvent( eFirstWorldBase);
  346. CEntity::HandleSentEvents();
  347. return TRUE;
  348. }
  349. /////////////////////////////////////////////////////////////////////////////
  350. // CWorldEditorDoc serialization
  351. void CWorldEditorDoc::Serialize(CArchive& ar)
  352. {
  353. // must not get here
  354. ASSERT(FALSE);
  355. }
  356. /////////////////////////////////////////////////////////////////////////////
  357. // CWorldEditorDoc diagnostics
  358. #ifdef _DEBUG
  359. void CWorldEditorDoc::AssertValid() const
  360. {
  361. CDocument::AssertValid();
  362. }
  363. void CWorldEditorDoc::Dump(CDumpContext& dc) const
  364. {
  365. CDocument::Dump(dc);
  366. }
  367. #endif //_DEBUG
  368. /////////////////////////////////////////////////////////////////////////////
  369. // CWorldEditorDoc commands
  370. /////////////////////////////////////////////////////////////////////////////
  371. void CWorldEditorDoc::SetupBackdropTextureObject( CTFileName fnPicture, CTextureObject &to)
  372. {
  373. CImageInfo iiImageInfo;
  374. try
  375. {
  376. iiImageInfo.LoadAnyGfxFormat_t( fnPicture);
  377. // both dimension must be potentions of 2
  378. if( (iiImageInfo.ii_Width == 1<<((int)Log2( (FLOAT)iiImageInfo.ii_Width))) &&
  379. (iiImageInfo.ii_Height == 1<<((int)Log2( (FLOAT)iiImageInfo.ii_Height))) )
  380. {
  381. CTFileName fnTexture = fnPicture.FileDir()+fnPicture.FileName()+".tex";
  382. // creates new texture with one frame
  383. CTextureData tdPicture;
  384. tdPicture.Create_t( &iiImageInfo, iiImageInfo.ii_Width, 1, FALSE);
  385. tdPicture.Save_t( fnTexture);
  386. to.SetData_t( fnTexture);
  387. }
  388. }
  389. catch( char *strError)
  390. {
  391. (void) strError;
  392. }
  393. }
  394. BOOL CWorldEditorDoc::OnOpenDocument(LPCTSTR lpszPathName)
  395. {
  396. CTFileName fnOpenFileName;
  397. // open the world
  398. fnOpenFileName = CTString(CStringA(lpszPathName));
  399. if( fnOpenFileName.FileExt()!=".wld") return FALSE;
  400. try
  401. {
  402. fnOpenFileName.RemoveApplicationPath_t();
  403. // if the file is read only
  404. if(IsFileReadOnly(fnOpenFileName))
  405. {
  406. // warn user about it
  407. WarningMessage("'%s' is read only. You have to check it out to be able to save it.",
  408. (const char*)fnOpenFileName);
  409. // remember it
  410. m_bReadOnly = TRUE;
  411. }
  412. _pfWorldEditingProfile.Reset();
  413. m_woWorld.Load_t( fnOpenFileName);
  414. m_woWorld.ReinitializeEntities();
  415. _pfWorldEditingProfile.Report( theApp.m_strCSGAndShadowStatistics);
  416. theApp.m_strCSGAndShadowStatistics.SaveVar(CTString("Temp\\Profile_Open.txt"));
  417. // try to load textures for backdrops
  418. if( m_woWorld.wo_strBackdropUp != "")
  419. {
  420. SetupBackdropTextureObject( m_woWorld.wo_strBackdropUp, m_toBackdropUp);
  421. }
  422. if( m_woWorld.wo_strBackdropFt != "")
  423. {
  424. SetupBackdropTextureObject( m_woWorld.wo_strBackdropFt, m_toBackdropFt);
  425. }
  426. if( m_woWorld.wo_strBackdropRt != "")
  427. {
  428. SetupBackdropTextureObject( m_woWorld.wo_strBackdropRt, m_toBackdropRt);
  429. }
  430. POSITION pos = GetFirstViewPosition();
  431. CWorldEditorView *pWedView = (CWorldEditorView *) GetNextView(pos);
  432. ASSERT( pWedView != NULL);
  433. CChildFrame *pWedChild = pWedView->GetChildFrame();
  434. ASSERT( pWedChild != NULL);
  435. pWedChild->m_mvViewer.mv_plViewer = m_woWorld.wo_plFocus;
  436. pWedChild->m_mvViewer.mv_fTargetDistance = m_woWorld.wo_fTargetDistance;
  437. }
  438. catch( char *strError)
  439. {
  440. AfxMessageBox( CString(strError));
  441. return FALSE;
  442. }
  443. // try to load object for backdrops
  444. if( m_woWorld.wo_strBackdropObject != "")
  445. {
  446. // try to
  447. try
  448. {
  449. // load 3D lightwawe object
  450. FLOATmatrix3D mStretch;
  451. mStretch.Diagonal(1.0f);
  452. m_o3dBackdropObject.LoadAny3DFormat_t( m_woWorld.wo_strBackdropObject, mStretch);
  453. }
  454. // catch and
  455. catch( char *strError)
  456. {
  457. // report errors
  458. AfxMessageBox( CString(strError));
  459. }
  460. }
  461. if( theApp.m_Preferences.ap_bShowAllOnOpen)
  462. {
  463. OnShowAllEntities();
  464. OnShowAllSectors();
  465. }
  466. // flush stale caches
  467. _pShell->Execute("FreeUnusedStock();");
  468. return TRUE;
  469. }
  470. // overridden from mfc
  471. void CWorldEditorDoc::SetModifiedFlag( BOOL bModified /*= TRUE*/ )
  472. {
  473. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  474. CDocument::SetModifiedFlag(bModified);
  475. if (!bModified) {
  476. return;
  477. }
  478. try
  479. {
  480. if (IsFileReadOnly(m_woWorld.wo_fnmFileName) && !m_bAskedToCheckOut)
  481. {
  482. // ask for check out
  483. if( ::MessageBoxA( pMainFrame->m_hWnd, "Do you want to open the world for edit?",
  484. "Warning !", MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON1 |
  485. MB_TASKMODAL | MB_TOPMOST) == IDYES)
  486. {
  487. m_bAskedToCheckOut = TRUE;
  488. OnCheckEdit();
  489. }
  490. }
  491. }
  492. catch( char *strError)
  493. {
  494. AfxMessageBox( CString(strError));
  495. return;
  496. }
  497. }
  498. BOOL CWorldEditorDoc::OnSaveDocument(LPCTSTR lpszPathName)
  499. {
  500. CTFileName fnSaveFileName;
  501. // save the world
  502. fnSaveFileName = CTString(CStringA(lpszPathName));
  503. try
  504. {
  505. fnSaveFileName.RemoveApplicationPath_t();
  506. // if the file is read only
  507. if(IsFileReadOnly(fnSaveFileName))
  508. {
  509. // don't allow saving
  510. WarningMessage( "World file is read-only. You can't save it.");
  511. return FALSE;
  512. }
  513. POSITION pos = GetFirstViewPosition();
  514. CWorldEditorView *pWedView = (CWorldEditorView *) GetNextView(pos);
  515. CChildFrame *pWedChild = pWedView->GetChildFrame();
  516. m_woWorld.wo_plFocus = pWedChild->m_mvViewer.mv_plViewer;
  517. m_woWorld.wo_fTargetDistance = pWedChild->m_mvViewer.mv_fTargetDistance;
  518. m_woWorld.Save_t( fnSaveFileName);
  519. SetModifiedFlag(FALSE);
  520. }
  521. catch( char *strError)
  522. {
  523. AfxMessageBox( CString(strError));
  524. return FALSE;
  525. }
  526. // write file's directory into application's .ini file
  527. theApp.WriteProfileString(L"World editor", L"Open directory",
  528. CString(_fnmApplicationPath+fnSaveFileName.FileDir()));
  529. // save thumbnail
  530. SaveThumbnail();
  531. m_bWasEverSaved = TRUE;
  532. return TRUE;
  533. }
  534. static BOOL _bDontRecalculateBase = FALSE;
  535. // start creating primitive from current application's primitive, don't recreate base
  536. void CWorldEditorDoc::ApplyCurrentPrimitiveSettings(void)
  537. {
  538. ASSERT( m_pwoSecondLayer != NULL);
  539. // destroy second layer world
  540. delete m_pwoSecondLayer;
  541. m_pwoSecondLayer = NULL;
  542. INDEX iPreCSGMode = m_iPreCSGMode;
  543. // force not recreation of primitive base
  544. _bDontRecalculateBase = TRUE;
  545. StartPrimitiveCSG( theApp.m_vfpCurrent.vfp_plPrimitive, FALSE);
  546. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  547. pMainFrame->m_TriangularisationCombo.SetCurSel( (int)theApp.m_vfpCurrent.vfp_ttTriangularisationType);
  548. m_iPreCSGMode = iPreCSGMode;
  549. }
  550. // start creating primitive
  551. void CWorldEditorDoc::StartPrimitiveCSG( CPlacement3D plPrimitive, BOOL bResetAngles/*=TRUE*/)
  552. {
  553. ApplyAutoColorize();
  554. if( theApp.m_ptdActiveTexture == NULL)
  555. {
  556. AfxMessageBox( L"You have to select active texture first (double click on texture in browser).");
  557. return;
  558. }
  559. if( !((theApp.m_vfpCurrent.vfp_ptPrimitiveType == PT_CONUS) ||
  560. (theApp.m_vfpCurrent.vfp_ptPrimitiveType == PT_TORUS) ||
  561. (theApp.m_vfpCurrent.vfp_ptPrimitiveType == PT_STAIRCASES) ||
  562. (theApp.m_vfpCurrent.vfp_ptPrimitiveType == PT_SPHERE) ||
  563. (theApp.m_vfpCurrent.vfp_ptPrimitiveType == PT_TERRAIN) ) )
  564. {
  565. WarningMessage( "This type of primitive not yet supported. Please be patient !!!");
  566. return;
  567. }
  568. POSITION pos = GetFirstViewPosition();
  569. CWorldEditorView *pWedView = (CWorldEditorView *) GetNextView(pos);
  570. CChildFrame *pWedChild = pWedView->GetChildFrame();
  571. // remember auto mip brushing flag
  572. pWedChild->m_bLastAutoMipBrushingOn = pWedChild->m_bAutoMipBrushingOn;
  573. // turn off auto mip brushing
  574. pWedChild->m_bAutoMipBrushingOn = FALSE;
  575. m_pwoSecondLayer = new CWorld;
  576. m_bPrimitiveMode = TRUE;
  577. // position the second layer
  578. m_plSecondLayer = plPrimitive;
  579. // if angle reset requested
  580. if( bResetAngles)
  581. {
  582. // reset angles so they are alligned to current grid
  583. m_plSecondLayer.pl_OrientationAngle = m_plGrid.pl_OrientationAngle;
  584. }
  585. // create the World entity
  586. CPlacement3D plPrimitiveEntity;
  587. plPrimitiveEntity.pl_PositionVector = FLOAT3D(0.0f,0.0f,0.0f);
  588. plPrimitiveEntity.pl_OrientationAngle = ANGLE3D(0,0,0);
  589. try
  590. {
  591. m_penPrimitive = m_pwoSecondLayer->CreateEntity_t( plPrimitiveEntity,
  592. CTFILENAME("Classes\\WorldBase.ecl"));
  593. }
  594. catch( char *err_str)
  595. {
  596. AfxMessageBox( CString(err_str));
  597. // discard initialized variables needed for CSG
  598. delete m_pwoSecondLayer;
  599. m_pwoSecondLayer = NULL;
  600. m_bPrimitiveMode = FALSE;
  601. return;
  602. }
  603. // prepare the entity
  604. m_penPrimitive->Initialize();
  605. // store current mode
  606. m_iPreCSGMode = m_iMode;
  607. // start CSG mode
  608. SetEditingMode( CSG_MODE);
  609. // create primitive for the first time
  610. //m_bPrimitiveCreatedFirstTime = TRUE;
  611. CreatePrimitive();
  612. // if preferences say so, show info
  613. if( theApp.m_Preferences.ap_AutomaticInfo)
  614. {
  615. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  616. pMainFrame->ShowInfoWindow();
  617. }
  618. // invalidate document (i.e. all views)
  619. UpdateAllViews( NULL);
  620. }
  621. // start CSG with world template
  622. void CWorldEditorDoc::StartTemplateCSG( CPlacement3D plTemplate,
  623. const CTFileName &fnWorld, BOOL bResetAngles/*=TRUE*/)
  624. {
  625. POSITION pos = GetFirstViewPosition();
  626. CWorldEditorView *pWedView = (CWorldEditorView *) GetNextView(pos);
  627. CChildFrame *pWedChild = pWedView->GetChildFrame();
  628. // remember auto mip brushing flag
  629. pWedChild->m_bLastAutoMipBrushingOn = pWedChild->m_bAutoMipBrushingOn;
  630. // turn off auto mip brushing
  631. pWedChild->m_bAutoMipBrushingOn = FALSE;
  632. m_pwoSecondLayer = new CWorld;
  633. m_bPrimitiveMode = FALSE;
  634. // remember name of last template used for CSG
  635. m_fnLastDroppedTemplate = fnWorld;
  636. // position the second layer
  637. m_plSecondLayer = plTemplate;
  638. // if angle reset was requested
  639. if( bResetAngles)
  640. {
  641. // reset angles so they are alligned to current grid
  642. m_plSecondLayer.pl_OrientationAngle = m_plGrid.pl_OrientationAngle;
  643. }
  644. try
  645. {
  646. // load the World
  647. m_pwoSecondLayer->Load_t( fnWorld);
  648. }
  649. catch( char *err_str)
  650. {
  651. AfxMessageBox( CString(err_str));
  652. delete m_pwoSecondLayer;
  653. m_pwoSecondLayer = NULL;
  654. return;
  655. }
  656. // invalidate document (i.e. all views)
  657. UpdateAllViews( NULL);
  658. // store current mode
  659. m_iPreCSGMode = m_iMode;
  660. // start CSG mode
  661. SetEditingMode( CSG_MODE);
  662. // update position property page for the first time
  663. m_chSelections.MarkChanged();
  664. // if preferences say so, show info
  665. if( theApp.m_Preferences.ap_AutomaticInfo)
  666. {
  667. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  668. pMainFrame->ShowInfoWindow();
  669. }
  670. // don't join layers !!!!
  671. /*
  672. // if none of entities in dropped world has brush rendering type
  673. // for all of the world's entities
  674. {FOREACHINDYNAMICCONTAINER(m_pwoSecondLayer->wo_cenEntities, CEntity, iten)
  675. {
  676. CEntity::RenderType rt = iten->GetRenderType();
  677. // if the entity is brush and it is not empty
  678. if( (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH) && ( !iten->IsEmptyBrush()) &&
  679. (CTString(iten->GetClass()->ec_pdecDLLClass->dec_strName) == "WorldBase") )
  680. {
  681. // if preferences say so, show info
  682. if( theApp.m_Preferences.ap_AutomaticInfo)
  683. {
  684. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  685. pMainFrame->ShowInfoWindow();
  686. }
  687. // don't join layers
  688. return;
  689. }
  690. }}
  691. // call join layers
  692. OnJoinLayers();
  693. */
  694. }
  695. #define CT_PRIMITIVES_IN_HISTORY_BUFFER 1024
  696. // apply current CSG operation
  697. void CWorldEditorDoc::ApplyCSG(enum CSGType CSGType)
  698. {
  699. if((CSGType==CSG_ADD ||
  700. CSGType==CSG_ADD_REVERSE ||
  701. CSGType==CSG_REMOVE ||
  702. CSGType==CSG_REMOVE_REVERSE ||
  703. CSGType==CSG_ADD_ENTITIES ||
  704. CSGType==CSG_SPLIT_POLYGONS ||
  705. CSGType==CSG_JOIN_LAYERS) && (m_pwoSecondLayer==NULL)) return;
  706. POSITION pos = GetFirstViewPosition();
  707. CWorldEditorView *pWedView = (CWorldEditorView *) GetNextView(pos);
  708. CChildFrame *pWedChild = pWedView->GetChildFrame();
  709. // restore auto mip brushing flag
  710. pWedChild->m_bAutoMipBrushingOn = pWedChild->m_bLastAutoMipBrushingOn;
  711. // set wait cursor
  712. CWaitCursor StartWaitCursor;
  713. if( theApp.m_bCSGReportEnabled)
  714. {
  715. _pfWorldEditingProfile.Reset();
  716. }
  717. RememberUndo();
  718. // remember last used CSG operation
  719. m_csgtPreLastUsedCSGOperation = m_csgtLastUsedCSGOperation;
  720. m_csgtLastUsedCSGOperation = CSGType;
  721. // set flag telling is last used CSG was primitive
  722. m_bPreLastUsedPrimitiveMode = m_bLastUsedPrimitiveMode;
  723. m_bLastUsedPrimitiveMode = m_bPrimitiveMode;
  724. // invalving entities
  725. CEntity *penThis;
  726. CEntity *penOther;
  727. BOOL bThisFound = FALSE;
  728. BOOL bOtherFound = FALSE;
  729. // calculate delta placement
  730. m_plDeltaPlacement = m_plSecondLayer;
  731. // convert it into absolute space of last used placement (delta calculated)
  732. m_plDeltaPlacement.AbsoluteToRelative( m_plLastPlacement);
  733. // remember position of last applied CSG
  734. m_plLastPlacement = m_plSecondLayer;
  735. theApp.m_vfpCurrent.vfp_plPrimitive = m_plSecondLayer;
  736. // calculate width, height, sheer,... delta to be able to use it for next clone CSG
  737. theApp.m_vfpDelta = theApp.m_vfpCurrent - theApp.m_vfpLast;
  738. // remember last values for primitive as prelast used ones
  739. theApp.m_vfpPreLast = theApp.m_vfpLast;
  740. // remember current values for primitive as last used ones
  741. theApp.m_vfpLast = theApp.m_vfpCurrent;
  742. if( m_bPrimitiveMode)
  743. {
  744. // if there are too many primitives in history buffer
  745. if( theApp.m_lhPrimitiveHistory.Count() >= CT_PRIMITIVES_IN_HISTORY_BUFFER)
  746. {
  747. // remove last used one
  748. CPrimitiveInHistoryBuffer *ppihbLast =
  749. LIST_TAIL( theApp.m_lhPrimitiveHistory, CPrimitiveInHistoryBuffer, pihb_lnNode);
  750. theApp.m_lhPrimitiveHistory.RemTail();
  751. delete ppihbLast;
  752. }
  753. // add this primtive into history buffer
  754. CPrimitiveInHistoryBuffer *ppihbMember = new CPrimitiveInHistoryBuffer;
  755. ppihbMember->pihb_vfpPrimitive = theApp.m_vfpCurrent;
  756. ppihbMember->pihb_vfpPrimitive.vfp_csgtCSGOperation = CSGType;
  757. theApp.m_lhPrimitiveHistory.AddHead( ppihbMember->pihb_lnNode);
  758. // save primitives history buffer
  759. CTFileStream strmFile;
  760. try
  761. {
  762. strmFile.Create_t( CTString("Data\\PrimitivesHistory.pri"));
  763. INDEX ctHistory = theApp.m_lhPrimitiveHistory.Count();
  764. strmFile << ctHistory;
  765. // write history primitives list
  766. FOREACHINLIST( CPrimitiveInHistoryBuffer, pihb_lnNode, theApp.m_lhPrimitiveHistory, itPrim)
  767. {
  768. itPrim->pihb_vfpPrimitive.Write_t( strmFile);
  769. }
  770. }
  771. catch( char *strError)
  772. {
  773. WarningMessage( strError);
  774. }
  775. // remember used values for primitive to be used as default values for next primitive
  776. // of same type
  777. switch( theApp.m_vfpCurrent.vfp_ptPrimitiveType)
  778. {
  779. case PT_CONUS:{ theApp.m_vfpConus = theApp.m_vfpCurrent; break;}
  780. case PT_TORUS:{ theApp.m_vfpTorus = theApp.m_vfpCurrent; break;}
  781. case PT_STAIRCASES:{ theApp.m_vfpStaircases = theApp.m_vfpCurrent; break;}
  782. case PT_SPHERE:{ theApp.m_vfpSphere = theApp.m_vfpCurrent; break;}
  783. case PT_TERRAIN:{ theApp.m_vfpTerrain = theApp.m_vfpCurrent; break;}
  784. default: ASSERTALWAYS( "Wrong primitive type occured");
  785. }
  786. }
  787. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  788. // join operations are not really CSG operations because we do not have second layer
  789. BOOL bJoinOperation = (
  790. CSGType==CSG_JOIN_LAYERS ||
  791. CSGType==CSG_JOIN_SECTORS ||
  792. CSGType==CSG_JOIN_POLYGONS ||
  793. CSGType==CSG_JOIN_POLYGONS_KEEP_TEXTURES ||
  794. CSGType==CSG_JOIN_ALL_POLYGONS ||
  795. CSGType==CSG_JOIN_ALL_POLYGONS_KEEP_TEXTURES);
  796. if( !bJoinOperation)
  797. {
  798. // for real CSG operations search for invalving entities
  799. penThis = pMainFrame->m_CSGDesitnationCombo.GetSelectedBrushEntity();
  800. if( penThis != NULL)
  801. {
  802. bThisFound = TRUE;
  803. }
  804. if( !bThisFound)
  805. {
  806. WarningMessage( "Destination for CSG can't be optained, canceling CSG.");
  807. StopCSG();
  808. return;
  809. }
  810. // find other entity
  811. {FOREACHINDYNAMICCONTAINER(m_pwoSecondLayer->wo_cenEntities, CEntity, itenOther) {
  812. if (CTString(itenOther->GetClass()->ec_pdecDLLClass->dec_strName) == "WorldBase") {
  813. penOther = &itenOther.Current();
  814. bOtherFound = TRUE;
  815. break;
  816. }
  817. }}
  818. // if other entity can't be obtained, switch to join layers mode
  819. if( !bOtherFound)
  820. {
  821. CSGType = CSG_JOIN_LAYERS;
  822. }
  823. }
  824. // act acording requested CSG operation
  825. switch( CSGType)
  826. {
  827. case CSG_ADD:
  828. {
  829. ClearSelections();
  830. // apply "add"
  831. m_woWorld.CSGAdd(*penThis, *m_pwoSecondLayer, *penOther, m_plSecondLayer);
  832. break;
  833. }
  834. case CSG_ADD_REVERSE:
  835. {
  836. ClearSelections();
  837. // apply "add reverse"
  838. m_woWorld.CSGAddReverse(*penThis, *m_pwoSecondLayer, *penOther, m_plSecondLayer);
  839. break;
  840. }
  841. case CSG_REMOVE:
  842. {
  843. ClearSelections();
  844. // apply "remove"
  845. m_woWorld.CSGRemove(*penThis, *m_pwoSecondLayer, *penOther, m_plSecondLayer);
  846. break;
  847. }
  848. case CSG_REMOVE_REVERSE:
  849. {
  850. //ClearSelections();
  851. // apply "remove reverse"
  852. // m_woWorld.CSGRemoveReverse(*penThis, *m_pwoSecondLayer, *penOther, m_plSecondLayer);
  853. break;
  854. }
  855. case CSG_SPLIT_SECTORS:
  856. {
  857. // clear all selections except sector seletion
  858. ClearSelections( ST_SECTOR);
  859. // apply "split sectors"
  860. m_woWorld.SplitSectors(*penThis, m_selSectorSelection,
  861. *m_pwoSecondLayer, *penOther, m_plSecondLayer);
  862. break;
  863. }
  864. case CSG_JOIN_SECTORS:
  865. {
  866. // clear all selections except sector seletion
  867. ClearSelections( ST_SECTOR);
  868. // join selected sectors
  869. m_woWorld.JoinSectors( m_selSectorSelection);
  870. // store current mode
  871. m_iPreCSGMode = m_iMode;
  872. break;
  873. }
  874. case CSG_SPLIT_POLYGONS:
  875. {
  876. // clear all selections except polygon seletion
  877. ClearSelections( ST_POLYGON);
  878. // apply "split polygons"
  879. m_woWorld.SplitPolygons(*penThis, m_selPolygonSelection,
  880. *m_pwoSecondLayer, *penOther, m_plSecondLayer);
  881. break;
  882. }
  883. case CSG_JOIN_POLYGONS:
  884. case CSG_JOIN_POLYGONS_KEEP_TEXTURES:
  885. {
  886. // clear all selections except polygon seletion
  887. ClearSelections( ST_POLYGON);
  888. // join selected polygons
  889. m_woWorld.JoinPolygons(m_selPolygonSelection);
  890. // store current mode
  891. m_iPreCSGMode = m_iMode;
  892. break;
  893. }
  894. case CSG_JOIN_ALL_POLYGONS:
  895. case CSG_JOIN_ALL_POLYGONS_KEEP_TEXTURES:
  896. {
  897. // clear all selections except polygon seletion
  898. ClearSelections( ST_POLYGON);
  899. // join selected polygons
  900. m_woWorld.JoinAllPossiblePolygons(
  901. m_selPolygonSelection, CSGType==CSG_JOIN_ALL_POLYGONS_KEEP_TEXTURES, m_iTexture);
  902. // store current mode
  903. m_iPreCSGMode = m_iMode;
  904. break;
  905. }
  906. case CSG_JOIN_LAYERS:
  907. {
  908. theApp.m_vfpCurrent.vfp_csgtCSGOperation = CSG_JOIN_LAYERS;
  909. // clear entity selections
  910. m_selEntitySelection.Clear();
  911. m_cenEntitiesSelectedByVolume.Clear();
  912. // mark that selections have been changed
  913. m_chSelections.MarkChanged();
  914. // make container of entities to copy
  915. CDynamicContainer<CEntity> cenToCopy;
  916. cenToCopy = m_pwoSecondLayer->wo_cenEntities;
  917. // remove empty brushes from it
  918. {FOREACHINDYNAMICCONTAINER(m_pwoSecondLayer->wo_cenEntities, CEntity, iten)
  919. {
  920. if( iten->IsEmptyBrush() && (iten->GetFlags()&ENF_ZONING))
  921. {
  922. cenToCopy.Remove(iten);
  923. }
  924. }}
  925. // copy entities in container
  926. m_woWorld.CopyEntities( *m_pwoSecondLayer, cenToCopy,
  927. m_selEntitySelection, m_plSecondLayer);
  928. m_iPreCSGMode = ENTITY_MODE;
  929. break;
  930. }
  931. default:
  932. {
  933. ASSERTALWAYS( "Illegal CSG operation type requested!");
  934. }
  935. }
  936. // increase auto colorize color's index
  937. theApp.m_iLastAutoColorizeColor=(theApp.m_iLastAutoColorizeColor+1)%32;
  938. m_chSelections.MarkChanged();
  939. SetModifiedFlag(TRUE);
  940. m_chDocument.MarkChanged();
  941. StopCSG();
  942. if( theApp.m_bCSGReportEnabled)
  943. {
  944. // create CSG report
  945. _pfWorldEditingProfile.Report( theApp.m_strCSGAndShadowStatistics);
  946. theApp.m_strCSGAndShadowStatistics.SaveVar(CTString("Temp\\Profile_CSG.txt"));
  947. }
  948. m_iMirror = 0;
  949. }
  950. // clean up after doing a CSG
  951. void CWorldEditorDoc::StopCSG(void)
  952. {
  953. if( m_pwoSecondLayer == NULL) return;
  954. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  955. // destroy second layer world
  956. delete m_pwoSecondLayer;
  957. m_pwoSecondLayer = NULL;
  958. m_bPrimitiveMode = FALSE;
  959. // if preferences say so, hide info
  960. if( theApp.m_Preferences.ap_AutomaticInfo)
  961. {
  962. pMainFrame->HideInfoWindow();
  963. }
  964. // restore mode
  965. SetEditingMode( m_iPreCSGMode);
  966. // if info frame exist
  967. if( pMainFrame->m_pInfoFrame != NULL)
  968. {
  969. // force immidiate page refilling
  970. pMainFrame->m_pInfoFrame->m_pInfoSheet->OnIdle( 0);
  971. }
  972. // invalidate document (i.e. all views)
  973. UpdateAllViews( NULL);
  974. }
  975. // cancel current CSG operation
  976. void CWorldEditorDoc::CancelCSG(void)
  977. {
  978. StopCSG();
  979. }
  980. void CWorldEditorDoc::OnIdle(void)
  981. {
  982. CValuesForPrimitive &vfp=theApp.m_vfpCurrent;
  983. if( m_pwoSecondLayer!=NULL && m_bPrimitiveMode &&
  984. vfp.vfp_ptPrimitiveType==PT_TERRAIN &&
  985. vfp.vfp_fnDisplacement!="" &&
  986. theApp.m_Preferences.ap_bAutoUpdateDisplaceMap)
  987. {
  988. try
  989. {
  990. SLONG slFileTime=GetFileTimeStamp_t(vfp.vfp_fnDisplacement);
  991. if(slFileTime>m_slDisplaceTexTime)
  992. {
  993. CreatePrimitive();
  994. UpdateAllViews( NULL);
  995. }
  996. }
  997. catch(char *strError)
  998. {
  999. (void) strError;
  1000. }
  1001. }
  1002. POSITION pos = GetFirstViewPosition();
  1003. CWorldEditorView *pWedView;
  1004. FOREVER
  1005. {
  1006. pWedView = (CWorldEditorView *) GetNextView(pos);
  1007. if( pWedView == NULL) break;
  1008. pWedView->OnIdle();
  1009. }
  1010. if( GetEditingMode()==TERRAIN_MODE)
  1011. {
  1012. UpdateAllViews( NULL);
  1013. }
  1014. }
  1015. // does "snap to grid" for given coordinate
  1016. void CWorldEditorDoc::SnapFloat( FLOAT &fDest, FLOAT fStep /* SNAP_FLOAT_GRID */)
  1017. {
  1018. // this must use floor() to get proper snapping of negative values.
  1019. FLOAT fDiv = fDest/fStep;
  1020. FLOAT fRound = fDiv + 0.5f;
  1021. int iSnap = int( floor(fRound));
  1022. FLOAT fRes = iSnap * fStep;
  1023. fDest = fRes;
  1024. }
  1025. // does "snap to grid" for given angle
  1026. void CWorldEditorDoc::SnapAngle( ANGLE &angDest, ANGLE angStep /* SNAP_ANGLE_GRID */)
  1027. {
  1028. /* Watch out for unsigned-signed mixing!
  1029. All sub-expression and arguments must be unsigned for this to work correctly!
  1030. Unfortunately, ANGLE is not an unsigned type by default, so we must cast it.
  1031. Also, angStep must be a divisor of ANGLE_180!
  1032. */
  1033. SnapFloat( angDest, angStep);
  1034. /*
  1035. ASSERT(ANGLE_180%angStep == 0); // don't test with ANGLE_360 ,since it is 0!
  1036. angDest = ANGLE( ((UWORD(angDest)+UWORD(angStep)/2U)/UWORD(angStep))*UWORD(angStep) );
  1037. */
  1038. }
  1039. // does "snap to grid" for given placement
  1040. void CWorldEditorDoc::SnapToGrid( CPlacement3D &plPlacement, FLOAT fSnapValue)
  1041. {
  1042. FLOAT fAngleSnap = SNAP_ANGLE_GRID;
  1043. if( fSnapValue < SNAP_FLOAT_CM) fSnapValue = SNAP_FLOAT_CM;
  1044. if( !m_bAutoSnap)
  1045. {
  1046. fSnapValue = SNAP_FLOAT_CM;
  1047. fAngleSnap = ANGLE_SNAP/32.0f;
  1048. }
  1049. // snap X coordinate
  1050. SnapFloat( plPlacement.pl_PositionVector(1), fSnapValue);
  1051. // snap Y coordinate
  1052. SnapFloat( plPlacement.pl_PositionVector(2), fSnapValue);
  1053. // snap Z coordinate
  1054. SnapFloat( plPlacement.pl_PositionVector(3), fSnapValue);
  1055. /*
  1056. // snap H angle
  1057. SnapAngle( plPlacement.pl_OrientationAngle(1));
  1058. // snap P angle
  1059. SnapAngle( plPlacement.pl_OrientationAngle(2));
  1060. // snap B angle
  1061. SnapAngle( plPlacement.pl_OrientationAngle(3));
  1062. */
  1063. // snap X coordinate
  1064. SnapFloat( plPlacement.pl_PositionVector(1), SNAP_FLOAT_CM);
  1065. // snap Y coordinate
  1066. SnapFloat( plPlacement.pl_PositionVector(2), SNAP_FLOAT_CM);
  1067. // snap Z coordinate
  1068. SnapFloat( plPlacement.pl_PositionVector(3), SNAP_FLOAT_CM);
  1069. // snap H angle
  1070. SnapAngle( plPlacement.pl_OrientationAngle(1), fAngleSnap);
  1071. // snap P angle
  1072. SnapAngle( plPlacement.pl_OrientationAngle(2), fAngleSnap);
  1073. // snap B angle
  1074. SnapAngle( plPlacement.pl_OrientationAngle(3), fAngleSnap);
  1075. }
  1076. // static vars used for polygon creation in primitives
  1077. static BOOL _bAutoCreateMipBrushes;
  1078. static BOOL _bClosed;
  1079. static CObjectMaterial *_pomMaterial;
  1080. static CObjectSector *_poscSector;
  1081. static CTextureData *_pPrimitiveTexture;
  1082. static DOUBLE _fTextureWidth;
  1083. static DOUBLE _fTextureHeight;
  1084. void DisplaceVertex( DOUBLE3D &vVtx, CImageInfo *pII,
  1085. DOUBLE fMinX, DOUBLE fMaxX, DOUBLE fMinZ, DOUBLE fMaxZ,
  1086. INDEX iSlicesPerW, INDEX iSlicesPerL, FLOAT fAmplitude)
  1087. {
  1088. if( pII == NULL) return;
  1089. FLOAT fPix = (fMaxX-fMinX)/(pII->ii_Width-1);
  1090. FLOAT fDelta = (vVtx(1)-fMinX);
  1091. FLOAT fMaxDelta = (fMaxX-fMinX);
  1092. FLOAT fTmp = ((pII->ii_Width-1) / fMaxDelta * fDelta);
  1093. PIX pixX = (PIX)((pII->ii_Width-1) /(fMaxX-fMinX) * (vVtx(1) + fPix/2.0f -fMinX) );
  1094. PIX pixY = (PIX)((pII->ii_Height-1)/(fMaxZ-fMinZ) * (vVtx(3) + fPix/2.0f -fMinZ) );
  1095. if( pixX >= pII->ii_Width) pixX = pII->ii_Width -1;
  1096. if( pixY >= pII->ii_Height) pixY = pII->ii_Height-1;
  1097. SLONG slPicPosition = (pII->ii_Width*pixY +pixX) * (pII->ii_BitsPerPixel/8);
  1098. vVtx(2) += fAmplitude/256.0f * pII->ii_Picture[slPicPosition];
  1099. }
  1100. #define HEIGHT_EPSILON 0.001
  1101. void AddPolygon(INDEX vtxCt, DOUBLE3D *avVtx, BOOL bInvert,
  1102. DOUBLE3D f3dMappingTranslation = DOUBLE3D(0.0f,0.0f,0.0f),
  1103. CImageInfo *pII=NULL,
  1104. DOUBLE fMinX=0.0f, DOUBLE fMaxX=0.0f,
  1105. DOUBLE fMinZ=0.0f, DOUBLE fMaxZ=0.0f,
  1106. INDEX iSlicesPerW=0, INDEX iSlicesPerL=0,
  1107. FLOAT fAmplitude=0.0f,
  1108. DOUBLE fRaiseHeight=0.0f)
  1109. {
  1110. // copy array of vertices
  1111. DOUBLE3D *avVtxCopy = new DOUBLE3D[vtxCt];
  1112. for( INDEX iCopy=0; iCopy<vtxCt; iCopy++)
  1113. {
  1114. avVtxCopy[iCopy] = avVtx[iCopy];
  1115. }
  1116. // displace all vertices
  1117. if( pII != NULL)
  1118. {
  1119. for( INDEX iVtx=0; iVtx<vtxCt; iVtx++)
  1120. {
  1121. if( Abs(avVtxCopy[iVtx](2)-fRaiseHeight)<HEIGHT_EPSILON)
  1122. {
  1123. DisplaceVertex( avVtxCopy[iVtx], pII, fMinX, fMaxX, fMinZ, fMaxZ,
  1124. iSlicesPerW, iSlicesPerL, fAmplitude);
  1125. }
  1126. }
  1127. }
  1128. /*
  1129. // report it
  1130. _RPT1(_CRT_WARN, "\n%d:", vtxCt);
  1131. for(INDEX ivx=0; ivx<vtxCt; ivx++) {
  1132. // report it
  1133. _RPT3(_CRT_WARN, " (%f, %f, %f)",
  1134. avVtx[ivx](1),
  1135. avVtx[ivx](2),
  1136. avVtx[ivx](3));
  1137. }
  1138. */
  1139. switch( theApp.m_vfpCurrent.vfp_ttTriangularisationType)
  1140. {
  1141. case TT_NONE:
  1142. {
  1143. // create polygon
  1144. CObjectPolygon *pObjectPolygon = _poscSector->CreatePolygon(
  1145. vtxCt, avVtxCopy, *_pomMaterial, NULL, bInvert);
  1146. if( pObjectPolygon != NULL) {
  1147. // set shadow cluster size to 2m
  1148. ((CBrushPolygonProperties&)(pObjectPolygon->opo_ubUserData)).bpp_sbShadowClusterSize=2;
  1149. }
  1150. break;
  1151. }
  1152. case TT_CENTER_VERTEX:
  1153. {
  1154. // calculate center vertex
  1155. DOUBLE3D vCenter = DOUBLE3D( 0.0, 0.0, 0.0);
  1156. INDEX iVtx=0;
  1157. for( ; iVtx<vtxCt; iVtx++)
  1158. {
  1159. vCenter+=avVtxCopy[iVtx];
  1160. }
  1161. vCenter /= vtxCt;
  1162. // create polygons
  1163. DOUBLE3D avPolygon[ 3];
  1164. for( iVtx=0; iVtx<vtxCt; iVtx++)
  1165. {
  1166. INDEX iNextVtx = (iVtx+1)%vtxCt;
  1167. avPolygon[ 0] = avVtxCopy[iVtx];
  1168. avPolygon[ 1] = avVtxCopy[iNextVtx];
  1169. avPolygon[ 2] = vCenter;
  1170. CObjectPolygon *pObjectPolygon = _poscSector->CreatePolygon(
  1171. 3, avPolygon, *_pomMaterial, NULL, bInvert);
  1172. if( pObjectPolygon != NULL) {
  1173. // set shadow cluster size to 2m
  1174. ((CBrushPolygonProperties&)(pObjectPolygon->opo_ubUserData)).bpp_sbShadowClusterSize=2;
  1175. }
  1176. }
  1177. break;
  1178. }
  1179. default:
  1180. {
  1181. INDEX iStartVtx = 0;
  1182. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX00) iStartVtx = 0;
  1183. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX01) iStartVtx = 1;
  1184. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX02) iStartVtx = 2;
  1185. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX03) iStartVtx = 3;
  1186. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX04) iStartVtx = 4;
  1187. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX05) iStartVtx = 5;
  1188. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX06) iStartVtx = 6;
  1189. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX07) iStartVtx = 7;
  1190. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX08) iStartVtx = 8;
  1191. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX09) iStartVtx = 9;
  1192. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX10) iStartVtx =10;
  1193. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX11) iStartVtx =11;
  1194. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX12) iStartVtx =12;
  1195. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX13) iStartVtx =13;
  1196. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX14) iStartVtx =14;
  1197. if( theApp.m_vfpCurrent.vfp_ttTriangularisationType == TT_FROM_VTX15) iStartVtx =15;
  1198. iStartVtx %= vtxCt;
  1199. // create polygons
  1200. DOUBLE3D avPolygon[ 3];
  1201. for( INDEX iVtx=iStartVtx; iVtx<iStartVtx+vtxCt-2; iVtx++)
  1202. {
  1203. INDEX iNextVtx = (iVtx+1)%vtxCt;
  1204. INDEX iNextNextVtx = (iNextVtx+1)%vtxCt;
  1205. avPolygon[ 0] = avVtxCopy[iStartVtx];
  1206. avPolygon[ 1] = avVtxCopy[iNextVtx];
  1207. avPolygon[ 2] = avVtxCopy[iNextNextVtx];
  1208. CObjectPolygon *pObjectPolygon = _poscSector->CreatePolygon(
  1209. 3, avPolygon, *_pomMaterial, NULL, bInvert);
  1210. if( pObjectPolygon != NULL) {
  1211. // set shadow cluster size to 2m
  1212. ((CBrushPolygonProperties&)(pObjectPolygon->opo_ubUserData)).bpp_sbShadowClusterSize=2;
  1213. }
  1214. }
  1215. break;
  1216. }
  1217. }
  1218. delete[] avVtxCopy;
  1219. }
  1220. void CWorldEditorDoc::ConvertObject3DToBrush(CObject3D &ob, BOOL bApplyProjectedMapping/*=FALSE*/,
  1221. INDEX iMipBrush/*=0*/, FLOAT fSwitchFactor/*=1E6f*/,
  1222. BOOL bApplyDefaultPolygonProperties/*=TRUE*/)
  1223. {
  1224. CObject3D obTmp = ob;
  1225. obTmp.RecalculatePlanes();
  1226. // try to
  1227. try
  1228. {
  1229. // turn this on to dump all primitives
  1230. #ifndef NDEBUG
  1231. //theApp.m_vfpCurrent.vfp_o3dPrimitive.DebugDump();
  1232. #endif //NDEBUG
  1233. if( !obTmp.ArePolygonsPlanar())
  1234. {
  1235. throw( "ERROR: Primitive that You want to use has non planar polygons.\n"
  1236. "Make sure that stretch x and stretch y are same or use triangularisation.");
  1237. }
  1238. if( bApplyProjectedMapping)
  1239. {
  1240. DOUBLE xMin = theApp.m_vfpCurrent.vfp_fXMin;
  1241. DOUBLE xMax = theApp.m_vfpCurrent.vfp_fXMax;
  1242. DOUBLE zMin = theApp.m_vfpCurrent.vfp_fZMin;
  1243. DOUBLE zMax = theApp.m_vfpCurrent.vfp_fZMax;
  1244. // create mapping to be stretched over the top of primitive
  1245. FLOATplane3D plHorizontal(FLOAT3D(0,1,0),0);
  1246. CMappingDefinitionUI mduiHorizontal;
  1247. mduiHorizontal.mdui_aURotation = mduiHorizontal.mdui_aVRotation = AngleDeg(90.0f);
  1248. mduiHorizontal.mdui_fUStretch = FLOAT((xMax-xMin)/_fTextureWidth);
  1249. mduiHorizontal.mdui_fVStretch = FLOAT((zMax-zMin)/_fTextureHeight);
  1250. mduiHorizontal.mdui_fUOffset = FLOAT(xMin)/mduiHorizontal.mdui_fUStretch;
  1251. mduiHorizontal.mdui_fVOffset = FLOAT(zMin)/mduiHorizontal.mdui_fVStretch;
  1252. CMappingDefinition mdHorizontal;
  1253. mdHorizontal.FromUI(mduiHorizontal);
  1254. // for each polygon in primitive
  1255. CObject3D &ob = obTmp;
  1256. ob.ob_aoscSectors.Lock();
  1257. CObjectSector &osc = ob.ob_aoscSectors[0];
  1258. osc.osc_aopoPolygons.Lock();
  1259. FOREACHINDYNAMICARRAY( osc.osc_aopoPolygons, CObjectPolygon, itopo) {
  1260. CObjectPolygon &opo = *itopo;
  1261. // project mapping to the polygon
  1262. opo.opo_amdMappings[0].ProjectMapping(plHorizontal, mdHorizontal,
  1263. DOUBLEtoFLOAT(*opo.opo_Plane));
  1264. opo.opo_amdMappings[1] = opo.opo_amdMappings[0];
  1265. opo.opo_amdMappings[2] = opo.opo_amdMappings[0];
  1266. }
  1267. osc.osc_aopoPolygons.Unlock();
  1268. ob.ob_aoscSectors.Unlock();
  1269. }
  1270. // convert it into brush
  1271. CBrush3D *pbr = m_penPrimitive->GetBrush();
  1272. if( iMipBrush == 0)
  1273. {
  1274. pbr->Clear();
  1275. }
  1276. pbr->AddMipBrushFromObject3D_t(obTmp, fSwitchFactor);
  1277. if( bApplyDefaultPolygonProperties)
  1278. {
  1279. // --- Apply default values for primitive polygons ---
  1280. // for each mip in its brush
  1281. FOREACHINLIST(CBrushMip, bm_lnInBrush, pbr->br_lhBrushMips, itbm) {
  1282. // for all sectors in this mip
  1283. FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) {
  1284. // for all polygons in sector
  1285. FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
  1286. {
  1287. itbpo->CopyPropertiesWithoutTexture( *theApp.m_pbpoPolygonWithDeafultValues);
  1288. }
  1289. }
  1290. }
  1291. }
  1292. pbr->CalculateBoundingBoxes();
  1293. }
  1294. // report errors
  1295. catch( char *err_str)
  1296. {
  1297. AfxMessageBox( CString(err_str));
  1298. }
  1299. }
  1300. void CWorldEditorDoc::ApplyAutoColorize(void)
  1301. {
  1302. // if primitive auto colorization is on
  1303. if( theApp.m_Preferences.ap_bAutoColorize)
  1304. {
  1305. theApp.m_vfpCurrent.vfp_colPolygonsColor = acol_ColorizePallete[theApp.m_iLastAutoColorizeColor];
  1306. theApp.m_vfpCurrent.vfp_colSectorsColor = theApp.m_vfpCurrent.vfp_colPolygonsColor;
  1307. }
  1308. }
  1309. void CWorldEditorDoc::CreateConusPrimitive(void)
  1310. {
  1311. /*
  1312. // report it
  1313. _RPT0(_CRT_WARN, "\nConus\n");
  1314. */
  1315. // calculate height
  1316. DOUBLE fHeight = theApp.m_vfpCurrent.vfp_fYMax-theApp.m_vfpCurrent.vfp_fYMin;
  1317. if( fHeight < SNAP_FLOAT_GRID) fHeight = SNAP_FLOAT_GRID;
  1318. // get count of vertices on the base
  1319. INDEX vtxCt = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive.Count();
  1320. // get shear values
  1321. DOUBLE dx = theApp.m_vfpCurrent.vfp_fShearX;
  1322. DOUBLE dz = theApp.m_vfpCurrent.vfp_fShearZ;
  1323. // get stretch value for top-base vertices
  1324. DOUBLE fStretchX = theApp.m_vfpCurrent.vfp_fStretchX;
  1325. DOUBLE fStretchY = theApp.m_vfpCurrent.vfp_fStretchY;
  1326. // base polygon
  1327. DOUBLE3D *avBottomPolygon = new DOUBLE3D[ vtxCt];
  1328. for(INDEX iVtxBottom=0; iVtxBottom<vtxCt; iVtxBottom++)
  1329. {
  1330. avBottomPolygon[ iVtxBottom] = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ iVtxBottom];
  1331. avBottomPolygon[ iVtxBottom](2) = theApp.m_vfpCurrent.vfp_fYMin;
  1332. }
  1333. AddPolygon( vtxCt, avBottomPolygon, _bClosed);
  1334. // top polygon
  1335. DOUBLE3D *avTopPolygon = new DOUBLE3D[ vtxCt];
  1336. for(INDEX iVtxTop=0; iVtxTop<vtxCt; iVtxTop++)
  1337. {
  1338. avTopPolygon[ iVtxTop] = DOUBLE3D(
  1339. theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ iVtxTop](1) * fStretchX + dx,
  1340. theApp.m_vfpCurrent.vfp_fYMax,
  1341. theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ iVtxTop](3) * fStretchY + dz);
  1342. }
  1343. if( (fStretchX != 0.0f) && (fStretchY != 0.0f) )
  1344. {
  1345. AddPolygon( vtxCt, avTopPolygon, !_bClosed);
  1346. }
  1347. // side polygons
  1348. DOUBLE3D *avSidePolygon = new DOUBLE3D[ 4];
  1349. for( INDEX iBaseVtx=0; iBaseVtx<vtxCt; iBaseVtx++)
  1350. {
  1351. INDEX iNextVtx = (iBaseVtx+1) % vtxCt;
  1352. avSidePolygon[ 0] = avBottomPolygon[ iBaseVtx];
  1353. avSidePolygon[ 0](2) = theApp.m_vfpCurrent.vfp_fYMin;
  1354. avSidePolygon[ 1] = avTopPolygon[ iBaseVtx];
  1355. avSidePolygon[ 1](2) = theApp.m_vfpCurrent.vfp_fYMax;
  1356. avSidePolygon[ 2] = avTopPolygon[ iNextVtx];
  1357. avSidePolygon[ 2](2) = theApp.m_vfpCurrent.vfp_fYMax;
  1358. avSidePolygon[ 3] = avBottomPolygon[ iNextVtx];
  1359. avSidePolygon[ 3](2) = theApp.m_vfpCurrent.vfp_fYMin;
  1360. // get lenght of base edge
  1361. DOUBLE fEdgeLenght =
  1362. (theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ 1] -
  1363. theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ 0]).Length();
  1364. // calculate how many times we wrapped (tiled) one texture
  1365. INDEX iWrappedTimes = INDEX( (iBaseVtx * fEdgeLenght) / _fTextureWidth);
  1366. // prepare vector of mapping translation (allign to left)
  1367. DOUBLE3D f3dMappingTranslation = avSidePolygon[ 0];
  1368. // add primitive-texture height difference to start from top
  1369. f3dMappingTranslation -= DOUBLE3D( 0.0f, fHeight-_fTextureHeight, 0.0f);
  1370. // calculate last edge's mapping remainings for "continous" mapping
  1371. DOUBLE fMappingRemaining = iBaseVtx*fEdgeLenght - iWrappedTimes*_fTextureWidth;
  1372. // calculate edge vector going from end toward start vertice of base edge
  1373. DOUBLE3D f3dEdge = avSidePolygon[ 3] - avSidePolygon[ 0];
  1374. // normalize it
  1375. f3dEdge.Normalize();
  1376. // multiply it with mapping remaining value
  1377. f3dEdge *= fMappingRemaining;
  1378. // add its influence into mapping translation vector
  1379. f3dMappingTranslation += f3dEdge;
  1380. // create polygons on side of conus
  1381. AddPolygon( 4, avSidePolygon, _bClosed, f3dMappingTranslation);
  1382. }
  1383. delete avBottomPolygon;
  1384. delete avTopPolygon;
  1385. delete avSidePolygon;
  1386. theApp.m_vfpCurrent.vfp_o3dPrimitive.Optimize();
  1387. ConvertObject3DToBrush(theApp.m_vfpCurrent.vfp_o3dPrimitive);
  1388. }
  1389. void CWorldEditorDoc::CreateTorusPrimitive(void)
  1390. {
  1391. /*
  1392. // report it
  1393. _RPT0(_CRT_WARN, "\nTorus\n");
  1394. */
  1395. // get count of vertices that will be used for creating base polygon
  1396. INDEX vtxCt = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive.Count();
  1397. // get torus parameters
  1398. INDEX iSlicesIn360 = theApp.m_vfpCurrent.vfp_iSlicesIn360;
  1399. INDEX iNoOfSlices = theApp.m_vfpCurrent.vfp_iNoOfSlices;
  1400. FLOAT fHeight = theApp.m_vfpCurrent.vfp_fYMax-theApp.m_vfpCurrent.vfp_fYMin;
  1401. // clamp no of slices
  1402. if(iNoOfSlices<1) iNoOfSlices=1;
  1403. //if(iNoOfSlices>iSlicesIn360) iNoOfSlices=iSlicesIn360;
  1404. DOUBLE3D **papvBases = new DOUBLE3D *[iNoOfSlices+1];
  1405. DOUBLE3D vCenter = DOUBLE3D( theApp.m_vfpCurrent.vfp_fRadius, 0.0f, 0.0f);
  1406. BOOL bInvert = _bClosed;
  1407. // rotate base vertices to calculate torus slices
  1408. INDEX iSlice=0;
  1409. for( ; iSlice<iNoOfSlices+1; iSlice++)
  1410. {
  1411. // create rotation matrix
  1412. ANGLE3D angSlice = ANGLE3D( 0, 0, AngleDeg( (360.0f/iSlicesIn360)*iSlice));
  1413. if( theApp.m_vfpCurrent.vfp_fRadius>0.0f)
  1414. {
  1415. angSlice(3) = -angSlice(3);
  1416. }
  1417. DOUBLEmatrix3D matrixRot;
  1418. matrixRot ^= angSlice;
  1419. papvBases[iSlice] = new DOUBLE3D[vtxCt];
  1420. // calculate vertex coordinates for each slice
  1421. for(INDEX iBaseVtx=0; iBaseVtx<vtxCt; iBaseVtx++)
  1422. {
  1423. // create vector from center to rotating vertex
  1424. DOUBLE3D vCT = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ iBaseVtx]-vCenter;
  1425. papvBases[iSlice][iBaseVtx] = vCT*matrixRot+vCenter;
  1426. papvBases[iSlice][iBaseVtx](3) += iSlice*fHeight;
  1427. }
  1428. }
  1429. if(iNoOfSlices!=iSlicesIn360 || fHeight!=0)
  1430. {
  1431. // create torus starting polygon
  1432. AddPolygon( vtxCt, papvBases[0], bInvert);
  1433. // create torus ending polygon
  1434. AddPolygon( vtxCt, papvBases[iNoOfSlices], !bInvert);
  1435. }
  1436. DOUBLE3D avPolygonVertices[4];
  1437. // create polygons on sides
  1438. for(iSlice=0; iSlice<iNoOfSlices; iSlice++)
  1439. {
  1440. INDEX iNextSlice = (iSlice+1)%(iNoOfSlices+1);
  1441. for(INDEX iVtx=0; iVtx<vtxCt; iVtx++)
  1442. {
  1443. INDEX iNextVtx = (iVtx+1)%vtxCt;
  1444. avPolygonVertices[0] = papvBases[iSlice][iVtx];
  1445. avPolygonVertices[1] = papvBases[iSlice][iNextVtx];
  1446. avPolygonVertices[2] = papvBases[iNextSlice][iNextVtx];
  1447. avPolygonVertices[3] = papvBases[iNextSlice][iVtx];
  1448. AddPolygon( 4, avPolygonVertices, !bInvert);
  1449. }
  1450. }
  1451. // free allocated arrays
  1452. for( INDEX iFree=0; iFree<iNoOfSlices+1; iFree++)
  1453. {
  1454. delete papvBases[iFree];
  1455. }
  1456. delete papvBases;
  1457. theApp.m_vfpCurrent.vfp_o3dPrimitive.Optimize();
  1458. ConvertObject3DToBrush(theApp.m_vfpCurrent.vfp_o3dPrimitive);
  1459. }
  1460. void CWorldEditorDoc::CreateStaircasesPrimitive(void)
  1461. {
  1462. /*
  1463. // report it
  1464. _RPT0(_CRT_WARN, "\nStaircases\n");
  1465. */
  1466. // calculate height
  1467. DOUBLE fWidth = theApp.m_vfpCurrent.vfp_fXMax-theApp.m_vfpCurrent.vfp_fXMin;
  1468. if( fWidth < SNAP_FLOAT_GRID) fWidth = SNAP_FLOAT_GRID;
  1469. DOUBLE fHeight = theApp.m_vfpCurrent.vfp_fYMax-theApp.m_vfpCurrent.vfp_fYMin;
  1470. if( fHeight < SNAP_FLOAT_GRID) fHeight = SNAP_FLOAT_GRID;
  1471. DOUBLE fLenght = (theApp.m_vfpCurrent.vfp_fZMax-theApp.m_vfpCurrent.vfp_fZMin);
  1472. if( fLenght < SNAP_FLOAT_12) fLenght = SNAP_FLOAT_12;
  1473. // get parameters for staircases
  1474. INDEX iStairsIn360 = theApp.m_vfpCurrent.vfp_iSlicesIn360;
  1475. INDEX iNoOfStairs = theApp.m_vfpCurrent.vfp_iNoOfSlices;
  1476. DOUBLE fRadius = theApp.m_vfpCurrent.vfp_fRadius;
  1477. DOUBLE angle = 360.0/iStairsIn360;
  1478. DOUBLE angleAdd = 0.0;
  1479. // if base is created inside circle
  1480. if( theApp.m_vfpCurrent.vfp_bOuter && !theApp.m_vfpCurrent.vfp_bLinearStaircases)
  1481. {
  1482. fRadius = fRadius/Cos(FLOAT(angle/2));
  1483. angleAdd = -angle/2.0;
  1484. fWidth = fWidth/Cos(FLOAT(angle/2));
  1485. }
  1486. BOOL bTopSlope = theApp.m_vfpCurrent.vfp_iTopShape == 1;
  1487. BOOL bTopCeiling = theApp.m_vfpCurrent.vfp_iTopShape == 2;
  1488. BOOL bBottomSlope = theApp.m_vfpCurrent.vfp_iBottomShape == 1;
  1489. BOOL bBottomFloor = theApp.m_vfpCurrent.vfp_iBottomShape == 2;
  1490. DOUBLE3D **papvBases = new DOUBLE3D *[iNoOfStairs];
  1491. DOUBLE3D vCenter = DOUBLE3D( 0.0f, 0.0f, 0.0f);
  1492. BOOL bInvert = _bClosed;
  1493. // rotate base vertices to calculate rotating staircases
  1494. INDEX iStair=0;
  1495. for( ; iStair<iNoOfStairs; iStair++)
  1496. {
  1497. // create rotation matrix
  1498. ANGLE3D angRotation1;
  1499. ANGLE3D angRotation2;
  1500. if( fRadius>0.0f)
  1501. {
  1502. angRotation1 = ANGLE3D( -AngleDeg( FLOAT((angle)*iStair+angleAdd)), 0, 0);
  1503. angRotation2 = ANGLE3D( -AngleDeg( FLOAT((angle)*(iStair+1)+angleAdd)), 0, 0);
  1504. }
  1505. else
  1506. {
  1507. angRotation1 = ANGLE3D( AngleDeg( FLOAT((angle)*iStair+angleAdd)), 0, 0);
  1508. angRotation2 = ANGLE3D( AngleDeg( FLOAT((angle)*(iStair+1)+angleAdd)), 0, 0);
  1509. }
  1510. DOUBLEmatrix3D matrixRot1;
  1511. matrixRot1 ^= angRotation1;
  1512. DOUBLEmatrix3D matrixRot2;
  1513. matrixRot2 ^= angRotation2;
  1514. papvBases[iStair] = new DOUBLE3D[4];
  1515. if( theApp.m_vfpCurrent.vfp_bLinearStaircases)
  1516. {
  1517. papvBases[iStair][0] = DOUBLE3D( -fWidth/2.0f, fHeight*iStair, -fLenght*iStair);
  1518. papvBases[iStair][1] = DOUBLE3D( -fWidth/2.0f, fHeight*iStair, -fLenght*(iStair+1));
  1519. papvBases[iStair][2] = DOUBLE3D( fWidth/2.0f, fHeight*iStair, -fLenght*(iStair+1));
  1520. papvBases[iStair][3] = DOUBLE3D( fWidth/2.0f, fHeight*iStair, -fLenght*iStair);
  1521. }
  1522. else
  1523. {
  1524. // calculate vertex coordinates for each rotating stair base
  1525. for(INDEX iBaseVtx=0; iBaseVtx<4; iBaseVtx++)
  1526. {
  1527. DOUBLE3D vCT1, vCT2;
  1528. // create vector from center to rotating vertex
  1529. if( fRadius>0.0f)
  1530. {
  1531. vCT1 = DOUBLE3D(-fRadius,0.0,0.0)-vCenter;
  1532. vCT2 = DOUBLE3D(-fRadius+fWidth,0.0,0.0)-vCenter;
  1533. }
  1534. else
  1535. {
  1536. vCT1 = DOUBLE3D(-fRadius-fWidth,0.0,0.0)-vCenter;
  1537. vCT2 = DOUBLE3D(-fRadius,0.0,0.0)-vCenter;
  1538. }
  1539. papvBases[iStair][3] = vCT2*matrixRot1+vCenter;
  1540. papvBases[iStair][3](2) = fHeight*iStair;
  1541. papvBases[iStair][2] = vCT2*matrixRot2+vCenter;
  1542. papvBases[iStair][2](2) = fHeight*iStair;
  1543. papvBases[iStair][1] = vCT1*matrixRot2+vCenter;
  1544. papvBases[iStair][1](2) = fHeight*iStair;
  1545. papvBases[iStair][0] = vCT1*matrixRot1+vCenter;
  1546. papvBases[iStair][0](2) = fHeight*iStair;
  1547. }
  1548. }
  1549. }
  1550. DOUBLE3D avVtx[8];
  1551. // create polygons of stairs
  1552. for(iStair=0; iStair<iNoOfStairs; iStair++)
  1553. {
  1554. // add only first front polygon if rest are eaten by stairs material
  1555. BOOL bAddFrontVerticalPolygon = TRUE;
  1556. if( (bTopSlope || bTopCeiling) && (iStair != 0) )
  1557. bAddFrontVerticalPolygon = FALSE;
  1558. // add only last back polygon if rest are eaten by stairs material
  1559. BOOL bAddBackVerticalPolygon = TRUE;
  1560. if( (bBottomSlope || bBottomFloor) && (iStair != (iNoOfStairs-1)) )
  1561. bAddBackVerticalPolygon = FALSE;
  1562. avVtx[0] = papvBases[iStair][0];
  1563. avVtx[1] = papvBases[iStair][1];
  1564. avVtx[2] = papvBases[iStair][2];
  1565. avVtx[3] = papvBases[iStair][3];
  1566. avVtx[4] = papvBases[iStair][0];
  1567. avVtx[4](2) += fHeight;
  1568. avVtx[5] = papvBases[iStair][1];
  1569. avVtx[5](2) += fHeight;
  1570. avVtx[6] = papvBases[iStair][2];
  1571. avVtx[6](2) += fHeight;
  1572. avVtx[7] = papvBases[iStair][3];
  1573. avVtx[7](2) += fHeight;
  1574. // if bottom shape is slope
  1575. if( bBottomSlope)
  1576. {
  1577. avVtx[1](2) += fHeight;
  1578. avVtx[2](2) += fHeight;
  1579. }
  1580. // if top shape is slope
  1581. if( bTopSlope)
  1582. {
  1583. avVtx[5](2) += fHeight;
  1584. avVtx[6](2) += fHeight;
  1585. }
  1586. DOUBLE3D avPolygon[4];
  1587. avPolygon[0] = avVtx[0];
  1588. avPolygon[1] = avVtx[1];
  1589. avPolygon[2] = avVtx[5];
  1590. avPolygon[3] = avVtx[4];
  1591. // if bottom shape is floor
  1592. if( bBottomFloor)
  1593. {
  1594. avPolygon[0](2) = 0.0;
  1595. avPolygon[1](2) = 0.0;
  1596. }
  1597. // if top shape is ceiling
  1598. if( bTopCeiling)
  1599. {
  1600. avPolygon[2](2) = fHeight*iNoOfStairs;
  1601. avPolygon[3](2) = fHeight*iNoOfStairs;
  1602. }
  1603. AddPolygon( 4, avPolygon, !bInvert);
  1604. avPolygon[0] = avVtx[3];
  1605. avPolygon[1] = avVtx[2];
  1606. avPolygon[2] = avVtx[6];
  1607. avPolygon[3] = avVtx[7];
  1608. // if bottom shape is floor
  1609. if( bBottomFloor)
  1610. {
  1611. avPolygon[0](2) = 0.0;
  1612. avPolygon[1](2) = 0.0;
  1613. }
  1614. // if top shape is ceiling
  1615. if( bTopCeiling)
  1616. {
  1617. avPolygon[2](2) = fHeight*iNoOfStairs;
  1618. avPolygon[3](2) = fHeight*iNoOfStairs;
  1619. }
  1620. AddPolygon( 4, avPolygon, bInvert);
  1621. if( bAddFrontVerticalPolygon)
  1622. {
  1623. avPolygon[0] = avVtx[0];
  1624. avPolygon[1] = avVtx[4];
  1625. avPolygon[2] = avVtx[7];
  1626. avPolygon[3] = avVtx[3];
  1627. // if top shape is ceiling
  1628. if( bTopCeiling)
  1629. {
  1630. avPolygon[1](2) = fHeight*iNoOfStairs;
  1631. avPolygon[2](2) = fHeight*iNoOfStairs;
  1632. }
  1633. AddPolygon( 4, avPolygon, !bInvert);
  1634. }
  1635. // if bottom shape is slope, top is stairs, don't create polygon because its area is 0
  1636. if( !(bBottomSlope && !bTopSlope) && bAddBackVerticalPolygon)
  1637. {
  1638. avPolygon[0] = avVtx[1];
  1639. avPolygon[1] = avVtx[5];
  1640. avPolygon[2] = avVtx[6];
  1641. avPolygon[3] = avVtx[2];
  1642. if( bBottomFloor)
  1643. {
  1644. avPolygon[0](2) = 0.0;
  1645. avPolygon[3](2) = 0.0;
  1646. }
  1647. AddPolygon( 4, avPolygon, bInvert);
  1648. }
  1649. // if top shape is slope
  1650. if( bTopSlope == 1)
  1651. {
  1652. avPolygon[0] = avVtx[4];
  1653. avPolygon[1] = avVtx[6];
  1654. avPolygon[2] = avVtx[7];
  1655. AddPolygon( 3, avPolygon, !bInvert);
  1656. avPolygon[0] = avVtx[4];
  1657. avPolygon[1] = avVtx[5];
  1658. avPolygon[2] = avVtx[6];
  1659. AddPolygon( 3, avPolygon, !bInvert);
  1660. }
  1661. else
  1662. {
  1663. avPolygon[0] = avVtx[4];
  1664. avPolygon[1] = avVtx[5];
  1665. avPolygon[2] = avVtx[6];
  1666. avPolygon[3] = avVtx[7];
  1667. // if top shape is ceiling
  1668. if( bTopCeiling)
  1669. {
  1670. avPolygon[0](2) = fHeight*iNoOfStairs;
  1671. avPolygon[1](2) = fHeight*iNoOfStairs;
  1672. avPolygon[2](2) = fHeight*iNoOfStairs;
  1673. avPolygon[3](2) = fHeight*iNoOfStairs;
  1674. }
  1675. AddPolygon( 4, avPolygon, !bInvert);
  1676. }
  1677. // if bottom shape is slope
  1678. if( bBottomSlope == 1)
  1679. {
  1680. avPolygon[0] = avVtx[0];
  1681. avPolygon[1] = avVtx[2];
  1682. avPolygon[2] = avVtx[3];
  1683. AddPolygon( 3, avPolygon, bInvert);
  1684. avPolygon[0] = avVtx[0];
  1685. avPolygon[1] = avVtx[1];
  1686. avPolygon[2] = avVtx[2];
  1687. AddPolygon( 3, avPolygon, bInvert);
  1688. }
  1689. else
  1690. {
  1691. avPolygon[0] = avVtx[0];
  1692. avPolygon[1] = avVtx[1];
  1693. avPolygon[2] = avVtx[2];
  1694. avPolygon[3] = avVtx[3];
  1695. // if bottom shape is floor
  1696. if( bBottomFloor)
  1697. {
  1698. avPolygon[0](2) = 0.0;
  1699. avPolygon[1](2) = 0.0;
  1700. avPolygon[2](2) = 0.0;
  1701. avPolygon[3](2) = 0.0;
  1702. }
  1703. AddPolygon( 4, avPolygon, bInvert);
  1704. }
  1705. }
  1706. // free allocated arrays
  1707. for( INDEX iFree=0; iFree<iNoOfStairs; iFree++)
  1708. {
  1709. delete papvBases[iFree];
  1710. }
  1711. delete papvBases;
  1712. theApp.m_vfpCurrent.vfp_o3dPrimitive.Optimize();
  1713. ConvertObject3DToBrush(theApp.m_vfpCurrent.vfp_o3dPrimitive);
  1714. }
  1715. void CWorldEditorDoc::CreateSpherePrimitive(void)
  1716. {
  1717. // calculate width, lenght and height but as radiuses !!! (divided by 2)
  1718. DOUBLE fWidth = (theApp.m_vfpCurrent.vfp_fXMax-theApp.m_vfpCurrent.vfp_fXMin)/2.0;
  1719. if( fWidth < SNAP_FLOAT_GRID) fWidth = SNAP_FLOAT_GRID;
  1720. DOUBLE fHeight = (theApp.m_vfpCurrent.vfp_fYMax-theApp.m_vfpCurrent.vfp_fYMin)/2.0;
  1721. if( fHeight < SNAP_FLOAT_GRID) fHeight = SNAP_FLOAT_GRID;
  1722. DOUBLE fLenght = (theApp.m_vfpCurrent.vfp_fZMax-theApp.m_vfpCurrent.vfp_fZMin)/2.0;
  1723. if( fLenght < SNAP_FLOAT_12) fLenght = SNAP_FLOAT_12;
  1724. // get parameters for staircases
  1725. INDEX iMeridians = theApp.m_vfpCurrent.vfp_iMeridians;
  1726. INDEX iParalels = theApp.m_vfpCurrent.vfp_iParalels;
  1727. BOOL bInvert = _bClosed;
  1728. // calculate bases
  1729. DOUBLE3D **papvSlices = new DOUBLE3D *[iParalels+1];
  1730. ANGLE angleSliceDelta = AngleDeg(180.0f)/iParalels;
  1731. ANGLE angleSlice = -90.0f;
  1732. // calculate all slices on sphere
  1733. INDEX iSlice=0;
  1734. for( ; iSlice<iParalels+1; iSlice++)
  1735. {
  1736. DOUBLE fSliceHeight, dA, dB;
  1737. // if equal slices
  1738. if( theApp.m_vfpCurrent.vfp_bLinearStaircases)
  1739. {
  1740. fSliceHeight = -fHeight + (fHeight*2/iParalels*iSlice);
  1741. }
  1742. else
  1743. {
  1744. fSliceHeight = Sin( angleSlice) * fHeight;
  1745. }
  1746. // snap X coordinate (1 cm)
  1747. //Snap(fSliceHeight, SNAP_DOUBLE_CM);
  1748. // calculate width and lenght of elipse for current slice
  1749. dA = sqrt((fWidth*fWidth*fHeight*fHeight-
  1750. fWidth*fWidth*fSliceHeight*fSliceHeight)/(fHeight*fHeight));
  1751. dB = sqrt((fLenght*fLenght*fHeight*fHeight-
  1752. fLenght*fLenght*fSliceHeight*fSliceHeight)/(fHeight*fHeight));
  1753. // array for vertices of this slice
  1754. papvSlices[iSlice] = new DOUBLE3D[iMeridians];
  1755. ANGLE angle = AngleDeg(360.0f)/iMeridians;
  1756. ANGLE angleCt = 0;
  1757. for( INDEX iVtx=0; iVtx<iMeridians; iVtx++)
  1758. {
  1759. DOUBLE x = Cos( angleCt) * dA + (theApp.m_vfpCurrent.vfp_fXMin+theApp.m_vfpCurrent.vfp_fXMax)/2.0f;
  1760. DOUBLE z = Sin( angleCt) * dB + (theApp.m_vfpCurrent.vfp_fZMin+theApp.m_vfpCurrent.vfp_fZMax)/2.0f;
  1761. // snap X coordinate (1 cm)
  1762. //Snap(x, SNAP_DOUBLE_CM);
  1763. // snap Y coordinate (1 cm)
  1764. //Snap(z, SNAP_DOUBLE_CM);
  1765. papvSlices[iSlice][iVtx] = DOUBLE3D( x, fSliceHeight, z);
  1766. angleCt += angle;
  1767. }
  1768. angleSlice += angleSliceDelta;
  1769. }
  1770. DOUBLE3D avPolygon[4];
  1771. // create polygons
  1772. for( iSlice=0; iSlice<iParalels; iSlice++)
  1773. {
  1774. INDEX iNextSlice = iSlice+1;
  1775. for( INDEX iVtx=0; iVtx<iMeridians; iVtx++)
  1776. {
  1777. INDEX iNextVtx = (iVtx+1)%iMeridians;
  1778. if (iSlice == 0) {
  1779. avPolygon[0] = papvSlices[iNextSlice][iVtx];
  1780. avPolygon[1] = papvSlices[iNextSlice][iNextVtx];
  1781. avPolygon[2] = papvSlices[iSlice][0];
  1782. AddPolygon( 3, avPolygon, bInvert);
  1783. } else if (iSlice == iParalels-1) {
  1784. avPolygon[0] = papvSlices[iNextSlice][0];
  1785. avPolygon[1] = papvSlices[iSlice][iNextVtx];
  1786. avPolygon[2] = papvSlices[iSlice][iVtx];
  1787. AddPolygon( 3, avPolygon, bInvert);
  1788. } else {
  1789. avPolygon[0] = papvSlices[iNextSlice][iVtx];
  1790. avPolygon[1] = papvSlices[iNextSlice][iNextVtx];
  1791. avPolygon[2] = papvSlices[iSlice][iNextVtx];
  1792. avPolygon[3] = papvSlices[iSlice][iVtx];
  1793. AddPolygon( 4, avPolygon, bInvert);
  1794. }
  1795. }
  1796. }
  1797. // free allocated arrays
  1798. for( INDEX iFree=0; iFree<iParalels+1; iFree++)
  1799. {
  1800. delete papvSlices[iFree];
  1801. }
  1802. delete papvSlices;
  1803. theApp.m_vfpCurrent.vfp_o3dPrimitive.Optimize();
  1804. ConvertObject3DToBrush(theApp.m_vfpCurrent.vfp_o3dPrimitive);
  1805. }
  1806. void InitializeObject3DForPrimitive(void)
  1807. {
  1808. // clear Object3D that will be used for creating primitive
  1809. theApp.m_vfpCurrent.vfp_o3dPrimitive.Clear();
  1810. // create sector
  1811. _poscSector = theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.New(1);
  1812. _poscSector->osc_colColor = theApp.m_vfpCurrent.vfp_colSectorsColor;
  1813. // create material
  1814. _pomMaterial = _poscSector->osc_aomtMaterials.New(1);
  1815. _pPrimitiveTexture = theApp.m_ptdActiveTexture;
  1816. _fTextureWidth = METERS_MEX( _pPrimitiveTexture->GetWidth());
  1817. _fTextureHeight = METERS_MEX( _pPrimitiveTexture->GetHeight());
  1818. *_pomMaterial = CObjectMaterial( _pPrimitiveTexture->GetName());
  1819. _pomMaterial->SetColor( theApp.m_vfpCurrent.vfp_colPolygonsColor);
  1820. // Pick up primitive-related variables
  1821. _bClosed = theApp.m_vfpCurrent.vfp_bClosed;
  1822. _bAutoCreateMipBrushes = theApp.m_vfpCurrent.vfp_bAutoCreateMipBrushes;
  1823. }
  1824. void GetTerrainPolygonEdges(CObjectSector &osec, INDEX iPolygon, INDEX iSlicesX, INDEX iSlicesZ,
  1825. CObjectEdge *&poe0, CObjectEdge *&poe1, CObjectEdge *&poe2,
  1826. CObjectEdge *&poe3, CObjectEdge *&poe4);
  1827. void CWorldEditorDoc::CreateTerrainPrimitive(void)
  1828. {
  1829. CImageInfo iiDisplace;
  1830. CImageInfo *piiDisplace = &iiDisplace;
  1831. if( theApp.m_vfpCurrent.vfp_fnDisplacement != "")
  1832. {
  1833. try
  1834. {
  1835. iiDisplace.LoadAnyGfxFormat_t( theApp.m_vfpCurrent.vfp_fnDisplacement);
  1836. m_slDisplaceTexTime=GetFileTimeStamp_t(theApp.m_vfpCurrent.vfp_fnDisplacement);
  1837. }
  1838. catch( char *strError)
  1839. {
  1840. (void) strError;
  1841. piiDisplace = NULL;
  1842. }
  1843. }
  1844. else
  1845. {
  1846. piiDisplace = NULL;
  1847. }
  1848. // get parameters for slices
  1849. INDEX iSlicesX = theApp.m_vfpCurrent.vfp_iSlicesPerWidth;
  1850. if( iSlicesX < 1) iSlicesX = 1;
  1851. INDEX iSlicesZ = theApp.m_vfpCurrent.vfp_iSlicesPerHeight;
  1852. if( iSlicesZ < 1) iSlicesZ = 1;
  1853. INDEX iMip=0;
  1854. // auto create mip brushes
  1855. while( iSlicesX>=1 && iSlicesZ>=1 && ((iMip==0)||_bAutoCreateMipBrushes))
  1856. {
  1857. CreateTerrainObject3D( piiDisplace, iSlicesX, iSlicesZ, iMip);
  1858. ConvertObject3DToBrush(theApp.m_vfpCurrent.vfp_o3dPrimitive, TRUE, iMip, 5.0f+iMip*1.5, FALSE);
  1859. iSlicesX /= 2;
  1860. iSlicesZ /= 2;
  1861. iMip++;
  1862. }
  1863. }
  1864. void CWorldEditorDoc::CreateTerrainObject3D( CImageInfo *piiDisplace, INDEX iSlicesX, INDEX iSlicesZ, INDEX iMip)
  1865. {
  1866. // calculate width, lenght and heigth
  1867. DOUBLE fWidth = (theApp.m_vfpCurrent.vfp_fXMax-theApp.m_vfpCurrent.vfp_fXMin);
  1868. if( fWidth < SNAP_FLOAT_GRID) fWidth = SNAP_FLOAT_GRID;
  1869. DOUBLE fHeight = (theApp.m_vfpCurrent.vfp_fYMax-theApp.m_vfpCurrent.vfp_fYMin);
  1870. if( fHeight < SNAP_FLOAT_GRID) fHeight = SNAP_FLOAT_GRID;
  1871. DOUBLE fLenght = (theApp.m_vfpCurrent.vfp_fZMax-theApp.m_vfpCurrent.vfp_fZMin);
  1872. if( fLenght < SNAP_FLOAT_12) fLenght = SNAP_FLOAT_12;
  1873. DOUBLE fMinX = theApp.m_vfpCurrent.vfp_fXMin;
  1874. DOUBLE fMaxX = theApp.m_vfpCurrent.vfp_fXMax;
  1875. DOUBLE fMinY = theApp.m_vfpCurrent.vfp_fYMin;
  1876. DOUBLE fMaxY = theApp.m_vfpCurrent.vfp_fYMax;
  1877. DOUBLE fMinZ = theApp.m_vfpCurrent.vfp_fZMin;
  1878. DOUBLE fMaxZ = theApp.m_vfpCurrent.vfp_fZMax;
  1879. DOUBLE fDX = fWidth/iSlicesX;
  1880. DOUBLE fDZ = fLenght/iSlicesZ;
  1881. FLOAT fAmplitude = theApp.m_vfpCurrent.vfp_fAmplitude;
  1882. ULONG ulNonFllorPolygonFlags = BPOF_FULLBRIGHT|BPOF_DETAILPOLYGON|BPOF_PORTAL;
  1883. if( !_bClosed)
  1884. {
  1885. // swap min and max y coordinates
  1886. FLOAT fTemp = fMinY;
  1887. fMinY = fMaxY;
  1888. fMaxY = fTemp;
  1889. ulNonFllorPolygonFlags = BPOF_FULLBRIGHT|BPOF_DETAILPOLYGON;
  1890. }
  1891. // initialize object 3D
  1892. InitializeObject3DForPrimitive();
  1893. // get sector reference
  1894. CObjectSector &osec = *_poscSector;
  1895. INDEX ctVertices = (iSlicesX+1)*(iSlicesZ+1)+4;
  1896. osec.osc_aovxVertices.New(ctVertices);
  1897. osec.osc_aovxVertices.Lock();
  1898. // create 'floor' vertices
  1899. {for( INDEX iz=0; iz<=iSlicesZ; iz++) {
  1900. {for( INDEX ix=0; ix<=iSlicesX; ix++) {
  1901. INDEX iVtx = iz*(iSlicesX+1)+ix;
  1902. CObjectVertex &ov = osec.osc_aovxVertices[iVtx];
  1903. ov = DOUBLE3D(fMinX+fDX*ix, fMinY, fMinZ+fDZ*iz);
  1904. DisplaceVertex( ov, piiDisplace, fMinX, fMaxX, fMinZ, fMaxZ, iSlicesX, iSlicesZ, fAmplitude);
  1905. }}
  1906. }}
  1907. // create four 'ceiling' vertices
  1908. #define START_OF_CEILING_VERTICES ((iSlicesX+1)*(iSlicesZ+1))
  1909. INDEX iVtx = START_OF_CEILING_VERTICES;
  1910. osec.osc_aovxVertices[iVtx+0] = DOUBLE3D(fMinX, fMaxY, fMaxZ);
  1911. osec.osc_aovxVertices[iVtx+1] = DOUBLE3D(fMaxX, fMaxY, fMaxZ);
  1912. osec.osc_aovxVertices[iVtx+2] = DOUBLE3D(fMaxX, fMaxY, fMinZ);
  1913. osec.osc_aovxVertices[iVtx+3] = DOUBLE3D(fMinX, fMaxY, fMinZ);
  1914. // allocate edges
  1915. INDEX ctEdges = iSlicesX*(iSlicesZ+1)+iSlicesZ*(iSlicesX+1)+iSlicesX*iSlicesZ+8;
  1916. osec.osc_aoedEdges.New(ctEdges);
  1917. // create edges from vertices
  1918. osec.osc_aoedEdges.Lock();
  1919. // create horizontal edges
  1920. {for( INDEX iz=0; iz<iSlicesZ+1; iz++)
  1921. {
  1922. {for( INDEX ix=0; ix<iSlicesX; ix++)
  1923. {
  1924. INDEX iVtx1 = iz*(iSlicesX+1)+ix;
  1925. INDEX iEdg = iz*iSlicesX+ix;
  1926. CObjectEdge &oedg = osec.osc_aoedEdges[iEdg];
  1927. oedg.oed_Vertex0 = &osec.osc_aovxVertices[iVtx1];
  1928. oedg.oed_Vertex1 = &osec.osc_aovxVertices[iVtx1+1];
  1929. }
  1930. }
  1931. }}
  1932. // create vertical edges
  1933. #define START_OF_VERTICAL_EDGES (iSlicesX*(iSlicesZ+1))
  1934. {for( INDEX iz=0; iz<iSlicesZ; iz++)
  1935. {
  1936. {for( INDEX ix=0; ix<iSlicesX+1; ix++)
  1937. {
  1938. INDEX iVtx1 = iz*(iSlicesX+1)+ix;
  1939. INDEX iEdg = START_OF_VERTICAL_EDGES + iz*(iSlicesX+1)+ix;
  1940. CObjectEdge &oedg = osec.osc_aoedEdges[iEdg];
  1941. oedg.oed_Vertex0 = &osec.osc_aovxVertices[iVtx1];
  1942. oedg.oed_Vertex1 = &osec.osc_aovxVertices[iVtx1+(iSlicesX+1)];
  1943. }
  1944. }
  1945. }}
  1946. // create slope edges
  1947. #define START_OF_SLOPE_EDGES (iSlicesX*(iSlicesZ+1)+(iSlicesX+1)*iSlicesZ)
  1948. {for( INDEX iz=0; iz<iSlicesZ; iz++)
  1949. {
  1950. {for( INDEX ix=0; ix<iSlicesX; ix++)
  1951. {
  1952. INDEX iVtx1 = iz*(iSlicesX+1)+ix;
  1953. INDEX iEdg = START_OF_SLOPE_EDGES + iz*iSlicesX+ix;
  1954. CObjectEdge &oedg = osec.osc_aoedEdges[iEdg];
  1955. oedg.oed_Vertex0 = &osec.osc_aovxVertices[iVtx1];
  1956. oedg.oed_Vertex1 = &osec.osc_aovxVertices[iVtx1+iSlicesX+1+1];
  1957. }
  1958. }
  1959. }}
  1960. // create border edges
  1961. #define START_OF_BORDER_EDGES (iSlicesX*(iSlicesZ+1)+(iSlicesX+1)*iSlicesZ+iSlicesX*iSlicesZ)
  1962. {
  1963. // 0
  1964. INDEX iEdg = START_OF_BORDER_EDGES + 0;
  1965. CObjectEdge &oedg = osec.osc_aoedEdges[iEdg];
  1966. INDEX iVtx0 = (iSlicesX+1)*iSlicesZ;
  1967. oedg.oed_Vertex0 = &osec.osc_aovxVertices[iVtx0];
  1968. oedg.oed_Vertex1 = &osec.osc_aovxVertices[START_OF_CEILING_VERTICES+0];
  1969. }
  1970. {
  1971. // 1
  1972. INDEX iEdg = START_OF_BORDER_EDGES + 1;
  1973. CObjectEdge &oedg = osec.osc_aoedEdges[iEdg];
  1974. INDEX iVtx0 = (iSlicesX+1)*(iSlicesZ+1)-1;
  1975. oedg.oed_Vertex0 = &osec.osc_aovxVertices[iVtx0];
  1976. oedg.oed_Vertex1 = &osec.osc_aovxVertices[START_OF_CEILING_VERTICES+1];
  1977. }
  1978. {
  1979. // 2
  1980. INDEX iEdg = START_OF_BORDER_EDGES + 2;
  1981. CObjectEdge &oedg = osec.osc_aoedEdges[iEdg];
  1982. INDEX iVtx0 = iSlicesX;
  1983. oedg.oed_Vertex0 = &osec.osc_aovxVertices[iVtx0];
  1984. oedg.oed_Vertex1 = &osec.osc_aovxVertices[START_OF_CEILING_VERTICES+2];
  1985. }
  1986. {
  1987. // 3
  1988. INDEX iEdg = START_OF_BORDER_EDGES + 3;
  1989. CObjectEdge &oedg = osec.osc_aoedEdges[iEdg];
  1990. INDEX iVtx0 = 0;
  1991. oedg.oed_Vertex0 = &osec.osc_aovxVertices[iVtx0];
  1992. oedg.oed_Vertex1 = &osec.osc_aovxVertices[START_OF_CEILING_VERTICES+3];
  1993. }
  1994. // create ceiling edges
  1995. #define START_OF_CEILING_EDGES (START_OF_BORDER_EDGES + 4)
  1996. {
  1997. // 0
  1998. INDEX iEdg = START_OF_CEILING_EDGES + 0;
  1999. CObjectEdge &oedg = osec.osc_aoedEdges[iEdg];
  2000. oedg.oed_Vertex0 = &osec.osc_aovxVertices[START_OF_CEILING_VERTICES];
  2001. oedg.oed_Vertex1 = &osec.osc_aovxVertices[START_OF_CEILING_VERTICES+1];
  2002. }
  2003. {
  2004. // 1
  2005. INDEX iEdg = START_OF_CEILING_EDGES + 1;
  2006. CObjectEdge &oedg = osec.osc_aoedEdges[iEdg];
  2007. oedg.oed_Vertex0 = &osec.osc_aovxVertices[START_OF_CEILING_VERTICES+1];
  2008. oedg.oed_Vertex1 = &osec.osc_aovxVertices[START_OF_CEILING_VERTICES+2];
  2009. }
  2010. {
  2011. // 2
  2012. INDEX iEdg = START_OF_CEILING_EDGES + 2;
  2013. CObjectEdge &oedg = osec.osc_aoedEdges[iEdg];
  2014. oedg.oed_Vertex0 = &osec.osc_aovxVertices[START_OF_CEILING_VERTICES+2];
  2015. oedg.oed_Vertex1 = &osec.osc_aovxVertices[START_OF_CEILING_VERTICES+3];
  2016. }
  2017. {
  2018. // 3
  2019. INDEX iEdg = START_OF_CEILING_EDGES + 3;
  2020. CObjectEdge &oedg = osec.osc_aoedEdges[iEdg];
  2021. oedg.oed_Vertex0 = &osec.osc_aovxVertices[START_OF_CEILING_VERTICES+3];
  2022. oedg.oed_Vertex1 = &osec.osc_aovxVertices[START_OF_CEILING_VERTICES+0];
  2023. }
  2024. // get material
  2025. CObjectMaterial &omat = *_pomMaterial;
  2026. // allocate polygons and their planes
  2027. INDEX ctPolygons = iSlicesX*iSlicesZ*2+4+1;
  2028. osec.osc_aopoPolygons.New(ctPolygons);
  2029. osec.osc_aoplPlanes.New(ctPolygons);
  2030. osec.osc_aopoPolygons.Lock();
  2031. osec.osc_aoplPlanes.Lock();
  2032. // create floor polygons and their planes
  2033. for( INDEX iPolygon=0; iPolygon<iSlicesX*iSlicesZ; iPolygon++)
  2034. {
  2035. // obtain edges of one broken checked polygon
  2036. CObjectEdge *poe0, *poe1, *poe2, *poe3, *poe4;
  2037. GetTerrainPolygonEdges(osec, iPolygon, iSlicesX, iSlicesZ, poe0, poe1, poe2, poe3, poe4);
  2038. {
  2039. // create upper polygon
  2040. CObjectPlane &opl = osec.osc_aoplPlanes[iPolygon*2+0];
  2041. opl = DOUBLEplane3D( *poe3->oed_Vertex1, *poe3->oed_Vertex0, *poe0->oed_Vertex0);
  2042. CObjectPolygon &opo = osec.osc_aopoPolygons[iPolygon*2+0];
  2043. opo.opo_Plane = &opl;
  2044. // set polygon edges
  2045. opo.opo_PolygonEdges.New(3);
  2046. opo.opo_PolygonEdges.Lock();
  2047. opo.opo_PolygonEdges[0].ope_Edge = poe0;
  2048. opo.opo_PolygonEdges[0].ope_Backward = TRUE;
  2049. opo.opo_PolygonEdges[1].ope_Edge = poe4;
  2050. opo.opo_PolygonEdges[1].ope_Backward = FALSE;
  2051. opo.opo_PolygonEdges[2].ope_Edge = poe3;
  2052. opo.opo_PolygonEdges[2].ope_Backward = TRUE;
  2053. opo.opo_PolygonEdges.Unlock();
  2054. // set other polygon properties
  2055. opo.opo_Material = &omat;
  2056. opo.opo_ulFlags = BPOF_FULLBRIGHT|BPOF_DETAILPOLYGON;
  2057. opo.opo_colorColor = theApp.m_vfpCurrent.vfp_colPolygonsColor;
  2058. }
  2059. {
  2060. // create lower polygon
  2061. CObjectPlane &opl = osec.osc_aoplPlanes[iPolygon*2+1];
  2062. opl = DOUBLEplane3D( *poe1->oed_Vertex0, *poe1->oed_Vertex1, *poe2->oed_Vertex1);
  2063. CObjectPolygon &opo = osec.osc_aopoPolygons[iPolygon*2+1];
  2064. opo.opo_Plane = &opl;
  2065. // set polygon edges
  2066. opo.opo_PolygonEdges.New(3);
  2067. opo.opo_PolygonEdges.Lock();
  2068. opo.opo_PolygonEdges[0].ope_Edge = poe1;
  2069. opo.opo_PolygonEdges[0].ope_Backward = FALSE;
  2070. opo.opo_PolygonEdges[1].ope_Edge = poe2;
  2071. opo.opo_PolygonEdges[1].ope_Backward = FALSE;
  2072. opo.opo_PolygonEdges[2].ope_Edge = poe4;
  2073. opo.opo_PolygonEdges[2].ope_Backward = TRUE;
  2074. opo.opo_PolygonEdges.Unlock();
  2075. // set other polygon properties
  2076. opo.opo_Material = &omat;
  2077. opo.opo_ulFlags = BPOF_FULLBRIGHT|BPOF_DETAILPOLYGON;
  2078. opo.opo_colorColor = theApp.m_vfpCurrent.vfp_colPolygonsColor;
  2079. }
  2080. }
  2081. // create side polygons and their planes
  2082. #define START_OF_SIDE_POLYGONS (iSlicesX*iSlicesZ*2)
  2083. {
  2084. // side polygon 0
  2085. CObjectPolygon &opo = osec.osc_aopoPolygons[START_OF_SIDE_POLYGONS+0];
  2086. CObjectEdge &oe0 = osec.osc_aoedEdges[ START_OF_BORDER_EDGES+0];
  2087. CObjectEdge &oe1 = osec.osc_aoedEdges[ START_OF_CEILING_EDGES+0];
  2088. CObjectPlane &opl = osec.osc_aoplPlanes[START_OF_SIDE_POLYGONS+0];
  2089. opl = DOUBLEplane3D( *oe0.oed_Vertex0, *oe0.oed_Vertex1, *oe1.oed_Vertex1);
  2090. opo.opo_Plane = &opl;
  2091. opo.opo_PolygonEdges.New(iSlicesX+3);
  2092. opo.opo_PolygonEdges.Lock();
  2093. INDEX iEdg=0;
  2094. for( ; iEdg<iSlicesX; iEdg++)
  2095. {
  2096. INDEX iEdgeIdx = iSlicesX*iSlicesZ+iEdg;
  2097. opo.opo_PolygonEdges[iEdg].ope_Edge = &osec.osc_aoedEdges[ iEdgeIdx];
  2098. opo.opo_PolygonEdges[iEdg].ope_Backward = TRUE;
  2099. }
  2100. opo.opo_PolygonEdges[iEdg+0].ope_Edge = &osec.osc_aoedEdges[ START_OF_BORDER_EDGES+0];
  2101. opo.opo_PolygonEdges[iEdg+0].ope_Backward = FALSE;
  2102. opo.opo_PolygonEdges[iEdg+1].ope_Edge = &osec.osc_aoedEdges[ START_OF_CEILING_EDGES+0];
  2103. opo.opo_PolygonEdges[iEdg+1].ope_Backward = FALSE;
  2104. opo.opo_PolygonEdges[iEdg+2].ope_Edge = &osec.osc_aoedEdges[ START_OF_BORDER_EDGES+1];
  2105. opo.opo_PolygonEdges[iEdg+2].ope_Backward = TRUE;
  2106. opo.opo_Material = &omat;
  2107. opo.opo_ulFlags = ulNonFllorPolygonFlags;
  2108. opo.opo_colorColor = theApp.m_vfpCurrent.vfp_colPolygonsColor;
  2109. opo.opo_PolygonEdges.Unlock();
  2110. }
  2111. {
  2112. // side polygon 1
  2113. CObjectPolygon &opo = osec.osc_aopoPolygons[START_OF_SIDE_POLYGONS+1];
  2114. CObjectEdge &oe0 = osec.osc_aoedEdges[ START_OF_BORDER_EDGES+1];
  2115. CObjectEdge &oe1 = osec.osc_aoedEdges[ START_OF_CEILING_EDGES+1];
  2116. CObjectPlane &opl = osec.osc_aoplPlanes[START_OF_SIDE_POLYGONS+1];
  2117. opl = DOUBLEplane3D( *oe0.oed_Vertex0, *oe0.oed_Vertex1, *oe1.oed_Vertex1);
  2118. opo.opo_Plane = &opl;
  2119. opo.opo_PolygonEdges.New(iSlicesZ+3);
  2120. opo.opo_PolygonEdges.Lock();
  2121. INDEX iEdg=0;
  2122. for( ; iEdg<iSlicesZ; iEdg++)
  2123. {
  2124. opo.opo_PolygonEdges[iEdg].ope_Edge = &osec.osc_aoedEdges[ START_OF_VERTICAL_EDGES+iSlicesX+iEdg*(iSlicesX+1)];
  2125. opo.opo_PolygonEdges[iEdg].ope_Backward = FALSE;
  2126. }
  2127. opo.opo_PolygonEdges[iEdg+0].ope_Edge = &osec.osc_aoedEdges[ START_OF_BORDER_EDGES+1];
  2128. opo.opo_PolygonEdges[iEdg+0].ope_Backward = FALSE;
  2129. opo.opo_PolygonEdges[iEdg+1].ope_Edge = &osec.osc_aoedEdges[ START_OF_CEILING_EDGES+1];
  2130. opo.opo_PolygonEdges[iEdg+1].ope_Backward = FALSE;
  2131. opo.opo_PolygonEdges[iEdg+2].ope_Edge = &osec.osc_aoedEdges[ START_OF_BORDER_EDGES+2];
  2132. opo.opo_PolygonEdges[iEdg+2].ope_Backward = TRUE;
  2133. opo.opo_Material = &omat;
  2134. opo.opo_ulFlags = ulNonFllorPolygonFlags;
  2135. opo.opo_colorColor = theApp.m_vfpCurrent.vfp_colPolygonsColor;
  2136. opo.opo_PolygonEdges.Unlock();
  2137. }
  2138. {
  2139. // side polygon 2
  2140. CObjectPolygon &opo = osec.osc_aopoPolygons[START_OF_SIDE_POLYGONS+2];
  2141. CObjectEdge &oe0 = osec.osc_aoedEdges[ START_OF_BORDER_EDGES+2];
  2142. CObjectEdge &oe1 = osec.osc_aoedEdges[ START_OF_CEILING_EDGES+2];
  2143. CObjectPlane &opl = osec.osc_aoplPlanes[START_OF_SIDE_POLYGONS+2];
  2144. opl = DOUBLEplane3D( *oe0.oed_Vertex0, *oe0.oed_Vertex1, *oe1.oed_Vertex1);
  2145. opo.opo_Plane = &opl;
  2146. opo.opo_PolygonEdges.New(iSlicesX+3);
  2147. opo.opo_PolygonEdges.Lock();
  2148. INDEX iEdg=0;
  2149. for( ; iEdg<iSlicesX; iEdg++)
  2150. {
  2151. opo.opo_PolygonEdges[iEdg].ope_Edge = &osec.osc_aoedEdges[ iEdg];
  2152. opo.opo_PolygonEdges[iEdg].ope_Backward = FALSE;
  2153. }
  2154. opo.opo_PolygonEdges[iEdg+0].ope_Edge = &osec.osc_aoedEdges[ START_OF_BORDER_EDGES+2];
  2155. opo.opo_PolygonEdges[iEdg+0].ope_Backward = FALSE;
  2156. opo.opo_PolygonEdges[iEdg+1].ope_Edge = &osec.osc_aoedEdges[ START_OF_CEILING_EDGES+2];
  2157. opo.opo_PolygonEdges[iEdg+1].ope_Backward = FALSE;
  2158. opo.opo_PolygonEdges[iEdg+2].ope_Edge = &osec.osc_aoedEdges[ START_OF_BORDER_EDGES+3];
  2159. opo.opo_PolygonEdges[iEdg+2].ope_Backward = TRUE;
  2160. opo.opo_Material = &omat;
  2161. opo.opo_ulFlags = ulNonFllorPolygonFlags;
  2162. opo.opo_colorColor = theApp.m_vfpCurrent.vfp_colPolygonsColor;
  2163. opo.opo_PolygonEdges.Unlock();
  2164. }
  2165. {
  2166. // side polygon 3
  2167. CObjectPolygon &opo = osec.osc_aopoPolygons[START_OF_SIDE_POLYGONS+3];
  2168. CObjectEdge &oe0 = osec.osc_aoedEdges[ START_OF_BORDER_EDGES+3];
  2169. CObjectEdge &oe1 = osec.osc_aoedEdges[ START_OF_CEILING_EDGES+3];
  2170. CObjectPlane &opl = osec.osc_aoplPlanes[START_OF_SIDE_POLYGONS+3];
  2171. opl = DOUBLEplane3D( *oe0.oed_Vertex0, *oe0.oed_Vertex1, *oe1.oed_Vertex1);
  2172. opo.opo_Plane = &opl;
  2173. opo.opo_PolygonEdges.New(iSlicesZ+3);
  2174. opo.opo_PolygonEdges.Lock();
  2175. INDEX iEdg=0;
  2176. for( ; iEdg<iSlicesZ; iEdg++)
  2177. {
  2178. opo.opo_PolygonEdges[iEdg].ope_Edge = &osec.osc_aoedEdges[ START_OF_VERTICAL_EDGES+iEdg*(iSlicesX+1)];
  2179. opo.opo_PolygonEdges[iEdg].ope_Backward = TRUE;
  2180. }
  2181. opo.opo_PolygonEdges[iEdg+0].ope_Edge = &osec.osc_aoedEdges[ START_OF_BORDER_EDGES+3];
  2182. opo.opo_PolygonEdges[iEdg+0].ope_Backward = FALSE;
  2183. opo.opo_PolygonEdges[iEdg+1].ope_Edge = &osec.osc_aoedEdges[ START_OF_CEILING_EDGES+3];
  2184. opo.opo_PolygonEdges[iEdg+1].ope_Backward = FALSE;
  2185. opo.opo_PolygonEdges[iEdg+2].ope_Edge = &osec.osc_aoedEdges[ START_OF_BORDER_EDGES+0];
  2186. opo.opo_PolygonEdges[iEdg+2].ope_Backward = TRUE;
  2187. opo.opo_Material = &omat;
  2188. opo.opo_ulFlags = ulNonFllorPolygonFlags;
  2189. opo.opo_colorColor = theApp.m_vfpCurrent.vfp_colPolygonsColor;
  2190. opo.opo_PolygonEdges.Unlock();
  2191. }
  2192. // create ceiling polygon and its plane
  2193. #define CEILING_POLYGON (iSlicesX*iSlicesZ*2+4)
  2194. {
  2195. // ceiling polygon
  2196. CObjectPolygon &opo = osec.osc_aopoPolygons[CEILING_POLYGON];
  2197. CObjectEdge &oe0 = osec.osc_aoedEdges[ START_OF_CEILING_EDGES+0];
  2198. CObjectEdge &oe1 = osec.osc_aoedEdges[ START_OF_CEILING_EDGES+1];
  2199. CObjectPlane &opl = osec.osc_aoplPlanes[CEILING_POLYGON];
  2200. opl = DOUBLEplane3D( *oe1.oed_Vertex1, *oe1.oed_Vertex0, *oe0.oed_Vertex0);
  2201. opo.opo_Plane = &opl;
  2202. opo.opo_PolygonEdges.New(4);
  2203. opo.opo_PolygonEdges.Lock();
  2204. opo.opo_PolygonEdges[0].ope_Edge = &osec.osc_aoedEdges[ START_OF_CEILING_EDGES+0];
  2205. opo.opo_PolygonEdges[0].ope_Backward = TRUE;
  2206. opo.opo_PolygonEdges[1].ope_Edge = &osec.osc_aoedEdges[ START_OF_CEILING_EDGES+1];
  2207. opo.opo_PolygonEdges[1].ope_Backward = TRUE;
  2208. opo.opo_PolygonEdges[2].ope_Edge = &osec.osc_aoedEdges[ START_OF_CEILING_EDGES+2];
  2209. opo.opo_PolygonEdges[2].ope_Backward = TRUE;
  2210. opo.opo_PolygonEdges[3].ope_Edge = &osec.osc_aoedEdges[ START_OF_CEILING_EDGES+3];
  2211. opo.opo_PolygonEdges[3].ope_Backward = TRUE;
  2212. opo.opo_Material = &omat;
  2213. opo.opo_ulFlags = ulNonFllorPolygonFlags;
  2214. opo.opo_colorColor = theApp.m_vfpCurrent.vfp_colPolygonsColor;
  2215. opo.opo_PolygonEdges.Unlock();
  2216. }
  2217. osec.osc_aovxVertices.Unlock();
  2218. osec.osc_aoedEdges.Unlock();
  2219. osec.osc_aoplPlanes.Unlock();
  2220. osec.osc_aopoPolygons.Unlock();
  2221. theApp.m_vfpCurrent.vfp_o3dPrimitive.Optimize();
  2222. }
  2223. void GetTerrainPolygonEdges(CObjectSector &osec, INDEX iPolygon, INDEX iSlicesX, INDEX iSlicesZ,
  2224. CObjectEdge *&poe0, CObjectEdge *&poe1, CObjectEdge *&poe2,
  2225. CObjectEdge *&poe3, CObjectEdge *&poe4)
  2226. {
  2227. INDEX iPolX = iPolygon%iSlicesX;
  2228. INDEX iPolZ = iPolygon/iSlicesX;
  2229. INDEX iEdge0 = iPolZ*iSlicesX+iPolX;
  2230. poe0 = &osec.osc_aoedEdges[ iEdge0];
  2231. INDEX iEdge1 = START_OF_VERTICAL_EDGES+iPolZ*(iSlicesX+1)+iPolX;
  2232. poe1 = &osec.osc_aoedEdges[ iEdge1];
  2233. INDEX iEdge2 = iEdge0+iSlicesX;
  2234. poe2 = &osec.osc_aoedEdges[ iEdge2];
  2235. INDEX iEdge3 = iEdge1+1;
  2236. poe3 = &osec.osc_aoedEdges[ iEdge3];
  2237. INDEX iEdge4 = START_OF_SLOPE_EDGES+iPolZ*iSlicesX+iPolX;
  2238. poe4 = &osec.osc_aoedEdges[ iEdge4];
  2239. }
  2240. void CWorldEditorDoc::CreatePrimitive(void)
  2241. {
  2242. // this is patch because deleting of primitive property page can call this
  2243. if( m_iMode != CSG_MODE) return;
  2244. // activ texture must exist
  2245. ASSERT( theApp.m_ptdActiveTexture != NULL);
  2246. InitializeObject3DForPrimitive();
  2247. switch( theApp.m_vfpCurrent.vfp_ptPrimitiveType)
  2248. {
  2249. case PT_CONUS:
  2250. case PT_TORUS:
  2251. {
  2252. // calculate width, height and lenght
  2253. DOUBLE fWidth = theApp.m_vfpCurrent.vfp_fXMax-theApp.m_vfpCurrent.vfp_fXMin;
  2254. DOUBLE fHeight = theApp.m_vfpCurrent.vfp_fYMax-theApp.m_vfpCurrent.vfp_fYMin;
  2255. DOUBLE fLenght = theApp.m_vfpCurrent.vfp_fZMax-theApp.m_vfpCurrent.vfp_fZMin;
  2256. // some values must be valid, so if they are not, coorect them
  2257. if( fWidth < SNAP_FLOAT_GRID) fWidth = SNAP_FLOAT_GRID;
  2258. if( fHeight < SNAP_FLOAT_GRID) fHeight = SNAP_FLOAT_GRID;
  2259. if( fLenght < SNAP_FLOAT_GRID) fLenght = SNAP_FLOAT_GRID;
  2260. // divide width and lenght by two because these values are used as radiuses
  2261. fWidth /= 2.0f;
  2262. fLenght/= 2.0f;
  2263. // get count of vertices that will be used for creating base polygon
  2264. INDEX vtxCt = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive.Count();
  2265. // if currently used number of vertices is not same as one used for last create primitive,
  2266. // or if change occure in width or lenght
  2267. if( (m_bPrimitiveCreatedFirstTime) ||
  2268. (m_ctLastPrimitiveVertices != vtxCt) ||
  2269. (m_fLastPrimitiveWidth != fWidth) ||
  2270. (m_fLastPrimitiveLenght != fLenght) ||
  2271. (m_bLastIfOuter != theApp.m_vfpCurrent.vfp_bOuter) ||
  2272. (m_ttLastTriangularisationType != theApp.m_vfpCurrent.vfp_ttTriangularisationType) )
  2273. {
  2274. // recreate base vertices (discard vertex dragging)
  2275. if( !_bDontRecalculateBase)
  2276. {
  2277. theApp.m_vfpCurrent.CalculatePrimitiveBase();
  2278. }
  2279. _bDontRecalculateBase = FALSE;
  2280. // and remember new values for base, wait with recreating before any
  2281. // change occure or until CSG operaton is applyed
  2282. m_bPrimitiveCreatedFirstTime = FALSE;
  2283. m_ctLastPrimitiveVertices = vtxCt;
  2284. m_fLastPrimitiveWidth = fWidth;
  2285. m_fLastPrimitiveLenght = fLenght;
  2286. m_bLastIfOuter = theApp.m_vfpCurrent.vfp_bOuter;
  2287. m_ttLastTriangularisationType = theApp.m_vfpCurrent.vfp_ttTriangularisationType;
  2288. }
  2289. // create primitive for the first time
  2290. if( theApp.m_vfpCurrent.vfp_ptPrimitiveType == PT_CONUS)
  2291. {
  2292. CreateConusPrimitive();
  2293. }
  2294. else
  2295. {
  2296. CreateTorusPrimitive();
  2297. }
  2298. break;
  2299. }
  2300. case PT_STAIRCASES:
  2301. {
  2302. CreateStaircasesPrimitive();
  2303. break;
  2304. }
  2305. case PT_SPHERE:
  2306. {
  2307. CreateSpherePrimitive();
  2308. break;
  2309. }
  2310. case PT_TERRAIN:
  2311. {
  2312. CreateTerrainPrimitive();
  2313. break;
  2314. }
  2315. default:
  2316. {
  2317. ASSERTALWAYS( "Invalid primitive type found!");
  2318. }
  2319. }
  2320. // update position property page
  2321. m_chSelections.MarkChanged();
  2322. }
  2323. /*
  2324. * refresh primitive page
  2325. */
  2326. void CWorldEditorDoc::RefreshPrimitivePage(void)
  2327. {
  2328. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  2329. // if info exists and active page is primitive page
  2330. if( (pMainFrame->m_pInfoFrame != NULL) &&
  2331. (pMainFrame->m_pInfoFrame->m_pInfoSheet->GetActivePage() ==
  2332. &pMainFrame->m_pInfoFrame->m_pInfoSheet->m_PgPrimitive) )
  2333. {
  2334. // refresh primitive page
  2335. pMainFrame->m_pInfoFrame->m_pInfoSheet->m_PgPrimitive.UpdateData( FALSE);
  2336. }
  2337. }
  2338. /*
  2339. * refresh position page
  2340. */
  2341. void CWorldEditorDoc::RefreshCurrentInfoPage(void)
  2342. {
  2343. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  2344. // if info exists
  2345. if( pMainFrame->m_pInfoFrame != NULL)
  2346. {
  2347. // if active page is position page
  2348. if( pMainFrame->m_pInfoFrame->m_pInfoSheet->GetActivePage() ==
  2349. &pMainFrame->m_pInfoFrame->m_pInfoSheet->m_PgPosition)
  2350. {
  2351. // refresh position page
  2352. pMainFrame->m_pInfoFrame->m_pInfoSheet->m_PgPosition.UpdateData( FALSE);
  2353. }
  2354. // if active page is texture page
  2355. else if( pMainFrame->m_pInfoFrame->m_pInfoSheet->GetActivePage() ==
  2356. &pMainFrame->m_pInfoFrame->m_pInfoSheet->m_PgTexture)
  2357. {
  2358. // refresh polygon page
  2359. pMainFrame->m_pInfoFrame->m_pInfoSheet->m_PgTexture.UpdateData( FALSE);
  2360. }
  2361. }
  2362. }
  2363. /*
  2364. * snaps parameters for creating primitive to grid
  2365. */
  2366. void CWorldEditorDoc::SnapPrimitiveValuesToGrid(void)
  2367. {
  2368. /*
  2369. SnapFloat( theApp.m_vfpCurrent.vfp_fShearX);
  2370. SnapFloat( theApp.m_vfpCurrent.vfp_fShearZ);
  2371. SnapFloat( theApp.m_vfpCurrent.vfp_fXMin);
  2372. SnapFloat( theApp.m_vfpCurrent.vfp_fXMax);
  2373. SnapFloat( theApp.m_vfpCurrent.vfp_fYMin);
  2374. SnapFloat( theApp.m_vfpCurrent.vfp_fYMax);
  2375. SnapFloat( theApp.m_vfpCurrent.vfp_fZMin);
  2376. SnapFloat( theApp.m_vfpCurrent.vfp_fZMax);
  2377. */
  2378. }
  2379. /*
  2380. * Constructor.
  2381. */
  2382. CUndo::CUndo(void) // throw char *
  2383. {
  2384. static INDEX iUndoFile = 0; // counter for undo files
  2385. static char achUndoFileName[256];
  2386. // create a temporary file name
  2387. sprintf(achUndoFileName, "Temp\\WED_Undo%d.tmp", iUndoFile);
  2388. m_fnmUndoFile = CTString(achUndoFileName);
  2389. // increment the counter of undo files
  2390. iUndoFile++;
  2391. }
  2392. /*
  2393. * Destructor.
  2394. */
  2395. CUndo::~CUndo(void)
  2396. {
  2397. // delete the temporary file
  2398. RemoveFile(m_fnmUndoFile);
  2399. }
  2400. /*
  2401. * Loads state of the world from given undo/redo object
  2402. */
  2403. void CWorldEditorDoc::LoadWorldFromUndoRedoList( CUndo *pUndoRedo)
  2404. {
  2405. // try to
  2406. try
  2407. {
  2408. // load new world from the undo file
  2409. m_woWorld.Load_t(pUndoRedo->m_fnmUndoFile);
  2410. // m_woWorld.ReinitializeEntities();
  2411. // flush stale caches
  2412. _pShell->Execute("FreeUnusedStock();");
  2413. // invalidate document (i.e. all views)
  2414. UpdateAllViews( NULL);
  2415. }
  2416. // report errors
  2417. catch( char *err_str)
  2418. {
  2419. AfxMessageBox( CString(err_str));
  2420. }
  2421. }
  2422. /*
  2423. * Saves current state of the world as tail of give undo/redo list
  2424. */
  2425. void CWorldEditorDoc::SaveWorldIntoUndoRedoList( CListHead &lhList)
  2426. {
  2427. // try to
  2428. try
  2429. {
  2430. // allocate new undo/redo object
  2431. CUndo *pUndoRedo = new CUndo;
  2432. // save the world to the undo file
  2433. m_woWorld.Save_t(pUndoRedo->m_fnmUndoFile);
  2434. // add new undo as tail into undo list
  2435. lhList.AddTail( pUndoRedo->m_lnListNode);
  2436. }
  2437. // report errors
  2438. catch( char *err_str)
  2439. {
  2440. AfxMessageBox( CString(err_str));
  2441. }
  2442. }
  2443. /*
  2444. * Remebers last operation into undo buffer
  2445. */
  2446. void CWorldEditorDoc::RememberUndo(void)
  2447. {
  2448. // if undo remembering is disabled
  2449. if( !theApp.m_bRememberUndo)
  2450. {
  2451. return;
  2452. }
  2453. // delete redo list
  2454. FORDELETELIST(CUndo, m_lnListNode, m_lhRedo, itRedo)
  2455. {
  2456. delete &itRedo.Current();
  2457. }
  2458. // while there are more members in undo buffer than allowed or list isn't empty
  2459. while( (m_lhUndo.Count() >= theApp.m_Preferences.ap_iUndoLevels) &&
  2460. (!m_lhUndo.IsEmpty()) )
  2461. {
  2462. // get first member in undo list
  2463. CUndo *pUndo = LIST_HEAD( m_lhUndo, CUndo, m_lnListNode);
  2464. // remove it
  2465. pUndo->m_lnListNode.Remove();
  2466. // and delete it
  2467. delete pUndo;
  2468. }
  2469. // if undo level is 0, don't remember any undo
  2470. if( theApp.m_Preferences.ap_iUndoLevels == 0)
  2471. {
  2472. return;
  2473. }
  2474. // save current state of level into undo list
  2475. SaveWorldIntoUndoRedoList( m_lhUndo);
  2476. }
  2477. /*
  2478. * Undoes last operation
  2479. */
  2480. void CWorldEditorDoc::Undo(void)
  2481. {
  2482. // if undo level is 0, or undo list is empty, don't do any undo
  2483. if( (theApp.m_Preferences.ap_iUndoLevels == 0) ||
  2484. (m_lhUndo.IsEmpty()) )
  2485. {
  2486. return;
  2487. }
  2488. // clear selections
  2489. ClearSelections();
  2490. // get tail member from undo buffer
  2491. CUndo *pUndo = LIST_TAIL( m_lhUndo, CUndo, m_lnListNode);
  2492. // remove it from undo buffer
  2493. pUndo->m_lnListNode.Remove();
  2494. // save current state of level into redo list
  2495. SaveWorldIntoUndoRedoList( m_lhRedo);
  2496. // restore last saved state from undo list
  2497. LoadWorldFromUndoRedoList( pUndo);
  2498. // delete just used undo member
  2499. delete pUndo;
  2500. }
  2501. /*
  2502. * Redoes last operation
  2503. */
  2504. void CWorldEditorDoc::Redo(void)
  2505. {
  2506. // if redo list is empty, don't do any redo
  2507. if( m_lhRedo.IsEmpty() )
  2508. {
  2509. return;
  2510. }
  2511. // clear selections
  2512. ClearSelections();
  2513. // get tail member from redo buffer
  2514. CUndo *pRedo = LIST_TAIL( m_lhRedo, CUndo, m_lnListNode);
  2515. // remove it from redo buffer
  2516. pRedo->m_lnListNode.Remove();
  2517. // save current state of level into undo list
  2518. SaveWorldIntoUndoRedoList( m_lhUndo);
  2519. // restore last saved state from redo list
  2520. LoadWorldFromUndoRedoList( pRedo);
  2521. // delete just used redo member
  2522. delete pRedo;
  2523. }
  2524. void CWorldEditorDoc::OnEditUndo()
  2525. {
  2526. if( GetEditingMode()==TERRAIN_MODE)
  2527. {
  2528. if( m_iCurrentTerrainUndo>=0)
  2529. {
  2530. ApplyTerrainUndo(&m_dcTerrainUndo[m_iCurrentTerrainUndo]);
  2531. }
  2532. }
  2533. else
  2534. {
  2535. Undo();
  2536. }
  2537. m_chDocument.MarkChanged();
  2538. UpdateAllViews( NULL);
  2539. }
  2540. void CWorldEditorDoc::OnUpdateEditUndo(CCmdUI* pCmdUI)
  2541. {
  2542. if( GetEditingMode()==TERRAIN_MODE)
  2543. {
  2544. pCmdUI->Enable( m_iCurrentTerrainUndo>=0);
  2545. }
  2546. else
  2547. {
  2548. pCmdUI->Enable( !m_lhUndo.IsEmpty());
  2549. }
  2550. }
  2551. void CWorldEditorDoc::OnEditRedo()
  2552. {
  2553. if( GetEditingMode()==TERRAIN_MODE)
  2554. {
  2555. INDEX ctRedos=m_dcTerrainUndo.Count()-1-m_iCurrentTerrainUndo;
  2556. if( ctRedos>0)
  2557. {
  2558. ApplyTerrainRedo(&m_dcTerrainUndo[m_iCurrentTerrainUndo+1]);
  2559. }
  2560. }
  2561. else
  2562. {
  2563. Redo();
  2564. }
  2565. m_chDocument.MarkChanged();
  2566. UpdateAllViews( NULL);
  2567. }
  2568. void CWorldEditorDoc::OnUpdateEditRedo(CCmdUI* pCmdUI)
  2569. {
  2570. if( GetEditingMode()==TERRAIN_MODE)
  2571. {
  2572. INDEX ctRedos=m_dcTerrainUndo.Count()-1-m_iCurrentTerrainUndo;
  2573. pCmdUI->Enable( ctRedos>0);
  2574. }
  2575. else
  2576. {
  2577. pCmdUI->Enable( !m_lhRedo.IsEmpty());
  2578. }
  2579. }
  2580. // paste given texture over polygon selection
  2581. void CWorldEditorDoc::PasteTextureOverSelection_t( CTFileName fnTexName)
  2582. {
  2583. // for each of the selected polygons
  2584. FOREACHINDYNAMICCONTAINER( m_selPolygonSelection, CBrushPolygon, itbpo)
  2585. {
  2586. CTextureData *pTD = (CTextureData *) itbpo->bpo_abptTextures[m_iTexture].bpt_toTexture.GetData();
  2587. if( (pTD == NULL) || (pTD->GetName() != fnTexName) )
  2588. {
  2589. itbpo->bpo_abptTextures[m_iTexture].bpt_toTexture.SetData_t( fnTexName);
  2590. // mark that document has been modified
  2591. SetModifiedFlag( TRUE);
  2592. // mark that selections have been changed
  2593. m_chSelections.MarkChanged();
  2594. }
  2595. }
  2596. // update all views
  2597. UpdateAllViews( NULL);
  2598. }
  2599. FLOAT _fLastTimeDeselectAllUsed = -10000.0f;
  2600. // delete all selected members in current selection mode
  2601. void CWorldEditorDoc::DeselectAll(void)
  2602. {
  2603. // if browse entities mode is on
  2604. if( m_bBrowseEntitiesMode)
  2605. {
  2606. // cancel browse entities mode
  2607. OnBrowseEntitiesMode();
  2608. }
  2609. else
  2610. {
  2611. FLOAT fCurrentTime = _pTimer->GetRealTimeTick();
  2612. if( (fCurrentTime-_fLastTimeDeselectAllUsed)<1.0f)
  2613. {
  2614. ClearSelections();
  2615. _fLastTimeDeselectAllUsed = fCurrentTime;
  2616. return;
  2617. }
  2618. _fLastTimeDeselectAllUsed = fCurrentTime;
  2619. // according to current selection mode clear selected members
  2620. switch( GetEditingMode())
  2621. {
  2622. case POLYGON_MODE:
  2623. {
  2624. m_selPolygonSelection.Clear();
  2625. break;
  2626. };
  2627. case SECTOR_MODE:
  2628. {
  2629. m_selSectorSelection.Clear();
  2630. break;
  2631. };
  2632. case ENTITY_MODE:
  2633. {
  2634. m_selEntitySelection.Clear();
  2635. break;
  2636. };
  2637. case VERTEX_MODE:
  2638. {
  2639. m_selVertexSelection.Clear();
  2640. break;
  2641. };
  2642. case CSG_MODE:
  2643. {
  2644. break;
  2645. };
  2646. case TERRAIN_MODE:
  2647. {
  2648. m_ptrSelectedTerrain=NULL;
  2649. theApp.m_ctTerrainPage.MarkChanged();
  2650. break;
  2651. };
  2652. default:
  2653. {
  2654. FatalError("Unknown editing mode.");
  2655. break;
  2656. };
  2657. }
  2658. }
  2659. // mark that selections have been changed
  2660. m_chSelections.MarkChanged();
  2661. // redraw all viewes
  2662. UpdateAllViews( NULL);
  2663. }
  2664. void CWorldEditorDoc::OnWorldSettings()
  2665. {
  2666. CDlgWorldSettings dlgWorldSettings;
  2667. dlgWorldSettings.SetupBcgSettings( FALSE);
  2668. if( dlgWorldSettings.DoModal() != IDOK) return;
  2669. try
  2670. {
  2671. // !!!! m_woWorld.SetBackgroundTexture_t(CTString(dlgWorldSettings.m_fnBackgroundPicture));
  2672. }
  2673. catch( char *strError)
  2674. {
  2675. AfxMessageBox( CString(strError));
  2676. }
  2677. m_woWorld.SetBackgroundColor( dlgWorldSettings.m_BackgroundColor.GetColor());
  2678. m_woWorld.SetDescription( CTString(CStringA(dlgWorldSettings.m_strMissionDescription)));
  2679. SetModifiedFlag( TRUE);
  2680. UpdateAllViews( NULL);
  2681. }
  2682. /*
  2683. * CSG Add
  2684. */
  2685. void CWorldEditorDoc::OnCsgAdd()
  2686. {
  2687. BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
  2688. if( bShift) PreApplyCSG( CSG_ADD_REVERSE); // reverse priorities
  2689. else PreApplyCSG( CSG_ADD);
  2690. }
  2691. void CWorldEditorDoc::PreApplyCSG(enum CSGType CSGType)
  2692. {
  2693. if( GetEditingMode() != CSG_MODE)
  2694. {
  2695. // search for destination entity
  2696. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  2697. CEntity *penTarget = pMainFrame->m_CSGDesitnationCombo.GetSelectedBrushEntity();
  2698. if( (penTarget == NULL) || (penTarget->IsSelected( ENF_SELECTED)) )
  2699. {
  2700. AfxMessageBox( L"Illegal CSG operands (target must not be selected) !");
  2701. return;
  2702. }
  2703. // create temporary world
  2704. CWorld woDummyWorld;
  2705. // create zero placement
  2706. CPlacement3D plZeroPlacement;
  2707. plZeroPlacement.pl_PositionVector = FLOAT3D(0.0f,0.0f,0.0f);
  2708. plZeroPlacement.pl_OrientationAngle = ANGLE3D(0,0,0);
  2709. CDynamicContainer<CEntity> dcenDummy;
  2710. // for all still selected brush entities
  2711. {FOREACHINDYNAMICCONTAINER(m_selEntitySelection, CEntity, iten)
  2712. {
  2713. CEntity::RenderType rt = iten->GetRenderType();
  2714. // if the entity is brush and it is not empty
  2715. if( rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
  2716. {
  2717. // copy entity into dummy world
  2718. woDummyWorld.CopyOneEntity( *iten, plZeroPlacement);
  2719. }
  2720. // deselect entities that are not brushes
  2721. else
  2722. {
  2723. // deselect clicked sector
  2724. dcenDummy.Add( &iten.Current());
  2725. }
  2726. }}
  2727. // for entities that should be deselected
  2728. {FOREACHINDYNAMICCONTAINER(dcenDummy, CEntity, iten)
  2729. {
  2730. m_selEntitySelection.Deselect( *iten);
  2731. }}
  2732. dcenDummy.Clear();
  2733. // remember undo before doing CSG operations
  2734. RememberUndo();
  2735. // clear all selections except entity
  2736. ClearSelections( ST_ENTITY);
  2737. // delete all brush entities that are still selected
  2738. m_woWorld.DestroyEntities( m_selEntitySelection);
  2739. // set wait cursor
  2740. CWaitCursor StartWaitCursor;
  2741. m_csgtLastUsedCSGOperation = CSG_ADD_ENTITIES;
  2742. m_bPreLastUsedPrimitiveMode = m_bLastUsedPrimitiveMode;
  2743. m_bLastUsedPrimitiveMode = FALSE;
  2744. // for all of the dummy world's entities
  2745. {FOREACHINDYNAMICCONTAINER(woDummyWorld.wo_cenEntities, CEntity, iten)
  2746. {
  2747. // create another dummy world
  2748. CWorld woOneBrush;
  2749. // copy entity from dummy world to world containing only one brush
  2750. CEntity *penOnlyBrush = woOneBrush.CopyOneEntity( *iten, plZeroPlacement);
  2751. // ----------- Do CSG beetween current entity and destination combo's entity
  2752. switch( CSGType)
  2753. {
  2754. case CSG_ADD:
  2755. {
  2756. m_woWorld.CSGAdd(*penTarget, woOneBrush, *penOnlyBrush, plZeroPlacement);
  2757. break;
  2758. }
  2759. case CSG_ADD_REVERSE:
  2760. {
  2761. m_woWorld.CSGAddReverse(*penTarget, woOneBrush, *penOnlyBrush, plZeroPlacement);
  2762. break;
  2763. }
  2764. case CSG_REMOVE:
  2765. {
  2766. m_woWorld.CSGRemove(*penTarget, woOneBrush, *penOnlyBrush, plZeroPlacement);
  2767. break;
  2768. }
  2769. case CSG_SPLIT_SECTORS:
  2770. {
  2771. m_woWorld.SplitSectors(*penTarget, m_selSectorSelection, woOneBrush, *penOnlyBrush, plZeroPlacement);
  2772. break;
  2773. }
  2774. case CSG_SPLIT_POLYGONS:
  2775. {
  2776. m_woWorld.SplitPolygons(*penTarget, m_selPolygonSelection, woOneBrush, *penOnlyBrush, plZeroPlacement);
  2777. break;
  2778. }
  2779. default:
  2780. {
  2781. ASSERTALWAYS("PreAplyCSG() function called with illegal CSG operation.");
  2782. return;
  2783. }
  2784. }
  2785. }}
  2786. // mark that selections have been changed
  2787. SetModifiedFlag(TRUE);
  2788. m_chSelections.MarkChanged();
  2789. m_chDocument.MarkChanged();
  2790. }
  2791. else
  2792. {
  2793. ApplyCSG( CSGType);
  2794. }
  2795. UpdateAllViews( NULL);
  2796. }
  2797. BOOL CWorldEditorDoc::IsEntityCSGEnabled(void)
  2798. {
  2799. if(m_pwoSecondLayer != NULL) return TRUE;
  2800. // if we are in entity mode
  2801. if( GetEditingMode() != CSG_MODE)
  2802. {
  2803. // for all selected entities
  2804. FOREACHINDYNAMICCONTAINER(m_selEntitySelection, CEntity, iten)
  2805. {
  2806. CEntity::RenderType rt = iten->GetRenderType();
  2807. if( rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
  2808. {
  2809. return TRUE;
  2810. }
  2811. }
  2812. }
  2813. return FALSE;
  2814. }
  2815. void CWorldEditorDoc::OnUpdateCsgAdd(CCmdUI* pCmdUI)
  2816. {
  2817. pCmdUI->Enable( IsEntityCSGEnabled());
  2818. }
  2819. /*
  2820. * CSG Remove
  2821. */
  2822. void CWorldEditorDoc::OnCsgRemove()
  2823. {
  2824. PreApplyCSG( CSG_REMOVE);
  2825. }
  2826. void CWorldEditorDoc::OnUpdateCsgRemove(CCmdUI* pCmdUI)
  2827. {
  2828. pCmdUI->Enable( IsEntityCSGEnabled());
  2829. }
  2830. /*
  2831. * CSG Split Sectors.
  2832. */
  2833. void CWorldEditorDoc::OnCsgSplitSectors()
  2834. {
  2835. PreApplyCSG( CSG_SPLIT_SECTORS);
  2836. }
  2837. void CWorldEditorDoc::OnUpdateCsgSplitSectors(CCmdUI* pCmdUI)
  2838. {
  2839. pCmdUI->Enable( IsEntityCSGEnabled());
  2840. }
  2841. /*
  2842. * CSG Join Sectors.
  2843. */
  2844. void CWorldEditorDoc::OnCsgJoinSectors()
  2845. {
  2846. ApplyCSG( CSG_JOIN_SECTORS);
  2847. }
  2848. void CWorldEditorDoc::OnUpdateCsgJoinSectors(CCmdUI* pCmdUI)
  2849. {
  2850. pCmdUI->Enable( m_woWorld.CanJoinSectors( m_selSectorSelection));
  2851. }
  2852. /*
  2853. * CSG Split Polygons.
  2854. */
  2855. void CWorldEditorDoc::OnCsgSplitPolygons()
  2856. {
  2857. PreApplyCSG( CSG_SPLIT_POLYGONS);
  2858. }
  2859. void CWorldEditorDoc::OnUpdateCsgSplitPolygons(CCmdUI* pCmdUI)
  2860. {
  2861. pCmdUI->Enable( IsEntityCSGEnabled() && m_selPolygonSelection.Count() > 0);
  2862. }
  2863. /*
  2864. * CSG Join Polygons.
  2865. */
  2866. void CWorldEditorDoc::OnCsgJoinPolygons()
  2867. {
  2868. BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
  2869. if (bCtrl) {
  2870. ApplyCSG(CSG_JOIN_POLYGONS_KEEP_TEXTURES); // keep textures if control pressed
  2871. } else {
  2872. ApplyCSG(CSG_JOIN_POLYGONS);
  2873. }
  2874. }
  2875. void CWorldEditorDoc::OnUpdateCsgJoinPolygons(CCmdUI* pCmdUI)
  2876. {
  2877. // check for polygon mode and count (crashed here right after merging vertices)
  2878. if( (m_iMode == POLYGON_MODE) && (m_selPolygonSelection.Count() != 0) )
  2879. {
  2880. pCmdUI->Enable( m_woWorld.CanJoinPolygons(m_selPolygonSelection));
  2881. }
  2882. else
  2883. {
  2884. pCmdUI->Enable( FALSE);
  2885. }
  2886. }
  2887. void CWorldEditorDoc::OnCsgJoinAllPolygons()
  2888. {
  2889. BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
  2890. if (bCtrl) {
  2891. ApplyCSG(CSG_JOIN_ALL_POLYGONS_KEEP_TEXTURES); // keep textures if control pressed
  2892. } else {
  2893. ApplyCSG(CSG_JOIN_ALL_POLYGONS);
  2894. }
  2895. }
  2896. void CWorldEditorDoc::OnUpdateCsgJoinAllPolygons(CCmdUI* pCmdUI)
  2897. {
  2898. pCmdUI->Enable( m_woWorld.CanJoinAllPossiblePolygons(m_selPolygonSelection));
  2899. }
  2900. /*
  2901. * Cancel CSG.
  2902. */
  2903. void CWorldEditorDoc::OnCsgCancel()
  2904. {
  2905. if( m_iMode == CSG_MODE)
  2906. {
  2907. CancelCSG();
  2908. }
  2909. else
  2910. {
  2911. SetEditingMode( VERTEX_MODE);
  2912. }
  2913. }
  2914. void CWorldEditorDoc::OnShowOrientation()
  2915. {
  2916. m_bOrientationIcons = !m_bOrientationIcons;
  2917. theApp.WriteProfileInt(L"World editor", L"Orientation icons", m_bOrientationIcons);
  2918. UpdateAllViews( NULL);
  2919. }
  2920. void CWorldEditorDoc::OnUpdateShowOrientation(CCmdUI* pCmdUI)
  2921. {
  2922. pCmdUI->SetCheck( m_bOrientationIcons);
  2923. }
  2924. void CWorldEditorDoc::OnAutoSnap()
  2925. {
  2926. m_bAutoSnap = !m_bAutoSnap;
  2927. }
  2928. void CWorldEditorDoc::OnUpdateAutoSnap(CCmdUI* pCmdUI)
  2929. {
  2930. pCmdUI->SetCheck( m_bAutoSnap);
  2931. }
  2932. void CWorldEditorDoc::OnCalculateShadows()
  2933. {
  2934. RememberUndo(); // this is before wait cursor, so that we can see if it gets blocked here
  2935. // set wait cursor
  2936. CWaitCursor StartWaitCursor;
  2937. // reset profile
  2938. _pfWorldEditingProfile.Reset();
  2939. m_woWorld.CalculateDirectionalShadows();
  2940. if( GetEditingMode()==TERRAIN_MODE)
  2941. {
  2942. CTerrain *ptTerrain=GetTerrain();
  2943. if(ptTerrain!=NULL) ptTerrain->UpdateShadowMap();
  2944. }
  2945. // create shadows report
  2946. _pfWorldEditingProfile.Report( theApp.m_strCSGAndShadowStatistics);
  2947. theApp.m_strCSGAndShadowStatistics.SaveVar(CTString("Temp\\Profile_Shadows.txt"));
  2948. // mark that document has changed
  2949. SetModifiedFlag(TRUE);
  2950. m_chDocument.MarkChanged();
  2951. // invalidate document (i.e. all views)
  2952. UpdateAllViews( NULL);
  2953. }
  2954. void CWorldEditorDoc::OnHideSelected()
  2955. {
  2956. if( m_iMode == ENTITY_MODE)
  2957. {
  2958. OnHideSelectedEntities();
  2959. }
  2960. else
  2961. {
  2962. OnHideSelectedSectors();
  2963. }
  2964. }
  2965. void CWorldEditorDoc::OnHideUnselected()
  2966. {
  2967. if( m_iMode == ENTITY_MODE)
  2968. {
  2969. OnHideUnselectedEntities();
  2970. }
  2971. if( m_iMode == SECTOR_MODE)
  2972. {
  2973. OnHideUnselectedSectors();
  2974. }
  2975. if( m_iMode == TERRAIN_MODE)
  2976. {
  2977. theApp.m_iTerrainBrushMode=TBM_MAXIMUM;
  2978. theApp.m_ctTerrainPageCanvas.MarkChanged();
  2979. SetStatusLineModeInfoMessage();
  2980. }
  2981. }
  2982. void CWorldEditorDoc::OnShowAll()
  2983. {
  2984. if( m_iMode == ENTITY_MODE)
  2985. {
  2986. OnShowAllEntities();
  2987. }
  2988. if( m_iMode == SECTOR_MODE)
  2989. {
  2990. OnShowAllSectors();
  2991. }
  2992. }
  2993. void CWorldEditorDoc::OnUpdateHideSelected(CCmdUI* pCmdUI)
  2994. {
  2995. // enable button if selection is not empty
  2996. if( m_iMode == ENTITY_MODE)
  2997. {
  2998. pCmdUI->Enable( m_selEntitySelection.Count() != 0);
  2999. }
  3000. else
  3001. {
  3002. pCmdUI->Enable( m_selSectorSelection.Count() != 0);
  3003. }
  3004. }
  3005. void CWorldEditorDoc::OnHideSelectedSectors()
  3006. {
  3007. // hide selected sectors
  3008. m_woWorld.HideSelectedSectors( m_selSectorSelection);
  3009. // update all views
  3010. UpdateAllViews( NULL);
  3011. }
  3012. void CWorldEditorDoc::OnHideUnselectedSectors()
  3013. {
  3014. // hide unselected sectors
  3015. m_woWorld.HideUnselectedSectors();
  3016. // update all views
  3017. UpdateAllViews( NULL);
  3018. }
  3019. void CWorldEditorDoc::OnShowAllSectors()
  3020. {
  3021. // hide unselected sectors
  3022. m_woWorld.ShowAllSectors();
  3023. // update all views
  3024. UpdateAllViews( NULL);
  3025. }
  3026. void CWorldEditorDoc::OnHideSelectedEntities()
  3027. {
  3028. // hide selected entities
  3029. m_woWorld.HideSelectedEntities( m_selEntitySelection);
  3030. // update all views
  3031. UpdateAllViews( NULL);
  3032. }
  3033. void CWorldEditorDoc::OnHideUnselectedEntities()
  3034. {
  3035. // hide unselected entities
  3036. m_woWorld.HideUnselectedEntities();
  3037. // update all views
  3038. UpdateAllViews( NULL);
  3039. }
  3040. void CWorldEditorDoc::OnShowAllEntities()
  3041. {
  3042. // hide unselected entities
  3043. m_woWorld.ShowAllEntities();
  3044. // update all views
  3045. UpdateAllViews( NULL);
  3046. }
  3047. // How box is created from 2 vertices: indices of first or second vertice, one that gives
  3048. // current coordinate for one of box's vertices (we have two source points, T0 and T1.
  3049. // Coordinate for box vertice 0 is B0(xT0, yT0, zT0), vertice 1 is B1(xT1, yT0, zT0) ...)
  3050. static INDEX _aiBoxCreation[8][3] = {
  3051. 0,0,0,
  3052. 1,0,0,
  3053. 1,0,1,
  3054. 0,0,1,
  3055. 0,1,0,
  3056. 1,1,0,
  3057. 1,1,1,
  3058. 0,1,1
  3059. };
  3060. // Array of indices to vertices that need to be corrected if one of box's vertices is moved
  3061. // (if vertice 0 moved, copy its x coordinate to vertices 3,7,4, copy y coordinate to
  3062. // vertices 1,2,3, z to 1,5,4...)
  3063. static INDEX _aiCorrectVertices[8][3*3] = {
  3064. 3,7,4, 1,2,3, 1,5,4,
  3065. 2,5,6, 0,2,3, 0,4,5,
  3066. 1,5,6, 0,1,3, 3,6,7,
  3067. 0,4,7, 0,1,2, 2,6,7,
  3068. 0,3,7, 5,6,7, 0,1,5,
  3069. 1,2,6, 4,6,7, 0,1,4,
  3070. 1,2,5, 4,5,7, 2,3,7,
  3071. 0,3,4, 4,5,6, 2,3,6
  3072. };
  3073. // Selects entity with given index inside volume
  3074. void CWorldEditorDoc::SelectGivenEntity( INDEX iEntityToSelect)
  3075. {
  3076. // clear normal entity selection
  3077. m_selEntitySelection.Clear();
  3078. // if there is any entity in volume container
  3079. if( m_cenEntitiesSelectedByVolume.Count() != 0)
  3080. {
  3081. // clip requested entity
  3082. if( iEntityToSelect >= m_cenEntitiesSelectedByVolume.Count())
  3083. {
  3084. iEntityToSelect = 0;
  3085. }
  3086. m_iSelectedEntityInVolume = iEntityToSelect;
  3087. // lock the selection
  3088. m_cenEntitiesSelectedByVolume.Lock();
  3089. // get requested entity
  3090. CEntity *penEntity = m_cenEntitiesSelectedByVolume.Pointer(m_iSelectedEntityInVolume);
  3091. // unlock the selection
  3092. m_cenEntitiesSelectedByVolume.Unlock();
  3093. // add entity into normal selection
  3094. m_selEntitySelection.Select( *penEntity);
  3095. // center entity
  3096. POSITION pos = GetFirstViewPosition();
  3097. CWorldEditorView *pWedView = (CWorldEditorView *) GetNextView(pos);
  3098. pWedView->OnCenterEntity();
  3099. }
  3100. // mark that selections have been changed
  3101. m_chSelections.MarkChanged();
  3102. // obtain main frame ptr
  3103. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  3104. // and refresh property combo manualy calling on idle
  3105. pMainFrame->m_PropertyComboBar.m_PropertyComboBox.OnIdle( 0);
  3106. // update all views
  3107. UpdateAllViews( NULL);
  3108. }
  3109. /*
  3110. * Function puts world's entites occupied by volume box to volume box selection
  3111. */
  3112. void CWorldEditorDoc::SelectEntitiesByVolumeBox(void)
  3113. {
  3114. m_iSelectedEntityInVolume = 0;
  3115. // create volume box (for browsing entities)
  3116. FLOAT3D vMinMax[2];
  3117. vMinMax[0] = m_vCreateBoxVertice0;
  3118. vMinMax[1] = m_vCreateBoxVertice1;
  3119. // create coordinates for box's vertices
  3120. for( INDEX iBoxVertice=0;iBoxVertice<8;iBoxVertice++)
  3121. {
  3122. m_avVolumeBoxVertice[iBoxVertice] = FLOAT3D( vMinMax[_aiBoxCreation[iBoxVertice][0]](1),
  3123. vMinMax[_aiBoxCreation[iBoxVertice][1]](2),
  3124. vMinMax[_aiBoxCreation[iBoxVertice][2]](3) );
  3125. }
  3126. // create bbox from requested volume
  3127. FLOATaabbox3D bboxVolume( m_vCreateBoxVertice0, m_vCreateBoxVertice1);
  3128. // clear entity volume container
  3129. m_cenEntitiesSelectedByVolume.Clear();
  3130. // clear normal entity selection
  3131. m_selEntitySelection.Clear();
  3132. // for all of the world's entities
  3133. FOREACHINDYNAMICCONTAINER(m_woWorld.wo_cenEntities, CEntity, iten)
  3134. {
  3135. CPlacement3D plEntityPlacement = iten->GetPlacement();
  3136. // if entity handle is inside volume box
  3137. if( bboxVolume.HasContactWith( FLOATaabbox3D(plEntityPlacement.pl_PositionVector)) )
  3138. {
  3139. // add entity into volume container
  3140. m_cenEntitiesSelectedByVolume.Add( iten);
  3141. }
  3142. }
  3143. SetStatusLineModeInfoMessage();
  3144. }
  3145. /*
  3146. * Function corects coordinates of vertices that represent box because given vertice is
  3147. * moved and box has invalid geometry
  3148. */
  3149. void CWorldEditorDoc::CorrectBox(INDEX iMovedVtx, FLOAT3D vNewPosition)
  3150. {
  3151. for( INDEX iCoordinate=0;iCoordinate<3; iCoordinate++)
  3152. {
  3153. for( INDEX iVtxToCorrect=0;iVtxToCorrect<3; iVtxToCorrect++)
  3154. {
  3155. // copy coordinate
  3156. m_avVolumeBoxVertice[ _aiCorrectVertices[iMovedVtx][iCoordinate*3+iVtxToCorrect]]
  3157. (iCoordinate+1) = vNewPosition(iCoordinate+1);
  3158. }
  3159. }
  3160. // copy new moved vertice's position
  3161. m_avVolumeBoxVertice[ iMovedVtx] = vNewPosition;
  3162. // set new values for next creation of volume box
  3163. m_vCreateBoxVertice0 = m_avVolumeBoxVertice[ 0];
  3164. m_vCreateBoxVertice1 = m_avVolumeBoxVertice[ 6];
  3165. }
  3166. void CWorldEditorDoc::OnBrowseEntitiesMode()
  3167. {
  3168. m_bBrowseEntitiesMode = !m_bBrowseEntitiesMode;
  3169. // if we should start select by volume (or browse entities) mode
  3170. if( m_bBrowseEntitiesMode)
  3171. {
  3172. SelectEntitiesByVolumeBox();
  3173. }
  3174. // stop select by volume mode
  3175. else
  3176. {
  3177. // write to ini last vertices used for volume box creation
  3178. char strIni[ 128];
  3179. sprintf( strIni, "%f %f %f",
  3180. m_vCreateBoxVertice0(1), m_vCreateBoxVertice0(2), m_vCreateBoxVertice0(3));
  3181. theApp.WriteProfileString( L"World editor", L"Volume box min", CString(strIni));
  3182. sprintf( strIni, "%f %f %f",
  3183. m_vCreateBoxVertice1(1), m_vCreateBoxVertice1(2), m_vCreateBoxVertice1(3));
  3184. theApp.WriteProfileString( L"World editor", L"Volume box max", CString(strIni));
  3185. m_chSelections.MarkChanged();
  3186. }
  3187. // update all views
  3188. UpdateAllViews( NULL);
  3189. }
  3190. void CWorldEditorDoc::OnUpdateBrowseEntitiesMode(CCmdUI* pCmdUI)
  3191. {
  3192. pCmdUI->SetCheck( m_bBrowseEntitiesMode);
  3193. pCmdUI->Enable( GetEditingMode() == ENTITY_MODE);
  3194. }
  3195. void CWorldEditorDoc::OnPreviousSelectedEntity()
  3196. {
  3197. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  3198. INDEX iEntityToSelect = (m_iSelectedEntityInVolume+
  3199. m_cenEntitiesSelectedByVolume.Count()-1)%m_cenEntitiesSelectedByVolume.Count();
  3200. // clip entity index
  3201. if( iEntityToSelect >= m_cenEntitiesSelectedByVolume.Count())
  3202. {
  3203. iEntityToSelect = 0;
  3204. }
  3205. CTString strMessage;
  3206. strMessage.PrintF("Entity %d/%d", iEntityToSelect, m_cenEntitiesSelectedByVolume.Count());
  3207. pMainFrame->SetStatusBarMessage( strMessage, STATUS_LINE_PANE, 2);
  3208. SelectGivenEntity( iEntityToSelect);
  3209. }
  3210. void CWorldEditorDoc::OnNextSelectedEntity()
  3211. {
  3212. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  3213. INDEX iEntityToSelect = (m_iSelectedEntityInVolume+1)%m_cenEntitiesSelectedByVolume.Count();
  3214. // clip entity index
  3215. if( iEntityToSelect >= m_cenEntitiesSelectedByVolume.Count() )
  3216. {
  3217. iEntityToSelect = 0;
  3218. }
  3219. CTString strMessage;
  3220. strMessage.PrintF("Entity %d/%d", iEntityToSelect, m_cenEntitiesSelectedByVolume.Count());
  3221. pMainFrame->SetStatusBarMessage( strMessage, STATUS_LINE_PANE, 2);
  3222. SelectGivenEntity( iEntityToSelect);
  3223. }
  3224. void CWorldEditorDoc::OnUpdatePreviousSelectedEntity(CCmdUI* pCmdUI)
  3225. {
  3226. pCmdUI->Enable( m_cenEntitiesSelectedByVolume.Count()>0);
  3227. }
  3228. void CWorldEditorDoc::OnUpdateNextSelectedEntity(CCmdUI* pCmdUI)
  3229. {
  3230. pCmdUI->Enable( m_cenEntitiesSelectedByVolume.Count()>0);
  3231. }
  3232. void CWorldEditorDoc::OnSelectAllInVolume( void)
  3233. {
  3234. // for each of the entities selected by volume
  3235. FOREACHINDYNAMICCONTAINER( m_cenEntitiesSelectedByVolume, CEntity, iten)
  3236. {
  3237. if( !iten->IsSelected( ENF_SELECTED))
  3238. {
  3239. // add entity into normal selection
  3240. m_selEntitySelection.Select( *iten);
  3241. }
  3242. }
  3243. // clear volume container
  3244. //m_cenEntitiesSelectedByVolume.Clear();
  3245. // go out of browse by volume mode
  3246. if( m_bBrowseEntitiesMode) OnBrowseEntitiesMode();
  3247. // mark that selections have been changed
  3248. m_chSelections.MarkChanged();
  3249. // obtain main frame ptr
  3250. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  3251. // and refresh property combo manualy calling on idle
  3252. pMainFrame->m_PropertyComboBar.m_PropertyComboBox.OnIdle( 0);
  3253. // update all views
  3254. UpdateAllViews( NULL);
  3255. }
  3256. void CWorldEditorDoc::OnJoinLayers()
  3257. {
  3258. ApplyCSG( CSG_JOIN_LAYERS);
  3259. }
  3260. void CWorldEditorDoc::OnUpdateSelectByClass(CCmdUI* pCmdUI)
  3261. {
  3262. pCmdUI->Enable( TRUE);
  3263. }
  3264. void CWorldEditorDoc::OnSelectByClass()
  3265. {
  3266. CWorldEditorView *pWorldEditorView = theApp.GetActiveView();
  3267. CDlgBrowseByClass dlgBrowseByClass;
  3268. INDEX ctEntities = m_cenEntitiesSelectedByVolume.Count();
  3269. // auto start in all entities mode if no entities are selected
  3270. dlgBrowseByClass.m_bShowVolume = (ctEntities != 0);
  3271. if( dlgBrowseByClass.DoModal() == IDOK)
  3272. {
  3273. m_chSelections.MarkChanged();
  3274. SetEditingMode( ENTITY_MODE);
  3275. UpdateAllViews( NULL);
  3276. if( (pWorldEditorView != NULL) &&
  3277. (dlgBrowseByClass.m_bCenterSelected) )
  3278. {
  3279. pWorldEditorView->CenterSelected();
  3280. }
  3281. }
  3282. }
  3283. void CWorldEditorDoc::OnSelectByClassImportant()
  3284. {
  3285. CWorldEditorView *pWorldEditorView = theApp.GetActiveView();
  3286. CDlgBrowseByClass dlgBrowseByClass;
  3287. dlgBrowseByClass.m_bShowImportants = TRUE;
  3288. if( dlgBrowseByClass.DoModal() == IDOK)
  3289. {
  3290. m_chSelections.MarkChanged();
  3291. SetEditingMode( ENTITY_MODE);
  3292. UpdateAllViews( NULL);
  3293. if( (pWorldEditorView != NULL) &&
  3294. (dlgBrowseByClass.m_bCenterSelected) )
  3295. {
  3296. pWorldEditorView->CenterSelected();
  3297. }
  3298. }
  3299. }
  3300. void CWorldEditorDoc::OnCrossroadForN()
  3301. {
  3302. if( m_iMode == VERTEX_MODE)
  3303. {
  3304. CDlgSnapVertex dlg;
  3305. dlg.DoModal();
  3306. }
  3307. else
  3308. {
  3309. OnSelectByClassAll();
  3310. }
  3311. }
  3312. void CWorldEditorDoc::OnSelectByClassAll()
  3313. {
  3314. CWorldEditorView *pWorldEditorView = theApp.GetActiveView();
  3315. CDlgBrowseByClass dlgBrowseByClass;
  3316. dlgBrowseByClass.m_bShowVolume = FALSE;
  3317. if( dlgBrowseByClass.DoModal() == IDOK)
  3318. {
  3319. m_chSelections.MarkChanged();
  3320. SetEditingMode( ENTITY_MODE);
  3321. UpdateAllViews( NULL);
  3322. if( (pWorldEditorView != NULL) &&
  3323. (dlgBrowseByClass.m_bCenterSelected) )
  3324. {
  3325. pWorldEditorView->CenterSelected();
  3326. }
  3327. }
  3328. }
  3329. void CWorldEditorDoc::OnTexture1()
  3330. {
  3331. theApp.m_bTexture1 = !theApp.m_bTexture1;
  3332. UpdateAllViews( NULL);
  3333. }
  3334. void CWorldEditorDoc::OnUpdateTexture1(CCmdUI* pCmdUI)
  3335. {
  3336. pCmdUI->SetCheck( theApp.m_bTexture1);
  3337. }
  3338. void CWorldEditorDoc::OnTexture2()
  3339. {
  3340. theApp.m_bTexture2 = !theApp.m_bTexture2;
  3341. UpdateAllViews( NULL);
  3342. }
  3343. void CWorldEditorDoc::OnUpdateTexture2(CCmdUI* pCmdUI)
  3344. {
  3345. pCmdUI->SetCheck( theApp.m_bTexture2);
  3346. }
  3347. void CWorldEditorDoc::OnTexture3()
  3348. {
  3349. theApp.m_bTexture3 = !theApp.m_bTexture3;
  3350. UpdateAllViews( NULL);
  3351. }
  3352. void CWorldEditorDoc::OnUpdateTexture3(CCmdUI* pCmdUI)
  3353. {
  3354. pCmdUI->SetCheck( theApp.m_bTexture3);
  3355. }
  3356. void CWorldEditorDoc::SetActiveTextureLayer(INDEX iLayer)
  3357. {
  3358. if( GetEditingMode()==TERRAIN_MODE)
  3359. {
  3360. CTerrain *ptTerrain=GetTerrain();
  3361. if(ptTerrain==NULL) return;
  3362. if(iLayer>=ptTerrain->tr_atlLayers.Count()) return;
  3363. SelectLayer(iLayer);
  3364. m_chSelections.MarkChanged();
  3365. theApp.m_ctTerrainPageCanvas.MarkChanged();
  3366. }
  3367. else if(iLayer<3)
  3368. {
  3369. m_iTexture = iLayer;
  3370. m_chSelections.MarkChanged();
  3371. UpdateAllViews( NULL);
  3372. }
  3373. }
  3374. void CWorldEditorDoc::OnTextureMode1()
  3375. {
  3376. SetActiveTextureLayer(0);
  3377. }
  3378. void CWorldEditorDoc::OnTextureMode2()
  3379. {
  3380. SetActiveTextureLayer(1);
  3381. }
  3382. void CWorldEditorDoc::OnTextureMode3()
  3383. {
  3384. SetActiveTextureLayer(2);
  3385. }
  3386. void CWorldEditorDoc::OnTextureMode4()
  3387. {
  3388. SetActiveTextureLayer(3);
  3389. }
  3390. void CWorldEditorDoc::OnTextureMode5()
  3391. {
  3392. SetActiveTextureLayer(4);
  3393. }
  3394. void CWorldEditorDoc::OnTextureMode6()
  3395. {
  3396. SetActiveTextureLayer(5);
  3397. }
  3398. void CWorldEditorDoc::OnTextureMode7()
  3399. {
  3400. SetActiveTextureLayer(6);
  3401. }
  3402. void CWorldEditorDoc::OnTextureMode8()
  3403. {
  3404. SetActiveTextureLayer(7);
  3405. }
  3406. void CWorldEditorDoc::OnTextureMode9()
  3407. {
  3408. SetActiveTextureLayer(8);
  3409. }
  3410. void CWorldEditorDoc::OnTextureMode10()
  3411. {
  3412. SetActiveTextureLayer(9);
  3413. }
  3414. void CWorldEditorDoc::OnSaveThumbnail( void)
  3415. {
  3416. // remember current position for thumbnail saving into world
  3417. CWorldEditorView *pViewForThumbnail = theApp.GetActiveView();
  3418. if( pViewForThumbnail == NULL) return;
  3419. CChildFrame *pChild = pViewForThumbnail->GetChildFrame();
  3420. // set new viewer settings
  3421. m_woWorld.wo_plThumbnailFocus = pChild->m_mvViewer.mv_plViewer;
  3422. m_woWorld.wo_fThumbnailTargetDistance = pChild->m_mvViewer.mv_fTargetDistance;
  3423. // save thumbnail
  3424. SaveThumbnail();
  3425. }
  3426. void CWorldEditorDoc::SaveThumbnail()
  3427. {
  3428. CDrawPort *pDrawPort;
  3429. CImageInfo II;
  3430. CTextureData TD;
  3431. CAnimData AD;
  3432. ULONG flags = NONE;
  3433. // if document isn't saved, call save as
  3434. if( GetPathName() == "")
  3435. {
  3436. // if failed
  3437. if( !DoFileSave()) return;
  3438. }
  3439. // try to find perspective view
  3440. POSITION pos = GetFirstViewPosition();
  3441. CWorldEditorView *pViewForThumbnail = theApp.GetActiveView();
  3442. CWorldEditorView *pWedView;
  3443. FOREVER
  3444. {
  3445. pWedView = (CWorldEditorView *) GetNextView(pos);
  3446. if( pWedView == NULL) return;
  3447. if( pWedView->m_ptProjectionType == CSlaveViewer::PT_PERSPECTIVE)
  3448. {
  3449. pViewForThumbnail = pWedView;
  3450. break;
  3451. }
  3452. }
  3453. // if perspective view can't be found, don't do anything
  3454. if( pViewForThumbnail == NULL) return;
  3455. CChildFrame *pChild = pViewForThumbnail->GetChildFrame();
  3456. // create canvas to render picture
  3457. _pGfx->CreateWorkCanvas( 128, 128, &pDrawPort);
  3458. if( pDrawPort != NULL)
  3459. {
  3460. if( pDrawPort->Lock())
  3461. {
  3462. // remember old viewer settings
  3463. CPlacement3D plOrgPlacement = pChild->m_mvViewer.mv_plViewer;
  3464. FLOAT fOldTargetDistance = pChild->m_mvViewer.mv_fTargetDistance;
  3465. // set new viewer settings
  3466. pChild->m_mvViewer.mv_plViewer = m_woWorld.wo_plThumbnailFocus;
  3467. pChild->m_mvViewer.mv_fTargetDistance = m_woWorld.wo_fThumbnailTargetDistance;
  3468. // render vew from thumbnail position
  3469. pViewForThumbnail->RenderView( pDrawPort);
  3470. // restore orgiginal position
  3471. pChild->m_mvViewer.mv_plViewer = plOrgPlacement;
  3472. pChild->m_mvViewer.mv_fTargetDistance = fOldTargetDistance;
  3473. pDrawPort->Unlock();
  3474. }
  3475. CTFileName fnDocument = CTString( CStringA(GetPathName()));
  3476. CTFileName fnThumbnail = fnDocument.FileDir() + fnDocument.FileName() + CTString(".tbn");
  3477. pDrawPort->GrabScreen(II);
  3478. // try to
  3479. try {
  3480. // remove application path
  3481. fnThumbnail.RemoveApplicationPath_t();
  3482. // create image info from texture
  3483. TD.Create_t( &II, 128, MAX_MEX_LOG2, FALSE);
  3484. // save the thumbnail
  3485. CTFileStream File;
  3486. File.Create_t( fnThumbnail);
  3487. TD.Write_t( &File);
  3488. File.Close();
  3489. }
  3490. // if failed
  3491. catch (char *strError) {
  3492. // report error
  3493. AfxMessageBox(CString(strError));
  3494. }
  3495. _pGfx->DestroyWorkCanvas( pDrawPort);
  3496. pDrawPort = NULL;
  3497. }
  3498. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  3499. // refresh browser (open and close current virtual directory)
  3500. pMainFrame->m_Browser.CloseSelectedDirectory();
  3501. pMainFrame->m_Browser.OpenSelectedDirectory();
  3502. }
  3503. void CWorldEditorDoc::ResetPrimitive()
  3504. {
  3505. if( !m_bPrimitiveMode) return;
  3506. FLOAT fDX = (theApp.m_vfpCurrent.vfp_fXMax+theApp.m_vfpCurrent.vfp_fXMin)/2.0f;
  3507. FLOAT fDY = theApp.m_vfpCurrent.vfp_fYMin;
  3508. FLOAT fDZ = (theApp.m_vfpCurrent.vfp_fZMax+theApp.m_vfpCurrent.vfp_fZMin)/2.0f;
  3509. FLOAT fWidth = theApp.m_vfpCurrent.vfp_fXMax-theApp.m_vfpCurrent.vfp_fXMin;
  3510. FLOAT fHeight = theApp.m_vfpCurrent.vfp_fYMax-theApp.m_vfpCurrent.vfp_fYMin;
  3511. FLOAT fLenght = (theApp.m_vfpCurrent.vfp_fZMax-theApp.m_vfpCurrent.vfp_fZMin);
  3512. FLOAT3D vDelta = FLOAT3D( fDX, fDY, fDZ);
  3513. m_plSecondLayer.pl_PositionVector += vDelta;
  3514. theApp.m_vfpCurrent.vfp_plPrimitive = m_plSecondLayer;
  3515. theApp.m_vfpCurrent.vfp_fXMin = -fWidth/2.0f;
  3516. theApp.m_vfpCurrent.vfp_fXMax = fWidth/2.0f;
  3517. theApp.m_vfpCurrent.vfp_fYMin = 0.0f;
  3518. theApp.m_vfpCurrent.vfp_fYMax = fHeight;
  3519. theApp.m_vfpCurrent.vfp_fZMin = -fLenght/2.0f;
  3520. theApp.m_vfpCurrent.vfp_fZMax = fLenght/2.0f;
  3521. RefreshPrimitivePage();
  3522. m_bPrimitiveCreatedFirstTime = TRUE;
  3523. _bDontRecalculateBase = FALSE;
  3524. CreatePrimitive();
  3525. UpdateAllViews( NULL);
  3526. }
  3527. void CWorldEditorDoc::DeletePrimitiveVertex(INDEX iVtxToDelete)
  3528. {
  3529. // get count of vertices on the base
  3530. INDEX vtxCt = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive.Count();
  3531. if( vtxCt < 4) return;
  3532. CStaticArray<DOUBLE3D> avDecreased;
  3533. avDecreased.New(vtxCt-1);
  3534. INDEX iVtxNew = 0;
  3535. for( INDEX iVtxOld = 0; iVtxOld<vtxCt; iVtxOld++)
  3536. {
  3537. if( iVtxOld != iVtxToDelete)
  3538. {
  3539. avDecreased[iVtxNew] = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[iVtxOld];
  3540. iVtxNew++;
  3541. }
  3542. }
  3543. // copy new array back to primitive
  3544. theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive.Clear();
  3545. theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive.New(vtxCt-1);
  3546. for( INDEX iVtx=0; iVtx<vtxCt-1; iVtx++)
  3547. {
  3548. theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[iVtx] = avDecreased[iVtx];
  3549. }
  3550. m_ctLastPrimitiveVertices = vtxCt-1;
  3551. RefreshPrimitivePage();
  3552. CreatePrimitive();
  3553. UpdateAllViews( NULL);
  3554. }
  3555. void CWorldEditorDoc::InsertPrimitiveVertex(INDEX iEdge, FLOAT3D vVertexToInsert)
  3556. {
  3557. // get count of vertices on the base
  3558. INDEX vtxCt = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive.Count();
  3559. CStaticArray<DOUBLE3D> avIncreased;
  3560. avIncreased.New(vtxCt+1);
  3561. INDEX iVtxNew = 0;
  3562. for( INDEX iVtxOld = 0; iVtxOld<vtxCt; iVtxOld++)
  3563. {
  3564. avIncreased[iVtxNew] = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[iVtxOld];
  3565. iVtxNew++;
  3566. if( iVtxOld == iEdge)
  3567. {
  3568. avIncreased[iVtxNew] = FLOATtoDOUBLE(vVertexToInsert);
  3569. avIncreased[iVtxNew](2) = 0.0f;
  3570. iVtxNew++;
  3571. }
  3572. }
  3573. // copy new array back to primitive
  3574. theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive.Clear();
  3575. theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive.New(vtxCt+1);
  3576. for( INDEX iVtx=0; iVtx<vtxCt+1; iVtx++)
  3577. {
  3578. theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[iVtx] = avIncreased[iVtx];
  3579. }
  3580. m_ctLastPrimitiveVertices = vtxCt+1;
  3581. RefreshPrimitivePage();
  3582. CreatePrimitive();
  3583. UpdateAllViews( NULL);
  3584. }
  3585. void CWorldEditorDoc::OnUpdateLinks()
  3586. {
  3587. CWaitCursor wc;
  3588. m_woWorld.RebuildLinks();
  3589. }
  3590. void CWorldEditorDoc::OnSnapshot()
  3591. {
  3592. RememberUndo();
  3593. }
  3594. void CWorldEditorDoc::OnMirrorAndStretch()
  3595. {
  3596. if (!m_bPrimitiveMode) {
  3597. CDlgMirrorAndStretch dlg;
  3598. // set dialog name
  3599. if (m_pwoSecondLayer != NULL) {
  3600. dlg.m_strName = "Mirror and stretch second layer";
  3601. } else {
  3602. dlg.m_strName = "Mirror and stretch entire world";
  3603. }
  3604. if( dlg.DoModal() == IDOK)
  3605. {
  3606. ApplyMirrorAndStretch( dlg.m_iMirror, dlg.m_fStretch);
  3607. }
  3608. } else {
  3609. ASSERT(FALSE);
  3610. }
  3611. }
  3612. void CWorldEditorDoc::OnFlipLayer()
  3613. {
  3614. if (!m_bPrimitiveMode) {
  3615. ApplyMirrorAndStretch( m_iMirror, 1.0f);
  3616. m_iMirror = (m_iMirror+1)%4;
  3617. ApplyMirrorAndStretch( m_iMirror, 1.0f);
  3618. }
  3619. }
  3620. void CWorldEditorDoc::OnUpdateFlipLayer(CCmdUI* pCmdUI)
  3621. {
  3622. // enable only for second layer
  3623. pCmdUI->Enable( m_pwoSecondLayer != NULL && !m_bPrimitiveMode);
  3624. }
  3625. void CWorldEditorDoc::ApplyMirrorAndStretch(INDEX iMirror, FLOAT fStretch)
  3626. {
  3627. try
  3628. {
  3629. CWorld woDummy;
  3630. if( m_pwoSecondLayer != NULL)
  3631. {
  3632. woDummy.MirrorAndStretch( *m_pwoSecondLayer, fStretch,
  3633. (enum WorldMirrorType)iMirror);
  3634. woDummy.Save_t(CTString("Temp\\MirrorAndStretch.wld"));
  3635. m_pwoSecondLayer->Clear();
  3636. m_pwoSecondLayer->Load_t(CTString("Temp\\MirrorAndStretch.wld"));
  3637. }
  3638. else
  3639. {
  3640. int iRes = AfxMessageBox(L"Are you sure you want to mirror/stretch entire world?", MB_ICONEXCLAMATION|MB_YESNO|MB_DEFBUTTON2);
  3641. if (iRes!=IDYES) {
  3642. return;
  3643. }
  3644. CWaitCursor wcWait;
  3645. RememberUndo();
  3646. ClearSelections();
  3647. woDummy.MirrorAndStretch( m_woWorld, fStretch,
  3648. (enum WorldMirrorType)iMirror);
  3649. woDummy.Save_t(CTString("Temp\\MirrorAndStretch.wld"));
  3650. m_woWorld.Clear();
  3651. m_woWorld.Load_t(CTString("Temp\\MirrorAndStretch.wld"));
  3652. m_woWorld.CalculateNonDirectionalShadows();
  3653. m_chDocument.MarkChanged();
  3654. SetModifiedFlag();
  3655. }
  3656. }
  3657. catch (char *strError)
  3658. {
  3659. AfxMessageBox(CString(strError));
  3660. }
  3661. UpdateAllViews( NULL);
  3662. }
  3663. void CWorldEditorDoc::OnFilterSelection()
  3664. {
  3665. CDlgFilterPolygonSelection dlgFilterPolygonSelection;
  3666. dlgFilterPolygonSelection.DoModal();
  3667. }
  3668. BOOL CWorldEditorDoc::IsCloneUpdatingAllowed(void)
  3669. {
  3670. INDEX ctEntities = m_selEntitySelection.Count();
  3671. // if only one entity is selected
  3672. if( ctEntities == 1)
  3673. {
  3674. // get only selected entity
  3675. m_selEntitySelection.Lock();
  3676. CEntity *penOnlySelected = &m_selEntitySelection[0];
  3677. m_selEntitySelection.Unlock();
  3678. // if entity doesn't have parent
  3679. if( penOnlySelected->GetParent() == NULL)
  3680. {
  3681. // allow clone updating
  3682. return TRUE;
  3683. }
  3684. }
  3685. // disable clone updating
  3686. return FALSE;
  3687. }
  3688. void CWorldEditorDoc::OnUpdateUpdateClones(CCmdUI* pCmdUI)
  3689. {
  3690. pCmdUI->Enable( IsCloneUpdatingAllowed() );
  3691. }
  3692. // delete selected entity with all descendents
  3693. void DeleteEntityWithDescendents( CWorld &woWorld, CEntity *penParent)
  3694. {
  3695. FORDELETELIST( CEntity, en_lnInParent, penParent->en_lhChildren, itenChild)
  3696. {
  3697. DeleteEntityWithDescendents( woWorld, &*itenChild);
  3698. }
  3699. woWorld.DestroyOneEntity( penParent);
  3700. }
  3701. void CWorldEditorDoc::OnUpdateClones()
  3702. {
  3703. // for each case
  3704. if( m_selEntitySelection.Count() == 0)
  3705. {
  3706. return;
  3707. }
  3708. // get only selected entity
  3709. m_selEntitySelection.Lock();
  3710. CEntity *penOnlySelected = &m_selEntitySelection[0];
  3711. m_selEntitySelection.Unlock();
  3712. // clear selections before destroying some entities
  3713. ClearSelections();
  3714. // remember placements and delete all clones (entities with same name)
  3715. CTString strName = penOnlySelected->GetName();
  3716. if( strName == "World Base")
  3717. {
  3718. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  3719. if( ::MessageBoxA( pMainFrame->m_hWnd, "Are you sure that you want to execute update clones\n"
  3720. "on entity named: \"World Base\"?", "Warning !", MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON1|
  3721. MB_SYSTEMMODAL | MB_TOPMOST) != IDYES)
  3722. {
  3723. return;
  3724. }
  3725. }
  3726. RememberUndo();
  3727. CDynamicContainer<CEntity> apenClones;
  3728. {FOREACHINDYNAMICCONTAINER( m_woWorld.wo_cenEntities, CEntity, iten)
  3729. {
  3730. // if this is clone (by name), it is not original and it is not child of some other entity
  3731. if( (strName == iten->GetName()) && ( &*iten != penOnlySelected) && (iten->GetParent() == NULL) )
  3732. {
  3733. apenClones.Add( &*iten);
  3734. }
  3735. }}
  3736. apenClones.Lock();
  3737. // remember placements of clones
  3738. CStaticArray<CPlacement3D> aplClones;
  3739. INDEX ctEntities = apenClones.Count();
  3740. aplClones.New( ctEntities);
  3741. {for( INDEX iEntity=0; iEntity<ctEntities; iEntity++)
  3742. {
  3743. aplClones[ iEntity] = apenClones[ iEntity].GetPlacement();
  3744. }}
  3745. // delete clones with their descendents
  3746. {for( INDEX iEntity=0; iEntity<ctEntities; iEntity++)
  3747. {
  3748. DeleteEntityWithDescendents( m_woWorld, &apenClones[ iEntity]);
  3749. }}
  3750. // clone entity(ies) for each remembered placement
  3751. {for( INDEX iEntity=0; iEntity<ctEntities; iEntity++)
  3752. {
  3753. m_woWorld.CopyEntityInWorld( *penOnlySelected, aplClones[ iEntity]);
  3754. }}
  3755. apenClones.Unlock();
  3756. m_chSelections.MarkChanged();
  3757. m_chDocument.MarkChanged();
  3758. SetModifiedFlag();
  3759. UpdateAllViews( NULL);
  3760. }
  3761. void CWorldEditorDoc::SetCutMode( CWorldEditorView *pwedView)
  3762. {
  3763. POSITION pos = GetFirstViewPosition();
  3764. CWorldEditorView *pwedTemp;
  3765. FOREVER
  3766. {
  3767. pwedTemp = (CWorldEditorView *) GetNextView(pos);
  3768. if( pwedTemp == NULL) return;
  3769. if( pwedTemp == pwedView)
  3770. {
  3771. pwedTemp->m_bCutMode = TRUE;
  3772. }
  3773. }
  3774. }
  3775. void CreateCuttingWorld( FLOATplane3D &plPolygon, FLOATaabbox3D &box, CObject3D &o3d)
  3776. {
  3777. // ------------------- Create polygon that will be used for cutting
  3778. FLOAT3D v0, v1, v2, v3;
  3779. v0=v1=v2=v3= FLOAT3D( 0.0f, 0.0f, 0.0f);
  3780. // find major axes of the polygon plane
  3781. INDEX iMajorAxis1, iMajorAxis2;
  3782. GetMajorAxesForPlane( plPolygon, iMajorAxis1, iMajorAxis2);
  3783. FLOAT3D vCenter = box.Center();
  3784. FLOAT fSize = box.Size().Length();
  3785. v0(iMajorAxis1) = vCenter(iMajorAxis1)-fSize; v0(iMajorAxis2) = vCenter(iMajorAxis2)+fSize;
  3786. v1(iMajorAxis1) = vCenter(iMajorAxis1)+fSize; v1(iMajorAxis2) = vCenter(iMajorAxis2)+fSize;
  3787. v2(iMajorAxis1) = vCenter(iMajorAxis1)+fSize; v2(iMajorAxis2) = vCenter(iMajorAxis2)-fSize;
  3788. v3(iMajorAxis1) = vCenter(iMajorAxis1)-fSize; v3(iMajorAxis2) = vCenter(iMajorAxis2)-fSize;
  3789. // project coordinates back to plane
  3790. FLOAT3D vp0, vp1, vp2, vp3;
  3791. vp0 = plPolygon.ProjectPoint( v0);
  3792. vp1 = plPolygon.ProjectPoint( v1);
  3793. vp2 = plPolygon.ProjectPoint( v2);
  3794. vp3 = plPolygon.ProjectPoint( v3);
  3795. // add vertices
  3796. CObjectSector *pos = o3d.ob_aoscSectors.New(1);
  3797. pos->osc_aovxVertices.New(4);
  3798. pos->osc_aovxVertices.Lock();
  3799. pos->osc_aovxVertices[0] = FLOATtoDOUBLE(vp0);
  3800. pos->osc_aovxVertices[1] = FLOATtoDOUBLE(vp1);
  3801. pos->osc_aovxVertices[2] = FLOATtoDOUBLE(vp2);
  3802. pos->osc_aovxVertices[3] = FLOATtoDOUBLE(vp3);
  3803. // add edges
  3804. pos->osc_aoedEdges.New(4);
  3805. pos->osc_aoedEdges.Lock();
  3806. pos->osc_aoedEdges[0].oed_Vertex0 = &pos->osc_aovxVertices[0];
  3807. pos->osc_aoedEdges[0].oed_Vertex1 = &pos->osc_aovxVertices[1];
  3808. pos->osc_aoedEdges[1].oed_Vertex0 = &pos->osc_aovxVertices[1];
  3809. pos->osc_aoedEdges[1].oed_Vertex1 = &pos->osc_aovxVertices[2];
  3810. pos->osc_aoedEdges[2].oed_Vertex0 = &pos->osc_aovxVertices[2];
  3811. pos->osc_aoedEdges[2].oed_Vertex1 = &pos->osc_aovxVertices[3];
  3812. pos->osc_aoedEdges[3].oed_Vertex0 = &pos->osc_aovxVertices[3];
  3813. pos->osc_aoedEdges[3].oed_Vertex1 = &pos->osc_aovxVertices[0];
  3814. // add plane
  3815. CObjectPlane *popl = pos->osc_aoplPlanes.New(1);
  3816. *popl = FLOATtoDOUBLE(plPolygon);
  3817. // add material
  3818. CObjectMaterial *pom = pos->osc_aomtMaterials.New(1);
  3819. // set must-exist texture
  3820. pom->omt_Name = "Textures\\Editor\\Default.tex";
  3821. // add polygon
  3822. CObjectPolygon *pop = pos->osc_aopoPolygons.New(1);
  3823. pop->opo_Plane = popl;
  3824. pop->opo_Material = pom;
  3825. pop->opo_PolygonEdges.New(4);
  3826. pop->opo_PolygonEdges.Lock();
  3827. pop->opo_PolygonEdges[0].ope_Edge = &pos->osc_aoedEdges[0];
  3828. pop->opo_PolygonEdges[1].ope_Edge = &pos->osc_aoedEdges[1];
  3829. pop->opo_PolygonEdges[2].ope_Edge = &pos->osc_aoedEdges[2];
  3830. pop->opo_PolygonEdges[3].ope_Edge = &pos->osc_aoedEdges[3];
  3831. pop->opo_PolygonEdges.Unlock();
  3832. // unlock locked arrays
  3833. pos->osc_aovxVertices.Unlock();
  3834. pos->osc_aoedEdges.Unlock();
  3835. }
  3836. void CWorldEditorDoc::ApplyCut( void)
  3837. {
  3838. // find the view that defines cut plane
  3839. POSITION posView = GetFirstViewPosition();
  3840. if( m_pCutLineView == NULL)
  3841. {
  3842. ASSERTALWAYS( "Cut line view wasn't set properly!");
  3843. // don't allow calling without cutting view ptr set
  3844. return;
  3845. }
  3846. CWorldEditorView *pwedView;
  3847. FOREVER
  3848. {
  3849. pwedView = (CWorldEditorView *) GetNextView(posView);
  3850. // if we didn't find it in list of views
  3851. if( pwedView == NULL)
  3852. {
  3853. // don't do anything
  3854. return;
  3855. }
  3856. // if we found it
  3857. if( pwedView == m_pCutLineView)
  3858. {
  3859. // stop looping
  3860. break;
  3861. }
  3862. }
  3863. // calculate cutting plane
  3864. FLOAT3D &vcl0 = m_vCutLineStart;
  3865. FLOAT3D &vcl1 = m_vCutLineEnd;
  3866. // get cutting edge vector
  3867. FLOAT3D vCutLine = vcl1-vcl0;
  3868. // cross product with viewer direction vector will give us cutting plane normal
  3869. // so calculate viewer direction vector
  3870. CAnyProjection3D prProjection;
  3871. // create a slave viewer
  3872. CSlaveViewer svViewer(
  3873. m_pCutLineView->GetChildFrame()->m_mvViewer,
  3874. m_pCutLineView->m_ptProjectionType,
  3875. m_plGrid,
  3876. m_pCutLineView->m_pdpDrawPort);
  3877. svViewer.MakeProjection(prProjection);
  3878. prProjection->Prepare();
  3879. // make the ray from viewer point through the dummy point, in current projection
  3880. CPlacement3D plRay;
  3881. prProjection->RayThroughPoint( FLOAT3D(0.0f, 0.0f, 0.0f), plRay);
  3882. // get viewer's direction vector
  3883. FLOAT3D vDirection;
  3884. AnglesToDirectionVector( plRay.pl_OrientationAngle, vDirection);
  3885. // make cross product
  3886. FLOAT3D vNormal = vCutLine * vDirection;
  3887. // create plane from normal vector and one of cutting edge points
  3888. FLOATplane3D plPolygon(vNormal, vcl0);
  3889. // exit cut mode
  3890. theApp.m_bCutModeOn = FALSE;
  3891. // we need to obtain brush for CSG
  3892. CBrush3D *pbrBrush = NULL;
  3893. // if we are in polygon mode
  3894. if( GetEditingMode() == POLYGON_MODE)
  3895. {
  3896. CBrushPolygon *pbpo = m_selPolygonSelection.GetFirstInSelection();
  3897. if( pbpo == NULL)
  3898. {
  3899. ASSERTALWAYS( "Apply cut called in polygon mode, but none polygon is selected.");
  3900. return;
  3901. }
  3902. pbrBrush = pbpo->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush;
  3903. }
  3904. else if( GetEditingMode() == ENTITY_MODE)
  3905. {
  3906. // do nothing
  3907. }
  3908. else
  3909. {
  3910. // we must be in sector mode
  3911. ASSERT( GetEditingMode() == SECTOR_MODE);
  3912. CBrushSector *pbsc = m_selSectorSelection.GetFirstInSelection();
  3913. if( pbsc == NULL)
  3914. {
  3915. ASSERTALWAYS( "Apply cut called in sector mode, but none sector is selected.");
  3916. return;
  3917. }
  3918. pbrBrush = pbsc->bsc_pbmBrushMip->bm_pbrBrush;
  3919. }
  3920. // brush containing polygon or sector will be our target entity
  3921. CEntity *penTarget = NULL;
  3922. if( pbrBrush != NULL)
  3923. {
  3924. penTarget=pbrBrush->br_penEntity;
  3925. }
  3926. RememberUndo();
  3927. // ------------------- Create cutting world
  3928. // obtain child frame
  3929. CChildFrame *pWedChild = pwedView->GetChildFrame();
  3930. // remember auto mip brushing flag
  3931. BOOL bAutoMipBrushingOn = pWedChild->m_bAutoMipBrushingOn;
  3932. // turn off auto mip brushing
  3933. pWedChild->m_bAutoMipBrushingOn = FALSE;
  3934. // create world cutter
  3935. CWorld woCutter;
  3936. // create zero-placement
  3937. CPlacement3D plOrigin;
  3938. plOrigin.pl_PositionVector = FLOAT3D(0.0f,0.0f,0.0f);
  3939. plOrigin.pl_OrientationAngle = ANGLE3D(0,0,0);
  3940. // create main brush entity
  3941. CEntity *penCutter = NULL;
  3942. try
  3943. {
  3944. penCutter = woCutter.CreateEntity_t( plOrigin, CTFILENAME("Classes\\WorldBase.ecl"));
  3945. }
  3946. catch( char *err_str)
  3947. {
  3948. AfxMessageBox( CString(err_str));
  3949. return;
  3950. }
  3951. // prepare the entity
  3952. penCutter->Initialize();
  3953. if( GetEditingMode() == ENTITY_MODE)
  3954. {
  3955. }
  3956. else
  3957. {
  3958. // ------------------- Create brush mip and sector
  3959. CBrush3D *pbr = penCutter->GetBrush();
  3960. // brush must exist
  3961. if( pbr == NULL)
  3962. {
  3963. ASSERTALWAYS( "Brush not properly initialized!");
  3964. return;
  3965. }
  3966. FLOATaabbox3D box;
  3967. // obtain bounding box of selected polygons/sectors
  3968. if( GetEditingMode() == POLYGON_MODE)
  3969. {
  3970. FOREACHINDYNAMICCONTAINER(m_selPolygonSelection, CBrushPolygon, itbpo)
  3971. {
  3972. box |= itbpo->bpo_boxBoundingBox;
  3973. }
  3974. }
  3975. else if( GetEditingMode() == SECTOR_MODE)
  3976. {
  3977. FOREACHINDYNAMICCONTAINER(m_selSectorSelection, CBrushSector, itbsc)
  3978. {
  3979. box |= itbsc->bsc_boxBoundingBox;
  3980. }
  3981. }
  3982. // create object3d to hold plane-cutter primitive
  3983. CObject3D o3d;
  3984. CreateCuttingWorld( plPolygon, box, o3d);
  3985. // convert object 3d to brush
  3986. try
  3987. {
  3988. pbr->FromObject3D_t( o3d);
  3989. pbr->CalculateBoundingBoxes();
  3990. }
  3991. // report errors
  3992. catch( char *err_str)
  3993. {
  3994. AfxMessageBox( CString(err_str));
  3995. }
  3996. // -------- Apply BSP cut operation
  3997. if( GetEditingMode() == POLYGON_MODE)
  3998. {
  3999. // clear all selections except polygon seletion
  4000. ClearSelections( ST_POLYGON);
  4001. // apply "split polygons"
  4002. m_woWorld.SplitPolygons(*penTarget, m_selPolygonSelection, woCutter, *penCutter, plOrigin);
  4003. }
  4004. else
  4005. {
  4006. // clear all selections except sector seletion
  4007. ClearSelections( ST_SECTOR);
  4008. // apply "split sectors"
  4009. m_woWorld.SplitSectors(*penTarget, m_selSectorSelection, woCutter, *penCutter, plOrigin);
  4010. }
  4011. }
  4012. // restore auto mip brushing
  4013. pWedChild->m_bAutoMipBrushingOn = bAutoMipBrushingOn;
  4014. m_chSelections.MarkChanged();
  4015. SetModifiedFlag(TRUE);
  4016. m_chDocument.MarkChanged();
  4017. UpdateAllViews( NULL);
  4018. }
  4019. void CWorldEditorDoc::ReloadWorld(void)
  4020. {
  4021. // clear selections
  4022. ClearSelections();
  4023. m_chDocument.MarkChanged();
  4024. // try to
  4025. try
  4026. {
  4027. // load new world from the undo file
  4028. m_woWorld.Load_t(m_woWorld.wo_fnmFileName);
  4029. // flush stale caches
  4030. _pShell->Execute("FreeUnusedStock();");
  4031. // invalidate document (i.e. all views)
  4032. UpdateAllViews( NULL);
  4033. }
  4034. // report errors
  4035. catch( char *err_str)
  4036. {
  4037. AfxMessageBox( CString(err_str));
  4038. }
  4039. }
  4040. void CWorldEditorDoc::OnCheckEdit(void)
  4041. {
  4042. CTFileName fnmFileName;
  4043. ExpandFilePath(EFP_READ, m_woWorld.wo_fnmFileName, fnmFileName);
  4044. CTString strCommand;
  4045. strCommand.PrintF("p4 edit %s", fnmFileName);
  4046. INDEX iResult = system(strCommand);
  4047. if(iResult != 0) {
  4048. WarningMessage( "Unable to perform open for edit!");
  4049. return;
  4050. }
  4051. ReloadWorld();
  4052. CTString strMessage;
  4053. strMessage.PrintF("Opened for edit: %s", (const char *)m_woWorld.wo_fnmFileName);
  4054. AfxMessageBox( CString(strMessage));
  4055. }
  4056. void CWorldEditorDoc::OnCheckAdd()
  4057. {
  4058. CTFileName fnmFileName;
  4059. ExpandFilePath(EFP_READ, m_woWorld.wo_fnmFileName, fnmFileName);
  4060. CTString strCommand;
  4061. strCommand.PrintF("p4 add %s", fnmFileName);
  4062. INDEX iResult = system(strCommand);
  4063. if(iResult != 0) {
  4064. WarningMessage( "Unable to perform open for add!");
  4065. return;
  4066. }
  4067. ReloadWorld();
  4068. CTString strMessage;
  4069. strMessage.PrintF( "Marked for add: %s", (const char *)m_woWorld.wo_fnmFileName);
  4070. AfxMessageBox( CString(strMessage));
  4071. }
  4072. void CWorldEditorDoc::OnCheckDelete()
  4073. {
  4074. CTFileName fnmFileName;
  4075. ExpandFilePath(EFP_READ, m_woWorld.wo_fnmFileName, fnmFileName);
  4076. CTString strCommand;
  4077. strCommand.PrintF("p4 delete %s", fnmFileName);
  4078. INDEX iResult = system(strCommand);
  4079. if(iResult != 0) {
  4080. WarningMessage( "Unable to perform open for delete!");
  4081. return;
  4082. }
  4083. ReloadWorld();
  4084. CTString strMessage;
  4085. strMessage.PrintF( "Marked for delete: %s", (const char *)m_woWorld.wo_fnmFileName);
  4086. AfxMessageBox( CString(strMessage));
  4087. }
  4088. BOOL CWorldEditorDoc::IsReadOnly(void)
  4089. {
  4090. return IsFileReadOnly(m_woWorld.wo_fnmFileName);
  4091. }
  4092. void CWorldEditorDoc::OnUpdateCheckEdit(CCmdUI* pCmdUI)
  4093. {
  4094. pCmdUI->Enable(TRUE);
  4095. }
  4096. void CWorldEditorDoc::OnUpdateCheckAdd(CCmdUI* pCmdUI)
  4097. {
  4098. pCmdUI->Enable(TRUE);
  4099. }
  4100. void CWorldEditorDoc::OnUpdateCheckDelete(CCmdUI* pCmdUI)
  4101. {
  4102. pCmdUI->Enable(TRUE);
  4103. }
  4104. BOOL CWorldEditorDoc::IsBrushUpdatingAllowed(void)
  4105. {
  4106. // if only one entity is selected
  4107. if( m_selEntitySelection.Count()==1)
  4108. {
  4109. // get only selected entity
  4110. CEntity *pen = m_selEntitySelection.GetFirstInSelection();
  4111. // if it is brush entity
  4112. if (pen->en_RenderType == CEntity::RT_BRUSH && pen->en_pbrBrush!=NULL)
  4113. {
  4114. // allow updating
  4115. return TRUE;
  4116. }
  4117. }
  4118. // disable updating
  4119. return FALSE;
  4120. }
  4121. void CWorldEditorDoc::OnUpdateBrushes()
  4122. {
  4123. POSITION pos = GetFirstViewPosition();
  4124. CWorldEditorView *pWedView = (CWorldEditorView *) GetNextView(pos);
  4125. ASSERT( pWedView != NULL);
  4126. RememberUndo();
  4127. // get only selected entity
  4128. CEntity *pen = m_selEntitySelection.GetFirstInSelection();
  4129. CTString strClone=pen->GetName();
  4130. FOREACHINDYNAMICCONTAINER(m_woWorld.wo_cenEntities, CEntity, iten)
  4131. {
  4132. if(iten!=pen &&
  4133. iten->GetName()==strClone &&
  4134. iten->en_RenderType==CEntity::RT_BRUSH)
  4135. {
  4136. iten->en_pbrBrush->Copy(*pen->en_pbrBrush, 1.0f, FALSE);
  4137. pWedView->DiscardShadows( &*iten);
  4138. }
  4139. }
  4140. UpdateAllViews( NULL);
  4141. }
  4142. void CWorldEditorDoc::OnInsert3dObject()
  4143. {
  4144. theApp.Insert3DObjects(this);
  4145. }
  4146. void CWorldEditorDoc::OnExport3dObject()
  4147. {
  4148. CTFileName fnName = _EngineGUI.FileRequester( "Export polygons as ...",
  4149. "Raw 3D object\0*.raw\0" FILTER_ALL FILTER_END, "Export geometry directory", "Worlds\\");
  4150. if( fnName == "") return;
  4151. try
  4152. {
  4153. CTFileStream strmFile;
  4154. strmFile.Create_t( fnName);
  4155. strmFile.PutLine_t("No name");
  4156. // for each of the selected polygons
  4157. FOREACHINDYNAMICCONTAINER( m_selPolygonSelection, CBrushPolygon, itbpo)
  4158. {
  4159. CBrushPolygon &bpo = *itbpo;
  4160. for( INDEX iVtx=0; iVtx<bpo.bpo_aiTriangleElements.Count(); iVtx+=3)
  4161. {
  4162. CBrushVertex &vtx1=*bpo.bpo_apbvxTriangleVertices[bpo.bpo_aiTriangleElements[iVtx+0]];
  4163. CBrushVertex &vtx2=*bpo.bpo_apbvxTriangleVertices[bpo.bpo_aiTriangleElements[iVtx+1]];
  4164. CBrushVertex &vtx3=*bpo.bpo_apbvxTriangleVertices[bpo.bpo_aiTriangleElements[iVtx+2]];
  4165. CTString strTemp;
  4166. strTemp.PrintF("%g %g %g %g %g %g %g %g %g",
  4167. vtx1.bvx_vAbsolute(1), vtx1.bvx_vAbsolute(2), vtx1.bvx_vAbsolute(3),
  4168. vtx2.bvx_vAbsolute(1), vtx2.bvx_vAbsolute(2), vtx2.bvx_vAbsolute(3),
  4169. vtx3.bvx_vAbsolute(1), vtx3.bvx_vAbsolute(2), vtx3.bvx_vAbsolute(3));
  4170. strmFile.PutLine_t( strTemp);
  4171. }
  4172. }
  4173. strmFile.Close();
  4174. }
  4175. catch( char *err_str)
  4176. {
  4177. AfxMessageBox( CString(err_str));
  4178. }
  4179. }
  4180. void CWorldEditorDoc::OnUpdateExport3dObject(CCmdUI* pCmdUI)
  4181. {
  4182. pCmdUI->Enable( m_selPolygonSelection.Count()!=0);
  4183. }
  4184. void CWorldEditorDoc::OnPopupVtxAllign()
  4185. {
  4186. CDlgAllignVertices dlg;
  4187. dlg.DoModal();
  4188. }
  4189. void CWorldEditorDoc::OnPopupVtxFilter()
  4190. {
  4191. CDlgFilterVertexSelection dlg;
  4192. dlg.DoModal();
  4193. }
  4194. void CWorldEditorDoc::OnPopupVtxNumeric()
  4195. {
  4196. CDlgSnapVertex dlg;
  4197. dlg.DoModal();
  4198. }
  4199. void CWorldEditorDoc::OnExportPlacements()
  4200. {
  4201. CStaticStackArray<CTString> astrNeddedSmc;
  4202. try
  4203. {
  4204. CTFileName fnWorld=m_woWorld.wo_fnmFileName;
  4205. // "entity placement and names"
  4206. CTFileName fnExport=fnWorld.FileDir()+fnWorld.FileName()+".epn";
  4207. // open text file
  4208. CTFileStream strmFile;
  4209. strmFile.Create_t( fnExport, CTStream::CM_TEXT);
  4210. // for each entity in world
  4211. FOREACHINDYNAMICCONTAINER(m_woWorld.wo_cenEntities, CEntity, iten)
  4212. {
  4213. CEntity &en=*iten;
  4214. // obtain entity class ptr
  4215. CDLLEntityClass *pdecDLLClass = en.GetClass()->ec_pdecDLLClass;
  4216. // obtain position
  4217. FLOAT3D vPos=en.GetPlacement().pl_PositionVector;
  4218. FLOAT3D vRot=en.GetPlacement().pl_OrientationAngle;
  4219. // dump class name and placement
  4220. CTString strLine;
  4221. CTString strName=en.GetName();
  4222. if(strName=="") {
  4223. strName="Dummy name";
  4224. }
  4225. strLine.PrintF("Class: \"%s\", Name: \"%s\", Position: (%f, %f, %f), Rotation: (%f, %f, %f)",
  4226. pdecDLLClass->dec_strName, strName, vPos(1), vPos(2), vPos(3), vRot(1), vRot(2), vRot(3));
  4227. strmFile.PutLine_t(strLine);
  4228. // if this is model holder 3 class, we should also dump model path
  4229. if(CTString(pdecDLLClass->dec_strName)=="ModelHolder3")
  4230. {
  4231. CTFileName fnmFile=CTString("Unknown");
  4232. FLOAT3D vStretch=FLOAT3D(1.0f,1.0f,1.0f);
  4233. // for all classes in hierarchy of this entity
  4234. for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
  4235. {
  4236. // for all properties
  4237. for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
  4238. {
  4239. CEntityProperty *pepProperty = &pdecDLLClass->dec_aepProperties[iProperty];
  4240. if( pepProperty->ep_eptType == CEntityProperty::EPT_FILENAME &&
  4241. CTString(pepProperty->ep_strName) == "Model file (.smc)")
  4242. {
  4243. // obtain file name
  4244. fnmFile = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, CTFileName);
  4245. BOOL bExistsInList=FALSE;
  4246. for(INDEX iSmc=0; iSmc<astrNeddedSmc.Count(); iSmc++)
  4247. {
  4248. if(astrNeddedSmc[iSmc]==CTString(fnmFile))
  4249. {
  4250. bExistsInList=TRUE;
  4251. break;
  4252. }
  4253. }
  4254. if(!bExistsInList)
  4255. {
  4256. CTString &strNew=astrNeddedSmc.Push();
  4257. strNew=CTString(fnmFile);
  4258. }
  4259. }
  4260. if( pepProperty->ep_eptType == CEntityProperty::EPT_FLOAT &&
  4261. CTString(pepProperty->ep_strName) == "StretchAll")
  4262. {
  4263. FLOAT fStretchAll = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, FLOAT);
  4264. vStretch(1)*=fStretchAll;
  4265. vStretch(2)*=fStretchAll;
  4266. vStretch(3)*=fStretchAll;
  4267. }
  4268. if( pepProperty->ep_eptType == CEntityProperty::EPT_ANGLE3D &&
  4269. CTString(pepProperty->ep_strName) == "StretchXYZ")
  4270. {
  4271. ANGLE3D vStretchXYZ = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, ANGLE3D);
  4272. vStretch(1)*=vStretchXYZ(1);
  4273. vStretch(2)*=vStretchXYZ(2);
  4274. vStretch(3)*=vStretchXYZ(3);
  4275. }
  4276. }
  4277. }
  4278. CTString strLine;
  4279. strLine.PrintF("Smc: \"%s\" Stretch: (%f, %f, %f)", CTString(fnmFile), vStretch(1), vStretch(2), vStretch(3));
  4280. strmFile.PutLine_t(strLine);
  4281. }
  4282. }
  4283. // "entity placement and names"
  4284. CTFileName fnSml=fnWorld.FileDir()+fnWorld.FileName()+".sml";
  4285. // open text file
  4286. CTFileStream strmSmlFile;
  4287. strmSmlFile.Create_t( fnSml, CTStream::CM_TEXT);
  4288. // save needed smc's
  4289. for(INDEX iSmc=0; iSmc<astrNeddedSmc.Count(); iSmc++)
  4290. {
  4291. strmSmlFile.PutLine_t(astrNeddedSmc[iSmc]);
  4292. }
  4293. AfxMessageBox(L"Placements exported!", MB_OK|MB_ICONINFORMATION);
  4294. }
  4295. catch( char *err_str)
  4296. {
  4297. AfxMessageBox( CString(err_str));
  4298. }
  4299. }
  4300. CTFileName CorrectSlashes(const CTFileName &fnmFile)
  4301. {
  4302. char afnmSlash[1024];
  4303. for(INDEX iChar=0; iChar<fnmFile.Length(); iChar++) {
  4304. afnmSlash[iChar] = fnmFile[iChar];
  4305. if(afnmSlash[iChar]=='\\') {
  4306. afnmSlash[iChar] = '/';
  4307. }
  4308. }
  4309. // end the string
  4310. afnmSlash[fnmFile.Length()] = 0;
  4311. return CTString(afnmSlash);
  4312. }
  4313. // Detects detail texture and replaces it with normal map texture
  4314. CTFileName RemapDetailTexturePath(CTFileName &fnmFile)
  4315. {
  4316. if(fnmFile.FindSubstr("/Detail/") >=0) {
  4317. return fnmFile.FileDir() + fnmFile.FileName() + "_NM.tex";
  4318. }
  4319. return fnmFile;
  4320. }
  4321. CTString FixQuotes(const CTString &strOrg)
  4322. {
  4323. char achrFixed[1024];
  4324. INDEX iFixedChar = 0;
  4325. for(INDEX iChar=0; iChar<strOrg.Length(); iChar++) {
  4326. // if we found a quote
  4327. if(strOrg[iChar]=='\"') {
  4328. // replace it with \"
  4329. achrFixed[iFixedChar++] = '\\';
  4330. achrFixed[iFixedChar++] = '\"';
  4331. } else {
  4332. achrFixed[iFixedChar++] = strOrg[iChar];
  4333. }
  4334. }
  4335. // end the string
  4336. achrFixed[iFixedChar] = 0;
  4337. return CTString(achrFixed);
  4338. }
  4339. // Class used to represent polygon during brush to .amf exporting
  4340. class CAmfNGon {
  4341. public:
  4342. CDynamicContainer<CBrushVertex> ang_cbpoVertices;
  4343. public:
  4344. void FromBrushPolygon(CBrushPolygon *pbpo);
  4345. };
  4346. // Class used to represent polygon during brush to .amf exporting
  4347. class CAmfPolygon {
  4348. public:
  4349. CStaticStackArray<CAmfNGon> amfp_aangNgons;
  4350. public:
  4351. void FromBrushPolygon(CBrushPolygon *pbpo);
  4352. };
  4353. // Creates polygon consisting of vertex loop from brush polygon
  4354. void CAmfPolygon::FromBrushPolygon(CBrushPolygon *pbpo)
  4355. {
  4356. // make copy of the index array
  4357. CStaticArray<INDEX> aiTriangles;
  4358. aiTriangles.CopyArray( pbpo->bpo_aiTriangleElements);
  4359. _nextNgon:
  4360. // copy loop into n-gon
  4361. CAmfNGon &aNgon = amfp_aangNgons.Push();
  4362. // find first triangle that is not handled
  4363. INDEX iFirstNGonTriangle = -1;
  4364. {for(INDEX iTri=0; iTri<aiTriangles.Count()/3; iTri++) {
  4365. if(aiTriangles[iTri*3] != -1) {
  4366. iFirstNGonTriangle=iTri;
  4367. break;
  4368. }
  4369. }}
  4370. // triangle must be found
  4371. if(iFirstNGonTriangle==-1) {
  4372. return;
  4373. }
  4374. // and add it to the loop and mark them as handled
  4375. aNgon.ang_cbpoVertices.Add( pbpo->bpo_apbvxTriangleVertices[aiTriangles[iFirstNGonTriangle*3+0]]); aiTriangles[iFirstNGonTriangle*3+0] = -1;
  4376. aNgon.ang_cbpoVertices.Add( pbpo->bpo_apbvxTriangleVertices[aiTriangles[iFirstNGonTriangle*3+1]]); aiTriangles[iFirstNGonTriangle*3+1] = -1;
  4377. aNgon.ang_cbpoVertices.Add( pbpo->bpo_apbvxTriangleVertices[aiTriangles[iFirstNGonTriangle*3+2]]); aiTriangles[iFirstNGonTriangle*3+2] = -1;
  4378. // re-entry point for expanding loop
  4379. _nextLoopEdge:;
  4380. // for each loop's edge
  4381. for(INDEX iLoopEdge=0; iLoopEdge<aNgon.ang_cbpoVertices.Count(); iLoopEdge++) {
  4382. // get edge vertices
  4383. CBrushVertex *pbvLoop0 = &aNgon.ang_cbpoVertices[iLoopEdge];
  4384. CBrushVertex *pbvLoop1 = &aNgon.ang_cbpoVertices[(iLoopEdge+1)%aNgon.ang_cbpoVertices.Count()];
  4385. // find triangle that shares edge
  4386. for(INDEX iTri=0; iTri<aiTriangles.Count()/3; iTri++) {
  4387. // for each edge in triangle
  4388. for(INDEX iTriEdge=0; iTriEdge<3; iTriEdge++) {
  4389. // fetch edge vertex indices
  4390. INDEX iTriVtx0 = aiTriangles[iTri*3+iTriEdge];
  4391. INDEX iTriVtx1 = aiTriangles[iTri*3+(iTriEdge+1)%3];
  4392. // if triangle is already handled
  4393. if(iTriVtx0==-1 || iTriVtx1==-1) {
  4394. break;
  4395. }
  4396. CBrushVertex *pbvEdg0 = pbpo->bpo_apbvxTriangleVertices[iTriVtx0];
  4397. CBrushVertex *pbvEdg1 = pbpo->bpo_apbvxTriangleVertices[iTriVtx1];
  4398. // if this edge is the same as the loop edge
  4399. if(pbvLoop0==pbvEdg1 && pbvLoop1==pbvEdg0) {
  4400. // find index of vertex to insert (third vertex)
  4401. INDEX iThirdVtxNo;
  4402. if(iTriEdge==0) { iThirdVtxNo=2;}
  4403. else if(iTriEdge==1) { iThirdVtxNo=0;}
  4404. else { iThirdVtxNo=1;}
  4405. INDEX iThirdVertex = aiTriangles[iTri*3+iThirdVtxNo];
  4406. // mark that triangle is integrated into the loop
  4407. aiTriangles[iTri*3+0] = -1;
  4408. aiTriangles[iTri*3+1] = -1;
  4409. aiTriangles[iTri*3+2] = -1;
  4410. CBrushVertex *pbvThird = pbpo->bpo_apbvxTriangleVertices[iThirdVertex];
  4411. aNgon.ang_cbpoVertices.Insert(pbvThird, iLoopEdge+1);
  4412. goto _nextLoopEdge;
  4413. }
  4414. }
  4415. }
  4416. }
  4417. // test if all triangles are cleared
  4418. {for(INDEX iTri=0; iTri<aiTriangles.Count()/3; iTri++) {
  4419. // if not all are cleared
  4420. if(aiTriangles[iTri*3] != -1) {
  4421. // add another ngon
  4422. goto _nextNgon;
  4423. }
  4424. }}
  4425. }
  4426. // Types of exported types
  4427. enum ExportType {
  4428. ET_RENDERING,
  4429. ET_VISIBILITY,
  4430. };
  4431. // Class used to collect surface data for brush to .amf exporting
  4432. class CAmfSurface {
  4433. public:
  4434. CDynamicContainer<CBrushPolygon> sf_cbpoPolygons;
  4435. CAnimData *sf_padAnimData; // surface's texture
  4436. UBYTE sf_ubMaterial; // surface's material
  4437. public:
  4438. CAmfSurface(void) {
  4439. sf_padAnimData = NULL;
  4440. };
  4441. // Calculates count of ngons
  4442. INDEX GetNGonCount(void) {
  4443. INDEX ctNgons = 0;
  4444. for(INDEX iPlg=0; iPlg<sf_cbpoPolygons.Count(); iPlg++) {
  4445. CBrushPolygon &bpo = sf_cbpoPolygons[iPlg];
  4446. CAmfPolygon *amfp = (CAmfPolygon *)bpo.bpo_pspoScreenPolygon;
  4447. ctNgons += amfp->amfp_aangNgons.Count();
  4448. }
  4449. return ctNgons;
  4450. };
  4451. // Calculates count of ngon vertices
  4452. INDEX GetNGonVertexCount(void) {
  4453. INDEX ctVertices = 0;
  4454. for(INDEX iPlg=0; iPlg<sf_cbpoPolygons.Count(); iPlg++) {
  4455. CBrushPolygon &bpo = sf_cbpoPolygons[iPlg];
  4456. CAmfPolygon *amfp = (CAmfPolygon *)bpo.bpo_pspoScreenPolygon;
  4457. for(INDEX iNgon=0; iNgon<amfp->amfp_aangNgons.Count(); iNgon++) {
  4458. CAmfNGon &aNgon = amfp->amfp_aangNgons[iNgon];
  4459. ctVertices += aNgon.ang_cbpoVertices.Count();
  4460. }
  4461. }
  4462. return ctVertices;
  4463. };
  4464. };
  4465. // Tests if given polygon is visible
  4466. BOOL IsPolygonVisible(const CBrushPolygon &bpo)
  4467. {
  4468. // if is invisible
  4469. if(bpo.bpo_ulFlags&BPOF_INVISIBLE) {
  4470. return FALSE;
  4471. }
  4472. // if is portal
  4473. if(bpo.bpo_ulFlags&BPOF_PORTAL) {
  4474. // if is translucent portal
  4475. if(bpo.bpo_ulFlags&BPOF_TRANSLUCENT) {
  4476. // it is visible
  4477. return TRUE;
  4478. }
  4479. return FALSE;
  4480. }
  4481. return TRUE;
  4482. }
  4483. // Exports one layer of given type
  4484. void ExportLayer_t(CWorldEditorDoc *pDoc, CEntity &en, ExportType etExportType, CBrushMip *pbmMip, CTFileStream &strmAmf,
  4485. const CString &strLayerName, INDEX iLayerNo, BOOL bFieldBrush, BOOL bCollisionOnlyBrush)
  4486. {
  4487. // sort brush polygons for their textures
  4488. CDynamicContainer<CAmfSurface> cbpoSurfaces;
  4489. // assume that there will not be any portals nor occluders
  4490. CStaticStackArray<INDEX> ciPortals;
  4491. CStaticStackArray<INDEX> ciOccluders;
  4492. CStaticStackArray<INDEX> ciClassifiers;
  4493. // for each sector in the brush mip
  4494. INDEX iPlgGlobal=0;
  4495. {for(INDEX iSector=0; iSector<pbmMip->bm_abscSectors.Count(); iSector++) {
  4496. CBrushSector &bs = pbmMip->bm_abscSectors[iSector];
  4497. // for each polygon in the sector
  4498. for(INDEX iPlg=0; iPlg<bs.bsc_abpoPolygons.Count(); iPlg++) {
  4499. CBrushPolygon &bpo = bs.bsc_abpoPolygons[iPlg];
  4500. // if we are exporting collision (e.g. for empty brushes)
  4501. if(etExportType==ET_RENDERING) {
  4502. if(!bFieldBrush && (!IsPolygonVisible(bpo) && !bCollisionOnlyBrush) ) {
  4503. continue;
  4504. }
  4505. CAnimData *pad = bpo.bpo_abptTextures[0].bpt_toTexture.GetData();
  4506. UBYTE ubMaterial = bpo.bpo_bppProperties.bpp_ubSurfaceType;
  4507. BOOL bFound = FALSE;
  4508. for(INDEX iSurf=0; iSurf<cbpoSurfaces.Count(); iSurf++) {
  4509. CAmfSurface &asSurf = cbpoSurfaces[iSurf];
  4510. // if this surface for the texture-surface pair is already defined
  4511. if( (asSurf.sf_padAnimData==pad) && (asSurf.sf_ubMaterial==ubMaterial) ) {
  4512. // add polygon to existing surface
  4513. asSurf.sf_cbpoPolygons.Add(&bpo);
  4514. bFound = TRUE;
  4515. break;
  4516. }
  4517. }
  4518. // if surface with current texture and material is not yet defined
  4519. if(!bFound) {
  4520. CAmfSurface *pSurf = (CAmfSurface *) new(CAmfSurface);
  4521. cbpoSurfaces.Add(pSurf);
  4522. pSurf->sf_cbpoPolygons.Add(&bpo);
  4523. pSurf->sf_padAnimData = pad;
  4524. pSurf->sf_ubMaterial = ubMaterial;
  4525. }
  4526. } else if(etExportType==ET_VISIBILITY) {
  4527. BOOL bClassifier = FALSE;
  4528. BOOL bOccluder = FALSE;
  4529. BOOL bPortal = FALSE;
  4530. // if this polygon is not involved in visibility
  4531. if(bpo.bpo_ulFlags&BPOF_DETAILPOLYGON) {
  4532. bClassifier = TRUE;
  4533. }
  4534. else if(bpo.bpo_ulFlags&BPOF_OCCLUDER) {
  4535. bOccluder = TRUE;
  4536. }
  4537. else if(bpo.bpo_ulFlags&BPOF_PORTAL) {
  4538. bPortal = TRUE;
  4539. }
  4540. // if surface is not yet defined
  4541. if(cbpoSurfaces.Count()==0) {
  4542. // add one
  4543. CAmfSurface *pSurf = (CAmfSurface *) new(CAmfSurface);
  4544. cbpoSurfaces.Add(pSurf);
  4545. }
  4546. CAmfPolygon *amfp = (CAmfPolygon *)bpo.bpo_pspoScreenPolygon;
  4547. for(INDEX iNgon=0; iNgon<amfp->amfp_aangNgons.Count(); iNgon++) {
  4548. if(bClassifier) { ciClassifiers.Push() = iPlgGlobal; }
  4549. if(bOccluder) { ciOccluders.Push() = iPlgGlobal; }
  4550. if(bPortal) { ciPortals.Push() = iPlgGlobal; }
  4551. iPlgGlobal++;
  4552. }
  4553. cbpoSurfaces[0].sf_cbpoPolygons.Add(&bpo);
  4554. }
  4555. }
  4556. }}
  4557. // count total surface polygons and vertices
  4558. INDEX ctTotalPolygons = 0;
  4559. INDEX ctTotalVertices = 0;
  4560. {for(INDEX iSurf=0; iSurf<cbpoSurfaces.Count(); iSurf++) {
  4561. CAmfSurface &amfs = cbpoSurfaces[iSurf];
  4562. ctTotalPolygons+=amfs.GetNGonCount();
  4563. ctTotalVertices+=amfs.GetNGonVertexCount();
  4564. }}
  4565. // if there is no polygons to export
  4566. if(ctTotalPolygons==0) {
  4567. return;
  4568. }
  4569. strmAmf.FPrintF_t(" LAYER_NAME \"%s\"\n", strLayerName);
  4570. strmAmf.FPrintF_t(" LAYER_INDEX %d\n", iLayerNo);
  4571. strmAmf.PutLine_t(" {");
  4572. INDEX ctVertexMaps = etExportType==ET_RENDERING ? 4 : 1;
  4573. strmAmf.FPrintF_t(" VERTEX_MAPS %d\n", ctVertexMaps);
  4574. strmAmf.PutLine_t(" {");
  4575. strmAmf.PutLine_t(" VERTEX_MAP \"morph.position\"");
  4576. strmAmf.PutLine_t(" {");
  4577. strmAmf.FPrintF_t(" ELEMENTS %d\n", ctTotalVertices);
  4578. strmAmf.PutLine_t(" {");
  4579. {for(INDEX iSurf=0; iSurf<cbpoSurfaces.Count(); iSurf++) {
  4580. CAmfSurface &asSurf = cbpoSurfaces[iSurf];
  4581. for(INDEX iPlg=0; iPlg<asSurf.sf_cbpoPolygons.Count(); iPlg++) {
  4582. CBrushPolygon &bpo = asSurf.sf_cbpoPolygons[iPlg];
  4583. CAmfPolygon *amfp = (CAmfPolygon *)bpo.bpo_pspoScreenPolygon;
  4584. for(INDEX iNgon=0; iNgon<amfp->amfp_aangNgons.Count(); iNgon++) {
  4585. CAmfNGon &aNgon = amfp->amfp_aangNgons[iNgon];
  4586. for(INDEX iVtx=0; iVtx<aNgon.ang_cbpoVertices.Count(); iVtx++) {
  4587. CBrushVertex &bVtx = aNgon.ang_cbpoVertices[iVtx];
  4588. strmAmf.FPrintF_t(" { %f, %f, %f; }\n", bVtx.bvx_vdPreciseRelative(1), bVtx.bvx_vdPreciseRelative(2), bVtx.bvx_vdPreciseRelative(3));
  4589. }
  4590. }
  4591. }
  4592. }}
  4593. strmAmf.PutLine_t(" }");
  4594. strmAmf.PutLine_t(" }");
  4595. if(etExportType==ET_RENDERING) {
  4596. for(INDEX iTextureLayer=0; iTextureLayer<3; iTextureLayer++) {
  4597. strmAmf.FPrintF_t(" VERTEX_MAP \"texcoord.Texture %d\"", iTextureLayer+1);
  4598. strmAmf.PutLine_t(" {");
  4599. strmAmf.FPrintF_t(" ELEMENTS %d\n", ctTotalVertices);
  4600. strmAmf.PutLine_t(" {");
  4601. {for(INDEX iSurf=0; iSurf<cbpoSurfaces.Count(); iSurf++) {
  4602. CAmfSurface &asSurf = cbpoSurfaces[iSurf];
  4603. for(INDEX iPlg=0; iPlg<asSurf.sf_cbpoPolygons.Count(); iPlg++) {
  4604. CBrushPolygon &bpo = asSurf.sf_cbpoPolygons[iPlg];
  4605. // fetch mapping parameters
  4606. CMappingVectors mvDefault;
  4607. mvDefault.FromPlane_DOUBLE(bpo.bpo_pbplPlane->bpl_pldPreciseRelative);
  4608. // calculate mapping transformation vectors
  4609. CMappingDefinition &md = bpo.bpo_abptTextures[iTextureLayer].bpt_mdMapping;
  4610. // if there is no texture
  4611. MEX mexTexSizeU, mexTexSizeV;
  4612. if(bpo.bpo_abptTextures[iTextureLayer].bpt_toTexture.GetData()==NULL) {
  4613. mexTexSizeU = 1024;
  4614. mexTexSizeV = 1024;
  4615. } else {
  4616. mexTexSizeU = bpo.bpo_abptTextures[iTextureLayer].bpt_toTexture.GetWidth();
  4617. mexTexSizeV = bpo.bpo_abptTextures[iTextureLayer].bpt_toTexture.GetHeight();
  4618. }
  4619. const FLOAT fMulU = 1024.0f /mexTexSizeU; // (no need to do shift-opt, because it won't speed up much!)
  4620. const FLOAT fMulV = 1024.0f /mexTexSizeV;
  4621. CMappingVectors mvTransform;
  4622. md.MakeMappingVectors(mvDefault, mvTransform);
  4623. CAmfPolygon *amfp = (CAmfPolygon *)bpo.bpo_pspoScreenPolygon;
  4624. for(INDEX iNgon=0; iNgon<amfp->amfp_aangNgons.Count(); iNgon++) {
  4625. CAmfNGon &aNgon = amfp->amfp_aangNgons[iNgon];
  4626. for(INDEX iVtx=0; iVtx<aNgon.ang_cbpoVertices.Count(); iVtx++) {
  4627. CBrushVertex &bVtx = aNgon.ang_cbpoVertices[iVtx];
  4628. // calculate mapping coordinates
  4629. FLOAT3D vUV = bVtx.bvx_vRelative-mvTransform.mv_vO;
  4630. FLOAT fU = vUV % mvTransform.mv_vU;
  4631. FLOAT fV = vUV % mvTransform.mv_vV;
  4632. fU *= fMulU;
  4633. fV *= fMulV;
  4634. // fix qnans
  4635. if(!_finite(fU)) { fU=0;}
  4636. if(!_finite(fV)) { fV=0;}
  4637. strmAmf.FPrintF_t(" { %f, %f; }\n", fU, fV);
  4638. }
  4639. }
  4640. }
  4641. }}
  4642. strmAmf.PutLine_t(" }");
  4643. strmAmf.PutLine_t(" }");
  4644. }
  4645. }
  4646. strmAmf.PutLine_t(" }");
  4647. strmAmf.FPrintF_t(" VERTICES %d\n", ctTotalVertices);
  4648. strmAmf.PutLine_t(" {");
  4649. for(INDEX iVtx=0; iVtx<ctTotalVertices; iVtx++) {
  4650. if(etExportType==ET_RENDERING) {
  4651. strmAmf.FPrintF_t(" { 4: 0[%d], 1[%d], 2[%d], 3[%d];}\n", iVtx, iVtx, iVtx, iVtx);
  4652. } else {
  4653. strmAmf.FPrintF_t(" { 1: 0[%d]; }\n", iVtx);
  4654. }
  4655. }
  4656. strmAmf.PutLine_t(" }");
  4657. strmAmf.FPrintF_t(" POLYGONS %d\n", ctTotalPolygons);
  4658. strmAmf.PutLine_t(" {");
  4659. INDEX iPlgVtx = 0;
  4660. {for(INDEX iSurf=0; iSurf<cbpoSurfaces.Count(); iSurf++) {
  4661. CAmfSurface &asSurf = cbpoSurfaces[iSurf];
  4662. for(INDEX iPlg=0; iPlg<asSurf.sf_cbpoPolygons.Count(); iPlg++) {
  4663. CBrushPolygon &bpo = asSurf.sf_cbpoPolygons[iPlg];
  4664. CAmfPolygon *amfp = (CAmfPolygon *)bpo.bpo_pspoScreenPolygon;
  4665. for(INDEX iNgon=0; iNgon<amfp->amfp_aangNgons.Count(); iNgon++) {
  4666. CAmfNGon &aNgon = amfp->amfp_aangNgons[iNgon];
  4667. INDEX ctPlgVertices = aNgon.ang_cbpoVertices.Count();
  4668. if(ctPlgVertices==0) {
  4669. strmAmf.FPrintF_t(" { 3: 0, 0, 0; }\n");
  4670. } else {
  4671. strmAmf.FPrintF_t(" { %d: ", ctPlgVertices);
  4672. for(INDEX iVtx=0; iVtx<ctPlgVertices; iVtx++) {
  4673. if(iVtx==ctPlgVertices-1) {
  4674. strmAmf.FPrintF_t("%d; }\n", iPlgVtx++);
  4675. } else {
  4676. strmAmf.FPrintF_t("%d, ", iPlgVtx++);
  4677. }
  4678. }
  4679. }
  4680. }
  4681. }
  4682. }}
  4683. strmAmf.PutLine_t(" }");
  4684. // for rendering
  4685. if(etExportType==ET_RENDERING) {
  4686. strmAmf.FPrintF_t(" POLYGON_MAPS %d\n", cbpoSurfaces.Count());
  4687. strmAmf.PutLine_t(" {");
  4688. // dump surfaces
  4689. INDEX iPlgGlobal=0;
  4690. {for(INDEX iSurf=0; iSurf<cbpoSurfaces.Count(); iSurf++) {
  4691. CAmfSurface &asSurf = cbpoSurfaces[iSurf];
  4692. CBrushPolygon &bpo = asSurf.sf_cbpoPolygons[0];
  4693. strmAmf.FPrintF_t(" POLYGON_MAP_NAME \"surface.Default_%d_%d\"\n", en.en_ulID, iSurf);
  4694. #if 1
  4695. // dump surface data
  4696. if(bCollisionOnlyBrush) {
  4697. strmAmf.PutLine_t(" POLYGON_MAP_SHADER \"\"");
  4698. } else {
  4699. strmAmf.PutLine_t(" POLYGON_MAP_SHADER \"Bin/Shaders.module|Standard\"");
  4700. }
  4701. strmAmf.PutLine_t(" {");
  4702. // export material info
  4703. CString strMaterial = pDoc->m_woWorld.wo_astSurfaceTypes[asSurf.sf_ubMaterial].st_strName;
  4704. strmAmf.FPrintF_t(" Material \"%s\";\n", strMaterial);
  4705. // export first layer data
  4706. CTFileName strPath;
  4707. strPath = bpo.bpo_abptTextures[0].bpt_toTexture.GetName();
  4708. strPath = CorrectSlashes(strPath);
  4709. strPath = RemapDetailTexturePath(strPath);
  4710. if(bFieldBrush) {
  4711. strmAmf.FPrintF_t(" \"base color\" Color %d;\n", C_GREEN|128);
  4712. strmAmf.FPrintF_t(" \"blend type\" BlendType \"%translucent\";\n");
  4713. strmAmf.FPrintF_t(" \"double sided\" Bool \"TRUE\";\n");
  4714. } else {
  4715. // setup blend type for translucent portals
  4716. if( (bpo.bpo_ulFlags&BPOF_PORTAL) && (bpo.bpo_ulFlags&BPOF_TRANSLUCENT) ) {
  4717. strmAmf.FPrintF_t(" \"blend type\" BlendType \"%translucent\";\n");
  4718. }
  4719. //strPath.SetAbsolutePath();
  4720. //strPath.ReplaceSubstr("\\", "\\\\");
  4721. //strmAmf.FPrintF_t(" \"base texture\" Texture \"%s\";\n", strPath);
  4722. //strmAmf.FPrintF_t(" \"base uvmap\" UVMap \"Texture 1\";\n");
  4723. strmAmf.FPrintF_t(" \"base color\" Color %d;\n", bpo.bpo_abptTextures[0].s.bpt_colColor);
  4724. // export second layer data
  4725. //strPath = bpo.bpo_abptTextures[1].bpt_toTexture.GetName();
  4726. //strPath = CorrectSlashes(strPath);
  4727. //strPath = RemapDetailTexturePath(strPath);
  4728. //strmAmf.FPrintF_t(" \"blend mask\" Texture \"%s\";\n", strPath);
  4729. //strmAmf.FPrintF_t(" \"mask uvmap\" UVMap \"Texture 2\";\n");
  4730. // export third layer data
  4731. //strPath = bpo.bpo_abptTextures[2].bpt_toTexture.GetName();
  4732. //strPath = CorrectSlashes(strPath);
  4733. //strPath = RemapDetailTexturePath(strPath);
  4734. //strmAmf.FPrintF_t(" \"detail normalmap\" Texture \"%s\";\n", strPath);
  4735. //strmAmf.FPrintF_t(" \"detail uvmap\" UVMap \"Texture 3\";\n");
  4736. //strmAmf.FPrintF_t(" \"tangent uvmap\" UVMap \"Texture 3\";\n");
  4737. }
  4738. strmAmf.PutLine_t(" }");
  4739. #else
  4740. strmAmf.PutLine_t(" POLYGON_MAP_SHADER \"Bin/GameSamHD.module|Architecture\"");
  4741. strmAmf.PutLine_t(" {");
  4742. // export material info
  4743. CString strMaterial = pDoc->m_woWorld.wo_astSurfaceTypes[asSurf.sf_ubMaterial].st_strName;
  4744. strmAmf.FPrintF_t(" Material \"%s\";\n", strMaterial);
  4745. // export first layer data
  4746. CTFileName strPath;
  4747. strPath = bpo.bpo_abptTextures[0].bpt_toTexture.GetName();
  4748. strPath = CorrectSlashes(strPath);
  4749. strPath = RemapDetailTexturePath(strPath);
  4750. strmAmf.FPrintF_t(" \"diffuse 1 texture\" Texture \"%s\";\n", strPath);
  4751. strmAmf.FPrintF_t(" \"diffuse 1 uvmap\" UVMap \"Texture 1\";\n");
  4752. // export second layer data
  4753. strPath = bpo.bpo_abptTextures[1].bpt_toTexture.GetName();
  4754. strPath = CorrectSlashes(strPath);
  4755. strPath = RemapDetailTexturePath(strPath);
  4756. strmAmf.FPrintF_t(" \"shade\" Texture \"%s\";\n", strPath);
  4757. strmAmf.FPrintF_t(" \"shade uvmap\" UVMap \"Texture 2\";\n");
  4758. // export third layer data
  4759. strPath = bpo.bpo_abptTextures[2].bpt_toTexture.GetName();
  4760. strPath = CorrectSlashes(strPath);
  4761. strPath = RemapDetailTexturePath(strPath);
  4762. strmAmf.FPrintF_t(" \"normal map 1\" Texture \"%s\";\n", strPath);
  4763. strmAmf.FPrintF_t(" \"normal 1 uvmap\" UVMap \"Texture 3\";\n");
  4764. strmAmf.FPrintF_t(" \"tangent uvmap\" UVMap \"Texture 3\";\n");
  4765. strmAmf.PutLine_t(" }");
  4766. #endif
  4767. strmAmf.PutLine_t(" POLYGON_MAP_SMOOTHING_ANGLE 30");
  4768. INDEX ctSurfacePolygons = asSurf.GetNGonCount();
  4769. strmAmf.FPrintF_t(" POLYGONS_COUNT %d\n", ctSurfacePolygons);
  4770. strmAmf.PutLine_t(" {");
  4771. for(INDEX iPlg=0; iPlg<ctSurfacePolygons; iPlg++) {
  4772. strmAmf.FPrintF_t(" %d;\n", iPlgGlobal++);
  4773. }
  4774. strmAmf.PutLine_t(" }");
  4775. }}
  4776. strmAmf.PutLine_t(" }");
  4777. } else if(etExportType==ET_VISIBILITY) {
  4778. // for visibility
  4779. INDEX ctSectors = pbmMip->bm_abscSectors.Count();
  4780. INDEX iOccluderPolyMaps = ciOccluders.Count()>0 ? 1 : 0;
  4781. INDEX iPortalPolyMaps = ciPortals.Count()>0 ? 1 : 0;
  4782. INDEX iClassifierPolyMaps = ciClassifiers.Count()>0 ? 1 : 0;
  4783. strmAmf.FPrintF_t(" POLYGON_MAPS %d\n", ctSectors+iOccluderPolyMaps+iPortalPolyMaps+iClassifierPolyMaps);
  4784. strmAmf.PutLine_t(" {");
  4785. // dump sectors as separate polygon maps
  4786. {for(INDEX iSector=0; iSector<pbmMip->bm_abscSectors.Count(); iSector++) {
  4787. // count sector polygons
  4788. INDEX ctSectorPolygons = 0;
  4789. CBrushSector *pbs = &pbmMip->bm_abscSectors[iSector];
  4790. {for(INDEX iSurf=0; iSurf<cbpoSurfaces.Count(); iSurf++) {
  4791. CAmfSurface &asSurf = cbpoSurfaces[iSurf];
  4792. for(INDEX iPlg=0; iPlg<asSurf.sf_cbpoPolygons.Count(); iPlg++) {
  4793. CBrushPolygon &bpo = asSurf.sf_cbpoPolygons[iPlg];
  4794. if(bpo.bpo_pbscSector==pbs) {
  4795. CAmfPolygon *amfp = (CAmfPolygon *)bpo.bpo_pspoScreenPolygon;
  4796. INDEX ctNgons = amfp->amfp_aangNgons.Count();
  4797. ctSectorPolygons += ctNgons;
  4798. }
  4799. }
  4800. }}
  4801. strmAmf.FPrintF_t(" POLYGON_MAP_NAME \"sector.Sector_%d\"\n", iSector);
  4802. strmAmf.FPrintF_t(" POLYGONS_COUNT %d\n", ctSectorPolygons);
  4803. strmAmf.PutLine_t(" {");
  4804. // dump polygon indices
  4805. INDEX iPlgGlobal = 0;
  4806. {for(INDEX iSurf=0; iSurf<cbpoSurfaces.Count(); iSurf++) {
  4807. CAmfSurface &asSurf = cbpoSurfaces[iSurf];
  4808. for(INDEX iPlg=0; iPlg<asSurf.sf_cbpoPolygons.Count(); iPlg++) {
  4809. CBrushPolygon &bpo = asSurf.sf_cbpoPolygons[iPlg];
  4810. CAmfPolygon *amfp = (CAmfPolygon *)bpo.bpo_pspoScreenPolygon;
  4811. for(INDEX iNgon=0; iNgon<amfp->amfp_aangNgons.Count(); iNgon++) {
  4812. if(bpo.bpo_pbscSector==pbs) {
  4813. strmAmf.FPrintF_t(" %d;\n", iPlgGlobal);
  4814. }
  4815. iPlgGlobal++;
  4816. }
  4817. }
  4818. }}
  4819. strmAmf.PutLine_t(" }");
  4820. }}
  4821. // dump portals
  4822. if(ciPortals.Count()>0) {
  4823. strmAmf.PutLine_t(" POLYGON_MAP_NAME \"portal.VisPortal\"");
  4824. strmAmf.FPrintF_t(" POLYGONS_COUNT %d\n", ciPortals.Count());
  4825. strmAmf.PutLine_t(" {");
  4826. // dump polygon indices
  4827. {for(INDEX iPlg=0; iPlg<ciPortals.Count(); iPlg++) {
  4828. strmAmf.FPrintF_t(" %d;\n", ciPortals[iPlg]);
  4829. }}
  4830. strmAmf.PutLine_t(" }");
  4831. }
  4832. // dump occluders
  4833. if(ciOccluders.Count()>0) {
  4834. strmAmf.PutLine_t(" POLYGON_MAP_NAME \"portal.VisOccluder\"");
  4835. strmAmf.FPrintF_t(" POLYGONS_COUNT %d\n", ciOccluders.Count());
  4836. strmAmf.PutLine_t(" {");
  4837. // dump polygon indices
  4838. {for(INDEX iPlg=0; iPlg<ciOccluders.Count(); iPlg++) {
  4839. strmAmf.FPrintF_t(" %d;\n", ciOccluders[iPlg]);
  4840. }}
  4841. strmAmf.PutLine_t(" }");
  4842. }
  4843. // dump classifiers
  4844. if(ciClassifiers.Count()>0) {
  4845. strmAmf.PutLine_t(" POLYGON_MAP_NAME \"portal.VisClassifier\"");
  4846. strmAmf.FPrintF_t(" POLYGONS_COUNT %d\n", ciClassifiers.Count());
  4847. strmAmf.PutLine_t(" {");
  4848. // dump polygon indices
  4849. {for(INDEX iPlg=0; iPlg<ciClassifiers.Count(); iPlg++) {
  4850. strmAmf.FPrintF_t(" %d;\n", ciClassifiers[iPlg]);
  4851. }}
  4852. strmAmf.PutLine_t(" }");
  4853. }
  4854. strmAmf.PutLine_t(" }");
  4855. }
  4856. strmAmf.PutLine_t(" }");
  4857. }
  4858. // Tests if entity brushes are valid
  4859. BOOL IsBrushVisible(CEntity &en)
  4860. {
  4861. // fetch first mip
  4862. CBrushMip *pbmMip = en.en_pbrBrush->GetFirstMip();
  4863. if(pbmMip==NULL) {
  4864. return FALSE;
  4865. }
  4866. INDEX ctPolygons = 0;
  4867. for(INDEX iSector=0; iSector<pbmMip->bm_abscSectors.Count(); iSector++) {
  4868. CBrushSector &bs = pbmMip->bm_abscSectors[iSector];
  4869. // for each polygon in the sector
  4870. for(INDEX iPlg=0; iPlg<bs.bsc_abpoPolygons.Count(); iPlg++) {
  4871. CBrushPolygon &bpo = bs.bsc_abpoPolygons[iPlg];
  4872. if(!IsPolygonVisible(bpo)) {
  4873. continue;
  4874. }
  4875. ctPolygons++;
  4876. }
  4877. }
  4878. // if there was no polygons to export
  4879. return ctPolygons>0;
  4880. }
  4881. // Tests if entity brush is empty
  4882. BOOL IsBrushEmpty(CEntity &en)
  4883. {
  4884. // fetch first mip
  4885. CBrushMip *pbmMip = en.en_pbrBrush->GetFirstMip();
  4886. if(pbmMip==NULL) {
  4887. return FALSE;
  4888. }
  4889. INDEX ctPolygons = 0;
  4890. for(INDEX iSector=0; iSector<pbmMip->bm_abscSectors.Count(); iSector++) {
  4891. CBrushSector &bs = pbmMip->bm_abscSectors[iSector];
  4892. if(bs.bsc_abpoPolygons.Count()>0) {
  4893. return FALSE;
  4894. }
  4895. }
  4896. return TRUE;
  4897. }
  4898. // Exports given brush mip into .amf format
  4899. void ExportEntityToAMF_t(CWorldEditorDoc *pDoc, CEntity &en, const CTFileName &fnAmf, BOOL bFieldBrush, BOOL bInvisibleBrush, BOOL bEmptyBrush)
  4900. {
  4901. // fetch first mip
  4902. CBrushMip *pbmMip = en.en_pbrBrush->GetFirstMip();
  4903. // convert all of the brush polygons into ngons
  4904. // for each sector in the brush mip
  4905. {for(INDEX iSector=0; iSector<pbmMip->bm_abscSectors.Count(); iSector++) {
  4906. CBrushSector &bs = pbmMip->bm_abscSectors[iSector];
  4907. // for each polygon in the sector
  4908. for(INDEX iPlg=0; iPlg<bs.bsc_abpoPolygons.Count(); iPlg++) {
  4909. CBrushPolygon &bpo = bs.bsc_abpoPolygons[iPlg];
  4910. // convert it into ngons
  4911. CAmfPolygon *pap = new(CAmfPolygon);
  4912. pap->FromBrushPolygon(&bpo);
  4913. bpo.bpo_pspoScreenPolygon = (CScreenPolygon *) pap;
  4914. }
  4915. }}
  4916. try
  4917. {
  4918. // open .amf file
  4919. CTFileStream strmAmf;
  4920. strmAmf.Create_t( fnAmf, CTStream::CM_TEXT);
  4921. strmAmf.PutLine_t("SE_MESH 1.01");
  4922. strmAmf.PutLine_t("");
  4923. // export visibility for zoning brushes
  4924. INDEX ctLayers = en.en_ulFlags&ENF_ZONING ? 2 : 1;
  4925. if(bEmptyBrush) {
  4926. ctLayers = 0;
  4927. }
  4928. strmAmf.FPrintF_t("LAYERS %d\n", ctLayers);
  4929. strmAmf.PutLine_t("{");
  4930. if(bInvisibleBrush) {
  4931. ExportLayer_t(pDoc, en, ET_RENDERING, pbmMip, strmAmf, "Collision", 0, bFieldBrush, TRUE);
  4932. } else {
  4933. ExportLayer_t(pDoc, en, ET_RENDERING, pbmMip, strmAmf, "Rendering", 0, bFieldBrush, FALSE);
  4934. }
  4935. if(ctLayers>1) {
  4936. ExportLayer_t(pDoc, en, ET_VISIBILITY, pbmMip, strmAmf, "Visibility", 1, bFieldBrush, FALSE);
  4937. }
  4938. strmAmf.PutLine_t("}");
  4939. }
  4940. catch( char *err_str) {
  4941. AfxMessageBox( CString(err_str));
  4942. }
  4943. }
  4944. void CWorldEditorDoc::OnExportEntities()
  4945. {
  4946. CStaticStackArray<CTString> astrNeddedSmc;
  4947. try
  4948. {
  4949. CTFileName fnWorld=m_woWorld.wo_fnmFileName;
  4950. // "entity placement and names"
  4951. CTFileName fnExport=fnWorld.FileDir()+fnWorld.FileName()+".awf";
  4952. // open text file
  4953. CTFileStream strmFile;
  4954. strmFile.Create_t( fnExport, CTStream::CM_TEXT);
  4955. // prepare container of entities to export
  4956. CDynamicContainer<CEntity> dcEntitiesToExport;
  4957. // for each entity in world
  4958. {FOREACHINDYNAMICCONTAINER(m_woWorld.wo_cenEntities, CEntity, iten)
  4959. {
  4960. CEntity &en=*iten;
  4961. dcEntitiesToExport.Add(&en);
  4962. }}
  4963. // write count of entities
  4964. CTString strLine;
  4965. strLine.PrintF("ENTITIES %d {", dcEntitiesToExport.Count());
  4966. strmFile.PutLine_t(strLine);
  4967. // for each entity in world
  4968. FOREACHINDYNAMICCONTAINER(dcEntitiesToExport, CEntity, iten)
  4969. {
  4970. CEntity &en=*iten;
  4971. // obtain entity class ptr
  4972. CDLLEntityClass *pdecDLLClass = en.GetClass()->ec_pdecDLLClass;
  4973. // obtain position
  4974. FLOAT3D vPos=en.GetPlacement().pl_PositionVector;
  4975. FLOAT3D vRot=en.GetPlacement().pl_OrientationAngle;
  4976. // count entity attributes
  4977. INDEX ctEntityAttributes = 0;
  4978. // for all classes in hierarchy of this entity
  4979. CDLLEntityClass *pdecDLLClassCount = pdecDLLClass;
  4980. for(;pdecDLLClassCount!=NULL; pdecDLLClassCount = pdecDLLClassCount->dec_pdecBase) {
  4981. // for all properties
  4982. for(INDEX iProperty=0; iProperty<pdecDLLClassCount->dec_ctProperties; iProperty++) {
  4983. CEntityProperty *pepProperty = &pdecDLLClassCount->dec_aepProperties[iProperty];
  4984. if(pepProperty->ep_strName!=CTString("")) {
  4985. ctEntityAttributes++;
  4986. }
  4987. }
  4988. }
  4989. // if render type is brush
  4990. if( (en.en_RenderType==CEntity::RT_BRUSH || en.en_RenderType==CEntity::RT_FIELDBRUSH) && en.en_pbrBrush!=NULL) {
  4991. // add one more property because we will add one that will hint "InvisibleBrush"
  4992. ctEntityAttributes++;
  4993. }
  4994. // write count of entity attributes (add 5 fixed ones, for class, ID, spawn flags, parent, name, pos, rot)
  4995. strLine.PrintF(" ENTITY_ATTRIBUTES %d {", ctEntityAttributes+7);
  4996. strmFile.PutLine_t(strLine);
  4997. // entity class
  4998. strLine.PrintF(" \"ENTITYCLASS\" = string(\"SS1 %s\");", pdecDLLClass->dec_strName);
  4999. strmFile.PutLine_t(strLine);
  5000. // entity ID
  5001. strLine.PrintF(" \"ID\" = long(%d);", en.en_ulID);
  5002. strmFile.PutLine_t(strLine);
  5003. // entity spawn flags
  5004. strLine.PrintF(" \"SS1_SPAWN_FLAGS\" = long(%d);", en.en_ulSpawnFlags);
  5005. strmFile.PutLine_t(strLine);
  5006. // entity name
  5007. CTString strName=en.GetName();
  5008. if(strName=="") {
  5009. strName="<unnamed>";
  5010. }
  5011. SLONG idParent=-1;
  5012. CEntity *penParent = en.GetParent();
  5013. if(penParent!=NULL) {
  5014. idParent = penParent->en_ulID;
  5015. }
  5016. strLine.PrintF(" \"PARENT\" = long(%d);", idParent);
  5017. strmFile.PutLine_t(strLine);
  5018. strLine.PrintF(" \"NAME\" = string(\"%s\");", strName);
  5019. strmFile.PutLine_t(strLine);
  5020. // position
  5021. strLine.PrintF(" \"POS\" = float3(%f, %f, %f);", vPos(1), vPos(2), vPos(3));
  5022. strmFile.PutLine_t(strLine);
  5023. // rotation
  5024. strLine.PrintF(" \"ROT\" = float3(%f, %f, %f);", vRot(1), vRot(2), vRot(3));
  5025. strmFile.PutLine_t(strLine);
  5026. // for all classes in hierarchy of this entity
  5027. for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase) {
  5028. // for all properties
  5029. for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++) {
  5030. CEntityProperty *pepProperty = &pdecDLLClass->dec_aepProperties[iProperty];
  5031. if(pepProperty->ep_strName==CTString("")) {
  5032. continue;
  5033. }
  5034. // enumerator
  5035. if( pepProperty->ep_eptType == CEntityProperty::EPT_ENUM) {
  5036. INDEX iEnumValue = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, INDEX);
  5037. strLine.PrintF(" \"%s\" = long(%d);", pepProperty->ep_strName, iEnumValue);
  5038. strmFile.PutLine_t(strLine);
  5039. }
  5040. // boolean
  5041. if( pepProperty->ep_eptType == CEntityProperty::EPT_BOOL) {
  5042. INDEX iBooleanValue = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, BOOL);
  5043. strLine.PrintF(" \"%s\" = long(%d);", pepProperty->ep_strName, iBooleanValue);
  5044. strmFile.PutLine_t(strLine);
  5045. }
  5046. // float value
  5047. if( pepProperty->ep_eptType == CEntityProperty::EPT_FLOAT) {
  5048. FLOAT fFloat = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, FLOAT);
  5049. strLine.PrintF(" \"%s\" = float(%f);", pepProperty->ep_strName, fFloat);
  5050. strmFile.PutLine_t(strLine);
  5051. }
  5052. // color
  5053. if( pepProperty->ep_eptType == CEntityProperty::EPT_COLOR) {
  5054. COLOR colValue = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, COLOR);
  5055. strLine.PrintF(" \"%s\" = long(%d);", pepProperty->ep_strName, colValue);
  5056. strmFile.PutLine_t(strLine);
  5057. }
  5058. // string
  5059. if( pepProperty->ep_eptType == CEntityProperty::EPT_STRING) {
  5060. CTString strString = FixQuotes(ENTITYPROPERTY( &en, pepProperty->ep_slOffset, CTString));
  5061. strLine.PrintF(" \"%s\" = string(\"%s\");", pepProperty->ep_strName, strString);
  5062. strmFile.PutLine_t(strLine);
  5063. }
  5064. // range
  5065. if( pepProperty->ep_eptType == CEntityProperty::EPT_RANGE) {
  5066. FLOAT fFloat = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, FLOAT);
  5067. strLine.PrintF(" \"%s\" = float(%f);", pepProperty->ep_strName, fFloat);
  5068. strmFile.PutLine_t(strLine);
  5069. }
  5070. // entity ptr
  5071. if( pepProperty->ep_eptType == CEntityProperty::EPT_ENTITYPTR) {
  5072. // get the pointer
  5073. CEntityPointer &penPointed = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, CEntityPointer);
  5074. SLONG ulID = penPointed==NULL ? -1 : penPointed->en_ulID;
  5075. strLine.PrintF(" \"%s\" = long(%d);", pepProperty->ep_strName, ulID);
  5076. strmFile.PutLine_t(strLine);
  5077. }
  5078. // file name
  5079. if( pepProperty->ep_eptType == CEntityProperty::EPT_FILENAME ||
  5080. pepProperty->ep_eptType == CEntityProperty::EPT_FILENAMENODEP) {
  5081. CTFileName fnmFile = CorrectSlashes(ENTITYPROPERTY( &en, pepProperty->ep_slOffset, CTFileName));
  5082. strLine.PrintF(" \"%s\" = string(\"%s\");", pepProperty->ep_strName, fnmFile);
  5083. strmFile.PutLine_t(strLine);
  5084. }
  5085. // index value
  5086. if( pepProperty->ep_eptType == CEntityProperty::EPT_INDEX) {
  5087. INDEX iValue = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, INDEX);
  5088. strLine.PrintF(" \"%s\" = long(%d);", pepProperty->ep_strName, iValue);
  5089. strmFile.PutLine_t(strLine);
  5090. }
  5091. // animation value
  5092. if( pepProperty->ep_eptType == CEntityProperty::EPT_ANIMATION) {
  5093. INDEX iValue = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, INDEX);
  5094. strLine.PrintF(" \"%s\" = long(%d);", pepProperty->ep_strName, iValue);
  5095. strmFile.PutLine_t(strLine);
  5096. }
  5097. // illumination type
  5098. if( pepProperty->ep_eptType == CEntityProperty::EPT_ILLUMINATIONTYPE) {
  5099. INDEX iValue = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, INDEX);
  5100. strLine.PrintF(" \"%s\" = long(%d);", pepProperty->ep_strName, iValue);
  5101. strmFile.PutLine_t(strLine);
  5102. }
  5103. // angle
  5104. if( pepProperty->ep_eptType == CEntityProperty::EPT_ANGLE) {
  5105. INDEX iValue = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, INDEX);
  5106. strLine.PrintF(" \"%s\" = long(%d);", pepProperty->ep_strName, iValue);
  5107. strmFile.PutLine_t(strLine);
  5108. }
  5109. // float 3D
  5110. if( pepProperty->ep_eptType == CEntityProperty::EPT_FLOAT3D) {
  5111. FLOAT3D vValue = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, FLOAT3D);
  5112. strLine.PrintF(" \"%s\" = float3(%f, %f, %f);", pepProperty->ep_strName, vValue(1), vValue(2), vValue(3));
  5113. strmFile.PutLine_t(strLine);
  5114. }
  5115. // angle 3D
  5116. if( pepProperty->ep_eptType == CEntityProperty::EPT_ANGLE3D) {
  5117. ANGLE3D vAngle3D = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, ANGLE3D);
  5118. strLine.PrintF(" \"%s\" = float3(%f, %f, %f);", pepProperty->ep_strName, vAngle3D(1), vAngle3D(2), vAngle3D(3));
  5119. strmFile.PutLine_t(strLine);
  5120. }
  5121. // string trans
  5122. if( pepProperty->ep_eptType == CEntityProperty::EPT_STRINGTRANS) {
  5123. CTString strString = FixQuotes(ENTITYPROPERTY( &en, pepProperty->ep_slOffset, CTString));
  5124. strLine.PrintF(" \"%s\" = string(\"%s\");", pepProperty->ep_strName, strString);
  5125. strmFile.PutLine_t(strLine);
  5126. }
  5127. // flags
  5128. if( pepProperty->ep_eptType == CEntityProperty::EPT_FLAGS) {
  5129. ULONG ulValue = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, ULONG);
  5130. strLine.PrintF(" \"%s\" = long(%d);", pepProperty->ep_strName, ulValue);
  5131. strmFile.PutLine_t(strLine);
  5132. }
  5133. // EPT_FLOATAABBOX3D - bounding box
  5134. if( pepProperty->ep_eptType == CEntityProperty::EPT_FLOATAABBOX3D) {
  5135. // get value for bounding box
  5136. FLOATaabbox3D bboxOld = ENTITYPROPERTY( &en, pepProperty->ep_slOffset, FLOATaabbox3D);
  5137. FLOAT3D vMin = bboxOld.Min();
  5138. FLOAT3D vMax = bboxOld.Max();
  5139. strLine.PrintF(" \"%s\" = box(%f, %f, %f),(%f, %f, %f);", pepProperty->ep_strName,
  5140. vMin(1), vMin(2), vMin(3), vMax(1), vMax(2), vMax(3));
  5141. strmFile.PutLine_t(strLine);
  5142. }
  5143. }
  5144. }
  5145. // if render type is brush
  5146. if( (en.en_RenderType==CEntity::RT_BRUSH || en.en_RenderType==CEntity::RT_FIELDBRUSH) && en.en_pbrBrush!=NULL) {
  5147. // add one "fake" property that will hint "invisible brush" status
  5148. BOOL bInvisibleBrush = !IsBrushVisible(en);
  5149. BOOL bEmptyBrush = IsBrushEmpty(en);
  5150. strLine.PrintF(" \"Hint: Invisible brush\" = long(%d);", bInvisibleBrush);
  5151. strmFile.PutLine_t(strLine);
  5152. // ".amf" file name
  5153. CTString strEntityID;
  5154. strEntityID.PrintF("%d", en.en_ulID);
  5155. CTFileName fnAmf;
  5156. fnAmf.PrintF("%s_%s.amf", fnWorld.FileDir()+fnWorld.FileName(), strEntityID);
  5157. BOOL bFieldBrush = en.en_RenderType==CEntity::RT_FIELDBRUSH;
  5158. ExportEntityToAMF_t(this, en, fnAmf, bFieldBrush, bInvisibleBrush, bEmptyBrush);
  5159. }
  5160. // close entity attributes section
  5161. strLine.PrintF(" }");
  5162. strmFile.PutLine_t(strLine);
  5163. }
  5164. // close entity section
  5165. strLine.PrintF("}");
  5166. strmFile.PutLine_t(strLine);
  5167. // "entity placement and names"
  5168. CTFileName fnSml=fnWorld.FileDir()+fnWorld.FileName()+".sml";
  5169. // open text file
  5170. CTFileStream strmSmlFile;
  5171. strmSmlFile.Create_t( fnSml, CTStream::CM_TEXT);
  5172. // save needed smc's
  5173. for(INDEX iSmc=0; iSmc<astrNeddedSmc.Count(); iSmc++)
  5174. {
  5175. strmSmlFile.PutLine_t(astrNeddedSmc[iSmc]);
  5176. }
  5177. AfxMessageBox(L"Entities exported!", MB_OK|MB_ICONINFORMATION);
  5178. }
  5179. catch( char *err_str)
  5180. {
  5181. AfxMessageBox( CString(err_str));
  5182. }
  5183. }