12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753 |
- package hide.comp;
- import hrt.prefab.Reference;
- import h3d.scene.Mesh;
- import h3d.col.FPoint;
- import h3d.col.Ray;
- import h3d.col.PolygonBuffer;
- import h3d.prim.HMDModel;
- import h3d.col.Collider.OptimizedCollider;
- import h3d.Vector;
- import hxd.Key as K;
- import hxd.Math as M;
- import hrt.prefab.Prefab as PrefabElement;
- import hrt.prefab.Object2D;
- import hrt.prefab.Object3D;
- import h3d.scene.Object;
- import hide.comp.cdb.DataFiles;
- import hide.view.CameraController.CamController as CameraController;
- enum SelectMode {
- /**
- Update tree, add undo command
- **/
- Default;
- /**
- Update tree only
- **/
- NoHistory;
- /**
- Add undo but don't update tree
- **/
- NoTree;
- /**
- Don't refresh tree and don't undo command
- **/
- Nothing;
- }
- @:access(hide.comp.SceneEditor)
- class SceneEditorContext extends hide.prefab.EditContext {
- public var editor(default, null) : SceneEditor;
- public var elements : Array<PrefabElement>;
- public var rootObjects(default, null): Array<Object>;
- public var rootObjects2D(default, null): Array<h2d.Object>;
- public var rootElements(default, null): Array<PrefabElement>;
- public function new(ctx, elts, editor) {
- super(ctx);
- this.editor = editor;
- this.updates = editor.updates;
- this.elements = elts;
- rootObjects = [];
- rootObjects2D = [];
- rootElements = [];
- cleanups = [];
- for(elt in elements) {
- // var obj3d = elt.to(Object3D);
- // if(obj3d == null) continue;
- if(!SceneEditor.hasParent(elt, elements)) {
- rootElements.push(elt);
- var ctx = getContext(elt);
- if(ctx != null) {
- var pobj = elt.parent == editor.sceneData ? ctx.shared.root3d : getContextRec(elt.parent).local3d;
- var pobj2d = elt.parent == editor.sceneData ? ctx.shared.root2d : getContextRec(elt.parent).local2d;
- if( ctx.local3d != pobj )
- rootObjects.push(ctx.local3d);
- if( ctx.local2d != pobj2d )
- rootObjects2D.push(ctx.local2d);
- }
- }
- }
- }
- override function screenToGround(x:Float, y:Float, ?forPrefab:hrt.prefab.Prefab) {
- return editor.screenToGround(x, y, forPrefab);
- }
- override function positionToGroundZ(x:Float, y:Float, ?forPrefab:hrt.prefab.Prefab):Float {
- return editor.getZ(x, y, forPrefab);
- }
- override function getCurrentProps( p : hrt.prefab.Prefab ) {
- var cur = editor.curEdit;
- return cur != null && cur.elements[0] == p ? editor.properties.element : new Element();
- }
- function getContextRec( p : hrt.prefab.Prefab ) {
- if( p == null )
- return editor.context;
- var c = editor.context.shared.contexts.get(p);
- if( c == null )
- return getContextRec(p.parent);
- return c;
- }
- override function rebuildProperties() {
- editor.scene.setCurrent();
- editor.selectElements(elements, NoHistory);
- }
- override function rebuildPrefab( p : hrt.prefab.Prefab ) {
- // refresh all for now
- editor.refresh();
- }
- public function cleanup() {
- for( c in cleanups.copy() )
- c();
- cleanups = [];
- }
- override function onChange(p : PrefabElement, pname: String) {
- super.onChange(p, pname);
- editor.onPrefabChange(p, pname);
- }
- }
- enum RefreshMode {
- Partial;
- Full;
- }
- typedef CustomPivot = { elt : PrefabElement, mesh : Mesh, locPos : Vector };
- class SceneEditor {
- public var tree : hide.comp.IconTree<PrefabElement>;
- public var scene : hide.comp.Scene;
- public var properties : hide.comp.PropsEditor;
- public var context(default,null) : hrt.prefab.Context;
- public var curEdit(default, null) : SceneEditorContext;
- public var snapToGround = false;
- public var localTransform = true;
- public var cameraController : h3d.scene.CameraController;
- public var cameraController2D : hide.view.l3d.CameraController2D;
- public var editorDisplay(default,set) : Bool;
- public var camera2D(default,set) : Bool = false;
- public var objectAreSelectable = true;
- // Windows default is 0.5
- public var dblClickDuration = 0.2;
- var updates : Array<Float -> Void> = [];
- var showGizmo = true;
- var gizmo : hide.view.l3d.Gizmo;
- var gizmo2d : hide.view.l3d.Gizmo2D;
- static var customPivot : CustomPivot;
- var interactives : Map<PrefabElement, hxd.SceneEvents.Interactive>;
- var ide : hide.Ide;
- public var event(default, null) : hxd.WaitEvent;
- var hideList : Map<PrefabElement, Bool> = new Map();
- var undo(get, null):hide.ui.UndoHistory;
- function get_undo() { return view.undo; }
- public var view(default, null) : hide.view.FileView;
- var sceneData : PrefabElement;
- var lastRenderProps : hrt.prefab.RenderProps;
- var focusedSinceSelect = false;
- public function new(view, data) {
- ide = hide.Ide.inst;
- this.view = view;
- this.sceneData = data;
- event = new hxd.WaitEvent();
- var propsEl = new Element('<div class="props"></div>');
- properties = new hide.comp.PropsEditor(undo,null,propsEl);
- properties.saveDisplayKey = view.saveDisplayKey + "/properties";
- tree = new hide.comp.IconTree();
- tree.async = false;
- tree.autoOpenNodes = false;
- var sceneEl = new Element('<div class="heaps-scene"></div>');
- scene = new hide.comp.Scene(view.config, null, sceneEl);
- scene.editor = this;
- scene.onReady = onSceneReady;
- scene.onResize = function() {
- if( cameraController2D != null ) cameraController2D.toTarget();
- onResize();
- };
- context = new hrt.prefab.Context();
- context.shared = new hide.prefab.ContextShared(scene);
- context.shared.currentPath = view.state.path;
- context.init();
- editorDisplay = true;
- view.keys.register("copy", onCopy);
- view.keys.register("paste", onPaste);
- view.keys.register("cancel", deselect);
- view.keys.register("selectAll", selectAll);
- view.keys.register("duplicate", duplicate.bind(true));
- view.keys.register("duplicateInPlace", duplicate.bind(false));
- view.keys.register("group", groupSelection);
- view.keys.register("delete", () -> deleteElements(curEdit.rootElements));
- view.keys.register("search", function() tree.openFilter());
- view.keys.register("rename", function () {
- if(curEdit.rootElements.length > 0)
- tree.editNode(curEdit.rootElements[0]);
- });
- view.keys.register("sceneeditor.focus", focusSelection);
- view.keys.register("sceneeditor.lasso", startLassoSelect);
- view.keys.register("sceneeditor.hide", function() {
- var isHidden = isHidden(curEdit.rootElements[0]);
- setVisible(curEdit.elements, isHidden);
- });
- view.keys.register("sceneeditor.isolate", function() { isolate(curEdit.elements); });
- view.keys.register("sceneeditor.showAll", function() { setVisible(context.shared.elements(), true); });
- view.keys.register("sceneeditor.selectParent", function() {
- if(curEdit.rootElements.length > 0) {
- var p = curEdit.rootElements[0].parent;
- if( p != null && p != sceneData ) selectElements([p]);
- }
- });
- view.keys.register("sceneeditor.reparent", function() {
- if(curEdit.rootElements.length > 1) {
- var children = curEdit.rootElements.copy();
- var parent = children.pop();
- reparentElement(children, parent, 0);
- }
- });
- view.keys.register("sceneeditor.editPivot", editPivot);
- view.keys.register("sceneeditor.gatherToMouse", gatherToMouse);
- // Load display state
- {
- var all = sceneData.flatten(hrt.prefab.Prefab);
- var list = @:privateAccess view.getDisplayState("hideList");
- if(list != null) {
- var m = [for(i in (list:Array<Dynamic>)) i => true];
- for(p in all) {
- if(m.exists(p.getAbsPath(true)))
- hideList.set(p, true);
- }
- }
- }
- }
- public function dispose() {
- scene.dispose();
- tree.dispose();
- }
- function set_camera2D(b) {
- if( cameraController != null ) cameraController.visible = !b;
- if( cameraController2D != null ) cameraController2D.visible = b;
- return camera2D = b;
- }
- public function onResourceChanged(lib : hxd.fmt.hmd.Library) {
- var models = sceneData.findAll(p -> Std.downcast(p, PrefabElement));
- var toRebuild : Array<PrefabElement> = [];
- for(m in models) {
- @:privateAccess if(m.source == lib.resource.entry.path) {
- if (toRebuild.indexOf(m) < 0) {
- toRebuild.push(m);
- }
- }
- }
- for(m in toRebuild) {
- removeInstance(m);
- makeInstance(m);
- }
- }
- public dynamic function onResize() {
- }
- function set_editorDisplay(v) {
- context.shared.editorDisplay = v;
- return editorDisplay = v;
- }
- public function getSelection() {
- return curEdit != null ? curEdit.elements : [];
- }
- function makeCamController() : h3d.scene.CameraController {
- var c = new CameraController(scene.s3d, this);
- c.friction = 0.9;
- c.panSpeed = 0.6;
- c.zoomAmount = 1.05;
- c.smooth = 0.7;
- c.minDistance = 1;
- return c;
- }
- public function setFullScreen( b : Bool ) {
- view.fullScreen = b;
- if( b ) {
- view.element.find(".tabs").hide();
- } else {
- view.element.find(".tabs").show();
- }
- }
- function makeCamController2D() {
- return new hide.view.l3d.CameraController2D(context.shared.root2d);
- }
- function focusSelection() {
- if(curEdit.rootObjects.length > 0) {
- var bnds = new h3d.col.Bounds();
- var centroid = new h3d.Vector();
- for(obj in curEdit.rootObjects) {
- centroid = centroid.add(obj.getAbsPos().getPosition());
- bnds.add(obj.getBounds());
- }
- if(!bnds.isEmpty()) {
- var s = bnds.toSphere();
- var r = focusedSinceSelect ? s.r * 4.0 : null;
- cameraController.set(r, null, null, s.getCenter());
- }
- else {
- centroid.scale3(1.0 / curEdit.rootObjects.length);
- cameraController.set(centroid.toPoint());
- }
- }
- for(obj in curEdit.rootElements)
- tree.revealNode(obj);
- focusedSinceSelect = true;
- }
- function getAvailableTags(p: PrefabElement) : Array<{id: String, color: String}>{
- return null;
- }
- public function getTag(p: PrefabElement) {
- if(p.props != null) {
- var tagId = Reflect.field(p.props, "tag");
- if(tagId != null) {
- var tags = getAvailableTags(p);
- if(tags != null)
- return Lambda.find(tags, t -> t.id == tagId);
- }
- }
- return null;
- }
- public function setTag(p: PrefabElement, tag: String) {
- if(p.props == null)
- p.props = {};
- var prevVal = getTag(p);
- Reflect.setField(p.props, "tag", tag);
- onPrefabChange(p, "tag");
- undo.change(Field(p.props, "tag", prevVal), function() {
- onPrefabChange(p, "tag");
- });
- }
- function getTagMenu(p: PrefabElement) : Array<hide.comp.ContextMenu.ContextMenuItem> {
- var tags = getAvailableTags(p);
- if(tags == null) return null;
- var ret = [];
- for(tag in tags) {
- var style = 'background-color: ${tag.color};';
- ret.push({
- label: '<span class="tag-disp-expand"><span class="tag-disp" style="$style">${tag.id}</span></span>',
- click: function () {
- if(getTag(p) == tag)
- setTag(p, null);
- else
- setTag(p, tag.id);
- },
- checked: getTag(p) == tag,
- stayOpen: true,
- });
- }
- return ret;
- }
- function onSceneReady() {
- tree.saveDisplayKey = view.saveDisplayKey + '/tree';
- scene.s2d.addChild(context.shared.root2d);
- scene.s3d.addChild(context.shared.root3d);
- gizmo = new hide.view.l3d.Gizmo(scene);
- gizmo.moveStep = view.config.get("sceneeditor.gridSnapStep");
- gizmo2d = new hide.view.l3d.Gizmo2D();
- scene.s2d.add(gizmo2d, 1); // over local3d
- cameraController = makeCamController();
- cameraController.onClick = function(e) {
- switch( e.button ) {
- case K.MOUSE_RIGHT:
- selectNewObject();
- case K.MOUSE_LEFT:
- selectElements([]);
- }
- };
- if (!camera2D)
- resetCamera();
- var cam = @:privateAccess view.getDisplayState("Camera");
- if( cam != null ) {
- scene.s3d.camera.pos.set(cam.x, cam.y, cam.z);
- scene.s3d.camera.target.set(cam.tx, cam.ty, cam.tz);
- }
- cameraController.loadFromCamera();
- scene.s2d.defaultSmooth = true;
- context.shared.root2d.x = scene.s2d.width >> 1;
- context.shared.root2d.y = scene.s2d.height >> 1;
- cameraController2D = makeCamController2D();
- cameraController2D.onClick = cameraController.onClick;
- var cam2d = @:privateAccess view.getDisplayState("Camera2D");
- if( cam2d != null ) {
- context.shared.root2d.x = scene.s2d.width*0.5 + cam2d.x;
- context.shared.root2d.y = scene.s2d.height*0.5 + cam2d.y;
- context.shared.root2d.setScale(cam2d.z);
- }
- cameraController2D.loadFromScene();
- if (camera2D)
- resetCamera();
- scene.onUpdate = update;
- // BUILD scene tree
- var icons = new Map();
- var iconsConfig = view.config.get("sceneeditor.icons");
- for( f in Reflect.fields(iconsConfig) )
- icons.set(f, Reflect.field(iconsConfig,f));
- function makeItem(o:PrefabElement, ?state) : hide.comp.IconTree.IconTreeItem<PrefabElement> {
- var p = o.getHideProps();
- var ref = o.to(Reference);
- var icon = p.icon;
- var ct = o.getCdbType();
- if( ct != null && icons.exists(ct) )
- icon = icons.get(ct);
- var r : hide.comp.IconTree.IconTreeItem<PrefabElement> = {
- value : o,
- text : o.name,
- icon : "ico ico-"+icon,
- children : o.children.length > 0 || (ref != null && @:privateAccess ref.editMode),
- state: state
- };
- return r;
- }
- tree.get = function(o:PrefabElement) {
- var objs = o == null ? sceneData.children : Lambda.array(o);
- if( o != null && o.getHideProps().hideChildren != null ) {
- var hideChildren = o.getHideProps().hideChildren;
- var visibleObjs = [];
- for( o in objs ) {
- if( hideChildren(o) )
- continue;
- visibleObjs.push(o);
- }
- objs = visibleObjs;
- }
- var ref = o == null ? null : o.to(Reference);
- @:privateAccess if( ref != null && ref.editMode && ref.ref != null ) {
- for( c in ref.ref )
- objs.push(c);
- }
- var out = [for( o in objs ) makeItem(o)];
- return out;
- };
- function ctxMenu(tree, e) {
- e.preventDefault();
- var current = tree.getCurrentOver();
- if(current != null && (curEdit == null || curEdit.elements.indexOf(current) < 0)) {
- selectElements([current]);
- }
- var newItems = getNewContextMenu(current);
- var menuItems : Array<hide.comp.ContextMenu.ContextMenuItem> = [
- { label : "New...", menu : newItems },
- ];
- var actionItems : Array<hide.comp.ContextMenu.ContextMenuItem> = [
- { label : "Rename", enabled : current != null, click : function() tree.editNode(current), keys : view.config.get("key.rename") },
- { label : "Delete", enabled : current != null, click : function() deleteElements(curEdit.rootElements), keys : view.config.get("key.delete") },
- { label : "Duplicate", enabled : current != null, click : duplicate.bind(false), keys : view.config.get("key.duplicateInPlace") },
- ];
- var isObj = current != null && (current.to(Object3D) != null || current.to(Object2D) != null);
- var isRef = isReference(current);
- if( current != null ) {
- menuItems.push({ label : "Enable", checked : current.enabled, stayOpen : true, click : function() setEnabled(curEdit.elements, !current.enabled) });
- menuItems.push({ label : "Editor only", checked : current.editorOnly, stayOpen : true, click : function() setEditorOnly(curEdit.elements, !current.editorOnly) });
- }
- if( isObj ) {
- menuItems = menuItems.concat([
- { label : "Show in editor" , checked : !isHidden(current), stayOpen : true, click : function() setVisible(curEdit.elements, isHidden(current)), keys : view.config.get("key.sceneeditor.hide") },
- { label : "Locked", checked : current.locked, stayOpen : true, click : function() {
- current.locked = !current.locked;
- setLock(curEdit.elements, current.locked);
- } },
- { label : "Select all", click : selectAll, keys : view.config.get("key.selectAll") },
- { label : "Select children", enabled : current != null, click : function() selectElements(current.flatten()) },
- ]);
- if( !isRef )
- actionItems = actionItems.concat([
- { label : "Isolate", click : function() isolate(curEdit.elements), keys : view.config.get("key.sceneeditor.isolate") },
- { label : "Group", enabled : curEdit != null && canGroupSelection(), click : groupSelection, keys : view.config.get("key.group") },
- ]);
- }
- if( current != null ) {
- var menu = getTagMenu(current);
- if(menu != null)
- menuItems.push({ label : "Tag", menu: menu });
- }
- menuItems.push({ isSeparator : true, label : "" });
- new hide.comp.ContextMenu(menuItems.concat(actionItems));
- };
- tree.element.parent().contextmenu(ctxMenu.bind(tree));
- tree.allowRename = true;
- tree.init();
- tree.onClick = function(e, _) {
- selectElements(tree.getSelection(), NoTree);
- }
- tree.onDblClick = function(e) {
- focusSelection();
- return true;
- }
- tree.onRename = function(e, name) {
- var oldName = e.name;
- e.name = name;
- undo.change(Field(e, "name", oldName), function() {
- tree.refresh();
- refreshScene();
- });
- refreshScene();
- return true;
- };
- tree.onAllowMove = function(e, to) return checkAllowParent({cl : e.type, inf : e.getHideProps()}, to);
- // Batch tree.onMove, which is called for every node moved, causing problems with undo and refresh
- {
- var movetimer : haxe.Timer = null;
- var moved = [];
- tree.onMove = function(e, to, idx) {
- if(movetimer != null) {
- movetimer.stop();
- }
- moved.push(e);
- movetimer = haxe.Timer.delay(function() {
- reparentElement(moved, to, idx);
- movetimer = null;
- moved = [];
- }, 50);
- }
- }
- tree.applyStyle = function(p, el) applyTreeStyle(p, el);
- selectElements([]);
- refresh();
- this.camera2D = camera2D;
- }
- function checkAllowParent(prefabInf, prefabParent : PrefabElement) : Bool {
- if (prefabInf.inf.allowParent == null)
- if (prefabParent == null || prefabParent.getHideProps().allowChildren == null || (prefabParent.getHideProps().allowChildren != null && prefabParent.getHideProps().allowChildren(prefabInf.cl)))
- return true;
- else return false;
- if (prefabParent == null)
- if (prefabInf.inf.allowParent(sceneData))
- return true;
- else return false;
- if ((prefabParent.getHideProps().allowChildren == null || prefabParent.getHideProps().allowChildren != null && prefabParent.getHideProps().allowChildren(prefabInf.cl))
- && prefabInf.inf.allowParent(prefabParent))
- return true;
- return false;
- };
- public function refresh( ?mode: RefreshMode, ?callb: Void->Void) {
- if(mode == null || mode == Full) refreshScene();
- refreshTree(callb);
- }
- public function collapseTree() {
- tree.collapseAll();
- }
- function refreshTree( ?callb ) {
- tree.refresh(function() {
- var all = sceneData.flatten(hrt.prefab.Prefab);
- for(elt in all) {
- var el = tree.getElement(elt);
- if(el == null) continue;
- applyTreeStyle(elt, el);
- }
- if(callb != null) callb();
- });
- }
- function refreshProps() {
- selectElements(curEdit.elements, Nothing);
- }
- public function refreshScene() {
- var sh = context.shared;
- sh.root3d.remove();
- sh.root2d.remove();
- for( c in sh.contexts )
- if( c != null && c.cleanup != null )
- c.cleanup();
- context.shared = sh = new hide.prefab.ContextShared(scene);
- sh.editorDisplay = editorDisplay;
- sh.currentPath = view.state.path;
- scene.s3d.addChild(sh.root3d);
- scene.s2d.addChild(sh.root2d);
- sh.root2d.addChild(cameraController2D);
- scene.setCurrent();
- scene.onResize();
- context.init();
- sceneData.make(context);
- var bgcol = scene.engine.backgroundColor;
- scene.init();
- scene.engine.backgroundColor = bgcol;
- refreshInteractives();
- var all = sceneData.flatten(hrt.prefab.Prefab);
- for(elt in all)
- applySceneStyle(elt);
- if( lastRenderProps == null ) {
- var renderProps = getAllWithRefs(sceneData,hrt.prefab.RenderProps);
- for( r in renderProps )
- if( @:privateAccess r.isDefault ) {
- lastRenderProps = r;
- break;
- }
- if( lastRenderProps == null )
- lastRenderProps = renderProps[0];
- }
- if( lastRenderProps != null )
- lastRenderProps.applyProps(scene.s3d.renderer);
- else {
- var refPrefab = new Reference();
- refPrefab.source = view.config.getLocal("scene.renderProps");
- refPrefab.makeInstance(context);
- if( @:privateAccess refPrefab.ref != null ) {
- var renderProps = @:privateAccess refPrefab.ref.get(hrt.prefab.RenderProps);
- if( renderProps != null )
- renderProps.applyProps(scene.s3d.renderer);
- }
- }
- onRefresh();
- }
- function getAllWithRefs<T:hrt.prefab.Prefab>( p : hrt.prefab.Prefab, cl : Class<T>, ?arr : Array<T> ) : Array<T> {
- if( arr == null ) arr = [];
- var v = p.to(cl);
- if( v != null ) arr.push(v);
- for( c in p.children )
- getAllWithRefs(c, cl, arr);
- var ref = p.to(Reference);
- @:privateAccess if( ref != null && ref.ref != null ) getAllWithRefs(ref.ref, cl, arr);
- return arr;
- }
- public dynamic function onRefresh() {
- }
- function makeInteractive( elt : PrefabElement, ?shared : hrt.prefab.ContextShared ) {
- if( shared == null )
- shared = context.shared;
- var ctx = shared.contexts[elt];
- if( ctx == null )
- return;
- var int = elt.makeInteractive(ctx);
- if( int != null ) {
- initInteractive(elt,cast int);
- if( isLocked(elt) ) toggleInteractive(elt, false);
- }
- var ref = Std.downcast(elt,Reference);
- @:privateAccess if( ref != null && ref.editMode ) {
- var ctx = shared.getRef(elt);
- for( p in ref.ref.flatten() )
- makeInteractive(p, ctx);
- }
- }
- function toggleInteractive( e : PrefabElement, visible : Bool ) {
- var int = getInteractive(e);
- if( int == null ) return;
- var i2d = Std.downcast(int,h2d.Interactive);
- var i3d = Std.downcast(int,h3d.scene.Interactive);
- if( i2d != null ) i2d.visible = visible;
- if( i3d != null ) i3d.visible = visible;
- }
- function initInteractive( elt : PrefabElement, int : {
- dynamic function onPush(e:hxd.Event) : Void;
- dynamic function onMove(e:hxd.Event) : Void;
- dynamic function onRelease(e:hxd.Event) : Void;
- dynamic function onClick(e:hxd.Event) : Void;
- function handleEvent(e:hxd.Event) : Void;
- function preventClick() : Void;
- } ) {
- if( int == null ) return;
- var startDrag = null;
- var curDrag = null;
- var dragBtn = -1;
- var lastPush : Array<Float> = null;
- var i3d = Std.downcast(int, h3d.scene.Interactive);
- var i2d = Std.downcast(int, h2d.Interactive);
- var prevClickTime : Float = -1e20;
- int.onClick = function(e) {
- if(e.button == K.MOUSE_RIGHT) {
- var dist = hxd.Math.distance(scene.s2d.mouseX - lastPush[0], scene.s2d.mouseY - lastPush[1]);
- if( dist > 5 ) return;
- selectNewObject();
- e.propagate = false;
- return;
- }
- }
- int.onPush = function(e) {
- if( e.button == K.MOUSE_MIDDLE ) return;
- startDrag = [scene.s2d.mouseX, scene.s2d.mouseY];
- if( e.button == K.MOUSE_RIGHT )
- lastPush = startDrag;
- dragBtn = e.button;
- if( e.button == K.MOUSE_LEFT ) {
- var elts = null;
- if(K.isDown(K.SHIFT)) {
- if(Type.getClass(elt.parent) == hrt.prefab.Object3D)
- elts = [elt.parent];
- else
- elts = elt.parent.children;
- }
- else
- elts = [elt];
- if(K.isDown(K.CTRL)) {
- var current = curEdit.elements.copy();
- if(current.indexOf(elt) < 0) {
- for(e in elts) {
- if(current.indexOf(e) < 0)
- current.push(e);
- }
- }
- else {
- for(e in elts)
- current.remove(e);
- }
- selectElements(current);
- }
- else
- selectElements(elts);
- }
- // ensure we get onMove even if outside our interactive, allow fast click'n'drag
- if( e.button == K.MOUSE_LEFT ) {
- scene.sevents.startCapture(int.handleEvent);
- e.propagate = false;
- }
- };
- int.onRelease = function(e) {
- if( e.button == K.MOUSE_MIDDLE ) return;
- startDrag = null;
- curDrag = null;
- dragBtn = -1;
- if( e.button == K.MOUSE_LEFT ) {
- scene.sevents.stopCapture();
- e.propagate = false;
- var curTime = haxe.Timer.stamp();
- if( curTime - prevClickTime < dblClickDuration && !(elt.getHideProps().isGround)) {
- focusSelection();
- prevClickTime = -1e20;
- }
- else
- prevClickTime = curTime;
- }
- }
- int.onMove = function(e) {
- if(startDrag != null && hxd.Math.distance(startDrag[0] - scene.s2d.mouseX, startDrag[1] - scene.s2d.mouseY) > 5 ) {
- if(dragBtn == K.MOUSE_LEFT ) {
- if( i3d != null ) {
- moveGizmoToSelection();
- gizmo.startMove(MoveXY);
- }
- if( i2d != null ) {
- moveGizmoToSelection();
- gizmo2d.startMove(Pan);
- }
- }
- int.preventClick();
- startDrag = null;
- }
- }
- interactives.set(elt,cast int);
- }
- function selectNewObject() {
- if( !objectAreSelectable )
- return;
- var parentEl = sceneData;
- // for now always create at scene root, not `curEdit.rootElements[0];`
- var group = getParentGroup(parentEl);
- if( group != null )
- parentEl = group;
- var originPt = getPickTransform(parentEl).getPosition();
- var newItems = getNewContextMenu(parentEl, function(newElt) {
- var newObj3d = Std.downcast(newElt, Object3D);
- if(newObj3d != null) {
- var newPos = new h3d.Matrix();
- newPos.identity();
- newPos.setPosition(originPt);
- var invParent = getObject(parentEl).getAbsPos().clone();
- invParent.invert();
- newPos.multiply(newPos, invParent);
- newObj3d.setTransform(newPos);
- }
- var newObj2d = Std.downcast(newElt, Object2D);
- if( newObj2d != null ) {
- var pt = new h2d.col.Point(scene.s2d.mouseX, scene.s2d.mouseY);
- var l2d = getContext(parentEl).local2d;
- l2d.globalToLocal(pt);
- newObj2d.x = pt.x;
- newObj2d.y = pt.y;
- }
- });
- var menuItems : Array<hide.comp.ContextMenu.ContextMenuItem> = [
- { label : "New...", menu : newItems },
- { isSeparator : true, label : "" },
- {
- label : "Gather here",
- click : gatherToMouse,
- enabled : (curEdit.rootElements.length > 0),
- keys : view.config.get("key.sceneeditor.gatherToMouse"),
- },
- ];
- new hide.comp.ContextMenu(menuItems);
- }
- public function refreshInteractive(elt : PrefabElement) {
- var int = interactives.get(elt);
- if(int != null) {
- var i3d = Std.downcast(int, h3d.scene.Interactive);
- if( i3d != null ) i3d.remove() else cast(int,h2d.Interactive).remove();
- interactives.remove(elt);
- }
- makeInteractive(elt);
- }
- function refreshInteractives() {
- var contexts = context.shared.contexts;
- interactives = new Map();
- var all = contexts.keys();
- for(elt in all) {
- makeInteractive(elt);
- }
- }
- function setupGizmo() {
- if(curEdit == null) return;
- var posQuant = view.config.get("sceneeditor.xyzPrecision");
- var scaleQuant = view.config.get("sceneeditor.scalePrecision");
- var rotQuant = view.config.get("sceneeditor.rotatePrecision");
- inline function quantize(x: Float, step: Float) {
- if(step > 0) {
- x = Math.round(x / step) * step;
- x = untyped parseFloat(x.toFixed(5)); // Snap to closest nicely displayed float :cold_sweat:
- }
- return x;
- }
- gizmo.onStartMove = function(mode) {
- var objects3d = [for(o in curEdit.rootElements) {
- var obj3d = o.to(hrt.prefab.Object3D);
- if(obj3d != null)
- obj3d;
- }];
- var sceneObjs = [for(o in objects3d) getContext(o).local3d];
- var pivotPt = getPivot(sceneObjs);
- var pivot = new h3d.Matrix();
- pivot.initTranslation(pivotPt.x, pivotPt.y, pivotPt.z);
- var invPivot = pivot.clone();
- invPivot.invert();
- var localMats = [for(o in sceneObjs) {
- var m = worldMat(o);
- m.multiply(m, invPivot);
- m;
- }];
- var prevState = [for(o in objects3d) o.saveTransform()];
- gizmo.onMove = function(translate: h3d.Vector, rot: h3d.Quat, scale: h3d.Vector) {
- var transf = new h3d.Matrix();
- transf.identity();
- if(rot != null)
- rot.toMatrix(transf);
- if(translate != null)
- transf.translate(translate.x, translate.y, translate.z);
- for(i in 0...sceneObjs.length) {
- var newMat = localMats[i].clone();
- newMat.multiply(newMat, transf);
- newMat.multiply(newMat, pivot);
- if(snapToGround && mode == MoveXY) {
- newMat.tz = getZ(newMat.tx, newMat.ty);
- }
- var invParent = sceneObjs[i].parent.getAbsPos().clone();
- invParent.invert();
- newMat.multiply(newMat, invParent);
- if(scale != null) {
- newMat.prependScale(scale.x, scale.y, scale.z);
- }
- var obj3d = objects3d[i];
- var rot = newMat.getEulerAngles();
- obj3d.x = quantize(newMat.tx, posQuant);
- obj3d.y = quantize(newMat.ty, posQuant);
- obj3d.z = quantize(newMat.tz, posQuant);
- obj3d.rotationX = quantize(M.radToDeg(rot.x), rotQuant);
- obj3d.rotationY = quantize(M.radToDeg(rot.y), rotQuant);
- obj3d.rotationZ = quantize(M.radToDeg(rot.z), rotQuant);
- if(scale != null) {
- inline function scaleSnap(x: Float) {
- if(K.isDown(K.CTRL)) {
- var step = K.isDown(K.SHIFT) ? 0.5 : 1.0;
- x = Math.round(x / step) * step;
- }
- return x;
- }
- var s = newMat.getScale();
- obj3d.scaleX = quantize(scaleSnap(s.x), scaleQuant);
- obj3d.scaleY = quantize(scaleSnap(s.y), scaleQuant);
- obj3d.scaleZ = quantize(scaleSnap(s.z), scaleQuant);
- }
- obj3d.applyTransform(sceneObjs[i]);
- }
- }
- gizmo.onFinishMove = function() {
- var newState = [for(o in objects3d) o.saveTransform()];
- refreshProps();
- undo.change(Custom(function(undo) {
- if( undo ) {
- for(i in 0...objects3d.length) {
- objects3d[i].loadTransform(prevState[i]);
- objects3d[i].applyTransform(sceneObjs[i]);
- }
- refreshProps();
- }
- else {
- for(i in 0...objects3d.length) {
- objects3d[i].loadTransform(newState[i]);
- objects3d[i].applyTransform(sceneObjs[i]);
- }
- refreshProps();
- }
- for(o in objects3d)
- o.updateInstance(getContext(o));
- }));
- for(o in objects3d)
- o.updateInstance(getContext(o));
- }
- }
- gizmo2d.onStartMove = function(mode) {
- var objects2d = [for(o in curEdit.rootElements) {
- var obj = o.to(hrt.prefab.Object2D);
- if(obj != null) obj;
- }];
- var sceneObjs = [for(o in objects2d) getContext(o).local2d];
- var pivot = getPivot2D(sceneObjs);
- var center = pivot.getCenter();
- var prevState = [for(o in objects2d) o.saveTransform()];
- var startPos = [for(o in sceneObjs) o.getAbsPos()];
- gizmo2d.onMove = function(t) {
- t.x = Math.round(t.x);
- t.y = Math.round(t.y);
- for(i in 0...sceneObjs.length) {
- var pos = startPos[i].clone();
- var obj = objects2d[i];
- switch( mode ) {
- case Pan:
- pos.x += t.x;
- pos.y += t.y;
- case ScaleX, ScaleY, Scale:
- // no inherited rotation
- if( pos.b == 0 && pos.c == 0 ) {
- pos.x -= center.x;
- pos.y -= center.y;
- pos.x *= t.scaleX;
- pos.y *= t.scaleY;
- pos.x += center.x;
- pos.y += center.y;
- obj.scaleX = quantize(t.scaleX * prevState[i].scaleX, scaleQuant);
- obj.scaleY = quantize(t.scaleY * prevState[i].scaleY, scaleQuant);
- } else {
- var m2 = new h2d.col.Matrix();
- m2.initScale(t.scaleX, t.scaleY);
- pos.x -= center.x;
- pos.y -= center.y;
- pos.multiply(pos,m2);
- pos.x += center.x;
- pos.y += center.y;
- var s = pos.getScale();
- obj.scaleX = quantize(s.x, scaleQuant);
- obj.scaleY = quantize(s.y, scaleQuant);
- }
- case Rotation:
- pos.x -= center.x;
- pos.y -= center.y;
- var ca = Math.cos(t.rotation);
- var sa = Math.sin(t.rotation);
- var px = pos.x * ca - pos.y * sa;
- var py = pos.x * sa + pos.y * ca;
- pos.x = px + center.x;
- pos.y = py + center.y;
- var r = M.degToRad(prevState[i].rotation) + t.rotation;
- r = quantize(M.radToDeg(r), rotQuant);
- obj.rotation = r;
- }
- var pt = pos.getPosition();
- sceneObjs[i].parent.globalToLocal(pt);
- obj.x = quantize(pt.x, posQuant);
- obj.y = quantize(pt.y, posQuant);
- obj.applyTransform(sceneObjs[i]);
- }
- };
- gizmo2d.onFinishMove = function() {
- var newState = [for(o in objects2d) o.saveTransform()];
- refreshProps();
- undo.change(Custom(function(undo) {
- if( undo ) {
- for(i in 0...objects2d.length) {
- objects2d[i].loadTransform(prevState[i]);
- objects2d[i].applyTransform(sceneObjs[i]);
- }
- refreshProps();
- }
- else {
- for(i in 0...objects2d.length) {
- objects2d[i].loadTransform(newState[i]);
- objects2d[i].applyTransform(sceneObjs[i]);
- }
- refreshProps();
- }
- for(o in objects2d)
- o.updateInstance(getContext(o));
- }));
- for(o in objects2d)
- o.updateInstance(getContext(o));
- };
- };
- }
- function moveGizmoToSelection() {
- // Snap Gizmo at center of objects
- gizmo.getRotationQuat().identity();
- if(curEdit != null && curEdit.rootObjects.length > 0) {
- var pos = getPivot(curEdit.rootObjects);
- gizmo.visible = showGizmo;
- gizmo.setPosition(pos.x, pos.y, pos.z);
- if(curEdit.rootObjects.length == 1 && (localTransform || K.isDown(K.ALT))) {
- var obj = curEdit.rootObjects[0];
- var mat = worldMat(obj);
- var s = mat.getScale();
- if(s.x != 0 && s.y != 0 && s.z != 0) {
- mat.prependScale(1.0 / s.x, 1.0 / s.y, 1.0 / s.z);
- gizmo.getRotationQuat().initRotateMatrix(mat);
- }
- }
- }
- else {
- gizmo.visible = false;
- }
- if( curEdit != null && curEdit.rootObjects2D.length > 0 && !gizmo.visible ) {
- var pos = getPivot2D(curEdit.rootObjects2D);
- gizmo2d.visible = showGizmo;
- gizmo2d.setPosition(pos.getCenter().x, pos.getCenter().y);
- gizmo2d.setSize(pos.width, pos.height);
- } else {
- gizmo2d.visible = false;
- }
- }
- var inLassoMode = false;
- function startLassoSelect() {
- if(inLassoMode) {
- inLassoMode = false;
- return;
- }
- scene.setCurrent();
- inLassoMode = true;
- var g = new h2d.Object(scene.s2d);
- var overlay = new h2d.Bitmap(h2d.Tile.fromColor(0xffffff, 10000, 10000, 0.1), g);
- var intOverlay = new h2d.Interactive(10000, 10000, scene.s2d);
- var lastPt = new h2d.col.Point(scene.s2d.mouseX, scene.s2d.mouseY);
- var points : h2d.col.Polygon = [lastPt];
- var polyG = new h2d.Graphics(g);
- event.waitUntil(function(dt) {
- var curPt = new h2d.col.Point(scene.s2d.mouseX, scene.s2d.mouseY);
- if(curPt.distance(lastPt) > 3.0) {
- points.push(curPt);
- polyG.clear();
- polyG.beginFill(0xff0000, 0.5);
- polyG.lineStyle(1.0, 0, 1.0);
- polyG.moveTo(points[0].x, points[0].y);
- for(i in 1...points.length) {
- polyG.lineTo(points[i].x, points[i].y);
- }
- polyG.endFill();
- lastPt = curPt;
- }
- var finish = false;
- if(!inLassoMode || K.isDown(K.ESCAPE) || K.isDown(K.MOUSE_RIGHT)) {
- finish = true;
- }
- if(K.isDown(K.MOUSE_LEFT)) {
- var contexts = context.shared.contexts;
- var all = getAllSelectable3D();
- var inside = [];
- for(elt in all) {
- if(elt.to(Object3D) == null)
- continue;
- var ctx = contexts[elt];
- var o = ctx.local3d;
- if(o == null || !o.visible)
- continue;
- var absPos = o.getAbsPos();
- var screenPos = worldToScreen(absPos.tx, absPos.ty, absPos.tz);
- if(points.contains(screenPos, false)) {
- inside.push(elt);
- }
- }
- selectElements(inside);
- finish = true;
- }
- if(finish) {
- intOverlay.remove();
- g.remove();
- inLassoMode = false;
- return true;
- }
- return false;
- });
- }
- public function onPrefabChange(p: PrefabElement, ?pname: String) {
- var model = p.to(hrt.prefab.Model);
- if(model != null && pname == "source") {
- refreshScene();
- return;
- }
- if(p != sceneData) {
- var el = tree.getElement(p);
- if( el != null && el.toggleClass != null ) applyTreeStyle(p, el, pname);
- }
- applySceneStyle(p);
- }
- public function applyTreeStyle(p: PrefabElement, el: Element, ?pname: String) {
- var obj3d = p.to(Object3D);
- el.toggleClass("disabled", !p.enabled);
- var aEl = el.find("a").first();
- var tag = getTag(p);
- if(tag != null) {
- aEl.css("background", tag.color);
- el.find("ul").first().css("background", tag.color + "80");
- }
- else if(pname == "tag") {
- aEl.css("background", "");
- el.find("ul").first().css("background", "");
- }
- if(obj3d != null) {
- el.toggleClass("disabled", !p.enabled || !obj3d.visible);
- el.toggleClass("hidden", isHidden(obj3d));
- el.toggleClass("locked", p.locked);
- el.toggleClass("editorOnly", p.editorOnly);
- var visTog = el.find(".visibility-toggle").first();
- if(visTog.length == 0) {
- visTog = new Element('<i class="ico ico-eye visibility-toggle" title = "Hide (${view.config.get("key.sceneeditor.hide")})"/>').insertAfter(el.find("a.jstree-anchor").first());
- visTog.click(function(e) {
- if(curEdit.elements.indexOf(obj3d) >= 0)
- setVisible(curEdit.elements, isHidden(obj3d));
- else
- setVisible([obj3d], isHidden(obj3d));
- e.preventDefault();
- e.stopPropagation();
- });
- visTog.dblclick(function(e) {
- e.preventDefault();
- e.stopPropagation();
- });
- }
- var lockTog = el.find(".lock-toggle").first();
- if(lockTog.length == 0) {
- lockTog = new Element('<i class="ico ico-lock lock-toggle"/>').insertAfter(el.find("a.jstree-anchor").first());
- lockTog.click(function(e) {
- if(curEdit.elements.indexOf(obj3d) >= 0)
- setLock(curEdit.elements, !obj3d.locked);
- else
- setLock([obj3d], !obj3d.locked);
- e.preventDefault();
- e.stopPropagation();
- });
- lockTog.dblclick(function(e) {
- e.preventDefault();
- e.stopPropagation();
- });
- }
- lockTog.css({visibility: p.locked ? "visible" : "hidden"});
- }
- }
- public function applySceneStyle(p: PrefabElement) {
- var obj3d = p.to(Object3D);
- if(obj3d != null) {
- var visible = obj3d.visible && !isHidden(obj3d);
- for(ctx in getContexts(obj3d)) {
- ctx.local3d.visible = visible;
- }
- }
- }
- public function getInteractives(elt : PrefabElement) {
- var r = [getInteractive(elt)];
- for(c in elt.children) {
- r = r.concat(getInteractives(c));
- }
- return r;
- }
- public function getInteractive(elt: PrefabElement) {
- return interactives.get(elt);
- }
- public function getContext(elt : PrefabElement, ?shared : hrt.prefab.ContextShared) {
- if(elt == null) return null;
- if( shared == null ) shared = context.shared;
- var ctx = shared.contexts.get(elt);
- if( ctx == null ) {
- for( r in @:privateAccess shared.refsContexts ) {
- ctx = getContext(elt, r);
- if( ctx != null ) break;
- }
- }
- if( ctx == null && elt == sceneData )
- ctx = context;
- return ctx;
- }
- public function getContexts(elt: PrefabElement) {
- if(elt == null)
- return null;
- return context.shared.getContexts(elt);
- }
- public function getObject(elt: PrefabElement) {
- var ctx = getContext(elt);
- if(ctx != null)
- return ctx.local3d;
- return context.shared.root3d;
- }
- public function getSelfObject(elt: PrefabElement) {
- var ctx = getContext(elt);
- var parentCtx = getContext(elt.parent);
- if(ctx == null || parentCtx == null) return null;
- if(ctx.local3d != parentCtx.local3d)
- return ctx.local3d;
- return null;
- }
- function removeInstance(elt : PrefabElement) {
- var result = true;
- var contexts = context.shared.contexts;
- function recRemove(e: PrefabElement) {
- for(c in e.children)
- recRemove(c);
- var int = interactives.get(e);
- if(int != null) {
- var i3d = Std.downcast(int, h3d.scene.Interactive);
- if( i3d != null ) i3d.remove() else cast(int,h2d.Interactive).remove();
- interactives.remove(e);
- }
- for(ctx in getContexts(e)) {
- if(!e.removeInstance(ctx))
- result = false;
- contexts.remove(e);
- }
- }
- recRemove(elt);
- return result;
- }
- function makeInstance(elt: PrefabElement) {
- scene.setCurrent();
- var p = elt.parent;
- var parentCtx = null;
- while( p != null ) {
- parentCtx = getContext(p);
- if( parentCtx != null ) break;
- p = p.parent;
- }
- var ctx = elt.make(parentCtx);
- for( p in elt.flatten() )
- makeInteractive(p);
- scene.init(ctx.local3d);
- }
- function refreshParents( elts : Array<PrefabElement> ) {
- var parents = new Map();
- for( e in elts ) {
- if( e.parent == null ) throw e+" is missing parent";
- parents.set(e.parent, true);
- }
- for( p in parents.keys() ) {
- var h = p.getHideProps();
- if( h.onChildListChanged != null ) h.onChildListChanged();
- }
- if( lastRenderProps != null && parents.exists(lastRenderProps) )
- lastRenderProps.applyProps(scene.s3d.renderer);
- }
- public function addElements(elts : Array<PrefabElement>, selectObj : Bool = true, doRefresh : Bool = true, enableUndo = true) {
- for (e in elts) {
- makeInstance(e);
- }
- if (doRefresh) {
- refresh(Partial, if (selectObj) () -> selectElements(elts, NoHistory) else null);
- refreshParents(elts);
- }
- if( !enableUndo )
- return;
- undo.change(Custom(function(undo) {
- var fullRefresh = false;
- if(undo) {
- selectElements([], NoHistory);
- for (e in elts) {
- if(!removeInstance(e))
- fullRefresh = true;
- e.parent.children.remove(e);
- }
- refresh(fullRefresh ? Full : Partial);
- }
- else {
- for (e in elts) {
- e.parent.children.push(e);
- makeInstance(e);
- }
- refresh(Partial, () -> selectElements(elts,NoHistory));
- refreshParents(elts);
- }
- }));
- }
- function makeCdbProps( e : PrefabElement, type : cdb.Sheet ) {
- var props = type.getDefaults();
- Reflect.setField(props, "$cdbtype", DataFiles.getTypeName(type));
- if( type.idCol != null && !type.idCol.opt ) {
- var id = new haxe.io.Path(view.state.path).file;
- id = id.charAt(0).toUpperCase() + id.substr(1);
- id += "_"+e.name;
- Reflect.setField(props, type.idCol.name, id);
- }
- return props;
- }
- function fillProps( edit, e : PrefabElement ) {
- e.edit(edit);
- var typeName = e.getCdbType();
- if( typeName == null && e.props != null )
- return; // don't allow CDB data with props already used !
- var types = DataFiles.getAvailableTypes();
- if( types.length == 0 )
- return;
- var group = new hide.Element('
- <div class="group" name="CDB">
- <dl>
- <dt>
- <div class="btn-cdb-large ico ico-file-text"></div>
- Type
- </dt>
- <dd><select><option value="">- No props -</option></select></dd>
- </div>
- ');
- var cdbLarge = @:privateAccess view.getDisplayState("cdbLarge");
- var detachable = new DetachablePanel();
- detachable.saveDisplayKey = "detachedCdb";
- group.find(".btn-cdb-large").click((_) -> {
- cdbLarge = !cdbLarge;
- @:privateAccess view.saveDisplayState("cdbLarge", cdbLarge);
- group.toggleClass("cdb-large", cdbLarge);
- detachable.setDetached(cdbLarge);
- });
- group.toggleClass("cdb-large", cdbLarge == true);
- detachable.setDetached(cdbLarge == true);
- var select = group.find("select");
- for(t in types) {
- var id = DataFiles.getTypeName(t);
- new hide.Element("<option>").attr("value", id).text(id).appendTo(select);
- }
- var curType = DataFiles.resolveType(typeName);
- if(curType != null) select.val(DataFiles.getTypeName(curType));
- function changeProps(props: Dynamic) {
- properties.undo.change(Field(e, "props", e.props), ()->edit.rebuildProperties());
- e.props = props;
- edit.onChange(e, "props");
- edit.rebuildProperties();
- }
- select.change(function(v) {
- var typeId = select.val();
- if(typeId == null || typeId == "") {
- changeProps(null);
- return;
- }
- var props = makeCdbProps(e, DataFiles.resolveType(typeId));
- changeProps(props);
- });
- edit.properties.add(group);
- if(curType != null) {
- var props = new hide.Element('<div></div>').appendTo(group.find(".content"));
- var fileRef = view.state.path;
- var ctx = context.shared.getContexts(e)[0];
- if( ctx != null )
- fileRef = ctx.shared.currentPath;
- detachable.element.appendTo(props);
- var editor = new hide.comp.cdb.ObjEditor(curType, view.config, e.props, fileRef, detachable.element);
- editor.undo = properties.undo;
- editor.fileView = view;
- editor.onChange = function(pname) {
- edit.onChange(e, 'props.$pname');
- var e = Std.downcast(e, Object3D);
- if( e != null ) {
- for( ctx in context.shared.getContexts(e) )
- e.addEditorUI(ctx);
- }
- }
- }
- }
- public function showProps(e: PrefabElement) {
- scene.setCurrent();
- var edit = makeEditContext([e]);
- properties.clear();
- fillProps(edit, e);
- }
- function setElementSelected( p : PrefabElement, ctx : hrt.prefab.Context, b : Bool ) {
- return p.setSelected(ctx, b);
- }
- public function selectElements( elts : Array<PrefabElement>, ?mode : SelectMode = Default ) {
- function impl(elts,mode:SelectMode) {
- scene.setCurrent();
- if( curEdit != null )
- curEdit.cleanup();
- var edit = makeEditContext(elts);
- if (elts.length == 0 || (customPivot != null && customPivot.elt != edit.rootElements[0])) {
- customPivot = null;
- }
- properties.clear();
- if( elts.length > 0 ) fillProps(edit, elts[0]);
- switch( mode ) {
- case Default, NoHistory:
- tree.setSelection(elts);
- case Nothing, NoTree:
- }
- function getSelContext( e : PrefabElement ) {
- var ectx = context.shared.contexts.get(e);
- if( ectx == null ) ectx = context.shared.getContexts(e)[0];
- if( ectx == null ) ectx = context;
- return ectx;
- }
- var map = new Map<PrefabElement,Bool>();
- function selectRec(e : PrefabElement, b:Bool) {
- if( map.exists(e) )
- return;
- map.set(e, true);
- if(setElementSelected(e, getSelContext(e), b))
- for( e in e.children )
- selectRec(e,b);
- }
- for( e in elts )
- selectRec(e, true);
- edit.cleanups.push(function() {
- for( e in map.keys() ) {
- if( hasBeenRemoved(e) ) continue;
- setElementSelected(e, getSelContext(e), false);
- }
- });
- curEdit = edit;
- showGizmo = false;
- for( e in elts )
- if( !isLocked(e) ) {
- showGizmo = true;
- break;
- }
- setupGizmo();
- }
- var prev : Array<PrefabElement> = null;
- if( curEdit != null && mode.match(Default|NoTree) ) {
- prev = curEdit.rootElements.copy();
- undo.change(Custom(function(u) {
- if(u) impl(prev,NoHistory);
- else impl(elts,NoHistory);
- }),true);
- }
- impl(elts,mode);
- if( prev == null || curEdit.rootElements.length != prev.length ) {
- focusedSinceSelect = false;
- return;
- }
- for( i in 0...curEdit.rootElements.length ) {
- if( curEdit.rootElements[i] != prev[i] ) {
- focusedSinceSelect = false;
- return;
- }
- }
- }
- function hasBeenRemoved( e : hrt.prefab.Prefab ) {
- var root = sceneData;
- var eltCtx = context.shared.getContexts(e)[0];
- if( eltCtx != null && eltCtx.shared.parent != null ) {
- if( hasBeenRemoved(eltCtx.shared.parent.prefab) )
- return true;
- root = null;
- }
- while( e != null && e != root ) {
- if( e.parent != null && e.parent.children.indexOf(e) < 0 )
- return true;
- e = e.parent;
- }
- return e != root;
- }
- public function resetCamera(distanceFactor = 1.5) {
- if( camera2D ) {
- cameraController2D.initFromScene();
- } else {
- scene.s3d.camera.zNear = scene.s3d.camera.zFar = 0;
- scene.s3d.camera.fovY = 25; // reset to default fov
- scene.resetCamera(distanceFactor);
- cameraController.lockZPlanes = scene.s3d.camera.zNear != 0;
- cameraController.loadFromCamera();
- }
- }
- public function getPickTransform(parent: PrefabElement) {
- var proj = screenToGround(scene.s2d.mouseX, scene.s2d.mouseY);
- if(proj == null) return null;
- var localMat = new h3d.Matrix();
- localMat.initTranslation(proj.x, proj.y, proj.z);
- if(parent == null)
- return localMat;
- var parentMat = worldMat(getObject(parent));
- parentMat.invert();
- localMat.multiply(localMat, parentMat);
- return localMat;
- }
- public function onDragDrop( items : Array<String>, isDrop : Bool ) {
- var pickedEl = js.Browser.document.elementFromPoint(ide.mouseX, ide.mouseY);
- var propEl = properties.element[0];
- while( pickedEl != null ) {
- if( pickedEl == propEl )
- return properties.onDragDrop(items, isDrop);
- pickedEl = pickedEl.parentElement;
- }
- var supported = @:privateAccess hrt.prefab.Library.registeredExtensions;
- var paths = [];
- for(path in items) {
- var ext = haxe.io.Path.extension(path).toLowerCase();
- if( supported.exists(ext) || ext == "fbx" || ext == "hmd" )
- paths.push(path);
- }
- if( paths.length == 0 )
- return false;
- if(isDrop)
- dropElements(paths, sceneData);
- return true;
- }
- function dropElements(paths: Array<String>, parent: PrefabElement) {
- scene.setCurrent();
- var localMat = getPickTransform(parent);
- if(localMat == null) return;
- localMat.tx = hxd.Math.round(localMat.tx * 10) / 10;
- localMat.ty = hxd.Math.round(localMat.ty * 10) / 10;
- localMat.tz = hxd.Math.floor(localMat.tz * 10) / 10;
- var elts: Array<PrefabElement> = [];
- for(path in paths) {
- var obj3d : Object3D;
- var relative = ide.makeRelative(path);
- if(hrt.prefab.Library.getPrefabType(path) != null) {
- var ref = new hrt.prefab.Reference(parent);
- ref.source = relative;
- obj3d = ref;
- obj3d.name = new haxe.io.Path(relative).file;
- }
- else {
- obj3d = new hrt.prefab.Model(parent);
- obj3d.source = relative;
- }
- obj3d.setTransform(localMat);
- autoName(obj3d);
- elts.push(obj3d);
- }
- for(e in elts)
- makeInstance(e);
- refresh(Partial, () -> selectElements(elts));
- undo.change(Custom(function(undo) {
- if( undo ) {
- var fullRefresh = false;
- for(e in elts) {
- if(!removeInstance(e))
- fullRefresh = true;
- parent.children.remove(e);
- }
- refresh(fullRefresh ? Full : Partial);
- }
- else {
- for(e in elts) {
- parent.children.push(e);
- makeInstance(e);
- }
- refresh(Partial);
- }
- }));
- }
- function gatherToMouse() {
- var prevParent = sceneData;
- var localMat = getPickTransform(prevParent);
- if( localMat == null ) return;
- var objects3d = [for(o in curEdit.rootElements) {
- var obj3d = o.to(hrt.prefab.Object3D);
- if( obj3d != null && !obj3d.locked )
- obj3d;
- }];
- if( objects3d.length == 0 ) return;
- var sceneObjs = [for(o in objects3d) getContext(o).local3d];
- var prevState = [for(o in objects3d) o.saveTransform()];
- for( obj3d in objects3d ) {
- if( obj3d.parent != prevParent ) {
- prevParent = obj3d.parent;
- localMat = getPickTransform(prevParent);
- }
- if( localMat == null ) continue;
- obj3d.x = hxd.Math.round(localMat.tx * 10) / 10;
- obj3d.y = hxd.Math.round(localMat.ty * 10) / 10;
- obj3d.z = hxd.Math.floor(localMat.tz * 10) / 10;
- obj3d.updateInstance(getContext(obj3d));
- }
- var newState = [for(o in objects3d) o.saveTransform()];
- refreshProps();
- undo.change(Custom(function(undo) {
- if( undo ) {
- for(i in 0...objects3d.length) {
- objects3d[i].loadTransform(prevState[i]);
- objects3d[i].applyTransform(sceneObjs[i]);
- }
- refreshProps();
- }
- else {
- for(i in 0...objects3d.length) {
- objects3d[i].loadTransform(newState[i]);
- objects3d[i].applyTransform(sceneObjs[i]);
- }
- refreshProps();
- }
- for(o in objects3d)
- o.updateInstance(getContext(o));
- }));
- }
- function canGroupSelection() {
- var elts = curEdit.rootElements;
- if(elts.length == 0)
- return false;
- if(elts.length == 1)
- return true;
- // Only allow grouping of sibling elements
- var parent = elts[0].parent;
- for(e in elts)
- if(e.parent != parent)
- return false;
- return true;
- }
- function groupSelection() {
- if(!canGroupSelection())
- return;
- var elts = curEdit.rootElements;
- var parent = elts[0].parent;
- var parentMat = worldMat(parent);
- var invParentMat = parentMat.clone();
- invParentMat.invert();
- var pivot = new h3d.Vector();
- {
- var count = 0;
- for(elt in curEdit.rootElements) {
- var m = worldMat(elt);
- if(m != null) {
- pivot = pivot.add(m.getPosition());
- ++count;
- }
- }
- pivot.scale3(1.0 / count);
- }
- var local = new h3d.Matrix();
- local.initTranslation(pivot.x, pivot.y, pivot.z);
- local.multiply(local, invParentMat);
- var group = new hrt.prefab.Object3D(parent);
- @:privateAccess group.type = "object";
- autoName(group);
- group.x = local.tx;
- group.y = local.ty;
- group.z = local.tz;
- var parentCtx = getContext(parent);
- if(parentCtx == null)
- parentCtx = context;
- group.make(parentCtx);
- var groupCtx = getContext(group);
- var effectFunc = reparentImpl(elts, group, 0);
- undo.change(Custom(function(undo) {
- if(undo) {
- group.parent = null;
- context.shared.contexts.remove(group);
- effectFunc(true);
- }
- else {
- group.parent = parent;
- context.shared.contexts.set(group, groupCtx);
- effectFunc(false);
- }
- if(undo)
- refresh(()->selectElements([],NoHistory));
- else
- refresh(()->selectElements([group],NoHistory));
- }));
- refresh(effectFunc(false) ? Full : Partial, () -> selectElements([group],NoHistory));
- }
- function onCopy() {
- if(curEdit == null) return;
- if(curEdit.rootElements.length == 1) {
- view.setClipboard(curEdit.rootElements[0].saveData(), "prefab");
- }
- else {
- var lib = new hrt.prefab.Library();
- for(e in curEdit.rootElements) {
- lib.children.push(e);
- }
- view.setClipboard(lib.saveData(), "library");
- }
- }
- function onPaste() {
- var parent : PrefabElement = sceneData;
- if(curEdit != null && curEdit.elements.length > 0) {
- parent = curEdit.elements[0];
- }
- var obj = haxe.Json.parse(haxe.Json.stringify(view.getClipboard("prefab")));
- if(obj != null) {
- var p = hrt.prefab.Prefab.loadPrefab(obj, parent);
- autoName(p);
- addElements([p]);
- }
- else {
- obj = view.getClipboard("library");
- if(obj != null) {
- var lib = hrt.prefab.Prefab.loadPrefab(obj);
- for(c in lib.children) {
- autoName(c);
- parent.children.push(c);
- }
- addElements(lib.children);
- }
- }
- }
- public function isVisible(elt: PrefabElement) {
- if(elt == sceneData)
- return true;
- var o = elt.to(Object3D);
- if(o == null)
- return true;
- return o.visible && !isHidden(o) && (elt.parent != null ? isVisible(elt.parent) : true);
- }
- public function getAllSelectable3D() : Array<PrefabElement> {
- var ret = [];
- for(elt in interactives.keys()) {
- var i = interactives.get(elt);
- var p : h3d.scene.Object = Std.downcast(i, h3d.scene.Interactive);
- if( p == null )
- continue;
- while( p != null && p.visible )
- p = p.parent;
- if( p != null ) continue;
- ret.push(elt);
- }
- return ret;
- }
- public function selectAll() {
- selectElements(getAllSelectable3D());
- }
- public function deselect() {
- selectElements([]);
- }
- public function isSelected( p : PrefabElement ) {
- return curEdit != null && curEdit.elements.indexOf(p) >= 0;
- }
- public function setEnabled(elements : Array<PrefabElement>, enable: Bool) {
- var old = [for(e in elements) e.enabled];
- function apply(on) {
- for(i in 0...elements.length) {
- elements[i].enabled = on ? enable : old[i];
- onPrefabChange(elements[i]);
- }
- refreshScene();
- }
- apply(true);
- undo.change(Custom(function(undo) {
- if(undo)
- apply(false);
- else
- apply(true);
- }));
- }
- public function setEditorOnly(elements : Array<PrefabElement>, enable: Bool) {
- var old = [for(e in elements) e.editorOnly];
- function apply(on) {
- for(i in 0...elements.length) {
- elements[i].editorOnly = on ? enable : old[i];
- onPrefabChange(elements[i]);
- }
- refreshScene();
- }
- apply(true);
- undo.change(Custom(function(undo) {
- if(undo)
- apply(false);
- else
- apply(true);
- }));
- }
- public function isHidden(e: PrefabElement) {
- if(e == null)
- return false;
- return hideList.exists(e);
- }
- public function isLocked(e: PrefabElement) {
- while( e != null ) {
- if( e.locked ) return true;
- e = e.parent;
- }
- return false;
- }
- function saveDisplayState() {
- var state = [for (h in hideList.keys()) h.getAbsPath(true)];
- @:privateAccess view.saveDisplayState("hideList", state);
- }
- public function setVisible(elements : Array<PrefabElement>, visible: Bool) {
- for(o in elements) {
- for(c in o.flatten(Object3D)) {
- if( visible )
- hideList.remove(c);
- else
- hideList.set(o, true);
- var el = tree.getElement(c);
- if( el != null ) applyTreeStyle(c, el);
- applySceneStyle(c);
- }
- }
- saveDisplayState();
- }
- public function setLock(elements : Array<PrefabElement>, locked: Bool, enableUndo : Bool = true) {
- var prev = [for( o in elements ) o.locked];
- for(o in elements) {
- o.locked = locked;
- for( c in o.flatten(hrt.prefab.Prefab) ) {
- var el = tree.getElement(c);
- applyTreeStyle(c, el);
- applySceneStyle(c);
- toggleInteractive(c,!isLocked(c));
- }
- }
- if (enableUndo) {
- undo.change(Custom(function(redo) {
- for( i in 0...elements.length )
- elements[i].locked = redo ? locked : prev[i];
- }), function() {
- tree.refresh();
- refreshScene();
- });
- }
- saveDisplayState();
- showGizmo = !locked;
- moveGizmoToSelection();
- }
- function isolate(elts : Array<PrefabElement>) {
- var toShow = elts.copy();
- var toHide = [];
- function hideSiblings(elt: PrefabElement) {
- var p = elt.parent;
- for(c in p.children) {
- var needsVisible = c == elt || toShow.indexOf(c) >= 0 || hasChild(c, toShow);
- if(!needsVisible) {
- toHide.push(c);
- }
- }
- if(p != sceneData) {
- hideSiblings(p);
- }
- }
- for(e in toShow) {
- hideSiblings(e);
- }
- setVisible(toHide, false);
- }
- var isDuplicating = false;
- function duplicate(thenMove: Bool) {
- if(curEdit == null) return;
- var elements = curEdit.rootElements;
- if(elements == null || elements.length == 0)
- return;
- if( isDuplicating )
- return;
- isDuplicating = true;
- if( gizmo.moving ) {
- @:privateAccess gizmo.finishMove();
- }
- var undoes = [];
- var newElements = [];
- for(elt in elements) {
- var clone = elt.cloneData();
- var index = elt.parent.children.indexOf(elt) + 1;
- clone.parent = elt.parent;
- elt.parent.children.remove(clone);
- elt.parent.children.insert(index, clone);
- autoName(clone);
- makeInstance(clone);
- newElements.push(clone);
- undoes.push(function(undo) {
- if(undo) elt.parent.children.remove(clone);
- else elt.parent.children.insert(index, clone);
- });
- }
- refreshTree(function() {
- selectElements(newElements);
- tree.setSelection(newElements);
- if(thenMove && curEdit.rootObjects.length > 0) {
- gizmo.startMove(MoveXY, true);
- gizmo.onFinishMove = function() {
- refreshProps();
- }
- }
- isDuplicating = false;
- });
- undo.change(Custom(function(undo) {
- selectElements([], NoHistory);
- var fullRefresh = false;
- if(undo) {
- for(elt in newElements) {
- if(!removeInstance(elt)) {
- fullRefresh = true;
- break;
- }
- }
- }
- for(u in undoes) u(undo);
- if(!undo) {
- for(elt in newElements)
- makeInstance(elt);
- }
- refresh(fullRefresh ? Full : Partial);
- }));
- }
- function setTransform(elt: PrefabElement, ?mat: h3d.Matrix, ?position: h3d.Vector) {
- var obj3d = Std.downcast(elt, hrt.prefab.Object3D);
- if(obj3d == null)
- return;
- if(mat != null)
- obj3d.setTransform(mat);
- else {
- obj3d.x = position.x;
- obj3d.y = position.y;
- obj3d.z = position.z;
- }
- var ctx = getContext(obj3d);
- if(ctx != null)
- obj3d.updateInstance(ctx);
- }
- public function deleteElements(elts : Array<PrefabElement>, ?then: Void->Void, doRefresh : Bool = true, enableUndo : Bool = true) {
- var fullRefresh = false;
- var undoes = [];
- for(elt in elts) {
- if(!removeInstance(elt))
- fullRefresh = true;
- var index = elt.parent.children.indexOf(elt);
- elt.parent.children.remove(elt);
- undoes.unshift(function(undo) {
- if(undo) elt.parent.children.insert(index, elt);
- else elt.parent.children.remove(elt);
- });
- }
- function refreshFunc(then) {
- refresh(fullRefresh ? Full : Partial, then);
- if( !fullRefresh ) refreshParents(elts);
- }
- if (doRefresh)
- refreshFunc(then != null ? then : () -> selectElements([],NoHistory));
- if (enableUndo) {
- undo.change(Custom(function(undo) {
- if(!undo && !fullRefresh)
- for(e in elts) removeInstance(e);
- for(u in undoes) u(undo);
- if(undo)
- for(e in elts) makeInstance(e);
- refreshFunc(then != null ? then : selectElements.bind(undo ? elts : [],NoHistory));
- }));
- }
- }
- function reparentElement(e : Array<PrefabElement>, to : PrefabElement, index : Int) {
- if( to == null )
- to = sceneData;
- var ref = Std.downcast(to, Reference);
- @:privateAccess if( ref != null && ref.editMode ) to = ref.ref;
- var effectFunc = reparentImpl(e, to, index);
- undo.change(Custom(function(undo) {
- refresh(effectFunc(undo) ? Full : Partial);
- }));
- refresh(effectFunc(false) ? Full : Partial);
- }
- function makeTransform(mat: h3d.Matrix) {
- var rot = mat.getEulerAngles();
- var x = mat.tx;
- var y = mat.ty;
- var z = mat.tz;
- var s = mat.getScale();
- var scaleX = s.x;
- var scaleY = s.y;
- var scaleZ = s.z;
- var rotationX = hxd.Math.radToDeg(rot.x);
- var rotationY = hxd.Math.radToDeg(rot.y);
- var rotationZ = hxd.Math.radToDeg(rot.z);
- return { x : x, y : y, z : z, scaleX : scaleX, scaleY : scaleY, scaleZ : scaleZ, rotationX : rotationX, rotationY : rotationY, rotationZ : rotationZ };
- }
- function reparentImpl(elts : Array<PrefabElement>, toElt: PrefabElement, index: Int) : Bool -> Bool {
- var effects = [];
- var fullRefresh = false;
- var toRefresh : Array<PrefabElement> = null;
- for(elt in elts) {
- var prev = elt.parent;
- var prevIndex = prev.children.indexOf(elt);
- var obj3d = elt.to(Object3D);
- var preserveTransform = Std.is(toElt, hrt.prefab.fx.Emitter) || Std.is(prev, hrt.prefab.fx.Emitter);
- var toObj = getObject(toElt);
- var obj = getObject(elt);
- var prevState = null, newState = null;
- if(obj3d != null && toObj != null && obj != null && !preserveTransform) {
- var mat = worldMat(obj);
- var parentMat = worldMat(toObj);
- parentMat.invert();
- mat.multiply(mat, parentMat);
- prevState = obj3d.saveTransform();
- newState = makeTransform(mat);
- }
- effects.push(function(undo) {
- var refresh = false;
- if( undo ) {
- refresh = !removeInstance(elt);
- elt.parent = prev;
- prev.children.remove(elt);
- prev.children.insert(prevIndex, elt);
- if(obj3d != null && prevState != null)
- obj3d.loadTransform(prevState);
- } else {
- var refresh = !removeInstance(elt);
- elt.parent = toElt;
- toElt.children.remove(elt);
- toElt.children.insert(index, elt);
- if(obj3d != null && newState != null)
- obj3d.loadTransform(newState);
- };
- if(toRefresh.indexOf(elt) < 0)
- toRefresh.push(elt);
- return refresh;
- });
- }
- return function(undo) {
- var refresh = false;
- toRefresh = [];
- for(f in effects) {
- if(f(undo))
- refresh = true;
- }
- if(!refresh) {
- for(elt in toRefresh) {
- removeInstance(elt);
- makeInstance(elt);
- }
- }
- return refresh;
- }
- }
- function autoName(p : PrefabElement) {
- var uniqueName = false;
- if( p.type == "volumetricLightmap" || p.type == "light" )
- uniqueName = true;
- var prefix = null;
- if(p.name != null && p.name.length > 0) {
- if(uniqueName)
- prefix = ~/_+[0-9]+$/.replace(p.name, "");
- else
- prefix = p.name;
- }
- else
- prefix = p.getDefaultName();
- if(uniqueName) {
- prefix += "_";
- var id = 0;
- while( sceneData.getPrefabByName(prefix + id) != null )
- id++;
- p.name = prefix + id;
- }
- else
- p.name = prefix;
- for(c in p.children) {
- autoName(c);
- }
- }
- function update(dt:Float) {
- var cam = scene.s3d.camera;
- @:privateAccess view.saveDisplayState("Camera", { x : cam.pos.x, y : cam.pos.y, z : cam.pos.z, tx : cam.target.x, ty : cam.target.y, tz : cam.target.z });
- @:privateAccess view.saveDisplayState("Camera2D", { x : context.shared.root2d.x - scene.s2d.width*0.5, y : context.shared.root2d.y - scene.s2d.height*0.5, z : context.shared.root2d.scaleX });
- if(gizmo != null) {
- if(!gizmo.moving) {
- moveGizmoToSelection();
- }
- gizmo.update(dt);
- }
- event.update(dt);
- for( f in updates )
- f(dt);
- onUpdate(dt);
- }
- public dynamic function onUpdate(dt:Float) {
- }
- // Override
- function makeEditContext(elts : Array<PrefabElement>) : SceneEditorContext {
- var p = elts[0];
- var rootCtx = context;
- while( p != null ) {
- var ctx = context.shared.getContexts(p)[0];
- if( ctx != null ) rootCtx = ctx;
- p = p.parent;
- }
- // rootCtx might not be == context depending on references
- var edit = new SceneEditorContext(rootCtx, elts, this);
- edit.properties = properties;
- edit.scene = scene;
- return edit;
- }
- function getNewRecentContextMenu(current, ?onMake: PrefabElement->Void=null) : Array<hide.comp.ContextMenu.ContextMenuItem> {
- var parent = current == null ? sceneData : current;
- var grecent = [];
- var recents : Array<String> = ide.currentConfig.get("sceneeditor.newrecents", []);
- for( g in recents) {
- var pmodel = hrt.prefab.Library.getRegistered().get(g);
- if (pmodel != null && checkAllowParent({cl : g, inf : pmodel.inf}, parent))
- grecent.push(getNewTypeMenuItem(g, parent, onMake));
- }
- return grecent;
- }
- // Override
- function getNewContextMenu(current: PrefabElement, ?onMake: PrefabElement->Void=null, ?groupByType=true ) : Array<hide.comp.ContextMenu.ContextMenuItem> {
- var newItems = new Array<hide.comp.ContextMenu.ContextMenuItem>();
- var allRegs = hrt.prefab.Library.getRegistered().copy();
- allRegs.remove("reference");
- allRegs.remove("unknown");
- var parent = current == null ? sceneData : current;
- var groups = [];
- var gother = [];
- for( g in (view.config.get("sceneeditor.newgroups") : Array<String>) ) {
- var parts = g.split("|");
- var cl : Dynamic = Type.resolveClass(parts[1]);
- if( cl == null ) continue;
- groups.push({
- label : parts[0],
- cl : cl,
- group : [],
- });
- }
- for( ptype in allRegs.keys() ) {
- var pinf = allRegs.get(ptype);
- if (!checkAllowParent({cl : ptype, inf : pinf.inf}, parent)) continue;
- if(ptype == "shader") {
- newItems.push(getNewShaderMenu(parent, onMake));
- continue;
- }
- var m = getNewTypeMenuItem(ptype, parent, onMake);
- if( !groupByType )
- newItems.push(m);
- else {
- var found = false;
- for( g in groups )
- if( hrt.prefab.Library.isOfType(ptype,g.cl) ) {
- g.group.push(m);
- found = true;
- break;
- }
- if( !found ) gother.push(m);
- }
- }
- function sortByLabel(arr:Array<hide.comp.ContextMenu.ContextMenuItem>) {
- arr.sort(function(l1,l2) return Reflect.compare(l1.label,l2.label));
- }
- for( g in groups )
- if( g.group.length > 0 ) {
- sortByLabel(g.group);
- newItems.push({ label : g.label, menu : g.group });
- }
- sortByLabel(gother);
- sortByLabel(newItems);
- if( gother.length > 0 ) {
- if( newItems.length == 0 )
- return gother;
- newItems.push({ label : "Other", menu : gother });
- }
- return newItems;
- }
- function getNewTypeMenuItem(
- ptype: String,
- parent: PrefabElement,
- onMake: PrefabElement->Void,
- ?label: String,
- ?objectName: String,
- ?path: String
- ) : hide.comp.ContextMenu.ContextMenuItem {
- var pmodel = hrt.prefab.Library.getRegistered().get(ptype);
- return {
- label : label != null ? label : pmodel.inf.name,
- click : function() {
- function make(?sourcePath) {
- var p = Type.createInstance(pmodel.cl, [parent]);
- @:privateAccess p.type = ptype;
- if(sourcePath != null)
- p.source = sourcePath;
- if( objectName != null)
- p.name = objectName;
- else
- autoName(p);
- if(onMake != null)
- onMake(p);
- var recents : Array<String> = ide.currentConfig.get("sceneeditor.newrecents", []);
- recents.remove(p.type);
- recents.unshift(p.type);
- var recentSize : Int = view.config.get("sceneeditor.recentsize");
- if (recents.length > recentSize) recents.splice(recentSize, recents.length - recentSize);
- ide.currentConfig.set("sceneeditor.newrecents", recents);
- return p;
- }
- if( pmodel.inf.fileSource != null ) {
- if( path != null ) {
- var p = make(path);
- addElements([p]);
- var recents : Array<String> = ide.currentConfig.get("sceneeditor.newrecents", []);
- recents.remove(p.type);
- } else {
- ide.chooseFile(pmodel.inf.fileSource, function(path) {
- addElements([make(path)]);
- });
- }
- }
- else
- addElements([make()]);
- },
- icon : pmodel.inf.icon,
- };
- }
- function getNewShaderMenu(parentElt: PrefabElement, ?onMake: PrefabElement->Void) : hide.comp.ContextMenu.ContextMenuItem {
- function isClassShader(path) {
- if(StringTools.endsWith(path, ".hx")) path = path.substr(0, -3);
- var cpath = path.split("/").join(".");
- var cl = Type.resolveClass(cpath);
- return cl != null;
- }
- var shModel = hrt.prefab.Library.getRegistered().get("shader");
- var graphModel = hrt.prefab.Library.getRegistered().get("shgraph");
- var custom = {
- label : "Custom...",
- click : function() {
- ide.chooseFile(shModel.inf.fileSource.concat(graphModel.inf.fileSource), function(path) {
- var cl = isClassShader(path) ? shModel.cl : graphModel.cl;
- var p = Type.createInstance(cl, [parentElt]);
- p.source = path;
- autoName(p);
- if(onMake != null)
- onMake(p);
- addElements([p]);
- });
- },
- icon : shModel.inf.icon,
- };
- function classShaderItem(path) : hide.comp.ContextMenu.ContextMenuItem {
- var name = path;
- if(StringTools.endsWith(name, ".hx")) {
- name = new haxe.io.Path(path).file;
- }
- else {
- name = name.split(".").pop();
- }
- return getNewTypeMenuItem("shader", parentElt, onMake, name, name, path);
- }
- function graphShaderItem(path) : hide.comp.ContextMenu.ContextMenuItem {
- var name = new haxe.io.Path(path).file;
- return getNewTypeMenuItem("shgraph", parentElt, onMake, name, name, path);
- }
- var menu : Array<hide.comp.ContextMenu.ContextMenuItem> = [];
- var shaders : Array<String> = hide.Ide.inst.currentConfig.get("fx.shaders", []);
- for(path in shaders) {
- var strippedSlash = StringTools.endsWith(path, "/") ? path.substr(0, -1) : path;
- var fullPath = ide.getPath(strippedSlash);
- if( isClassShader(path) ) {
- menu.push(classShaderItem(path));
- } else if( StringTools.endsWith(path, ".shgraph")) {
- menu.push(graphShaderItem(path));
- } else if( sys.FileSystem.exists(fullPath) && sys.FileSystem.isDirectory(fullPath) ) {
- var submenu : Array<hide.comp.ContextMenu.ContextMenuItem> = [];
- for( c in sys.FileSystem.readDirectory(fullPath) ) {
- var relPath = ide.makeRelative(fullPath + "/" + c);
- if( isClassShader(relPath) ) {
- submenu.push(classShaderItem(relPath));
- } else if( StringTools.endsWith(relPath, ".shgraph")) {
- submenu.push(graphShaderItem(relPath));
- }
- }
- if( submenu.length > 0 ) {
- menu.push({ label : path, menu : submenu });
- }
- }
- }
- menu.sort(function(l1,l2) return Reflect.compare(l1.label,l2.label));
- menu.unshift(custom);
- return {
- label: "Shader",
- menu: menu
- };
- }
- public function getZ(x: Float, y: Float, ?paintOn : hrt.prefab.Prefab) {
- var offset = 1000000;
- var ray = h3d.col.Ray.fromValues(x, y, offset, 0, 0, -1);
- var dist = projectToGround(ray, paintOn);
- if(dist >= 0) {
- return offset - dist;
- }
- return 0.;
- }
- function getGroundPrefabs() : Array<PrefabElement> {
- function getAll(data:PrefabElement) {
- var all = data.findAll((p) -> p);
- for( a in all.copy() ) {
- var r = Std.downcast(a, hrt.prefab.Reference);
- if( r != null ) {
- var sub = @:privateAccess r.ref;
- if( sub != null ) all = all.concat(getAll(sub));
- }
- }
- return all;
- }
- var all = getAll(sceneData);
- var grounds = [for( p in all ) if( p.getHideProps().isGround ) p];
- var results = [];
- for( g in grounds )
- results = results.concat(getAll(g));
- return results;
- }
- public function projectToGround(ray: h3d.col.Ray, ?paintOn : hrt.prefab.Prefab ) {
- var minDist = -1.;
- for( elt in (paintOn == null ? getGroundPrefabs() : [paintOn]) ) {
- var obj = Std.downcast(elt, Object3D);
- if( obj == null ) continue;
- var ctx = getContext(elt);
- if( ctx == null ) continue;
- var lray = ray.clone();
- lray.transform(ctx.local3d.getInvPos());
- var dist = obj.localRayIntersection(ctx, lray);
- if( dist > 0 ) {
- var pt = lray.getPoint(dist);
- pt.transform(ctx.local3d.getAbsPos());
- var dist = pt.sub(ray.getPos()).length();
- if( minDist < 0 || dist < minDist )
- minDist = dist;
- }
- }
- if( minDist >= 0 )
- return minDist;
- var zPlane = h3d.col.Plane.Z(0);
- var pt = ray.intersect(zPlane);
- if( pt != null ) {
- minDist = pt.sub(ray.getPos()).length();
- var dirToPt = pt.sub(ray.getPos());
- if( dirToPt.dot(ray.getDir()) < 0 )
- return -1;
- }
- return minDist;
- }
- public function screenDistToGround(sx : Float, sy : Float, ?paintOn : hrt.prefab.Prefab) : Null<Float> {
- var camera = scene.s3d.camera;
- var ray = camera.rayFromScreen(sx, sy);
- var dist = projectToGround(ray, paintOn);
- if( dist >= 0 )
- return dist + camera.zNear;
- return null;
- }
- public function screenToGround(sx: Float, sy: Float, ?paintOn : hrt.prefab.Prefab ) {
- var camera = scene.s3d.camera;
- var ray = camera.rayFromScreen(sx, sy);
- var dist = projectToGround(ray, paintOn);
- if(dist >= 0) {
- return ray.getPoint(dist);
- }
- return null;
- }
- public function worldToScreen(wx: Float, wy: Float, wz: Float) {
- var camera = scene.s3d.camera;
- var pt = camera.project(wx, wy, wz, scene.s2d.width, scene.s2d.height);
- return new h2d.col.Point(pt.x, pt.y);
- }
- public function worldMat(?obj: Object, ?elt: PrefabElement) {
- if(obj != null) {
- if(obj.defaultTransform != null) {
- var m = obj.defaultTransform.clone();
- m.invert();
- m.multiply(m, obj.getAbsPos());
- return m;
- }
- else {
- return obj.getAbsPos().clone();
- }
- }
- else {
- var mat = new h3d.Matrix();
- mat.identity();
- var o = Std.downcast(elt, Object3D);
- while(o != null) {
- mat.multiply(mat, o.getTransform());
- o = o.parent.to(hrt.prefab.Object3D);
- }
- return mat;
- }
- }
- function editPivot() {
- if (curEdit.rootObjects.length == 1) {
- var ray = scene.s3d.camera.rayFromScreen(scene.s2d.mouseX, scene.s2d.mouseY);
- var polyColliders = new Array<PolygonBuffer>();
- var meshes = new Array<Mesh>();
- for (m in curEdit.rootObjects[0].getMeshes()) {
- var hmdModel = Std.downcast(m.primitive, HMDModel);
- if (hmdModel != null) {
- var optiCollider = Std.downcast(hmdModel.getCollider(), OptimizedCollider);
- var polyCollider = Std.downcast(optiCollider.b, PolygonBuffer);
- if (polyCollider != null) {
- polyColliders.push(polyCollider);
- meshes.push(m);
- }
- }
- }
- if (polyColliders.length > 0) {
- var pivot = getClosestVertex(polyColliders, meshes, ray);
- if (pivot != null) {
- pivot.elt = curEdit.rootElements[0];
- customPivot = pivot;
- } else {
- // mouse outside
- }
- } else {
- // no collider found
- }
- } else {
- throw "Can't edit when multiple objects are selected";
- }
- }
- function getClosestVertex( colliders : Array<PolygonBuffer>, meshes : Array<Mesh>, ray : Ray ) : CustomPivot {
- var best = -1.;
- var bestVertex : CustomPivot = null;
- for (idx in 0...colliders.length) {
- var c = colliders[idx];
- var m = meshes[idx];
- var r = ray.clone();
- r.transform(m.getInvPos());
- var rdir = new FPoint(r.lx, r.ly, r.lz);
- var r0 = new FPoint(r.px, r.py, r.pz);
- @:privateAccess var i = c.startIndex;
- @:privateAccess for( t in 0...c.triCount ) {
- var i0 = c.indexes[i++] * 3;
- var p0 = new FPoint(c.buffer[i0++], c.buffer[i0++], c.buffer[i0]);
- var i1 = c.indexes[i++] * 3;
- var p1 = new FPoint(c.buffer[i1++], c.buffer[i1++], c.buffer[i1]);
- var i2 = c.indexes[i++] * 3;
- var p2 = new FPoint(c.buffer[i2++], c.buffer[i2++], c.buffer[i2]);
- var e1 = p1.sub(p0);
- var e2 = p2.sub(p0);
- var p = rdir.cross(e2);
- var det = e1.dot(p);
- if( det < hxd.Math.EPSILON ) continue; // backface culling (negative) and near parallel (epsilon)
- var invDet = 1 / det;
- var T = r0.sub(p0);
- var u = T.dot(p) * invDet;
- if( u < 0 || u > 1 ) continue;
- var q = T.cross(e1);
- var v = rdir.dot(q) * invDet;
- if( v < 0 || u + v > 1 ) continue;
- var t = e2.dot(q) * invDet;
- if( t < hxd.Math.EPSILON ) continue;
- if( best < 0 || t < best ) {
- best = t;
- var ptIntersection = r.getPoint(t);
- var pI = new FPoint(ptIntersection.x, ptIntersection.y, ptIntersection.z);
- inline function distanceFPoints(a : FPoint, b : FPoint) : Float {
- var dx = a.x - b.x;
- var dy = a.y - b.y;
- var dz = a.z - b.z;
- return dx * dx + dy * dy + dz * dz;
- }
- var test0 = distanceFPoints(p0, pI);
- var test1 = distanceFPoints(p1, pI);
- var test2 = distanceFPoints(p2, pI);
- var locBestVertex : FPoint;
- if (test0 <= test1 && test0 <= test2) {
- locBestVertex = p0;
- } else if (test1 <= test0 && test1 <= test2) {
- locBestVertex = p1;
- } else {
- locBestVertex = p2;
- }
- bestVertex = { elt : null, mesh: m, locPos: new Vector(locBestVertex.x, locBestVertex.y, locBestVertex.z) };
- }
- }
- }
- return bestVertex;
- }
- static function isReference( what : PrefabElement ) : Bool {
- return what != null && what.to(hrt.prefab.Reference) != null;
- }
- static function getPivot(objects: Array<Object>) {
- if (customPivot != null) {
- return customPivot.mesh.localToGlobal(customPivot.locPos.toPoint());
- }
- var pos = new h3d.col.Point();
- for(o in objects) {
- pos = pos.add(o.getAbsPos().getPosition().toPoint());
- }
- pos.scale(1.0 / objects.length);
- return pos;
- }
- static function getPivot2D( objects : Array<h2d.Object> ) {
- var b = new h2d.col.Bounds();
- for( o in objects )
- b.addBounds(o.getBounds());
- return b;
- }
- public static function hasParent(elt: PrefabElement, list: Array<PrefabElement>) {
- for(p in list) {
- if(isParent(elt, p))
- return true;
- }
- return false;
- }
- public static function hasChild(elt: PrefabElement, list: Array<PrefabElement>) {
- for(p in list) {
- if(isParent(p, elt))
- return true;
- }
- return false;
- }
- public static function isParent(elt: PrefabElement, parent: PrefabElement) {
- var p = elt.parent;
- while(p != null) {
- if(p == parent) return true;
- p = p.parent;
- }
- return false;
- }
- static function getParentGroup(elt: PrefabElement) {
- while(elt != null) {
- if(elt.type == "object")
- return elt;
- elt = elt.parent;
- }
- return null;
- }
- }
|