123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667 |
- package hide.comp;
- import hrt.prefab.Reference;
- import h3d.col.Sphere;
- 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;
- 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;
- }
- class CameraController extends h3d.scene.CameraController {
- override function sync(ctx:h3d.scene.RenderContext) {
- var old = ctx.elapsedTime;
- ctx.elapsedTime = hxd.Timer.dt;
- super.sync(ctx);
- ctx.elapsedTime = old;
- }
- }
- @: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;
- // 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;
- 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);
- 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();
- cameraController.set(s.r * 4.0, null, null, s.getCenter());
- }
- else {
- centroid.scale3(1.0 / curEdit.rootObjects.length);
- cameraController.set(centroid.toPoint());
- }
- }
- for(obj in curEdit.rootElements)
- tree.revealNode(obj);
- }
- 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) });
- }
- 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() {
- 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);
- 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");
- group.find(".btn-cdb-large").click((_) -> {
- cdbLarge = !cdbLarge;
- @:privateAccess view.saveDisplayState("cdbLarge", cdbLarge);
- group.toggleClass("cdb-large", cdbLarge);
- });
- group.toggleClass("cdb-large", 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;
- var editor = new hide.comp.cdb.ObjEditor(curType, view.config, e.props, fileRef, props);
- 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();
- }
- if( curEdit != null && mode.match(Default|NoTree) ) {
- var prev = curEdit.rootElements.copy();
- undo.change(Custom(function(u) {
- if(u) impl(prev,NoHistory);
- else impl(elts,NoHistory);
- }),true);
- }
- impl(elts,mode);
- }
- 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() {
- 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(1.5);
- 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 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) : hide.comp.ContextMenu.ContextMenuItem {
- var pmodel = hrt.prefab.Library.getRegistered().get(ptype);
- return {
- label : label != null ? label : pmodel.inf.name,
- click : function() {
- function make(?path) {
- var p = Type.createInstance(pmodel.cl, [parent]);
- @:privateAccess p.type = ptype;
- if(path != null)
- p.source = path;
- 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 )
- ide.chooseFile(pmodel.inf.fileSource, function(path) {
- var p = make(path);
- addElements([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);
- });
- else
- addElements([make()]);
- },
- icon : pmodel.inf.icon,
- };
- }
- function getNewShaderMenu(parentElt: PrefabElement, onMake: PrefabElement->Void) : hide.comp.ContextMenu.ContextMenuItem {
- var custom = getNewTypeMenuItem("shader", parentElt, onMake, "Custom...");
- function shaderItem(name, path) : hide.comp.ContextMenu.ContextMenuItem {
- return {
- label : name,
- click : function() {
- var s = new hrt.prefab.DynamicShader(parentElt);
- s.source = path;
- s.name = name;
- addElements([s]);
- }
- }
- }
- var menu = [custom];
- var shaders : Array<String> = hide.Ide.inst.currentConfig.get("fx.shaders", []);
- for(path in shaders) {
- var name = path;
- if(StringTools.endsWith(name, ".hx")) {
- name = name.substr(0, -3);
- name = name.split("/").pop();
- }
- else {
- name = name.split(".").pop();
- }
- menu.push(shaderItem(name, path));
- }
- return {
- label: "Shaders",
- 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;
- }
- }
|