diff --git a/build/game-lib-min.js b/build/game-lib-min.js new file mode 100644 index 0000000..95efc6c --- /dev/null +++ b/build/game-lib-min.js @@ -0,0 +1,13 @@ +function GameLib(){}var __DATE__="Sun Nov 19 2017 14:40:05 GMT+0100 (CET)";if(void 0===GameLib.D3&&(GameLib.D3=function(){}),void 0===GameLib.D3.API&&(GameLib.D3.API=function(){}),void 0===GameLib.API&&(GameLib.API=function(){}),void 0===GameLib.D3.Runtime&&(GameLib.D3.Runtime=function(){}),void 0===Q){if("undefined"==typeof require)throw console.warn("You need the Q promise library for the GameLib.D3"),new Error("You need the Q promise library for the GameLib.D3");var Q=require("q")}if(void 0===_){if("undefined"==typeof require)throw console.warn("You need the lodash library for the GameLib.D3"),new Error("You need the lodash library for the GameLib.D3");var _=require("lodash")}console.log("Loading GameLib compiled at: "+__DATE__),GameLib.Event=function(){},GameLib.Event.Subscriptions={},GameLib.Event.OnceSubscriptions={},GameLib.Event.WINDOW_RESIZE=1,GameLib.Event.PARENT_SCENE_CHANGE=2,GameLib.Event.PARENT_ENTITY_CHANGE=3,GameLib.Event.INSTANCE_CLONED=4,GameLib.Event.LOAD_IMAGE=5,GameLib.Event.NEW_ENTITY=6,GameLib.Event.MATERIAL_TYPE_CHANGED=7,GameLib.Event.SAVE_COMPONENT=8,GameLib.Event.SAVE_COMPONENT_ERROR=9,GameLib.Event.COMPONENT_SAVED=10,GameLib.Event.LOAD_COMPONENT=11,GameLib.Event.LOAD_COMPONENT_ERROR=12,GameLib.Event.LOGGED_IN=13,GameLib.Event.COMPONENT_CREATED=14,GameLib.Event.COMPONENT_CLONED=15,GameLib.Event.TEXTURE_ANIMATED_CHANGE=16,GameLib.Event.ANIMATE_TEXTURE_INSTANCE=17,GameLib.Event.REMOVE_PARTICLE_ENGINE=18,GameLib.Event.PAUSE=19,GameLib.Event.TEXTURE_INSTANCE_UPDATED=20,GameLib.Event.PLAY_AUDIO=21,GameLib.Event.MATERIAL_INSTANCE_UPDATED=22,GameLib.Event.PAUSE_AUDIO=23,GameLib.Event.MESH_INSTANCE_UPDATED=24,GameLib.Event.STOP_AUDIO=25,GameLib.Event.LIGHT_INSTANCE_UPDATED=26,GameLib.Event.DELETE_COMPONENT=27,GameLib.Event.COMPONENT_DOWNLOAD_COMPLETE=28,GameLib.Event.COMPONENTS_LINKED=29,GameLib.Event.UNRESOLVED_DEPENDENCIES_UPDATE=30,GameLib.Event.REGISTER_UPDATE=31,GameLib.Event.BUILD_GUI=32,GameLib.Event.REMOVE_MESH=33,GameLib.Event.MESH_SELECTED=34,GameLib.Event.MESH_DESELECTED=35,GameLib.Event.COMPONENT_REGISTER=36,GameLib.Event.IMAGE_NOT_FOUND=37,GameLib.Event.BLENDER_DATA_RECEIVED=38,GameLib.Event.IMAGE_UPLOAD_COMPLETE=39,GameLib.Event.REMOVE_COMPONENT=40,GameLib.Event.KEY_DOWN=41,GameLib.Event.KEY_UP=42,GameLib.Event.RENDER=43,GameLib.Event.EVENT_LIST=44,GameLib.Event.COMPILE_SUCCESS=45,GameLib.Event.COMPILE_FAILED=46,GameLib.Event.IMAGE_CHANGED=47,GameLib.Event.PARENT_ENTITY_CHANGED=48,GameLib.Event.MATERIAL_TEXTURES_UPDATED=49,GameLib.Event.DELETE_COMPONENT_ERROR=50,GameLib.Event.COMPONENT_DELETED=51,GameLib.Event.COMPONENT_TYPES_UPDATED=52,GameLib.Event.AUDIO_ENDED=53,GameLib.Event.COMPONENT_LINKED=54,GameLib.Event.DONE_SAVING=55,GameLib.Event.BEFORE_RENDER=56,GameLib.Event.AFTER_RENDER=57,GameLib.Event.ARRAY_ITEM_ADDED=58,GameLib.Event.INSTANCE_CREATED=59,GameLib.Event.VISUALIZE=60,GameLib.Event.STOP_VISUALIZE=61,GameLib.Event.FETCH_COMPONENT_TYPES=62,GameLib.Event.FETCH_COMPONENTS=63,GameLib.Event.GET_API_URL=64,GameLib.Event.GET_PHYSICS_IMPLEMENTATION=65,GameLib.Event.PARENT_WORLD_CHANGE=66,GameLib.Event.ANIMATE=67,GameLib.Event.ANIMATION_COMPILE_SUCCESS=68,GameLib.Event.ANIMATION_COMPILE_FAILED=69,GameLib.Event.SAVING=70,GameLib.Event.GAME_OVER=71,GameLib.Event.GAME_START=72,GameLib.Event.TOUCH_START=73,GameLib.Event.TOUCH_END=74,GameLib.Event.TOUCH_MOVE=75,GameLib.Event.TOUCH_CANCEL=76,GameLib.Event.GET_REMOTE_API_URL=77,GameLib.Event.GET_GRAPHICS_IMPLEMENTATION=78,GameLib.Event.DELAYED_INSTANCE_ENCOUNTERED=79,GameLib.Event.GET_CODER_IMPLEMENTATION=80,GameLib.Event.ANIMATION_MESH_ADDED=81,GameLib.Event.ANIMATION_MESH_REMOVED=82,GameLib.Event.GET_SCENE=83,GameLib.Event.CUSTOM_CODE_WINDOW_RESIZE=84,GameLib.Event.LOAD_FONT=85,GameLib.Event.FONT_NOT_FOUND=86,GameLib.Event.STOP_ALL_AUDIO=87,GameLib.Event.REGISTER_DEPENDENCIES=88,GameLib.Event.GAME_LOADED=89,GameLib.Event.GAME_RESTART=90,GameLib.Event.LOAD_PROGRESS=91,GameLib.Event.ENTITY_LOADED=92,GameLib.Event.MOUSE_DOWN=93,GameLib.Event.MOUSE_MOVE=94,GameLib.Event.MOUSE_WHEEL=95,GameLib.Event.MOUSE_UP=96,GameLib.Event.PARTICLE_INSTANCE_UPDATED=97,GameLib.Event.GetEventName=function(e){switch(e){case 1:return"window_resize";case 2:return"parent_scene_change";case 3:return"parent_entity_change";case 4:return"instance_cloned";case 5:return"load_image";case 6:return"new_entity";case 7:return"material_type_changed";case 8:return"save_component";case 9:return"save_component_error";case 10:return"component_saved";case 11:return"load_component";case 12:return"load_component_error";case 13:return"logged_in";case 14:return"component_created";case 15:return"component_cloned";case 16:return"texture_animated_change";case 17:return"animate_texture_instance";case 18:return"remove_particle_engine";case 19:return"pause";case 20:return"texture_instance_updated";case 21:return"play_audio";case 22:return"material_instance_updated";case 23:return"pause_audio";case 24:return"mesh_instance_updated";case 25:return"stop_audio";case 26:return"light_instance_updated";case 27:return"delete_component";case 28:return"component_download_complete";case 29:return"components_linked";case 30:return"unresolved_dependencies_update";case 31:return"register_update";case 32:return"build_gui";case 33:return"remove_mesh";case 34:return"mesh_selected";case 35:return"mesh_deselected";case 36:return"component_register";case 37:return"image_not_found";case 38:return"blender_data_received";case 39:return"image_upload_complete";case 40:return"remove_component";case 41:return"key_down";case 42:return"key_up";case 43:return"render";case 44:return"event_list";case 45:return"compile_success";case 46:return"compile_failed";case 47:return"image_changed";case 48:return"parent_entity_changed";case 49:return"material_textures_updated";case 50:return"delete_component_error";case 51:return"component_deleted";case 52:return"component_types_updated";case 53:return"audio_ended";case 54:return"component_linked";case 55:return"done_saving";case 56:return"before_render";case 57:return"after_render";case 58:return"array_item_added";case 59:return"instance_created";case 60:return"visualize";case 61:return"stop_visualize";case 62:return"fetch_component_types";case 63:return"fetch_components";case 64:return"get_api_url";case 65:return"get_physics_implementation";case 66:return"parent_world_change";case 67:return"animate";case 68:return"animation_compile_success";case 69:return"animation_compile_failed";case 70:return"saving";case 71:return"game_over";case 72:return"game_start";case 73:return"touch_start";case 74:return"touch_end";case 75:return"touch_move";case 76:return"touch_cancel";case 77:return"get_remote_api_url";case 78:return"get_graphics_implementation";case 79:return"delayed_instance_encountered";case 80:return"get_coder_implementation";case 81:return"animation_mesh_added";case 82:return"animation_mesh_removed";case 83:return"get_scene";case 84:return"custom_code_window_resize";case 85:return"load_font";case 86:return"font_not_found";case 87:return"stop_all_audio";case 88:return"register_dependencies";case 89:return"game_loaded";case 90:return"game_restart";case 91:return"load_progress";case 92:return"entity_loaded";case 93:return"mouse_down";case 94:return"mouse_move";case 95:return"mouse_wheel";case 96:return"mouse_up";case 97:return"particle_instance_updated"}throw new error("unknown event id: "+e)},GameLib.Event.prototype.subscribe=function(e,t){return GameLib.Event.Subscribe(e,t.bind(this))},GameLib.Event.prototype.publish=function(e,t,i,n){return GameLib.Event.Emit(e,t,i,n)},GameLib.Event.Emit=function(e,t,i,n){var a=0;return GameLib.Event.Subscriptions.hasOwnProperty(e)?(0===GameLib.Event.Subscriptions[e].length&&(i&&i(),n&&n({message:"No subscriptions for event "+e})),GameLib.Event.Subscriptions[e].map(function(e){e&&(e(t,i,n),a++)})):(i&&i(),n&&n({message:"No subscriptions for event "+e})),a},GameLib.Event.Subscribe=function(e,t){return GameLib.Event.Subscriptions.hasOwnProperty(e)?GameLib.Event.Subscriptions[e].push(t):(GameLib.Event.Subscriptions[e]=[],GameLib.Event.Subscriptions[e].push(t)),{fn:t,remove:function(){var i=GameLib.Event.Subscriptions[e].indexOf(t);if(-1===i)throw new Error("could not remove subscription");GameLib.Event.Subscriptions[e].splice(i,1)}}},GameLib.Utils=function(){},GameLib.Utils.StripImageExtension=function(e){return e.replace(/(\.png$|\.gif$|\.jpeg$|\.jpg$)/,"")},GameLib.Utils.ObjectIdWithNameInArray=function(e,t){return t.reduce(function(t,i){return t||(e===i.name?i.id:null)},null)},GameLib.Utils.LoadIdsFromArrayToIdObject=function(e,t){},GameLib.Utils.LoadIdsFromObjectToIdObject=function(e,t){},GameLib.Utils.GetRandomInt=function(e,t){return e=Math.ceil(e),t=Math.floor(t),Math.floor(Math.random()*(t-e))+e},GameLib.Utils.GetRandomIntInclusive=function(e,t){return e=Math.ceil(e),t=Math.floor(t),Math.floor(Math.random()*(t-e+1))+e},GameLib.Utils.InterpolateArray=function(e,t){var i=[],n=Number((e.length-1)/(t-1));i[0]=e[0];for(var a=1;aMath.PI;)e-=2*Math.PI;for(;e<-Math.PI;)e+=2*Math.PI;i=e}}},GameLib.Utils.IdArrayOrEmptyArray=function(e){return GameLib.Utils.UndefinedOrNull(e)?[]:e.map(function(e){if(GameLib.Utils.UndefinedOrNull(e.id))throw new Error("No ID found while trying to store IDs to array");return e.id})},GameLib.Utils.Link=function(e,t,i,n){GameLib.Utils.UndefinedOrNull(i[e])||(t.hasOwnProperty(n)||console.warn("Linking failed for object:"+i.name),i[e]=t[n])},GameLib.Utils.RandomId=function(e){return GameLib.Utils.UndefinedOrNull(e)&&(e=10),Math.random().toString(36).substr(2,e)},GameLib.Utils.InvertWindingOrder=function(e){for(var t=0;t0;){var a=i.pop();if(a.triangle.v0index===a.edge.x&&a.triangle.v1index===a.edge.y||a.triangle.v1index===a.edge.x&&a.triangle.v2index===a.edge.y||a.triangle.v2index===a.edge.x&&a.triangle.v0index===a.edge.y){var s=a.triangle.v1index;a.triangle.v1index=a.triangle.v2index,a.triangle.v2index=s;var o=a.triangle.uvs[0][1];a.triangle.uvs[0][1]=a.triangle.uvs[0][2],a.triangle.uvs[0][2]=o}n.push(a);for(var r=[new GameLib.API.Vector2(a.triangle.v0index,a.triangle.v1index),new GameLib.API.Vector2(a.triangle.v1index,a.triangle.v2index),new GameLib.API.Vector2(a.triangle.v2index,a.triangle.v0index)],c=0;c9||console.log("The vertices are not in the right length : "+e.length);for(var i=[],n=new GameLib.API.Quaternion.Points,a=0;ae&&t.splice(0,1);var n=0;for(var a in t)n+=t[a];var s=e;return t.lengthe.length&&(i=t,t=e,e=i),e.filter(function(e){return t.indexOf(e)>-1}).filter(function(e,t,i){return i.indexOf(e)===t})},GameLib.Utils.Difference=function(e,t){var i;return t.length>e.length&&(i=t,t=e,e=i),e.filter(function(e){return-1===t.indexOf(e)}).filter(function(e,t,i){return i.indexOf(e)===t})},GameLib.Utils.PushUnique=function(e,t){-1===e.indexOf(t)&&e.push(t)},GameLib.Utils.IsEmpty=function(e){return 0===Object.keys(e).length&&e.constructor===Object},GameLib.Utils.isString=function(e){return"string"==typeof e},GameLib.Utils.isBoolean=function(e){return!0===e||!1===e},GameLib.Utils.isColor=function(e){return e instanceof GameLib.Color},GameLib.Utils.isNumber=function(e){return"number"==typeof e},GameLib.Utils.isVector2=function(e){return e instanceof GameLib.API.Vector2||e instanceof GameLib.Vector2},GameLib.Utils.isVector3=function(e){return e instanceof GameLib.API.Vector3||e instanceof GameLib.Vector3},GameLib.Utils.isVector4=function(e){return e instanceof GameLib.API.Vector4||e instanceof GameLib.Vector4||e instanceof GameLib.API.Quaternion||e instanceof GameLib.Quaternion},GameLib.Utils.LowerUnderscore=function(e){return e.toLowerCase().replace(/\s+/,"_")},GameLib.Utils.UpperCaseWordsSpaces=function(e){return e.replace(/[-_]/g," ").split(" ").reduce(function(e,t){return(e+=t[0].toUpperCase()+t.substr(1))+" "},"").trim()},GameLib.API.Component=function(e,t){this.componentType=e,GameLib.Utils.UndefinedOrNull(t)&&(t=null),this.parentEntity=t},GameLib.API.Component.prototype=Object.create(GameLib.Event.prototype),GameLib.API.Component.prototype.constructor=GameLib.API.Component,GameLib.Component=function(e,t,i){GameLib.Utils.UndefinedOrNull(t)&&(t={}),this.linkedObjects=t,this.linkedObjects.parentEntity=GameLib.Entity,GameLib.API.Component.call(this,e,this.parentEntity),this.idToObject={},this.selected=!1,this.building=!1,this.loaded=!1,this.linked=!1,this.cloneNumber=0,this.isClone=!1,GameLib.Utils.UndefinedOrNull(i)&&(i=!1),this.delayed=i,this.dependencies=this.getDependencies(),GameLib.Event.Emit(GameLib.Event.COMPONENT_REGISTER,{component:this}),0===this.dependencies.length?this.performInstanceCreation():GameLib.Event.Emit(GameLib.Event.REGISTER_DEPENDENCIES,{component:this})},GameLib.Component.prototype=Object.create(GameLib.API.Component.prototype),GameLib.Component.prototype.constructor=GameLib.Component,GameLib.Component.prototype.performInstanceCreation=function(){var e=!0;if(GameLib.Utils.UndefinedOrNull(this.dependencies)&&(e=!1),this.dependencies&&this.dependencies instanceof Array&&0===this.dependencies.length&&(e=!1),e)throw new Error("performInstanceCreation called while this object still has dependencies");if(delete this.dependencies,this.buildIdToObject(),this.linked)if(this.delayed)GameLib.Event.Emit(GameLib.Event.DELAYED_INSTANCE_ENCOUNTERED,{component:this});else try{this.createInstance()}catch(e){console.error(e)}},GameLib.Component.prototype.createInstance=function(){this.delayed=!1,this.instance&&(this.loaded=!0,GameLib.Event.Emit(GameLib.Event.INSTANCE_CREATED,{component:this})),this instanceof GameLib.Entity&&GameLib.Event.Emit(GameLib.Event.ENTITY_LOADED,{entity:this})},GameLib.Component.prototype.getDependencies=function(){var e=[];for(var t in this.linkedObjects)this.linkedObjects.hasOwnProperty(t)&&0!==t.indexOf("parent")&&this.hasOwnProperty(t)&&("string"==typeof this[t]&&GameLib.Utils.PushUnique(e,this[t]),this[t]instanceof Array&&this[t].map(function(t){"string"==typeof t&&GameLib.Utils.PushUnique(e,t),t&&t instanceof GameLib.Component&&GameLib.Utils.PushUnique(e,t.id)}),this[t]&&this[t]instanceof GameLib.Component&&GameLib.Utils.PushUnique(e,this[t].id));return e},GameLib.Component.prototype.toString=function(){return this.id},GameLib.Component.COMPONENT_PATH_FOLLOWING=1,GameLib.Component.COMPONENT_MATERIAL=2,GameLib.Component.COMPONENT_RENDERER=3,GameLib.Component.COMPONENT_LOOK_AT=4,GameLib.Component.COMPONENT_CAMERA=5,GameLib.Component.COMPONENT_FOLLOW=6,GameLib.Component.COMPONENT_MESH=7,GameLib.Component.COMPONENT_SPLINE=8,GameLib.Component.COMPONENT_LIGHT=9,GameLib.Component.COMPONENT_INPUT_DRIVE=10,GameLib.Component.COMPONENT_COMPOSER=11,GameLib.Component.COMPONENT_RENDER_TARGET=12,GameLib.Component.COMPONENT_PASS=13,GameLib.Component.COMPONENT_SCENE=14,GameLib.Component.COMPONENT_RAYCASTER=15,GameLib.Component.COMPONENT_INPUT_EDITOR=16,GameLib.Component.COMPONENT_EDITOR=17,GameLib.Component.COMPONENT_VIEWPORT=18,GameLib.Component.COMPONENT_SYSTEM=19,GameLib.Component.COMPONENT_GRAPHICS=20,GameLib.Component.COMPONENT_HELPER=21,GameLib.Component.COMPONENT_CUSTOM_CODE=22,GameLib.Component.COMPONENT_MOUSE=23,GameLib.Component.COMPONENT_SKELETON=24,GameLib.Component.COMPONENT_TEXTURE=25,GameLib.Component.COMPONENT_ENTITY_MANAGER=26,GameLib.Component.COMPONENT_DOM_ELEMENT=27,GameLib.Component.COMPONENT_IMAGE_FACTORY=28,GameLib.Component.COMPONENT_STATS=29,GameLib.Component.COMPONENT_GUI=30,GameLib.Component.COMPONENT_IMAGE=31,GameLib.Component.COMPONENT_ENTITY=32,GameLib.Component.COMPONENT_MESH_SPHERE=33,GameLib.Component.COMPONENT_MESH_PLANE=34,GameLib.Component.COMPONENT_MESH_CURVE=35,GameLib.Component.COMPONENT_PHYSICS_WORLD=36,GameLib.Component.COMPONENT_BROADPHASE=37,GameLib.Component.COMPONENT_SOLVER=38,GameLib.Component.COMPONENT_RIGID_BODY=39,GameLib.Component.COMPONENT_SHAPE=40,GameLib.Component.COMPONENT_SHAPE_BOX=41,GameLib.Component.COMPONENT_SHAPE_SPHERE=42,GameLib.Component.COMPONENT_SHAPE_TRI_MESH=43,GameLib.Component.COMPONENT_SHAPE_CONVEX_HULL=44,GameLib.Component.COMPONENT_SHAPE_CONVEX_HULL_CYLINDER=45,GameLib.Component.COMPONENT_SHAPE_HEIGHT_MAP=46,GameLib.Component.COMPONENT_SHAPE_PLANE=47,GameLib.Component.COMPONENT_CONTROLS=48,GameLib.Component.COMPONENT_CONTROLS_EDITOR=49,GameLib.Component.COMPONENT_CONTROLS_TOUCH=50,GameLib.Component.COMPONENT_FRICTION_MATERIAL=51;GameLib.Component.COMPONENT_FRICTION_CONTACT_MATERIAL=52,GameLib.Component.COMPONENT_RAYCAST_VEHICLE=53,GameLib.Component.COMPONENT_RAYCAST_WHEEL=54,GameLib.Component.COMPONENT_CLOCK=55,GameLib.Component.COMPONENT_ANIMATION=56,GameLib.Component.COMPONENT_CONTROLS_KEYBOARD=57,GameLib.Component.COMPONENT_CONTROLS_MOUSE=58,GameLib.Component.COMPONENT_MESH_TEXT=59,GameLib.Component.COMPONENT_FONT=60,GameLib.Component.COMPONENT_CANVAS=61,GameLib.Component.COMPONENT_BONE=62,GameLib.Component.COMPONENT_MESH_BOX=63,GameLib.Component.COMPONENT_MESH_CYLINDER=64,GameLib.Component.COMPONENT_SYSTEM_ANIMATION=65,GameLib.Component.COMPONENT_SYSTEM_CUSTOM_CODE=66,GameLib.Component.COMPONENT_SYSTEM_GUI=67,GameLib.Component.COMPONENT_SYSTEM_INPUT=68,GameLib.Component.COMPONENT_SYSTEM_LINKING=69,GameLib.Component.COMPONENT_SYSTEM_PHYSICS=70,GameLib.Component.COMPONENT_SYSTEM_RENDER=71,GameLib.Component.COMPONENT_SYSTEM_STORAGE=72,GameLib.Component.COMPONENT_SYSTEM_VISUALIZATION=73,GameLib.Component.COMPONENT_FOG=80,GameLib.Component.COMPONENT_MESH_LINE=81,GameLib.Component.COMPONENT_PARTICLE_ENGINE=82,GameLib.Component.COMPONENT_SYSTEM_PARTICLE=83,GameLib.Component.COMPONENT_PARTICLE=84,GameLib.Component.COMPONENT_AUDIO=85,GameLib.Component.COMPONENT_SYSTEM_AUDIO=86,GameLib.Component.GetComponentName=function(e){switch(e){case 1:return"GameLib.D3.PathFollowing";case 2:return"GameLib.D3.Material";case 3:return"GameLib.D3.Renderer";case 4:return"GameLib.D3.LookAt";case 5:return"GameLib.D3.Camera";case 6:return"GameLib.D3.Follow";case 7:return"GameLib.D3.Mesh";case 8:return"GameLib.D3.Spline";case 9:return"GameLib.D3.Light";case 10:return"GameLib.D3.InputDrive";case 11:return"GameLib.D3.Composer";case 12:return"GameLib.D3.RenderTarget";case 13:return"GameLib.D3.Pass";case 14:return"GameLib.D3.Scene";case 15:return"GameLib.D3.Raycaster";case 16:return"GameLib.D3.InputEditor";case 17:return"GameLib.D3.Editor";case 18:return"GameLib.D3.Viewport";case 19:return"GameLib.System";case 20:return"GameLib.D3.Graphics";case 21:return"GameLib.D3.Helper";case 22:return"GameLib.D3.CustomCode";case 23:return"GameLib.Mouse";case 24:return"GameLib.D3.Skeleton";case 25:return"GameLib.D3.Texture";case 26:return"GameLib.EntityManager";case 27:return"GameLib.DomElement";case 28:return"GameLib.D3.ImageFactory";case 29:return"GameLib.D3.Stats";case 30:return"GameLib.GUI";case 31:return"GameLib.D3.Image";case 32:return"GameLib.Entity";case 33:return"GameLib.D3.Mesh.Sphere";case 34:return"GameLib.D3.Mesh.Plane";case 35:return"GameLib.D3.Mesh.Curve";case 36:return"GameLib.D3.PhysicsWorld";case 37:return"GameLib.D3.Broadphase";case 38:return"GameLib.D3.Solver";case 39:return"GameLib.D3.RigidBody";case 40:return"GameLib.D3.Shape";case 41:return"GameLib.D3.Shape.Box";case 42:return"GameLib.D3.Shape.Sphere";case 43:return"GameLib.D3.Shape.TriMesh";case 44:return"GameLib.D3.Shape.ConvexHull";case 45:return"GameLib.D3.Shape.ConvexHull.Cylinder";case 46:return"GameLib.D3.Shape.HeightMap";case 47:return"GameLib.D3.Shape.Plane";case 48:return"GameLib.D3.Controls";case 49:return"GameLib.D3.Controls.Editor";case 50:return"GameLib.D3.Controls.Touch";case 51:return"GameLib.D3.FrictionMaterial";case 52:return"GameLib.D3.FrictionContactMaterial";case 53:return"GameLib.D3.RaycastVehicle";case 54:return"GameLib.D3.RaycastWheel";case 55:return"GameLib.Clock";case 56:return"GameLib.D3.Animation";case 57:return"GameLib.D3.Controls.Keyboard";case 58:return"GameLib.D3.Controls.Mouse";case 59:return"GameLib.D3.Mesh.Text";case 60:return"GameLib.D3.Font";case 61:return"GameLib.D3.Canvas";case 62:return"GameLib.D3.Bone";case 63:return"GameLib.D3.Mesh.Box";case 64:return"GameLib.D3.Mesh.Cylinder";case 65:return"GameLib.D3.System.Animation";case 66:return"GameLib.D3.System.CustomCode";case 67:return"GameLib.D3.System.GUI";case 68:return"GameLib.D3.System.Input";case 69:return"GameLib.D3.System.Linking";case 70:return"GameLib.D3.System.Physics";case 71:return"GameLib.D3.System.Render";case 72:return"GameLib.D3.System.Storage";case 73:return"GameLib.D3.System.Visualization";case 80:return"GameLib.D3.Fog";case 81:return"GameLib.D3.Mesh.Line";case 82:return"GameLib.D3.ParticleEngine";case 83:return"GameLib.D3.System.Particle";case 84:return"GameLib.D3.Particle";case 85:return"GameLib.D3.Audio";case 86:return"GameLib.D3.System.Audio"}throw new Error("Unknown component type: "+e)},GameLib.Component.prototype.toApiObject=function(){return this.id},GameLib.Component.prototype.processComponent=function(e){if(e instanceof GameLib.Component){e.buildIdToObject(),e.linked||(this.linked=!1);var t=e.idToObject;for(var i in t)t.hasOwnProperty(i)&&(this.idToObject[i]=t[i]);e.id?this.idToObject[e.id]=e:console.warn("Object with no ID passed: "+e)}else"string"==typeof e?this.linked=!1:console.warn("Unhandled type of object: ",e)},GameLib.Component.prototype.buildIdToObject=function(){if(!this.building){this.building=!0,this.linked=!0,this.idToObject={};for(var e in this.linkedObjects)this.linkedObjects.hasOwnProperty(e)&&this.hasOwnProperty(e)&&this[e]&&0!==e.indexOf("parent")&&(this.linkedObjects[e]instanceof Array?(this[e]=this[e].filter(function(e){return null!==e||(console.log("null object found and removed"),!1)}),this[e].map(function(e){this.processComponent(e)}.bind(this))):this.processComponent(this[e]));this instanceof GameLib.D3.Scene&&(this.storeClones||this.clones.map(function(e){this.idToObject.hasOwnProperty(e.id)&&delete this.idToObject[e.id]}.bind(this))),this.idToObject[this.id]=this,this.building=!1}},GameLib.Component.prototype.generateNewIds=function(){this.buildIdToObject();var e=GameLib.EntityManager.Instance.queryComponents(GameLib.D3.CustomCode);for(var t in this.idToObject)if(this.idToObject.hasOwnProperty(t)){var i=this.idToObject[t].id,n=GameLib.Utils.RandomId();this.idToObject[t].id=n,this.idToObject[t].name=this.idToObject[t].name.replace(i,n),e.map(function(e){e.code=e.code.replace(i,n)})}},GameLib.Component.prototype.remove=function(){this.buildIdToObject(),this.getDependencies().map(function(e){var t=this.idToObject[e];t instanceof GameLib.Component&&t.remove()}.bind(this)),GameLib.Event.Emit(GameLib.Event.REMOVE_COMPONENT,{component:this})},GameLib.Component.prototype.clone=function(){var e=this.toApiObject();this.cloneNumber+=1,e.id=GameLib.Utils.RandomId(),e.name=this.name+" Clone ("+this.cloneNumber+")";var t=null;try{t=new this.constructor(this.graphics,e)}catch(i){console.log(i);try{t=new this.constructor(this.physics,e)}catch(i){console.log(i);try{t=new this.constructor(this.coder,e)}catch(e){return console.log(e),void console.log("failed to construct a runtime component")}}}return t.isClone=!0,GameLib.Event.Emit(GameLib.Event.COMPONENT_CLONED,{parent:this,component:t}),t.parentEntity=null,t},GameLib.Component.prototype.cloneInstance=function(){var e=null;return this.instance&&this.instance.clone&&(this.instance.clone,!0)&&(e=this.instance.clone(),GameLib.Event.Emit(GameLib.Event.INSTANCE_CLONED,{component:this,instance:e})),e},GameLib.Component.prototype.saveToRemoteAPI=function(){this.save(!0)},GameLib.Component.prototype.save=function(e){var t=[],i=[],n=[];if(this.buildIdToObject(),this.saveSubscription||this.saveErrorSubscription)return void console.warn("another save is in progress");GameLib.Event.Emit(GameLib.Event.SAVING,{component:this}),this.saveSubscription=GameLib.Event.Subscribe(GameLib.Event.COMPONENT_SAVED,function(e){i.push(e.component),n.length+i.length===t.length&&(this.saveSubscription.remove(),this.saveSubscription=null,this.saveErrorSubscription.remove(),this.saveErrorSubscription=null,GameLib.Event.Emit(GameLib.Event.DONE_SAVING,{failed:n,saved:i}))}.bind(this)),this.saveErrorSubscription=GameLib.Event.Subscribe(GameLib.Event.SAVE_COMPONENT_ERROR,function(e){n.push(e.component),n.length+i.length===t.length&&(this.saveSubscription.remove(),this.saveSubscription=null,this.saveErrorSubscription.remove(),this.saveErrorSubscription=null,GameLib.Event.Emit(GameLib.Event.DONE_SAVING,{failed:n,saved:i}))}.bind(this));for(var a in this.idToObject)if(this.idToObject.hasOwnProperty(a)&&this.idToObject[a]instanceof GameLib.Component){var s=this.idToObject[a].toApiObject();s.componentType=this.idToObject[a].componentType,t.push(s),this.publish(GameLib.Event.SAVE_COMPONENT,{apiObject:s,remote:e})}},GameLib.API.Clock=function(e,t,i){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Clock ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=null),this.parentEntity=i},GameLib.API.Clock.prototype=Object.create(GameLib.Component.prototype),GameLib.API.Clock.prototype.constructor=GameLib.API.Clock,GameLib.API.Clock.FromObject=function(e){return new GameLib.API.Clock(e.id,e.name,e.parentEntity)},GameLib.API.Color=function(e,t,i,n){GameLib.Utils.UndefinedOrNull(e)&&(e=1),this.r=e,GameLib.Utils.UndefinedOrNull(t)&&(t=1),this.g=t,GameLib.Utils.UndefinedOrNull(i)&&(i=1),this.b=i,GameLib.Utils.UndefinedOrNull(n)&&(n=0),this.a=n},GameLib.API.Color.FromObject=function(e){return GameLib.Utils.UndefinedOrNull(e)&&(e={}),new GameLib.API.Color(e.r,e.g,e.b,e.a)},GameLib.API.Color.prototype.toHex=function(){this.r<0&&(this.r=0),this.g<0&&(this.g=0),this.b<0&&(this.b=0),this.r>1&&(this.r=1),this.g>1&&(this.g=1),this.b>1&&(this.b=1);var e=Math.floor(this.r>=1?255:256*this.r).toString(16),t=Math.floor(this.g>=1?255:256*this.g).toString(16),i=Math.floor(this.b>=1?255:256*this.b).toString(16);return e.length<2&&(e="0"+e),t.length<2&&(t="0"+t),i.length<2&&(i="0"+i),"#"+e+t+i},GameLib.API.Color.prototype.fromHex=function(e){var t=e.match(new RegExp("#+(..)(..)(..)"));this.r=parseInt(t[1],16)/255,this.g=parseInt(t[2],16)/255,this.b=parseInt(t[3],16)/255},GameLib.API.DomElement=function(e,t,i,n){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="DOM Element ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=""),this.domElementId=i,GameLib.Utils.UndefinedOrNull(n)&&(n=null),this.parentEntity=n},GameLib.API.DomElement.prototype=Object.create(GameLib.Component.prototype),GameLib.API.DomElement.prototype.constructor=GameLib.API.DomElement,GameLib.API.DomElement.FromObject=function(e){return new GameLib.API.DomElement(e.id,e.name,e.domElementId,e.parentEntity)},GameLib.API.EntityManager=function(e,t,i,n,a){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Entity Manager ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=[]),this.entities=i,GameLib.Utils.UndefinedOrNull(n)&&(n=null),this.defaultEntity=n,GameLib.Utils.UndefinedOrNull(a)&&(a=null),this.defaultRenderer=a},GameLib.API.EntityManager.prototype=Object.create(GameLib.Component.prototype),GameLib.API.EntityManager.prototype.constructor=GameLib.API.EntityManager,GameLib.API.EntityManager.FromObject=function(e){var t=e.entities.map(function(e){return GameLib.API.Entity.FromObject(e)});return new GameLib.API.EntityManager(e.id,e.name,t,e.defaultEntity,e.defaultRenderer)},GameLib.API.Entity=function(e,t,i,n,a){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Entity ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=[]),this.components=i,GameLib.Utils.UndefinedOrNull(n)&&(n=null),this.parentEntity=n,GameLib.Utils.UndefinedOrNull(a)&&(a=null),this.parentEntityManager=a,this.activeComponent=null},GameLib.API.Entity.prototype=Object.create(GameLib.Component.prototype),GameLib.API.Entity.prototype.constructor=GameLib.API.Entity,GameLib.API.Entity.FromObject=function(e){return new GameLib.API.Entity(e.id,e.name,e.components,e.parentEntity,e.parentEntityManager)},GameLib.API.Matrix4=function(e,t,i,n){this.rows=[],GameLib.Utils.UndefinedOrNull(e)&&(e=new GameLib.API.Vector4(1,0,0,0)),this.rows[0]=e,GameLib.Utils.UndefinedOrNull(t)&&(t=new GameLib.API.Vector4(0,1,0,0)),this.rows[1]=t,GameLib.Utils.UndefinedOrNull(i)&&(i=new GameLib.API.Vector4(0,0,1,0)),this.rows[2]=i,GameLib.Utils.UndefinedOrNull(n)&&(n=new GameLib.API.Vector4(0,0,0,1)),this.rows[3]=n,this.temp=[],this.temp.push(new GameLib.API.Vector4),this.temp.push(new GameLib.API.Vector4),this.temp.push(new GameLib.API.Vector4),this.temp.push(new GameLib.API.Vector4),this.forward=new GameLib.API.Vector4,this.left=new GameLib.API.Vector4,this.up=new GameLib.API.Vector4},GameLib.API.Matrix4.FromObject=function(e){if(e.rows)return new GameLib.API.Matrix4(GameLib.API.Vector4.FromObject(e.rows[0]),GameLib.API.Vector4.FromObject(e.rows[1]),GameLib.API.Vector4.FromObject(e.rows[2]),GameLib.API.Vector4.FromObject(e.rows[3]));if(e instanceof Array)return new GameLib.API.Matrix4(GameLib.API.Vector4.FromObject(e[0]),GameLib.API.Vector4.FromObject(e[1]),GameLib.API.Vector4.FromObject(e[2]),GameLib.API.Vector4.FromObject(e[3])) +;throw console.warn("Unsupported object matrix type - whats your DB version?"),new Error("Unsupported object matrix type - whats your DB version?")},GameLib.API.Matrix4.prototype.rotationMatrixX=function(e){return this.identity(),this.rows[1]=new GameLib.API.Vector4(0,Math.cos(e),-1*Math.sin(e),0),this.rows[2]=new GameLib.API.Vector4(0,Math.sin(e),Math.cos(e),0),this},GameLib.API.Matrix4.prototype.rotationMatrixY=function(e){return this.identity(),this.rows[0]=new GameLib.API.Vector4(Math.cos(e),0,Math.sin(e),0),this.rows[2]=new GameLib.API.Vector4(-1*Math.sin(e),0,Math.cos(e),0),this},GameLib.API.Matrix4.prototype.rotationMatrixZ=function(e){return this.identity(),this.rows[0]=new GameLib.API.Vector4(Math.cos(e),-1*Math.sin(e),0,0),this.rows[1]=new GameLib.API.Vector4(Math.sin(e),Math.cos(e),0,0),this},GameLib.API.Matrix4.prototype.rotateX=function(e,t){return this.identity(),this.rotationMatrixX(e),this.multiply(t)},GameLib.API.Matrix4.prototype.rotateY=function(e,t){return this.identity(),this.rotationMatrixY(e),this.multiply(t)},GameLib.API.Matrix4.prototype.rotateZ=function(e,t){return this.identity(),this.rotationMatrixZ(e),this.multiply(t)},GameLib.API.Matrix4.prototype.multiply=function(e){return e instanceof GameLib.API.Quaternion||e instanceof GameLib.API.Vector4?new GameLib.API.Quaternion(this.rows[0].x*e.x+this.rows[0].y*e.y+this.rows[0].z*e.z+this.rows[0].w*e.w,this.rows[1].x*e.x+this.rows[1].y*e.y+this.rows[1].z*e.z+this.rows[1].w*e.w,this.rows[2].x*e.x+this.rows[2].y*e.y+this.rows[2].z*e.z+this.rows[2].w*e.w,this.rows[3].x*e.x+this.rows[3].y*e.y+this.rows[3].z*e.z+this.rows[3].w*e.w):e instanceof GameLib.API.Vector3?new GameLib.API.Vector3(this.rows[0].x*e.x+this.rows[0].y*e.y+this.rows[0].z*e.z,this.rows[1].x*e.x+this.rows[1].y*e.y+this.rows[1].z*e.z,this.rows[2].x*e.x+this.rows[2].y*e.y+this.rows[2].z*e.z):void 0},GameLib.API.Matrix4.prototype.identity=function(){this.rows=[new GameLib.API.Vector4(1,0,0,0),new GameLib.API.Vector4(0,1,0,0),new GameLib.API.Vector4(0,0,1,0),new GameLib.API.Vector4(0,0,0,1)]},GameLib.API.Mouse=function(e,t,i,n,a){GameLib.Utils.UndefinedOrNull(a)&&(a=null),this.parentEntity=a,GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Mouse ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=0),this.x=i,GameLib.Utils.UndefinedOrNull(n)&&(n=0),this.y=n},GameLib.API.Mouse.prototype=Object.create(GameLib.Component.prototype),GameLib.API.Mouse.prototype.constructor=GameLib.API.Mouse,GameLib.API.Mouse.FromObject=function(e){return new GameLib.API.Mouse(e.id,e.name,e.x,e.y,e.parentEntity)},GameLib.API.Quaternion=function(e,t,i,n,a,s){GameLib.Utils.UndefinedOrNull(e)&&(e=0),this.x=e,GameLib.Utils.UndefinedOrNull(t)&&(t=0),this.y=t,GameLib.Utils.UndefinedOrNull(i)&&(i=0),this.z=i,GameLib.Utils.UndefinedOrNull(n)&&(n=1),this.w=n,GameLib.Utils.UndefinedOrNull(a)&&(a=new GameLib.API.Vector3),this.axis=a,GameLib.Utils.UndefinedOrNull(s)&&(s=0),this.angle=s},GameLib.API.Quaternion.prototype.translate=function(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this},GameLib.API.Quaternion.prototype.copy=function(){return new GameLib.API.Quaternion(this.x,this.y,this.z,this.w)},GameLib.API.Quaternion.prototype.normalize=function(){var e=this.x*this.x+this.y*this.y+this.z*this.z;if(e<1e-6)return this;var t=1/Math.sqrt(e);this.x*=t,this.y*=t,this.z*=t},GameLib.API.Quaternion.prototype.multiply=function(e){var t,i,n,a,s=e,o=this;if(e instanceof GameLib.API.Matrix4)return t=s.rows[0].x*o.x+s.rows[0].y*o.y+s.rows[0].z*o.z+s.rows[0].w*o.w,i=s.rows[1].x*o.x+s.rows[1].y*o.y+s.rows[1].z*o.z+s.rows[1].w*o.w,n=s.rows[2].x*o.x+s.rows[2].y*o.y+s.rows[2].z*o.z+s.rows[2].w*o.w,a=s.rows[3].x*o.x+s.rows[3].y*o.y+s.rows[3].z*o.z+s.rows[3].w*o.w,this.x=t,this.y=i,this.z=n,this.w=a,this;if(e instanceof GameLib.API.Quaternion)return t=s.x*o.x-s.y*o.y-s.z*o.z-s.w*s.w,i=s.x*o.y+s.y*o.x-s.z*o.w+s.w*s.z,n=s.x*o.z+s.y*o.w+s.z*o.x-s.w*s.y,a=s.x*o.w-s.y*o.z+s.z*o.y+s.w*s.x,this.x=t,this.y=i,this.z=n,this.w=a,this;throw console.log("This functionality not implemented - please do this"),new Error("This functionality not implemented - please do this")},GameLib.API.Quaternion.prototype.setFromAngle=function(e){return this.instance.setFromAxisAngle(this.axis.instance,e),this.x=this.instance.x,this.y=this.instance.y,this.z=this.instance.z,this.w=this.instance.w,this},GameLib.API.Quaternion.prototype.subtract=function(e){return e instanceof GameLib.API.Vector3&&(this.x-=e.x,this.y-=e.y,this.z-=e.z),e instanceof GameLib.API.Quaternion&&(this.x-=e.x,this.y-=e.y,this.z-=e.z,this.w-=e.w),this},GameLib.API.Quaternion.prototype.magnitude=function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},GameLib.API.Quaternion.prototype.normalize=function(){var e=this.magnitude();return e<1e-6?this:(this.x*=e,this.y*=e,this.z*=e,this.w*=e,this)},GameLib.API.Quaternion.prototype.setFromRotationMatrix=function(e){this.instance.setFromRotationMatrix(e.instance),this.x=this.instance.x,this.y=this.instance.y,this.z=this.instance.z,this.w=this.instance.w},GameLib.API.Quaternion.prototype.slerp=function(e,t){return this.updateInstance(),this.instance.slerp(e.instance,t),this.x=this.instance.x,this.y=this.instance.y,this.z=this.instance.z,this.w=this.instance.w,this},GameLib.API.Quaternion.FromObject=function(e){var t=null;return e.axis&&(t=GameLib.API.Vector3.FromObject(e.axis)),new GameLib.API.Quaternion(e.x,e.y,e.z,e.w,t,e.angle)},GameLib.API.Quaternion.Points=function(){this.vectors=[]},GameLib.API.Quaternion.Points.prototype.add=function(e){if(e instanceof GameLib.API.Vector3&&(e=new GameLib.API.Quaternion(e.x,e.y,e.z,1)),!e instanceof GameLib.API.Quaternion)throw console.warn("Vector needs to be of type Quaternion"),new Error("Vector needs to be of type Quaternion");return this.vectors.push(e),this},GameLib.API.Quaternion.Points.prototype.copy=function(){for(var e=[],t=0;ts&&(s=c.x,n=t*e)}this.vectors=a;for(var h=(new GameLib.API.Matrix4).rotationMatrixY(n),m=0;ms&&(s=c.y,n=t*e)}this.vectors=a;for(var h=(new GameLib.API.Matrix4).rotationMatrixX(n),m=0;mn&&(n=this.vectors[o].x),this.vectors[o].y>a&&(a=this.vectors[o].y),this.vectors[o].z>s&&(s=this.vectors[o].z);return new GameLib.API.Vector3(Math.abs(n-e),Math.abs(a-t),Math.abs(a-i))},GameLib.API.Quaternion.Points.prototype.average=function(){for(var e=0,t=0,i=0,n=0;n0},GameLib.API.Vector3.normal=function(e,t,i){var n=t.copy(),a=i.copy();return n.subtract(e).cross(a.subtract(e))},GameLib.API.Vector3.prototype.lookAt=function(e,t){var i=GameLib.API.Matrix4.lookAt(this,e,t);return this.multiply(i)},GameLib.API.Vector3.prototype.translate=function(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this},GameLib.API.Vector3.prototype.add=function(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this},GameLib.API.Vector3.prototype.squared=function(){return this.x*this.x+this.y*this.y+this.z*this.z},GameLib.API.Vector3.prototype.copy=function(){return new GameLib.API.Vector3(this.x,this.y,this.z)},GameLib.API.Vector3.prototype.set=function(e,t,i){this.x=e,this.y=t,this.z=i},GameLib.API.Vector3.prototype.lerp=function(e,t){return new GameLib.API.Vector3(this.x+(e.x-this.x)*t,this.y+(e.y-this.y)*t,this.z+(e.z-this.z)*t)},GameLib.API.Vector3.prototype.distanceTo=function(e){var t=this.x-e.x,i=this.y-e.y,n=this.z-e.z;return Math.sqrt(t*t+i*i+n*n)},GameLib.API.Vector3.AngleDirection=function(e,t,i){var n=e.cross(t),a=n.dot(i);return a>0?1:a<0?-1:0},GameLib.API.Vector3.prototype.multiply=function(e,t){var i,n,a,s=e,o=this;if(GameLib.Utils.UndefinedOrNull(t)&&(t=!1),"number"==typeof e)return t?(this.x*=e,this.y*=e,this.z*=e,this):this.x*e+this.y*e+this.z*e;if(e instanceof GameLib.API.Vector3)return t?(i=s.y*o.z-s.z*o.y,n=s.z*o.x-s.x*o.z,a=s.x*o.y-s.y*o.x,this.x=i,this.y=n,this.z=a,this):this.x*e.x+this.y*e.y+this.z*e.z;throw console.log("functionality not implemented - please do this"),new Error("not implemented")},GameLib.API.Vector3.prototype.dot=function(e){return this.x*e.x+this.y*e.y+this.z*e.z},GameLib.API.Vector3.prototype.normalize=function(){var e=this.squared();if(e<1e-6)return this;var t=1/Math.sqrt(e);return new GameLib.API.Vector3(this.x*t,this.y*t,this.z*t)},GameLib.API.Vector3.prototype.clone=function(){return new GameLib.API.Vector3(this.x,this.y,this.z)},GameLib.API.Vector3.prototype.applyQuaternion=function(e){var t=this.x,i=this.y,n=this.z,a=e.x,s=e.y,o=e.z,r=e.w,c=r*t+s*n-o*i,h=r*i+o*t-a*n,m=r*n+a*i-s*t,l=-a*t-s*i-o*n;return this.x=c*r+l*-a+h*-o-m*-s,this.y=h*r+l*-s+m*-a-c*-o,this.z=m*r+l*-o+c*-s-h*-a,this},GameLib.API.Vector3.prototype.clamp=function(e,t){return this.x=Math.max(e.x,Math.min(t.x,this.x)),this.y=Math.max(e.y,Math.min(t.y,this.y)),this.z=Math.max(e.z,Math.min(t.z,this.z)),this},GameLib.API.Vector3.prototype.length=function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},GameLib.API.Vector3.prototype.reflect=function(e){return this.sub(v1.copy(e).multiply(2*this.dot(e)))},GameLib.API.Vector3.prototype.angleTo=function(e){var t=this.dot(e)/Math.sqrt(this.lengthSq()*e.lengthSq());return Math.acos(exports.Math.clamp(t,-1,1))},GameLib.API.Vector3.FromObject=function(e){return new GameLib.API.Vector3(e.x,e.y,e.z)},GameLib.API.Vector4=function(e,t,i,n){GameLib.Utils.UndefinedOrNull(e)&&(e=0),this.x=e,GameLib.Utils.UndefinedOrNull(t)&&(t=0),this.y=t,GameLib.Utils.UndefinedOrNull(i)&&(i=0),this.z=i,GameLib.Utils.UndefinedOrNull(n)&&(n=1),this.w=n},GameLib.API.Vector4.prototype.equals=function(e){return this.x===e.x&&this.y===e.y&&this.z===e.z&&this.w===e.w},GameLib.API.Vector4.FromObject=function(e){return new GameLib.API.Vector4(e.x,e.y,e.z,e.w)},GameLib.Clock=function(e,t){if(this.implementation=e,this.implementation.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.Clock)return t;GameLib.API.Clock.call(this,t.id,t.name,t.parentEntity),GameLib.Component.call(this,GameLib.Component.COMPONENT_CLOCK)},GameLib.Clock.prototype=Object.create(GameLib.API.Clock.prototype),GameLib.Clock.prototype.constructor=GameLib.Clock,GameLib.Clock.prototype.createInstance=function(){this.instance=new THREE.Clock,GameLib.Component.prototype.createInstance.call(this)},GameLib.Clock.prototype.updateInstance=function(){},GameLib.Clock.prototype.getDelta=function(){var e=this.instance.getDelta();return e>1/30&&(e=1/30),e},GameLib.Clock.prototype.toApiObject=function(){return new GameLib.API.Clock(this.id,this.name,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.Clock.FromObject=function(e,t){var i=GameLib.API.Clock.FromObject(t);return new GameLib.Clock(e,i)},GameLib.Color=function(e,t,i,n){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.Color)return t;GameLib.API.Color.call(this,t.r,t.g,t.b,t.a),GameLib.Utils.UndefinedOrNull(i)&&(i=null),this.parentObject=i,GameLib.Utils.UndefinedOrNull(n)&&(n=.001),this.grain=n,this.createInstance()},GameLib.Color.prototype=Object.create(GameLib.API.Color.prototype),GameLib.Color.prototype.constructor=GameLib.Color,GameLib.Color.prototype.createInstance=function(){this.instance=new THREE.Color(this.r,this.g,this.b)},GameLib.Color.prototype.updateInstance=function(e){this.instance.r=this.r,this.instance.g=this.g,this.instance.b=this.b,this.parentObject&&this.parentObject.updateInstance&&this.parentObject.updateInstance(e)},GameLib.Color.prototype.toApiObject=function(){return new GameLib.API.Color(this.r,this.g,this.b,this.a)},GameLib.D3.API.Animation=function(e,t,i,n,a,s,o,r,c,h,m,l){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Animation ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=0),this.rotationSpeed=i,GameLib.Utils.UndefinedOrNull(n)&&(n=0),this.translationSpeed=n,GameLib.Utils.UndefinedOrNull(a)&&(a=0),this.scaleSpeed=a,GameLib.Utils.UndefinedOrNull(s)&&(s=null),this.rotationFn=s,GameLib.Utils.UndefinedOrNull(o)&&(o=null),this.translationFn=o,GameLib.Utils.UndefinedOrNull(r)&&(r=null),this.scaleFn=r,GameLib.Utils.UndefinedOrNull(c)&&(c={position:!1,rotation:!0,scale:!1}),this.blocking=c,GameLib.Utils.UndefinedOrNull(h)&&(h=!0),this.applyToMeshWhenDone=h,GameLib.Utils.UndefinedOrNull(m)&&(m=[]),this.meshes=m,GameLib.Utils.UndefinedOrNull(l)&&(l=null),this.parentEntity=l},GameLib.D3.API.Animation.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Animation.prototype.constructor=GameLib.D3.API.Animation,GameLib.D3.API.Animation.FromObject=function(e){return new GameLib.D3.API.Animation(e.id,e.name,e.rotationSpeed,e.translationSpeed,e.scaleSpeed,e.rotationFn,e.translationFn,e.scaleFn,e.blocking,e.applyToMeshWhenDone,e.meshes,e.parentEntity)},GameLib.D3.API.Audio=function(e,t,i,n,a,s,o,r){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Audio ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=""),this.path=i,GameLib.Utils.UndefinedOrNull(n)&&(n=!1),this.loop=n,GameLib.Utils.UndefinedOrNull(a)&&(a=.5),this.volume=a,GameLib.Utils.UndefinedOrNull(s)&&(s=null),this.camera=s,GameLib.Utils.UndefinedOrNull(o)&&(o=!1),this.overplay=o,GameLib.Utils.UndefinedOrNull(r)&&(r=null),this.parentEntity=r},GameLib.D3.API.Audio.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Audio.prototype.constructor=GameLib.D3.API.Audio,GameLib.D3.API.Audio.FromObject=function(e){var t=null;return e.camera&&(t=e.camera instanceof Object?GameLib.D3.API.Camera.FromObject(e.camera):e.camera),new GameLib.D3.API.Audio(e.id,e.name,e.path,e.loop,e.volume,t,e.overplay,e.parentEntity)},GameLib.D3.API.BoneWeight=function(e,t){this.boneIndex=e,this.weight=t},GameLib.D3.API.BoneWeight.FromObject=function(e){return new GameLib.D3.API.BoneWeight(e.boneIndex,e.weight)},GameLib.D3.API.Bone=function(e,t,i,n,a,s,o,r){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Bone ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=[]),this.childBoneIds=i,GameLib.Utils.UndefinedOrNull(n)&&(n=[]),this.parentBoneIds=n,GameLib.Utils.UndefinedOrNull(a)&&(a=new GameLib.API.Vector3),this.position=a,GameLib.Utils.UndefinedOrNull(s)&&(s=new GameLib.API.Quaternion),this.quaternion=s,GameLib.Utils.UndefinedOrNull(o)&&(o=new GameLib.API.Vector3(1,1,1)),this.scale=o,GameLib.Utils.UndefinedOrNull(r)&&(r=new GameLib.API.Vector3(0,1,0)),this.up=r},GameLib.D3.API.Bone.FromObject=function(e){return new GameLib.D3.API.Bone(e.id,e.name,e.childBoneIds,e.parentBoneIds,GameLib.API.Vector3.FromObject(e.position),GameLib.API.Quaternion.FromObject(e.quaternion),GameLib.API.Vector3.FromObject(e.scale),GameLib.API.Vector3.FromObject(e.up))},GameLib.D3.API.Broadphase=function(e,t,i,n){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Broadphase ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE),this.broadphaseType=i,GameLib.Utils.UndefinedOrNull(n)&&(n=null),this.parentEntity=n},GameLib.D3.API.Broadphase.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Broadphase.prototype.constructor=GameLib.D3.API.Broadphase,GameLib.D3.API.Broadphase.FromObject=function(e){return new GameLib.D3.API.Broadphase(e.id,e.name,e.broadphaseType,e.parentEntity)},GameLib.D3.API.Camera=function(e,t,i,n,a,s,o,r,c,h,m,l,p,u,b,d,L,G,f,E,y){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t=GameLib.D3.Camera.CAMERA_TYPE_PERSPECTIVE),this.cameraType=t,GameLib.Utils.UndefinedOrNull(i)&&(i="Camera ("+this.id+")"),this.name=i,GameLib.Utils.UndefinedOrNull(n)&&(n=75),this.fov=n,GameLib.Utils.UndefinedOrNull(a)&&(a=window.innerWidth/window.innerHeight),this.aspect=a,GameLib.Utils.UndefinedOrNull(s)&&(s=.01),this.near=s,GameLib.Utils.UndefinedOrNull(o)&&(o=1e3),this.far=o,GameLib.Utils.UndefinedOrNull(r)&&(r=new GameLib.API.Vector3(15,15,15)),this.position=r,GameLib.Utils.UndefinedOrNull(G)&&(G=new GameLib.API.Quaternion),this.quaternion=G,GameLib.Utils.UndefinedOrNull(c)&&(c=new GameLib.API.Vector3(0,0,0)),this.lookAt=c,GameLib.Utils.UndefinedOrNull(h)&&(h=-100),this.minX=h,GameLib.Utils.UndefinedOrNull(m)&&(m=100),this.maxX=m,GameLib.Utils.UndefinedOrNull(l)&&(l=-100),this.minY=l,GameLib.Utils.UndefinedOrNull(p)&&(p=100),this.maxY=p,GameLib.Utils.UndefinedOrNull(u)&&(u=-100),this.minZ=u,GameLib.Utils.UndefinedOrNull(b)&&(b=100),this.maxZ=b,GameLib.Utils.UndefinedOrNull(d)&&(d=0),this.offsetX=d,GameLib.Utils.UndefinedOrNull(L)&&(L=0),this.offsetY=L,GameLib.Utils.UndefinedOrNull(E)&&(E=30),this.eyeSeparation=E,GameLib.Utils.UndefinedOrNull(y)&&(y=150),this.focalLength=y,GameLib.Utils.UndefinedOrNull(f)&&(f=null),this.parentEntity=f},GameLib.D3.API.Camera.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Camera.prototype.constructor=GameLib.D3.API.Camera,GameLib.D3.API.Camera.FromObject=function(e){return new GameLib.D3.API.Camera(e.id,e.cameraType,e.name,e.fov,e.aspect,e.near,e.far,GameLib.API.Vector3.FromObject(e.position),GameLib.API.Vector3.FromObject(e.lookAt),e.minX,e.maxX,e.minY,e.maxY,e.minZ,e.maxZ,e.offsetX,e.offsetY,GameLib.API.Quaternion.FromObject(e.quaternion),e.parentEntity,e.eyeSeparation,e.focalLength)},GameLib.D3.API.Canvas=function(e,t,i,n,a){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Canvas ("+e+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=512),this.width=i,GameLib.Utils.UndefinedOrNull(n)&&(n=512),this.height=n,GameLib.Utils.UndefinedOrNull(a)&&(a=null),this.parentEntity=a},GameLib.D3.API.Canvas.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Canvas.prototype.constructor=GameLib.D3.API.Canvas,GameLib.D3.API.Canvas.FromObject=function(e){return new GameLib.D3.API.Canvas(e.id,e.name,e.width,e.height,e.parentEntity)},GameLib.D3.API.Composer=function(e,t,i,n,a,s){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Composer ("+e+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=null),this.renderer=i,GameLib.Utils.UndefinedOrNull(n)&&(n=null),this.renderTarget=n,GameLib.Utils.UndefinedOrNull(a)&&(a=[]),this.passes=a,GameLib.Utils.UndefinedOrNull(s)&&(s=null),this.parentEntity=s},GameLib.D3.API.Composer.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Composer.prototype.constructor=GameLib.D3.API.Composer,GameLib.D3.API.Composer.FromObject=function(e){return new GameLib.D3.API.Composer(e.id,e.name,e.renderer,e.renderTarget,e.passes,e.parentEntity)},GameLib.D3.API.Controls=function(e,t,i,n,a){if(GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(this instanceof GameLib.D3.Controls.Editor&&(t=GameLib.D3.Controls.CONTROLS_TYPE_EDITOR),this instanceof GameLib.D3.Controls.Touch&&(t=GameLib.D3.Controls.CONTROLS_TYPE_TOUCH),this instanceof GameLib.D3.Controls.Keyboard&&(t=GameLib.D3.Controls.CONTROLS_TYPE_KEYBOARD),this instanceof GameLib.D3.Controls.Mouse&&(t=GameLib.D3.Controls.CONTROLS_TYPE_MOUSE),GameLib.Utils.UndefinedOrNull(t)))throw new Error("Could not determine controls type from this");this.controlsType=t,GameLib.Utils.UndefinedOrNull(i)&&(t===GameLib.D3.Controls.CONTROLS_TYPE_EDITOR&&(i="Editing Controls"),t===GameLib.D3.Controls.CONTROLS_TYPE_TOUCH&&(i="Touch Controls"),t===GameLib.D3.Controls.CONTROLS_TYPE_KEYBOARD&&(i="Keyboard Controls"),t===GameLib.D3.Controls.CONTROLS_TYPE_MOUSE&&(i="Mouse Controls"),i+=" ("+this.id+")"),this.name=i,GameLib.Utils.UndefinedOrNull(n)&&(n=null),this.domElement=n,GameLib.Utils.UndefinedOrNull(a)&&(a=null),this.parentEntity=a},GameLib.D3.API.Controls.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Controls.prototype.constructor=GameLib.D3.API.Controls,GameLib.D3.API.Controls.FromObject=function(e){return new GameLib.D3.API.Controls(e.id,e.controlsType,e.name,e.domElement,e.parentEntity)},GameLib.D3.API.CustomCode=function(e,t,i,n,a){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="CustomCode ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=42),this.eventId=i,GameLib.Utils.UndefinedOrNull(n)&&(n="return null;\n//@ sourceURL="+this.name+".js"),this.code=n,GameLib.Utils.UndefinedOrNull(a)&&(a=null),this.parentEntity=a},GameLib.D3.API.CustomCode.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.CustomCode.prototype.constructor=GameLib.D3.API.CustomCode,GameLib.D3.API.CustomCode.FromObject=function(e){return new GameLib.D3.API.CustomCode(e.id,e.name,e.eventId,e.code,e.parentEntity)},GameLib.D3.API.Face=function(e,t,i,n,a,s,o,r,c,h,m){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Face "+e),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=-1),this.v0index=i,GameLib.Utils.UndefinedOrNull(n)&&(n=-1),this.v1index=n,GameLib.Utils.UndefinedOrNull(a)&&(a=-1),this.v2index=a,GameLib.Utils.UndefinedOrNull(s)&&(s=-1),this.materialIndex=s,GameLib.Utils.UndefinedOrNull(o)&&(o=[[]]),this.uvs=o,GameLib.Utils.UndefinedOrNull(r)&&(r=null),this.color=r,GameLib.Utils.UndefinedOrNull(c)&&(c=[]),this.vertexColors=c,GameLib.Utils.UndefinedOrNull(h)&&(h=[]),this.vertexNormals=h,GameLib.Utils.UndefinedOrNull(m)&&(m=null),this.normal=m},GameLib.D3.API.Face.FromObject=function(e){var t=e.uvs.reduce(function(e,t,i){return e[i]=t.reduce(function(e,t){return e.push(GameLib.API.Vector2.FromObject(t)),e},[]),e},[]),i=e.vertexColors.map(function(e){return GameLib.API.Color.FromObject(e)}),n=null;e.color&&(n=GameLib.API.Color.FromObject(e.color));var a=e.vertexNormals.map(function(e){return GameLib.API.Vector3.FromObject(e)}),s=null;return e.normal&&(s=GameLib.API.Vector3.FromObject(e.normal)),new GameLib.D3.API.Face(e.id,e.name,e.v0index,e.v1index,e.v2index,e.materialIndex,t,n,i,a,s)},GameLib.D3.API.Face.prototype.clone=function(){return new GameLib.D3.API.Face(this.id,this.name,this.v0index,this.v1index,this.v2index,this.materialIndex,this.uvs,this.color,this.vertexColors,this.vertexNormals,this.normal)},GameLib.D3.API.Face.prototype.equals=function(e){return this.v0index===e.v0index&&this.v1index===e.v1index&&this.v2index===e.v2index||this.v0index===e.v0index&&this.v1index===e.v2index&&this.v2index===e.v1index||this.v0index===e.v1index&&this.v1index===e.v0index&&this.v2index===e.v2index||this.v0index===e.v1index&&this.v1index===e.v2index&&this.v2index===e.v0index||this.v0index===e.v2index&&this.v1index===e.v0index&&this.v2index===e.v1index||this.v0index===e.v2index&&this.v1index===e.v1index&&this.v2index===e.v0index},GameLib.D3.API.Fog=function(e,t,i,n,a,s,o,r){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Fog ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=!1),this.exponential=i,GameLib.Utils.UndefinedOrNull(n)&&(n=new GameLib.API.Color(1,1,1,1)),this.color=n,GameLib.Utils.UndefinedOrNull(a)&&(a=1),this.near=a,GameLib.Utils.UndefinedOrNull(s)&&(s=1e3),this.far=s,GameLib.Utils.UndefinedOrNull(o)&&(o=25e-5),this.density=o,GameLib.Utils.UndefinedOrNull(r)&&(r=null),this.parentEntity=r},GameLib.D3.API.Fog.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Fog.prototype.constructor=GameLib.D3.API.Fog,GameLib.D3.API.Fog.FromObject=function(e){return new GameLib.D3.API.Fog(e.id,e.name,e.exponential,e.color,e.near,e.far,e.density,e.parentEntity)},GameLib.D3.API.Font=function(e,t,i,n){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Font ("+e+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i="/apiRelative/path/to/font"),this.url=i,GameLib.Utils.UndefinedOrNull(n)&&(n=null),this.parentEntity=n},GameLib.D3.API.Font.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Font.prototype.constructor=GameLib.D3.API.Font,GameLib.D3.API.Font.FromObject=function(e){return new GameLib.D3.API.Font(e.id,e.name,e.url,e.parentEntity)},GameLib.D3.API.FrictionContactMaterial=function(e,t,i,n,a,s,o,r,c,h){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Friction Material ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=[]),this.materials=i,GameLib.Utils.UndefinedOrNull(n)&&(n=.3),this.friction=n,GameLib.Utils.UndefinedOrNull(a)&&(a=.3),this.restitution=a,GameLib.Utils.UndefinedOrNull(s)&&(s=1e7),this.contactEquationStiffness=s,GameLib.Utils.UndefinedOrNull(o)&&(o=3),this.contactEquationRelaxation=o,GameLib.Utils.UndefinedOrNull(r)&&(r=1e7),this.frictionEquationStiffness=r,GameLib.Utils.UndefinedOrNull(c)&&(c=3),this.frictionEquationRelaxation=c,GameLib.Utils.UndefinedOrNull(h)&&(h=null),this.parentEntity=h},GameLib.D3.API.FrictionContactMaterial.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.FrictionContactMaterial.prototype.constructor=GameLib.D3.API.FrictionContactMaterial,GameLib.D3.API.FrictionContactMaterial.FromObject=function(e){return new GameLib.D3.API.FrictionContactMaterial(e.id,e.name,e.materials,e.friction,e.restitution,e.contactEquationStiffness,e.contactEquationRelaxation,e.frictionEquationStiffness,e.frictionEquationRelaxation,e.parentEntity)},GameLib.D3.API.FrictionMaterial=function(e,t,i,n,a){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Friction Material ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=-1),this.friction=i,GameLib.Utils.UndefinedOrNull(n)&&(n=-1),this.restitution=n,GameLib.Utils.UndefinedOrNull(a)&&(a=null),this.parentEntity=a};GameLib.D3.API.FrictionMaterial.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.FrictionMaterial.prototype.constructor=GameLib.D3.API.FrictionMaterial,GameLib.D3.API.FrictionMaterial.FromObject=function(e){return new GameLib.D3.API.FrictionMaterial(e.id,e.name,e.friction,e.restitution,e.parentEntity)},GameLib.D3.API.ImageFactory=function(e,t,i,n){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="ImageFactory ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i="",console.warn("No baseURL defined for image factory")),this.baseUrl=i,GameLib.Utils.UndefinedOrNull(n)&&(n=null),this.parentEntity=n},GameLib.D3.API.ImageFactory.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.ImageFactory.prototype.constructor=GameLib.D3.API.ImageFactory,GameLib.D3.API.ImageFactory.FromObject=function(e){return new GameLib.D3.API.ImageFactory(e.id,e.name,e.baseUrl,e.parentEntity)},GameLib.D3.API.Image=function(e,t,i,n,a,s,o,r){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Image "+e),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=GameLib.Utils.LowerUnderscore(t)),this.fileName=i,GameLib.Utils.UndefinedOrNull(n)&&(n=".unknown"),this.extension=n,GameLib.Utils.UndefinedOrNull(a)&&(a="/"),this.path=a,GameLib.Utils.UndefinedOrNull(s)&&(s="application/octet-stream",this.extension.match(/(png)$/i)&&(s="image/png"),this.extension.match(/(jpg|jpeg)$/i)&&(s="image/jpeg"),this.extension.match(/(gif)$/i)&&(s="image/gif")),this.contentType=s,GameLib.Utils.UndefinedOrNull(o)&&(o=0),this.size=o,GameLib.Utils.UndefinedOrNull(r)&&(r=null),this.parentEntity=r},GameLib.D3.API.Image.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Image.prototype.constructor=GameLib.D3.API.Image,GameLib.D3.API.Image.FromObject=function(e){return new GameLib.D3.API.Image(e.id,e.name,e.fileName,e.extension,e.path,e.contentType,e.size,e.parentEntity)}, +GameLib.D3.API.Light=function(e,t,i,n,a,s,o,r,c,h,m,l,p,u,b,d,L){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t=GameLib.D3.Light.LIGHT_TYPE_AMBIENT),this.lightType=t,GameLib.Utils.UndefinedOrNull(i)&&(this.lightType===GameLib.D3.Light.LIGHT_TYPE_AMBIENT&&(i="Ambient "),this.lightType===GameLib.D3.Light.LIGHT_TYPE_DIRECTIONAL&&(i="Directional "),this.lightType===GameLib.D3.Light.LIGHT_TYPE_POINT&&(i="Point "),this.lightType===GameLib.D3.Light.LIGHT_TYPE_SPOT&&(i="Spot "),i+="Light ("+e+")"),this.name=i,GameLib.Utils.UndefinedOrNull(n)&&(n=new GameLib.API.Color(1,1,1,1)),this.color=n,GameLib.Utils.UndefinedOrNull(a)&&(a=1),this.intensity=a,GameLib.Utils.UndefinedOrNull(s)&&(s=new GameLib.API.Vector3(10,10,10)),this.position=s,GameLib.Utils.UndefinedOrNull(o)&&(o=new GameLib.API.Vector3(0,0,0)),this.targetPosition=o,GameLib.Utils.UndefinedOrNull(r)&&(r=new GameLib.API.Quaternion),this.quaternion=r,GameLib.Utils.UndefinedOrNull(c)&&(c=new GameLib.API.Vector3(0,0,0)),this.rotation=c,GameLib.Utils.UndefinedOrNull(h)&&(h=new GameLib.API.Vector3(1,1,1)),this.scale=h,GameLib.Utils.UndefinedOrNull(m)&&(m=0),this.distance=m,GameLib.Utils.UndefinedOrNull(l)&&(l=1),this.decay=l,GameLib.Utils.UndefinedOrNull(p)&&(p=4*Math.PI),this.power=p,GameLib.Utils.UndefinedOrNull(u)&&(u=Math.PI/3),this.angle=u,GameLib.Utils.UndefinedOrNull(b)&&(b=0),this.penumbra=b,GameLib.Utils.UndefinedOrNull(d)&&(d=null),this.parentScene=d,GameLib.Utils.UndefinedOrNull(L)&&(L=null),this.parentEntity=L},GameLib.D3.API.Light.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Light.prototype.constructor=GameLib.D3.API.Light,GameLib.D3.API.Light.FromObject=function(e){return new GameLib.D3.API.Light(e.id,e.lightType,e.name,GameLib.API.Color.FromObject(e.color),e.intensity,GameLib.API.Vector3.FromObject(e.position),GameLib.API.Vector3.FromObject(e.targetPosition),GameLib.API.Quaternion.FromObject(e.quaternion),GameLib.API.Vector3.FromObject(e.rotation),GameLib.API.Vector3.FromObject(e.scale),e.distance,e.decay,e.power,e.angle,e.penumbra,e.parentScene,e.parentEntity)},GameLib.D3.API.LookAt=function(e,t,i,n,a,s,o){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t=this.constructor.name),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=null),this.currentComponent=i,GameLib.Utils.UndefinedOrNull(n)&&(n=null),this.targetComponent=n,GameLib.Utils.UndefinedOrNull(a)&&(a=new GameLib.API.Vector3(0,0,0)),this.targetPositionOffset=a,GameLib.Utils.UndefinedOrNull(s)&&(s=22),this.rotationSpeed=s,this.lookAtMatrix=new GameLib.API.Matrix4,this.up=new GameLib.API.Vector3(0,1,0),this.currentRotation=new GameLib.API.Quaternion,this.targetPosition=new GameLib.API.Vector3,GameLib.Utils.UndefinedOrNull(o)&&(o=null),this.parentEntity=o},GameLib.D3.API.LookAt.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.LookAt.prototype.constructor=GameLib.D3.API.LookAt,GameLib.D3.API.LookAt.FromObject=function(e){return new GameLib.D3.API.LookAt(e.id,e.name,e.currentComponent,e.targetComponent,GameLib.API.Vector3.FromObject(e.targetPositionOffset),e.rotationSpeed,e.parentEntity)},GameLib.D3.API.Material=function(e,t,i,n,a,s,o,r,c,h,m,l,p,u,b,d,L,G,f,E,y,O,D,P,T,I,g,A,N,C,S,U,v,M,_,w,x,R,F,j,V,Y,H,z,B,q,k,W,Q,X,K,Z,J,$,ee,te,ie,ne,ae,se,oe,re,ce,he,me,le,pe,ue,be){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t=GameLib.D3.Material.MATERIAL_TYPE_STANDARD),this.materialType=t,GameLib.Utils.UndefinedOrNull(i)&&(i="Material ("+t+")"),this.name=i,GameLib.Utils.UndefinedOrNull(n)&&(n=1),this.opacity=n,GameLib.Utils.UndefinedOrNull(a)&&(a=GameLib.D3.Material.TYPE_FRONT_SIDE),this.side=a,GameLib.Utils.UndefinedOrNull(s)&&(s=!1),this.transparent=s,GameLib.Utils.UndefinedOrNull(o)&&(o=new GameLib.API.Color(.06,.06,.06,.06)),this.specular=o,GameLib.Utils.UndefinedOrNull(r)&&(r=1),this.lightMapIntensity=r,GameLib.Utils.UndefinedOrNull(c)&&(c=1),this.aoMapIntensity=c,GameLib.Utils.UndefinedOrNull(h)&&(h=new GameLib.API.Color(1,1,1,1)),this.color=h,GameLib.Utils.UndefinedOrNull(m)&&(m=new GameLib.API.Color(0,0,0,0)),this.emissive=m,GameLib.Utils.UndefinedOrNull(l)&&(l=1),this.emissiveIntensity=l,GameLib.Utils.UndefinedOrNull(p)&&(p=GameLib.D3.Material.TYPE_MULTIPLY_OPERATION),this.combine=p,GameLib.Utils.UndefinedOrNull(u)&&(u=30),this.shininess=u,GameLib.Utils.UndefinedOrNull(b)&&(b=1),this.reflectivity=b,GameLib.Utils.UndefinedOrNull(d)&&(d=.98),this.refractionRatio=d,GameLib.Utils.UndefinedOrNull(L)&&(L=!0),this.fog=L,GameLib.Utils.UndefinedOrNull(G)&&(G=!1),this.wireframe=G,GameLib.Utils.UndefinedOrNull(f)&&(f=1),this.wireframeLineWidth=f,GameLib.Utils.UndefinedOrNull(E)&&(E="round"),this.wireframeLineCap=E,GameLib.Utils.UndefinedOrNull(y)&&(y="round"),this.wireframeLineJoin=y,GameLib.Utils.UndefinedOrNull(O)&&(O=GameLib.D3.Material.TYPE_NO_COLORS),this.vertexColors=O,GameLib.Utils.UndefinedOrNull(D)&&(D=!1),this.skinning=D,GameLib.Utils.UndefinedOrNull(P)&&(P=!1),this.morphTargets=P,GameLib.Utils.UndefinedOrNull(T)&&(T=!1),this.morphNormals=T,GameLib.Utils.UndefinedOrNull(B)&&(B=0),this.overdraw=B,GameLib.Utils.UndefinedOrNull(I)&&(I=1),this.lineWidth=I,GameLib.Utils.UndefinedOrNull(g)&&(g="round"),this.lineCap=g,GameLib.Utils.UndefinedOrNull(A)&&(A="round"),this.lineJoin=A,GameLib.Utils.UndefinedOrNull(N)&&(N=3),this.dashSize=N,GameLib.Utils.UndefinedOrNull(C)&&(C=1),this.gapWidth=C,GameLib.Utils.UndefinedOrNull(S)&&(S=GameLib.D3.Material.TYPE_NORMAL_BLENDING),this.blending=S,GameLib.Utils.UndefinedOrNull(U)&&(U=GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR),this.blendSrc=U,GameLib.Utils.UndefinedOrNull(v)&&(v=GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR),this.blendDst=v,GameLib.Utils.UndefinedOrNull(M)&&(M=GameLib.D3.Material.TYPE_ADD_EQUATION),this.blendEquation=M,GameLib.Utils.UndefinedOrNull(_)&&(_=!0),this.depthTest=_,GameLib.Utils.UndefinedOrNull(w)&&(w=GameLib.D3.Material.TYPE_LESS_EQUAL_DEPTH),this.depthFunc=w,GameLib.Utils.UndefinedOrNull(x)&&(x=!0),this.depthWrite=x,GameLib.Utils.UndefinedOrNull(R)&&(R=!1),this.polygonOffset=R,GameLib.Utils.UndefinedOrNull(F)&&(F=1),this.polygonOffsetFactor=F,GameLib.Utils.UndefinedOrNull(j)&&(j=1),this.polygonOffsetUnits=j,GameLib.Utils.UndefinedOrNull(V)&&(V=0),this.alphaTest=V,GameLib.Utils.UndefinedOrNull(Y)&&(Y=[]),this.clippingPlanes=Y,GameLib.Utils.UndefinedOrNull(H)&&(H=!1),this.clipShadows=H,GameLib.Utils.UndefinedOrNull(z)&&(z=!0),this.visible=z,GameLib.Utils.UndefinedOrNull(q)&&(q=!1),this.flatShading=q,GameLib.Utils.UndefinedOrNull(k)&&(k=1),this.bumpScale=k,GameLib.Utils.UndefinedOrNull(W)&&(W=1),this.normalScale=W,GameLib.Utils.UndefinedOrNull(Q)&&(Q=1),this.displacementScale=Q,GameLib.Utils.UndefinedOrNull(X)&&(X=0),this.displacementBias=X,GameLib.Utils.UndefinedOrNull(K)&&(K=.5),this.roughness=K,GameLib.Utils.UndefinedOrNull(Z)&&(Z=.5),this.metalness=Z,GameLib.Utils.UndefinedOrNull(J)&&(J=1),this.pointSize=J,GameLib.Utils.UndefinedOrNull($)&&($=!0),this.pointSizeAttenuation=$,GameLib.Utils.UndefinedOrNull(ee)&&(ee=0),this.spriteRotation=ee,GameLib.Utils.UndefinedOrNull(te)&&(te=1),this.envMapIntensity=te,GameLib.Utils.UndefinedOrNull(ie)&&(ie=null),this.alphaMap=ie,GameLib.Utils.UndefinedOrNull(ne)&&(ne=null),this.aoMap=ne,GameLib.Utils.UndefinedOrNull(ae)&&(ae=null),this.bumpMap=ae,GameLib.Utils.UndefinedOrNull(se)&&(se=null),this.diffuseMap=se,GameLib.Utils.UndefinedOrNull(oe)&&(oe=null),this.displacementMap=oe,GameLib.Utils.UndefinedOrNull(re)&&(re=null),this.emissiveMap=re,GameLib.Utils.UndefinedOrNull(ce)&&(ce=null),this.environmentMap=ce,GameLib.Utils.UndefinedOrNull(he)&&(he=null),this.lightMap=he,GameLib.Utils.UndefinedOrNull(me)&&(me=null),this.metalnessMap=me,GameLib.Utils.UndefinedOrNull(le)&&(le=null),this.normalMap=le,GameLib.Utils.UndefinedOrNull(pe)&&(pe=null),this.roughnessMap=pe,GameLib.Utils.UndefinedOrNull(ue)&&(ue=null),this.specularMap=ue,GameLib.Utils.UndefinedOrNull(be)&&(be=null),this.parentEntity=be,this.needsUpdate=!1},GameLib.D3.API.Material.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Material.prototype.constructor=GameLib.D3.API.Material,GameLib.D3.API.Material.FromObject=function(e){var t=null,i=null,n=null,a=null,s=null,o=null,r=null,c=null,h=null,m=null,l=null,p=null;return e.alphaMap&&(t=e.alphaMap),e.aoMap&&(i=e.aoMap),e.bumpMap&&(n=e.bumpMap),e.diffuseMap&&(a=e.diffuseMap),e.displacementMap&&(s=e.displacementMap),e.emissiveMap&&(o=e.emissiveMap),e.environmentMap&&(r=e.environmentMap),e.lightMap&&(c=e.lightMap),e.metalnessMap&&(h=e.metalnessMap),e.normalMap&&(m=e.normalMap),e.roughnessMap&&(l=e.roughnessMap),e.specularMap&&(p=e.specularMap),new GameLib.D3.API.Material(e.id,e.materialType,e.name,e.opacity,e.side,e.transparent,GameLib.API.Color.FromObject(e.specular),e.lightMapIntensity,e.aoMapIntensity,GameLib.API.Color.FromObject(e.color),GameLib.API.Color.FromObject(e.emissive),e.emissiveIntensity,e.combine,e.shininess,e.reflectivity,e.refractionRatio,e.fog,e.wireframe,e.wireframeLineWidth,e.wireframeLineCap,e.wireframeLineJoin,e.vertexColors,e.skinning,e.morphTargets,e.morphNormals,e.lineWidth,e.lineCap,e.lineJoin,e.dashSize,e.gapWidth,e.blending,e.blendSrc,e.blendDst,e.blendEquation,e.depthTest,e.depthFunc,e.depthWrite,e.polygonOffset,e.polygonOffsetFactor,e.polygonOffsetUnits,e.alphaTest,e.clippingPlanes,e.clipShadows,e.visible,e.overdraw,e.flatShading,e.bumpScale,e.normalScale,e.displacementScale,e.displacementBias,e.roughness,e.metalness,e.pointSize,e.pointSizeAttenuation,e.spriteRotation,e.envMapIntensity,t,i,n,a,s,o,r,c,h,m,l,p,e.parentEntity)},GameLib.D3.API.Mesh=function(e,t,i,n,a,s,o,r,c,h,m,l,p,u,b,d,L,G,f,E,y,O){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t=GameLib.D3.Mesh.MESH_TYPE_NORMAL),this.meshType=t,GameLib.Utils.UndefinedOrNull(i)&&(i="Mesh ("+e+")"),this.name=i,GameLib.Utils.UndefinedOrNull(n)&&(n=[]),this.vertices=n,GameLib.Utils.UndefinedOrNull(a)&&(a=[]),this.faces=a,GameLib.Utils.UndefinedOrNull(o)&&(o=null),this.parentMesh=o,GameLib.Utils.UndefinedOrNull(r)&&(r=null),this.parentScene=r,GameLib.Utils.UndefinedOrNull(c)&&(c=null),this.skeleton=c,GameLib.Utils.UndefinedOrNull(h)&&(h=[]),this.skinIndices=h,GameLib.Utils.UndefinedOrNull(m)&&(m=[]),this.skinWeights=m,(GameLib.Utils.UndefinedOrNull(s)||s instanceof Array&&0===s.length)&&(s=[new GameLib.D3.API.Material(null,GameLib.D3.Material.MATERIAL_TYPE_STANDARD,"Material ("+this.name+")")]),this.materials=s,GameLib.Utils.UndefinedOrNull(l)&&(l=new GameLib.API.Vector3(0,0,0)),this.position=l,GameLib.Utils.UndefinedOrNull(p)&&(p=new GameLib.API.Quaternion),this.quaternion=p,GameLib.Utils.UndefinedOrNull(u)&&(u=new GameLib.API.Vector3(0,0,0)),this.rotation=u,GameLib.Utils.UndefinedOrNull(b)&&(b=new GameLib.API.Vector3(1,1,1)),this.scale=b,GameLib.Utils.UndefinedOrNull(d)&&(d=new GameLib.API.Vector3(0,1,0)),this.up=d,GameLib.Utils.UndefinedOrNull(L)&&(L=new GameLib.API.Matrix4),this.modelMatrix=L,GameLib.Utils.UndefinedOrNull(f)&&(f=0),this.renderOrder=f,GameLib.Utils.UndefinedOrNull(G)&&(G=null),this.parentEntity=G,GameLib.Utils.UndefinedOrNull(E)&&(E=!1),this.isBufferMesh=E,GameLib.Utils.UndefinedOrNull(y)&&(y=!0),this.useQuaternion=y,GameLib.Utils.UndefinedOrNull(O)&&(O=!0),this.visible=O},GameLib.D3.API.Mesh.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Mesh.prototype.constructor=GameLib.D3.API.Mesh,GameLib.D3.API.Mesh.FromObject=function(e){var t=[];e.faces&&(t=e.faces.map(function(e){return GameLib.D3.API.Face.FromObject(e)}));var i=null;e.skeleton&&(i=GameLib.D3.API.Skeleton.FromObject(e.skeleton));var n=[];e.materials&&(n=e.materials.map(function(e){return e instanceof Object?GameLib.D3.API.Material.FromObject(e):e}));var a=[];e.vertices&&(a=e.vertices.map(function(e){return GameLib.D3.API.Vertex.FromObject(e)}));var s=new GameLib.API.Vector3;e.position&&(s=GameLib.API.Vector3.FromObject(e.position));var o=new GameLib.API.Vector3;e.rotation&&(o=GameLib.API.Vector3.FromObject(e.rotation));var r=new GameLib.API.Quaternion;e.quaternion&&(r=GameLib.API.Quaternion.FromObject(e.quaternion));var c=new GameLib.API.Vector3(1,1,1);e.scale&&(c=GameLib.API.Vector3.FromObject(e.scale));var h=new GameLib.API.Vector3(0,1,0);e.up&&(h=GameLib.API.Vector3.FromObject(e.up));var m=new GameLib.API.Matrix4;return e.modelMatrix&&(m=GameLib.API.Matrix4.FromObject(e.modelMatrix)),new GameLib.D3.API.Mesh(e.id,e.meshType,e.name,a,t,n,e.parentMesh,e.parentScene,i,e.skinIndices,e.skinWeights,s,r,o,c,h,m,e.parentEntity,e.renderOrder,e.isBufferMesh,e.useQuaternion,e.visible)},GameLib.D3.API.ParticleEngine=function(e,t,i,n,a,s,o,r,c,h,m,l){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="ParticleEngine ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=new GameLib.API.Vector3(0,0,0)),this.position=i,GameLib.Utils.UndefinedOrNull(n)&&(n=new GameLib.API.Vector3(0,1,0)),this.direction=n,GameLib.Utils.UndefinedOrNull(a)&&(a=!1),this.enabled=a,GameLib.Utils.UndefinedOrNull(s)&&(s=null),this.templateParticle=s,GameLib.Utils.UndefinedOrNull(o)&&(o=1),this.particlesPerSecond=o,GameLib.Utils.UndefinedOrNull(r)&&(r=Number(1/Number(this.particlesPerSecond))),this.frequency=r,GameLib.Utils.UndefinedOrNull(c)&&(c=0),this.elapsed=c,GameLib.Utils.UndefinedOrNull(h)&&(h=null),this.camera=h,GameLib.Utils.UndefinedOrNull(m)&&(m=!1),this.pulse=m,GameLib.Utils.UndefinedOrNull(l)&&(l=null),this.parentEntity=l},GameLib.D3.API.ParticleEngine.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.ParticleEngine.prototype.constructor=GameLib.D3.API.ParticleEngine,GameLib.D3.API.ParticleEngine.FromObject=function(e){var t=null;e.templateParticle&&(t=e.templateParticle instanceof Object?GameLib.D3.API.Particle.FromObject(e.templateParticle):e.templateParticle);var i=null;e.camera&&(i=e.camera instanceof Object?GameLib.D3.API.Camera.FromObject(e.camera):e.camera);var n=null;e.position&&(n=GameLib.API.Vector3.FromObject(e.position));var a=null;return e.direction&&(a=GameLib.API.Vector3.FromObject(e.direction)),new GameLib.D3.API.ParticleEngine(e.id,e.name,n,a,e.enabled,t,e.particlesPerSecond,e.frequency,e.elapsed,i,e.pulse,e.parentEntity)},GameLib.D3.API.Particle=function(e,t,i,n,a,s,o,r,c,h,m,l,p,u,b,d,L,G,f,E,y,O,D){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Particle ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=10),this.lifeTime=i,GameLib.Utils.UndefinedOrNull(n)&&(n=0),this.elapsed=n,GameLib.Utils.UndefinedOrNull(a)&&(a=null),this.mesh=a,GameLib.Utils.UndefinedOrNull(s)&&(s=GameLib.D3.Particle.OPACITY_TYPE_CONSTANT),this.opacityType=s,GameLib.Utils.UndefinedOrNull(o)&&(o=.01),this.opacityFactor=o,GameLib.Utils.UndefinedOrNull(r)&&(r=GameLib.D3.Particle.POSITION_OFFSET_TYPE_CONSTANT),this.positionOffsetType=r,GameLib.Utils.UndefinedOrNull(c)&&(c=new GameLib.API.Vector3(0,0,0)),this.positionOffset=c,GameLib.Utils.UndefinedOrNull(h)&&(h="//@ sourceURL=positionOffsetFn.js"),this.positionOffsetFn=h,GameLib.Utils.UndefinedOrNull(m)&&(m=GameLib.D3.Particle.DIRECTION_TYPE_CONSTANT),this.directionType=m,GameLib.Utils.UndefinedOrNull(l)&&(l=new GameLib.API.Vector3(0,1,0)),this.direction=l,GameLib.Utils.UndefinedOrNull(p)&&(p="//@ sourceURL=directionFn.js"),this.directionFn=p,GameLib.Utils.UndefinedOrNull(u)&&(u=GameLib.D3.Particle.SPEED_TYPE_CONSTANT),this.speedType=u,GameLib.Utils.UndefinedOrNull(b)&&(b=1),this.speed=b,GameLib.Utils.UndefinedOrNull(d)&&(d=GameLib.D3.Particle.SCALE_TYPE_CONSTANT),this.scaleType=d,GameLib.Utils.UndefinedOrNull(L)&&(L=new GameLib.API.Vector3(1,1,1)),this.scale=L,GameLib.Utils.UndefinedOrNull(G)&&(G="//@ sourceURL=scaleFn.js"),this.scaleFn=G,GameLib.Utils.UndefinedOrNull(f)&&(f=GameLib.D3.Particle.ROTATION_TYPE_CONSTANT),this.rotationType=f,GameLib.Utils.UndefinedOrNull(E)&&(E=new GameLib.API.Vector3(0,0,0)),this.rotation=E,GameLib.Utils.UndefinedOrNull(y)&&(y="//@ sourceURL=rotationFn.js"),this.rotationFn=y,GameLib.Utils.UndefinedOrNull(O)&&(O=null),this.parentEngine=O,GameLib.Utils.UndefinedOrNull(D)&&(D=null),this.parentEntity=D},GameLib.D3.API.Particle.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Particle.prototype.constructor=GameLib.D3.API.Particle,GameLib.D3.API.Particle.FromObject=function(e){var t=null;return e.mesh&&(t=e.mesh instanceof Object?GameLib.D3.API.Mesh.FromObject(e.mesh):e.mesh),new GameLib.D3.API.Particle(e.id,e.name,e.lifeTime,e.elapsed,t,e.opacityType,e.opacityFactor,e.positionOffsetType,GameLib.API.Vector3.FromObject(e.positionOffset),e.positionOffsetFn,e.directionType,GameLib.API.Vector3.FromObject(e.direction),e.directionFn,e.speedType,e.speed,e.scaleType,GameLib.API.Vector3.FromObject(e.scale),e.scaleFn,e.rotationType,GameLib.API.Vector3.FromObject(e.rotation),e.rotationFn,e.parentEngine,e.parentEntity)},GameLib.D3.API.Pass=function(e,t,i,n,a,s,o){if(GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Pass ("+e+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=GameLib.D3.Pass.PASS_TYPE_RENDER),this.passType=i,GameLib.Utils.UndefinedOrNull(n)&&(n=null),this.camera=n,GameLib.Utils.UndefinedOrNull(a)&&(a=null),this.scene=a,GameLib.Utils.UndefinedOrNull(s))if(this.passType===GameLib.D3.Pass.PASS_TYPE_RENDER)s=!1;else{if(!GameLib.D3.Pass.PASS_TYPE_COPY_SHADER)throw console.warn("Unsupported Render Pass Type : "+this.passType),new Error("Unsupported Render Pass Type : "+this.passType);s=!0}this.renderToScreen=s,GameLib.Utils.UndefinedOrNull(o)&&(o=null),this.parentEntity=o},GameLib.D3.API.Pass.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Pass.prototype.constructor=GameLib.D3.API.Pass,GameLib.D3.API.Pass.FromObject=function(e){return new GameLib.D3.API.Pass(e.id,e.name,e.passType,e.camera,e.scene,e.renderToScreen,e.parentEntity)},GameLib.D3.API.PathFollowing=function(e,t,i,n,a,s,o,r,c,h,m,l,p,u,b,d,L,G,f,E,y,O){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t=this.constructor.name),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=null),this.spline=i,GameLib.Utils.UndefinedOrNull(n)&&(n=null),this.mesh=n,GameLib.Utils.UndefinedOrNull(a)&&(a=null),this.raytraceMesh=a,GameLib.Utils.UndefinedOrNull(o)&&(o=.03),this.maxSpeed=o,GameLib.Utils.UndefinedOrNull(s)&&(s=.1),this.accelleration=s,GameLib.Utils.UndefinedOrNull(r)&&(r=new GameLib.API.Vector3),this.baseOffset=r,GameLib.Utils.UndefinedOrNull(c)&&(c=new GameLib.API.Vector3),this.maxOffset=c,GameLib.Utils.UndefinedOrNull(h)&&(h=1),this.steeringSpeed=h,GameLib.Utils.UndefinedOrNull(m)&&(m=new GameLib.API.Vector3),this.targetOffset=m,GameLib.Utils.UndefinedOrNull(l)&&(l=new GameLib.API.Vector3),this.currentOffset=l,GameLib.Utils.UndefinedOrNull(p)&&(p=0),this.currentPathValue=p,GameLib.Utils.UndefinedOrNull(u)&&(u=0),this.currentSpeed=u,GameLib.Utils.UndefinedOrNull(b)&&(b=1),this.direction=b,GameLib.Utils.UndefinedOrNull(d)&&(d=new GameLib.D3.API.Raycaster),this.raycaster=d,GameLib.Utils.UndefinedOrNull(L)&&(L=new GameLib.API.Vector3),this.currentPosition=L,GameLib.Utils.UndefinedOrNull(G)&&(G=new GameLib.API.Vector3),this.futurePosition=G,GameLib.Utils.UndefinedOrNull(f)&&(f=new GameLib.API.Vector3(0,1,0)),this.up=f,GameLib.Utils.UndefinedOrNull(E)&&(E=new GameLib.API.Matrix4),this.rotationMatrix=E,GameLib.Utils.UndefinedOrNull(y)&&(y=new GameLib.API.Quaternion),this.rotationVector=y,GameLib.Utils.UndefinedOrNull(O)&&(O=null),this.parentEntity=O},GameLib.D3.API.PathFollowing.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.PathFollowing.prototype.constructor=GameLib.D3.API.PathFollowing,GameLib.D3.API.PathFollowing.FromObject=function(e){var t=null;return e.raycaster&&(t=GameLib.D3.API.Raycaster.FromObject(e.raycaster)),new GameLib.D3.API.PathFollowing(e.id,e.name,e.spline,e.mesh,e.raytraceMesh,e.accelleration,e.maxSpeed,GameLib.API.Vector3.FromObject(e.baseOffset),GameLib.API.Vector3.FromObject(e.maxOffset),e.steeringSpeed,GameLib.API.Vector3.FromObject(e.targetOffset),GameLib.API.Vector3.FromObject(e.currentOffset),e.currentPathValue,e.currentSpeed,e.direction,t,GameLib.API.Vector3.FromObject(e.currentPosition),GameLib.API.Vector3.FromObject(e.futurePosition),GameLib.API.Vector3.FromObject(e.up),GameLib.API.Matrix4.FromObject(e.rotationMatrix),GameLib.API.Quaternion.FromObject(e.rotationVector),e.parentEntity)},GameLib.D3.API.PhysicsWorld=function(e,t,i,n,a,s,o,r,c,h){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Physics World ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=new GameLib.API.Vector3(0,-9.81,0)),this.gravity=i,GameLib.Utils.UndefinedOrNull(n)&&(n=new GameLib.D3.API.Broadphase(null,"Broadphase (Physics World "+this.id+")")),this.broadphase=n,GameLib.Utils.UndefinedOrNull(a)&&(a=new GameLib.D3.API.Solver(null,"Solver (Physics World "+this.id+")")),this.solver=a,GameLib.Utils.UndefinedOrNull(s)&&(s=[]),this.rigidBodies=s,GameLib.Utils.UndefinedOrNull(o)&&(o=[]),this.contactMaterials=o,GameLib.Utils.UndefinedOrNull(r)&&(r=!0),this.allowSleep=r,GameLib.Utils.UndefinedOrNull(c)&&(c=new GameLib.D3.API.FrictionContactMaterial(null,"Default Contact Material (Physics World "+this.id+")")),this.defaultContactMaterial=c,GameLib.Utils.UndefinedOrNull(h)&&(h=null),this.parentEntity=h},GameLib.D3.API.PhysicsWorld.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.PhysicsWorld.prototype.constructor=GameLib.D3.API.PhysicsWorld,GameLib.D3.API.PhysicsWorld.FromObject=function(e){return new GameLib.D3.API.PhysicsWorld(e.id,e.name,GameLib.API.Vector3.FromObject(e.gravity),e.broadphase,e.solver,e.rigidBodies,e.contactMaterials,e.allowSleep,e.defaultContactMaterial,e.parentEntity)},GameLib.D3.API.RaycastVehicle=function(e,t,i,n,a,s,o){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="RaycastVehicle ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=null),this.chassis=i,GameLib.Utils.UndefinedOrNull(n)&&(n=[]),this.wheels=n,GameLib.Utils.UndefinedOrNull(a)&&(a=[]),this.raycastWheels=a,GameLib.Utils.UndefinedOrNull(s)&&(s=null),this.parentWorld=s,GameLib.Utils.UndefinedOrNull(o)&&(o=null),this.parentEntity=o},GameLib.D3.API.RaycastVehicle.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.RaycastVehicle.prototype.constructor=GameLib.D3.API.RaycastVehicle,GameLib.D3.API.RaycastVehicle.FromObject=function(e){return new GameLib.D3.API.RaycastVehicle(e.id,e.name,e.chassis,e.wheels,e.raycastWheels,e.parentWorld,e.parentEntity)},GameLib.D3.API.RaycastWheel=function(e,t,i,n,a,s,o,r,c,h,m,l,p,u,b,d,L,G){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="RaycastWheel ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=.5),this.radius=i,GameLib.Utils.UndefinedOrNull(n)&&(n=new GameLib.API.Vector3(0,0,-1)),this.directionLocal=n,GameLib.Utils.UndefinedOrNull(a)&&(a=30),this.suspensionStiffness=a,GameLib.Utils.UndefinedOrNull(s)&&(s=.3),this.suspensionRestLength=s,GameLib.Utils.UndefinedOrNull(o)&&(o=5),this.frictionSlip=o,GameLib.Utils.UndefinedOrNull(r)&&(r=2.3),this.dampingRelaxation=r,GameLib.Utils.UndefinedOrNull(c)&&(c=4.4),this.dampingCompression=c,GameLib.Utils.UndefinedOrNull(h)&&(h=1e5),this.maxSuspensionForce=h,GameLib.Utils.UndefinedOrNull(m)&&(m=.01),this.rollInfluence=m,GameLib.Utils.UndefinedOrNull(l)&&(l=new GameLib.API.Vector3(0,1,0)),this.axleLocal=l,GameLib.Utils.UndefinedOrNull(p)&&(p=new GameLib.API.Vector3(1,1,0)),this.chassisConnectionPointLocal=p,GameLib.Utils.UndefinedOrNull(u)&&(u=.3),this.maxSuspensionTravel=u,GameLib.Utils.UndefinedOrNull(b)&&(b=-30),this.customSlidingRotationalSpeed=b,GameLib.Utils.UndefinedOrNull(d)&&(d=!0),this.useCustomSlidingRotationalSpeed=d,GameLib.Utils.UndefinedOrNull(L)&&(L=null),this.parentEntity=L,GameLib.Utils.UndefinedOrNull(G)&&(G=null),this.parentMesh=G},GameLib.D3.API.RaycastWheel.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.RaycastWheel.prototype.constructor=GameLib.D3.API.RaycastWheel,GameLib.D3.API.RaycastWheel.FromObject=function(e){return new GameLib.D3.API.RaycastWheel(e.id,e.name,e.radius,e.directionLocal,e.suspensionStiffness,e.suspensionRestLength,e.frictionSlip,e.dampingRelaxation,e.dampingCompression,e.maxSuspensionForce,e.rollInfluence,e.axleLocal,e.chassisConnectionPointLocal,e.maxSuspensionTravel,e.customSlidingRotationalSpeed,e.useCustomSlidingRotationalSpeed,e.parentEntity,e.parentMesh)},GameLib.D3.API.Raycaster=function(e,t,i,n){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Raycaster ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=new GameLib.API.Vector3),this.position=i,GameLib.Utils.UndefinedOrNull(n)&&(n=new GameLib.API.Vector3(0,-1,0)),this.direction=n},GameLib.D3.API.Raycaster.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Raycaster.prototype.constructor=GameLib.D3.API.Raycaster,GameLib.D3.API.Raycaster.FromObject=function(e){return new GameLib.D3.API.Raycaster(e.id,e.name,GameLib.API.Vector3.FromObject(e.position),GameLib.API.Vector3.FromObject(e.direction))},GameLib.D3.API.RenderTarget=function(e,t,i,n,a,s,o){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Render Target ("+e+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=800),this.width=i,GameLib.Utils.UndefinedOrNull(n)&&(n=600),this.height=n,GameLib.Utils.UndefinedOrNull(a)&&(a=!1),this.stencilBuffer=a,GameLib.Utils.UndefinedOrNull(s)&&(s=null),this.texture=s,GameLib.Utils.UndefinedOrNull(o)&&(o=null),this.parentEntity=o},GameLib.D3.API.RenderTarget.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.RenderTarget.prototype.constructor=GameLib.D3.API.RenderTarget,GameLib.D3.API.RenderTarget.FromObject=function(e){return new GameLib.D3.API.RenderTarget(e.id,e.name,e.width,e.height,e.stencilBuffer,e.texture,e.parentEntity)},GameLib.D3.API.Renderer=function(e,t,i,n,a,s,o,r,c,h,m,l,p,u,b,d,L,G,f){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Renderer ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=!0),this.autoClear=i,GameLib.Utils.UndefinedOrNull(n)&&(n=!1,p&&p.length>0&&(n=!0)),this.localClipping=n,GameLib.Utils.UndefinedOrNull(a)&&(a=800),this.width=a,GameLib.Utils.UndefinedOrNull(s)&&(s=600),this.height=s,GameLib.Utils.UndefinedOrNull(o)&&(o=!1),this.preserveDrawingBuffer=o,GameLib.Utils.UndefinedOrNull(r)&&(r=null),this.domElement=r,GameLib.Utils.UndefinedOrNull(c)&&(c=new GameLib.API.Color(.11,.11,.11)),this.clearColor=c,GameLib.Utils.UndefinedOrNull(h)&&(h=null),this.camera=h,GameLib.Utils.UndefinedOrNull(m)&&(m=[]),this.scenes=m,GameLib.Utils.UndefinedOrNull(l)&&(l=[]),this.viewports=l,GameLib.Utils.UndefinedOrNull(p)&&(p=[]),this.clippingPlanes=p,GameLib.Utils.UndefinedOrNull(u)&&(u=null),this.bufferScene=u,GameLib.Utils.UndefinedOrNull(b)&&(b=h),this.bufferCamera=b,GameLib.Utils.UndefinedOrNull(d)&&(d=null),this.renderTarget=d,GameLib.Utils.UndefinedOrNull(L)&&(L=null),this.defaultScene=L,GameLib.Utils.UndefinedOrNull(G)&&(G=!0),this.sortObjects=G,GameLib.Utils.UndefinedOrNull(f)&&(f=null),this.parentEntity=f},GameLib.D3.API.Renderer.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Renderer.prototype.constructor=GameLib.D3.API.Renderer,GameLib.D3.API.Renderer.FromObject=function(e){return new GameLib.D3.API.Renderer(e.id,e.name,e.autoClear,e.localClipping,e.width,e.height,e.preserveDrawingBuffer,e.domElement,e.clearColor,e.camera,e.scenes,e.viewports,e.clippingPlanes,e.bufferScene,e.bufferCamera,e.renderTarget,e.defaultScene,e.sortObjects,e.parentEntity)},GameLib.D3.API.RigidBody=function(e,t,i,n,a,s,o,r,c,h,m,l,p,u,b,d,L,G,f,E,y){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="RigidBody ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=0),this.mass=i,GameLib.Utils.UndefinedOrNull(n)&&(n=5),this.friction=n,GameLib.Utils.UndefinedOrNull(a)&&(a=new GameLib.API.Vector3(0,0,0)),this.position=a,GameLib.Utils.UndefinedOrNull(s)&&(s=new GameLib.API.Quaternion),this.quaternion=s,GameLib.Utils.UndefinedOrNull(o)&&(o=new GameLib.API.Vector3),this.velocity=o,GameLib.Utils.UndefinedOrNull(r)&&(r=new GameLib.API.Vector3),this.angularVelocity=r,GameLib.Utils.UndefinedOrNull(c)&&(c=.01),this.linearDamping=c,GameLib.Utils.UndefinedOrNull(h)&&(h=.01),this.angularDamping=h,GameLib.Utils.UndefinedOrNull(m)&&(m=!0),this.allowSleep=m,GameLib.Utils.UndefinedOrNull(l)&&(l=.1),this.sleepSpeedLimit=l,GameLib.Utils.UndefinedOrNull(p)&&(p=1),this.sleepTimeLimit=p,GameLib.Utils.UndefinedOrNull(u)&&(u=1),this.collisionFilterGroup=u,GameLib.Utils.UndefinedOrNull(b)&&(b=1),this.collisionFilterMask=b,GameLib.Utils.UndefinedOrNull(d)&&(d=!1),this.fixedRotation=d,GameLib.Utils.UndefinedOrNull(L)&&(L=[]),this.shapes=L,GameLib.Utils.UndefinedOrNull(G)&&(G=!1),this.kinematic=G,GameLib.Utils.UndefinedOrNull(f)&&(f=null),this.parentMesh=f,GameLib.Utils.UndefinedOrNull(E)&&(E=null),this.parentWorld=E,GameLib.Utils.UndefinedOrNull(y)&&(y=null),this.parentEntity=y},GameLib.D3.API.RigidBody.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.RigidBody.prototype.constructor=GameLib.D3.API.RigidBody,GameLib.D3.API.RigidBody.FromObject=function(e){return new GameLib.D3.API.RigidBody(e.id,e.name,e.mass,e.friction,e.position,e.quaternion,e.velocity,e.angularVelocity,e.linearDamping,e.angularDamping,e.allowSleep,e.sleepSpeedLimit,e.sleepTimeLimit,e.collisionFilterGroup,e.collisionFilterMask,e.fixedRotation,e.shapes,e.kinematic,e.parentMesh,e.parentWorld,e.parentEntity)},GameLib.D3.API.Scene=function(e,t,i,n,a,s,o,r,c,h,m,l,p,u){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Scene ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=[]),this.meshes=i,GameLib.Utils.UndefinedOrNull(n)&&(n=[]),this.lights=n,GameLib.Utils.UndefinedOrNull(a)&&(a=[]),this.textures=a,GameLib.Utils.UndefinedOrNull(s)&&(s=[]),this.materials=s,GameLib.Utils.UndefinedOrNull(o)&&(o=[]),this.images=o,GameLib.Utils.UndefinedOrNull(r)&&(r=null),this.fog=r,GameLib.Utils.UndefinedOrNull(c)&&(c=null),this.renderCamera=c,GameLib.Utils.UndefinedOrNull(h)&&(h=!0),this.showGrid=h,GameLib.Utils.UndefinedOrNull(m)&&(m=!0),this.showAxis=m,GameLib.Utils.UndefinedOrNull(l)&&(l=10),this.gridSize=l,GameLib.Utils.UndefinedOrNull(p)&&(p=new GameLib.API.Color(.1,.1,.1)),this.gridColor=p,GameLib.Utils.UndefinedOrNull(u)&&(u=null),this.parentEntity=u},GameLib.D3.API.Scene.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Scene.prototype.constructor=GameLib.D3.API.Scene,GameLib.D3.API.Scene.FromObject=function(e){var t=[],i=[],n=[],a=[],s=[];return e.meshes&&(t=e.meshes.map(function(e){return e instanceof Object?GameLib.D3.API.Mesh.FromObject(e):e})),e.lights&&(i=e.lights.map(function(e){return e instanceof Object?GameLib.D3.API.Light.FromObject(e):e})),e.textures&&(n=e.textures.map(function(e){return e instanceof Object?GameLib.D3.API.Texture.FromObject(e):e})),e.materials&&(a=e.materials.map(function(e){return e instanceof Object?GameLib.D3.API.Material.FromObject(e):e})),e.images&&(s=e.images.map(function(e){return e instanceof Object?GameLib.D3.API.Image.FromObject(e):e})),new GameLib.D3.API.Scene(e.id,e.name,t,i,n,a,s,e.fog,e.renderCamera,e.showGrid,e.showAxis,e.gridSize,GameLib.API.Color.FromObject(e.gridColor),e.parentEntity)},GameLib.D3.API.Shape=function(e,t,i,n,a,s,o){ +GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Shape ("+this.id+")",this instanceof GameLib.D3.Shape.ConvexHull&&(t="Shape Convex Hull ("+this.id+")"),this instanceof GameLib.D3.Shape.ConvexHull.Cylinder&&(t="Shape Convex Hull Cylinder ("+this.id+")"),this instanceof GameLib.D3.Shape.HeightMap&&(t="Shape Heightmap ("+this.id+")"),this instanceof GameLib.D3.Shape.Box&&(t="Shape Box ("+this.id+")"),this instanceof GameLib.D3.Shape.Plane&&(t="Shape Plane ("+this.id+")"),this instanceof GameLib.D3.Shape.Sphere&&(t="Shape Sphere ("+this.id+")"),this instanceof GameLib.D3.Shape.TriMesh&&(t="Shape TriMesh ("+this.id+")")),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=0),this.boundingSphereRadius=i,GameLib.Utils.UndefinedOrNull(n)&&(n=!0),this.collisionResponse=n,GameLib.Utils.UndefinedOrNull(a)&&(a=null),this.frictionMaterial=a,GameLib.Utils.UndefinedOrNull(s)&&(s=null),this.parentMesh=s,GameLib.Utils.UndefinedOrNull(o)&&(o=null),this.parentEntity=o},GameLib.D3.API.Shape.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Shape.prototype.constructor=GameLib.D3.API.Shape,GameLib.D3.API.Shape.FromObject=function(e){return new GameLib.D3.API.Shape(e.id,e.name,e.boundingSphereRadius,e.collisionResponse,e.frictionMaterial,e.parentMesh,e.parentEntity)},GameLib.D3.API.Skeleton=function(e,t,i,n,a,s,o,r,c,h){GameLib.Utils.UndefinedOrNull(h)&&(h=null),this.parentEntity=h,GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Skeleton"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=[]),this.bones=i,GameLib.Utils.UndefinedOrNull(n)&&(n=[]),this.boneInverses=n,GameLib.Utils.UndefinedOrNull(a)&&(a=!1),this.useVertexTexture=a,a&&console.warn("support for vertex texture bones is not supported yet - something could break somewhere"),GameLib.Utils.UndefinedOrNull(s)&&(s=0),this.boneTextureWidth=s,GameLib.Utils.UndefinedOrNull(o)&&(o=0),this.boneTextureHeight=o,GameLib.Utils.UndefinedOrNull(r)&&(r=[]),this.boneMatrices=r,GameLib.Utils.UndefinedOrNull(c)&&(c=null),this.boneTexture=c},GameLib.D3.API.Skeleton.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Skeleton.prototype.constructor=GameLib.D3.API.Skeleton,GameLib.D3.API.Skeleton.FromObject=function(e){return new GameLib.D3.API.Skeleton(e.id,e.name,e.bones.map(function(e){return GameLib.D3.API.Bone.FromObject(e)}),e.boneInverses.map(function(e){return GameLib.D3.API.Matrix4.FromObject(e)}),e.useVertexTexture,e.boneTextureWidth,e.boneTextureHeight,e.boneMatrices.map(function(e){return GameLib.D3.API.Matrix4.FromObject(e)}),e.boneTexture,e.parentEntity)},GameLib.D3.API.Solver=function(e,t,i,n,a,s){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Solver ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=GameLib.D3.Solver.GS_SOLVER),this.solverType=i,GameLib.Utils.UndefinedOrNull(n)&&(n=10),this.iterations=n,GameLib.Utils.UndefinedOrNull(a)&&(a=1e-7),this.tolerance=a,GameLib.Utils.UndefinedOrNull(s)&&(s=null),this.parentEntity=s},GameLib.D3.API.Solver.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Solver.prototype.constructor=GameLib.D3.API.Solver,GameLib.D3.API.Solver.FromObject=function(e){return new GameLib.D3.API.Solver(e.id,e.name,e.solverType,e.iterations,e.tolerance,e.parentEntity)},GameLib.D3.API.Spline=function(e,t,i,n){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Spline (unknown)"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=[]),this.vertices=i,GameLib.Utils.UndefinedOrNull(n)&&(n=null),this.parentEntity=n},GameLib.D3.API.Spline.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Spline.prototype.constructor=GameLib.D3.API.Spline,GameLib.D3.API.Spline.FromObject=function(e){return new GameLib.D3.API.Spline(e.id,e.name,e.vertices.map(function(e){return GameLib.API.Vector3.FromObject(e)}),e.parentEntity)},GameLib.D3.API.Texture=function(e,t,i,n,a,s,o,r,c,h,m,l,p,u,b,d,L,G,f,E,y,O,D,P,T,I,g){GameLib.Utils.UndefinedOrNull(g)&&(g=null),this.parentEntity=g,GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t=GameLib.D3.Texture.TEXTURE_TYPE_NORMAL),this.typeId=t,GameLib.Utils.UndefinedOrNull(i)&&(i="Texture ("+e+")"),this.name=i,GameLib.Utils.UndefinedOrNull(n)&&(n=null),this.image=n,GameLib.Utils.UndefinedOrNull(a)&&(a=[]),this.images=a,GameLib.Utils.UndefinedOrNull(s)&&(s=GameLib.D3.Texture.TYPE_REPEAT_WRAPPING),this.wrapS=s,GameLib.Utils.UndefinedOrNull(o)&&(o=GameLib.D3.Texture.TYPE_REPEAT_WRAPPING),this.wrapT=o,GameLib.Utils.UndefinedOrNull(r)&&(r=new GameLib.API.Vector2(1,1)),this.repeat=r,GameLib.Utils.UndefinedOrNull(c)&&(c=null),this.data=c,GameLib.Utils.UndefinedOrNull(h)&&(h=GameLib.D3.Texture.TYPE_RGBA_FORMAT),this.format=h,GameLib.Utils.UndefinedOrNull(m)&&(m=GameLib.D3.Texture.TYPE_UV_MAPPING),this.mapping=m,GameLib.Utils.UndefinedOrNull(l)&&(l=GameLib.D3.Texture.TYPE_LINEAR_FILTER),this.magFilter=l,GameLib.Utils.UndefinedOrNull(p)&&(p=GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER),this.minFilter=p,GameLib.Utils.UndefinedOrNull(u)&&(u=GameLib.D3.Texture.TYPE_UNSIGNED_BYTE),this.textureType=u,GameLib.Utils.UndefinedOrNull(b)&&(b=1),this.anisotropy=b,GameLib.Utils.UndefinedOrNull(d)&&(d=new GameLib.API.Vector2(0,0)),this.offset=d,GameLib.Utils.UndefinedOrNull(L)&&(L=!0),this.generateMipmaps=L,GameLib.Utils.UndefinedOrNull(G)&&(G=!0),this.flipY=G,GameLib.Utils.UndefinedOrNull(f)&&(f=[]),this.mipmaps=f,GameLib.Utils.UndefinedOrNull(E)&&(E=4),this.unpackAlignment=E,GameLib.Utils.UndefinedOrNull(y)&&(y=!1),this.premultiplyAlpha=y,GameLib.Utils.UndefinedOrNull(O)&&(O=GameLib.D3.Texture.TYPE_LINEAR_ENCODING),this.encoding=O,GameLib.Utils.UndefinedOrNull(D)&&(D=null),this.canvas=D,GameLib.Utils.UndefinedOrNull(P)&&(P=!1),this.animated=P,GameLib.Utils.UndefinedOrNull(T)&&(T=!1),this.reverseAnimation=T,GameLib.Utils.UndefinedOrNull(I)&&(I=!0),this.forward=I,this.needsUpdate=!1},GameLib.D3.API.Texture.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Texture.prototype.constructor=GameLib.D3.API.Texture,GameLib.D3.API.Texture.FromObject=function(e){return new GameLib.D3.API.Texture(e.id,e.typeId,e.name,e.image,e.images,e.wrapS,e.wrapT,GameLib.API.Vector2.FromObject(e.repeat),e.data,e.format,e.mapping,e.magFilter,e.minFilter,e.textureType,e.anisotropy,GameLib.API.Vector2.FromObject(e.offset),e.generateMipmaps,e.flipY,e.mipmaps,e.unpackAlignment,e.premultiplyAlpha,e.encoding,e.canvas,e.animated,e.reverseAnimation,e.forward,e.parentEntity)},GameLib.D3.API.Vertex=function(e,t){GameLib.Utils.UndefinedOrNull(e)&&(e=new GameLib.API.Vector3),this.position=e,GameLib.Utils.UndefinedOrNull(t)&&(t=[]),this.boneWeights=t},GameLib.D3.API.Vertex.FromObject=function(e){return new GameLib.D3.API.Vertex(GameLib.API.Vector3.FromObject(e.position),e.boneWeights.map(function(e){return GameLib.D3.API.BoneWeight.FromObject(e)}))},GameLib.D3.API.Viewport=function(e,t,i,n,a,s,o){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Viewport ("+this.id+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=800),this.width=i,GameLib.Utils.UndefinedOrNull(n)&&(n=600),this.height=n,GameLib.Utils.UndefinedOrNull(a)&&(a=0),this.x=a,GameLib.Utils.UndefinedOrNull(s)&&(s=0),this.y=s,GameLib.Utils.UndefinedOrNull(o)&&(o=null),this.parentEntity=o},GameLib.D3.API.Viewport.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.API.Viewport.prototype.constructor=GameLib.D3.API.Viewport,GameLib.D3.API.Viewport.FromObject=function(e){return new GameLib.D3.API.Viewport(e.id,e.name,e.width,e.height,e.x,e.y,e.parentEntity)},GameLib.D3.Animation=function(e){if(GameLib.Utils.UndefinedOrNull(e)&&(e={}),e instanceof GameLib.D3.Animation)return e;GameLib.D3.API.Animation.call(this,e.id,e.name,e.rotationSpeed,e.translationSpeed,e.scaleSpeed,e.rotationFn,e.translationFn,e.scaleFn,e.blocking,e.applyToMeshWhenDone,e.meshes,e.parentEntity),this.functionType=GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_ROTATION,this.editor=null,this.inProcess=!1,GameLib.Component.call(this,GameLib.Component.COMPONENT_ANIMATION,{meshes:[GameLib.D3.Mesh]})},GameLib.D3.Animation.prototype=Object.create(GameLib.D3.API.Animation.prototype),GameLib.D3.Animation.prototype.constructor=GameLib.D3.Animation,GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_ROTATION=1,GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_TRANSLATION=2,GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_SCALE=3,GameLib.D3.Animation.prototype.createInstance=function(){this.instance={rotation:null,translation:null,scale:null};try{this.rotationFn&&(this.instance.rotation=new Function("data",this.rotationFn).bind(this)),this.translationFn&&(this.instance.translation=new Function("data",this.translationFn).bind(this)),this.scaleFn&&(this.instance.scale=new Function("data",this.scaleFn).bind(this))}catch(e){console.error(e),this.publish(GameLib.Event.ANIMATION_COMPILE_FAILED,{component:this})}GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Animation.prototype.updateInstance=function(){try{this.rotationFn&&(this.instance.rotation=new Function("data",this.rotationFn).bind(this),this.publish(GameLib.Event.ANIMATION_COMPILE_SUCCESS,{component:this,type:GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_ROTATION})),this.translationFn&&(this.instance.translation=new Function("data",this.translationFn).bind(this),this.publish(GameLib.Event.ANIMATION_COMPILE_SUCCESS,{component:this,type:GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_TRANSLATION})),this.scaleFn&&(this.instance.scale=new Function("data",this.scaleFn).bind(this),this.publish(GameLib.Event.ANIMATION_COMPILE_SUCCESS,{component:this,type:GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_SCALE}))}catch(e){console.error(e),this.publish(GameLib.Event.ANIMATION_COMPILE_FAILED,{component:this})}},GameLib.D3.Animation.prototype.toApiObject=function(){return new GameLib.D3.API.Animation(this.id,this.name,this.rotationSpeed,this.translationSpeed,this.scaleSpeed,this.rotationFn,this.translationFn,this.scaleFn,this.blocking,this.applyToMeshWhenDone,this.meshes.map(function(e){return GameLib.Utils.IdOrNull(e)}),GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Animation.FromObject=function(e){var t=GameLib.D3.API.Animation.FromObject(e);return new GameLib.D3.Animation(t)},GameLib.D3.Animation.prototype.launchEditor=function(){GameLib.Event.Emit(GameLib.Event.GET_CODER_IMPLEMENTATION,null,function(e){this.coder=e,this.coder.isNotCodeMirrorThrow()}.bind(this));var e=null;this.functionType===GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_ROTATION&&(this.rotationFn="//when the animation is complete, return true\nreturn true;",e="rotationFn"),this.functionType===GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_TRANSLATION&&(this.translationFn="//when the animation is complete, return true\nreturn true;",e="translationFn"),this.functionType===GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_SCALE&&(this.scaleFn="//when the animation is complete, return true\nreturn true;",e="scaleFn"),e?(this.editor=this.coder.instance(document.body,{value:this[e],mode:"javascript",lineNumbers:!0,scrollbarStyle:"overlay"}),this.editor.on("change",function(){this[e]=this.editor.getValue(),this.updateInstance()}.bind(this))):console.warn("invalid function type selected")},GameLib.D3.Animation.prototype.closeEditor=function(){var e=this.editor.getWrapperElement();e.parentElement.removeChild(e)},GameLib.D3.Animation.prototype.addMesh=function(e){GameLib.Utils.PushUnique(this.meshes,e),GameLib.Event.Emit(GameLib.Event.ANIMATION_MESH_ADDED,{animation:this,mesh:e})},GameLib.D3.Animation.prototype.removeMesh=function(e){var t=this.meshes.indexOf(e);this.meshes.splice(t,1),GameLib.Event.Emit(GameLib.Event.ANIMATION_MESH_REMOVED,{animation:this,mesh:e})},GameLib.D3.Audio=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Audio)return t;GameLib.D3.API.Audio.call(this,t.id,t.name,t.path,t.loop,t.volume,t.camera,t.overplay,t.parentEntity),this.camera instanceof GameLib.D3.API.Camera&&(this.camera=new GameLib.D3.Camera(this.graphics,this.camera)),GameLib.Component.call(this,GameLib.Component.COMPONENT_AUDIO,{camera:GameLib.D3.Camera})},GameLib.D3.Audio.prototype=Object.create(GameLib.D3.API.Audio.prototype),GameLib.D3.Audio.prototype.constructor=GameLib.D3.Audio,GameLib.D3.Audio.prototype.createInstance=function(){if(GameLib.Utils.UndefinedOrNull(this.camera)||GameLib.Utils.UndefinedOrNull(this.camera.instance))return void console.log("audio not ready to create instance");GameLib.Event.Emit(GameLib.Event.GET_API_URL,null,function(e){this.apiUrl=e.apiUrl}.bind(this));var e=new THREE.AudioListener;this.camera.instance.add(e),this.instance=new THREE.Audio(e),(new THREE.AudioLoader).load(this.apiUrl+this.path,function(e){this.instance.setBuffer(e),this.instance.setLoop(this.loop),this.instance.setVolume(this.volume),GameLib.Component.prototype.createInstance.call(this)}.bind(this))},GameLib.D3.Audio.prototype.updateInstance=function(e){"loop"===e&&this.instance.setLoop(this.loop),"volume"===e&&this.instance.setVolume(this.volume)},GameLib.D3.Audio.prototype.toApiObject=function(){return new GameLib.D3.API.Audio(this.id,this.name,this.path,this.loop,this.volume,GameLib.Utils.IdOrNull(this.camera),this.overplay,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Audio.FromObject=function(e,t){var i=GameLib.D3.API.Audio.FromObject(t);return new GameLib.D3.Audio(e,i)},GameLib.D3.BoneWeight=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.BoneWeight)return t;GameLib.D3.API.BoneWeight.call(this,t.boneIndex,t.weight)},GameLib.D3.BoneWeight.prototype=Object.create(GameLib.D3.API.BoneWeight.prototype),GameLib.D3.BoneWeight.prototype.constructor=GameLib.D3.BoneWeight,GameLib.D3.BoneWeight.prototype.toApiObject=function(){return new GameLib.D3.API.BoneWeight(this.boneIndex,this.weight)},GameLib.D3.BoneWeight.FromObject=function(e,t){var i=GameLib.D3.API.BoneWeight.FromObject(t);return new GameLib.D3.BoneWeight(e,i)},GameLib.D3.Bone=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Bone)return t;GameLib.D3.API.Bone.call(this,t.id,t.name,t.childBoneIds,t.parentBoneIds,t.position,t.quaternion,t.scale,t.up),this.position=new GameLib.Vector3(e,this.position,this),this.quaternion=new GameLib.Quaternion(e,this.quaternion,this),this.scale=new GameLib.Vector3(e,this.scale,this),this.up=new GameLib.Vector3(e,this.up,this),GameLib.Component.call(this,GameLib.Component.COMPONENT_BONE)},GameLib.D3.Bone.prototype=Object.create(GameLib.D3.API.Bone.prototype),GameLib.D3.Bone.prototype.constructor=GameLib.D3.Bone,GameLib.D3.Bone.prototype.createInstance=function(){this.instance=new THREE.Bone,this.instance.name=this.name,this.instance.position.x=this.position.x,this.instance.position.y=this.position.y,this.instance.position.z=this.position.z,this.instance.quaternion.x=this.quaternion.x,this.instance.quaternion.y=this.quaternion.y,this.instance.quaternion.z=this.quaternion.z,this.instance.quaternion.w=this.quaternion.w,this.instance.scale.x=this.scale.x,this.instance.scale.y=this.scale.y,this.instance.scale.z=this.scale.z,this.instance.up.x=this.up.x,this.instance.up.y=this.up.y,this.instance.up.z=this.up.z,GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Bone.prototype.updateInstance=function(){this.instance.name=this.name,this.instance.position.x=this.position.x,this.instance.position.y=this.position.y,this.instance.position.z=this.position.z,this.instance.quaternion.x=this.quaternion.x,this.instance.quaternion.y=this.quaternion.y,this.instance.quaternion.z=this.quaternion.z,this.instance.quaternion.w=this.quaternion.w,this.instance.scale.x=this.scale.x,this.instance.scale.y=this.scale.y,this.instance.scale.z=this.scale.z,this.instance.up.x=this.up.x,this.instance.up.y=this.up.y,this.instance.up.z=this.up.z},GameLib.D3.Bone.prototype.toApiObject=function(){return new GameLib.D3.API.Bone(this.id,this.name,this.childBoneIds,this.parentBoneIds,this.position.toApiObject(),this.quaternion.toApiObject(),this.scale.toApiObject(),this.up.toApiObject())},GameLib.D3.Bone.FromObject=function(e,t){var i=GameLib.D3.API.Bone.FromObject(t);return GameLib.D3.Bone(e,i)},GameLib.D3.Broadphase=function(e,t){if(this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Broadphase)return t;GameLib.D3.API.Broadphase.call(this,t.id,t.name,t.broadphaseType,t.parentEntity),GameLib.Component.call(this,GameLib.Component.COMPONENT_BROADPHASE)},GameLib.D3.Broadphase.prototype=Object.create(GameLib.D3.API.Broadphase.prototype),GameLib.D3.Broadphase.prototype.constructor=GameLib.D3.Broadphase,GameLib.D3.Broadphase.prototype.createInstance=function(){if(this.broadphaseType===GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE)this.instance=new CANNON.NaiveBroadphase;else if(this.broadphaseType===GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID)this.instance=new CANNON.GridBroadphase;else{if(this.broadphaseType!==GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP)throw console.warn("Unsupported broadphase type: "+this.broadphaseType),new Error("Unsupported broadphase type: "+this.broadphaseType);this.instance=new CANNON.SAPBroadphase}GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Broadphase.prototype.updateInstance=function(){this.broadphaseType===GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE&&(this.instance instanceof CANNON.NaiveBroadphase||this.createInstance()),this.broadphaseType===GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID&&(this.instance instanceof CANNON.GridBroadphase||this.createInstance()),this.broadphaseType===GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP&&(this.instance instanceof CANNON.SAPBroadphase||this.createInstance())},GameLib.D3.Broadphase.prototype.toApiObject=function(){return new GameLib.D3.API.Broadphase(this.id,this.name,this.broadphaseType,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Broadphase.FromObject=function(e,t){var i=GameLib.D3.API.Broadphase.FromObject(t);return new GameLib.D3.Broadphase(e,i)},GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE=1,GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID=2,GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP=3,GameLib.D3.Camera=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Camera)return t;if(GameLib.D3.API.Camera.call(this,t.id,t.cameraType,t.name,t.fov,t.aspect,t.near,t.far,t.position,t.lookAt,t.minX,t.maxX,t.minY,t.maxY,t.minZ,t.maxZ,t.offsetX,t.offsetY,t.quaternion,t.parentEntity,t.eyeSeparation,t.focalLength),!(this.position instanceof GameLib.API.Vector3))throw console.warn("position not instance of API.Vector3"),new Error("position not instance of API.Vector3");if(this.position=new GameLib.Vector3(e,this.position,this),!(this.quaternion instanceof GameLib.API.Quaternion))throw console.warn("quaternion not instance of API.Quaternion"),new Error("quaternion not instance of API.Quaternion");if(this.quaternion=new GameLib.Quaternion(e,this.quaternion,this),!(this.lookAt instanceof GameLib.API.Vector3))throw console.warn("lookAt not instance of API.Vector3"),new Error("lookAt not instance of API.Vector3");this.lookAt=new GameLib.Vector3(e,this.lookAt,this),GameLib.Component.call(this,GameLib.Component.COMPONENT_CAMERA)},GameLib.D3.Camera.prototype=Object.create(GameLib.D3.API.Camera.prototype),GameLib.D3.Camera.prototype.constructor=GameLib.D3.Camera,GameLib.D3.Camera.CAMERA_TYPE_PERSPECTIVE=1,GameLib.D3.Camera.CAMERA_TYPE_ORTHOGONAL=2,GameLib.D3.Camera.CAMERA_TYPE_STEREO=3,GameLib.D3.Camera.prototype.createInstance=function(){if(this.cameraType===GameLib.D3.Camera.CAMERA_TYPE_PERSPECTIVE)this.instance=new THREE.PerspectiveCamera(this.fov,this.aspect,this.near,this.far);else if(this.cameraType===GameLib.D3.Camera.CAMERA_TYPE_ORTHOGONAL)this.instance=new THREE.OrthographicCamera(this.minX+this.offsetX,this.maxX+this.offsetX,this.maxY,this.minY,this.minZ,this.maxZ);else{if(this.cameraType!==GameLib.D3.Camera.CAMERA_TYPE_STEREO)throw new Error("unsupported camera type : "+this.cameraType);this.instance=new THREE.StereoCamera}this.instance.position.x=this.position.x,this.instance.position.y=this.position.y,this.instance.position.z=this.position.z,this.instance.quaternion.x=this.quaternion.x,this.instance.quaternion.y=this.quaternion.y,this.instance.quaternion.z=this.quaternion.z,this.instance.quaternion.w=this.quaternion.w,this.instance.lookAt(this.lookAt.instance),this.instance.updateProjectionMatrix(),GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Camera.prototype.updateInstance=function(e){GameLib.Utils.UndefinedOrNull(e)&&console.warn("no camera property specified for : "+this.name),"cameraType"===e&&(this.cameraType!==GameLib.D3.Camera.CAMERA_TYPE_ORTHOGONAL||this.instance instanceof THREE.OrthographicCamera||this.createInstance(),this.cameraType!==GameLib.D3.Camera.CAMERA_TYPE_PERSPECTIVE||this.instance instanceof THREE.PerspectiveCamera||this.createInstance()),"aspect"!==e&&"minX"!==e&&"maxX"!==e&&"minZ"!==e&&"maxZ"!==e&&"offsetX"!==e&&"offsetY"!==e&&"fov"!==e&&"near"!==e&&"far"!==e&&"eyeSeparation"!==e&&"focalLength"!==e||(this.cameraType===GameLib.D3.Camera.CAMERA_TYPE_ORTHOGONAL&&(this.minX=this.aspect*this.minY,this.maxX=this.aspect*this.maxY,this.instance.left=this.minX+this.offsetX,this.instance.right=this.maxX+this.offsetX,this.instance.bottom=this.minY+this.offsetY,this.instance.top=this.maxY+this.offsetY,this.instance.near=this.minZ,this.instance.far=this.maxZ),this.cameraType!==GameLib.D3.Camera.CAMERA_TYPE_PERSPECTIVE&&this.cameraType!==GameLib.D3.Camera.CAMERA_TYPE_STEREO||(this.instance.fov=this.fov,this.instance.aspect=this.aspect,this.instance.near=this.near,this.instance.far=this.far),this.cameraType===GameLib.D3.Camera.CAMERA_TYPE_STEREO&&(this.instance.eyeSeparation=this.eyeSeparation,this.instance.focalLength=this.focalLength,this.instance.update(this.instance))),"position"===e&&(this.instance.position.x=this.position.x,this.instance.position.y=this.position.y,this.instance.position.z=this.position.z),"quaternion"===e&&(this.instance.quaternion.x=this.quaternion.x,this.instance.quaternion.y=this.quaternion.y,this.instance.quaternion.z=this.quaternion.z,this.instance.quaternion.w=this.quaternion.w),"lookAt"===e&&(this.lookAt.instance.x=this.lookAt.x,this.lookAt.instance.y=this.lookAt.y,this.lookAt.instance.z=this.lookAt.z,this.instance.lookAt(this.lookAt.instance)),this.instance.updateProjectionMatrix()},GameLib.D3.Camera.prototype.resize=function(e,t){camera.aspect=e/t,camera.updateInstance()},GameLib.D3.Camera.prototype.toApiObject=function(){return new GameLib.D3.API.Camera(this.id,this.cameraType,this.name,this.fov,this.aspect,this.near,this.far,this.position.toApiObject(),this.lookAt.toApiObject(),this.minX,this.maxX,this.minY,this.maxY,this.minZ,this.maxZ,this.offsetX,this.offsetY,this.quaternion.toApiObject(),GameLib.Utils.IdOrNull(this.parentEntity),this.eyeSeparation,this.focalLength)},GameLib.D3.Camera.FromObject=function(e,t){var i=GameLib.D3.API.Camera.FromObject(t);return new GameLib.D3.Camera(e,i)},GameLib.D3.Canvas=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Canvas)return t;GameLib.D3.API.Canvas.call(this,t.id,t.name,t.width,t.height,t.parentEntity),GameLib.Component.call(this,GameLib.Component.COMPONENT_CANVAS)},GameLib.D3.Canvas.prototype=Object.create(GameLib.D3.API.Canvas.prototype),GameLib.D3.Canvas.prototype.constructor=GameLib.D3.Canvas,GameLib.D3.Canvas.prototype.createInstance=function(){this.instance=document.createElement("canvas"),this.instance.width=this.width,this.instance.height=this.height,GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Canvas.prototype.updateInstance=function(){GameLib.Utils.UndefinedOrNull(this.instance)&&this.createInstance(),this.instance.width=this.width,this.instance.height=this.height},GameLib.D3.Canvas.prototype.toApiObject=function(){return new GameLib.D3.API.Canvas(this.id,this.name,this.width,this.height,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Canvas.FromObject=function(e,t){return new GameLib.D3.Canvas(e,GameLib.D3.API.Canvas.FromObject(t))},GameLib.D3.Coder=function(e,t,i){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Coder ("+e+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=GameLib.D3.Coder.CODER_TYPE_CODE_MIRROR),this.coderType=i,this.createInstance()},GameLib.D3.Coder.CODER_TYPE_CODE_MIRROR=1,GameLib.D3.Coder.prototype.createInstance=function(){this.instance=CodeMirror},GameLib.D3.Coder.prototype.updateInstance=function(){},GameLib.D3.Coder.prototype.isCodeMirror=function(){return this.coderType===GameLib.D3.Coder.CODER_TYPE_CODE_MIRROR},GameLib.D3.Coder.prototype.isNotCodeMirrorThrow=function(){if(this.coderType!==GameLib.D3.Coder.CODER_TYPE_CODE_MIRROR)throw console.warn("Only CodeMirror supported for this function"),new Error("Only CodeMirror supported for this function")},GameLib.D3.Composer=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Composer)return t;GameLib.D3.API.Composer.call(this,t.id,t.name,t.renderer,t.renderTarget,t.passes,t.parentEntity),GameLib.Component.call(this,GameLib.Component.COMPONENT_COMPOSER,{renderer:GameLib.D3.Renderer,renderTarget:GameLib.D3.RenderTarget,passes:[GameLib.D3.Pass]})},GameLib.D3.Composer.prototype=Object.create(GameLib.D3.API.Composer.prototype),GameLib.D3.Composer.prototype.constructor=GameLib.D3.Composer,GameLib.D3.Composer.prototype.createInstance=function(){console.log("GameLib.D3.Composer.prototype.createInstance() - fix me"),GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Composer.prototype.updateInstance=function(){console.log("GameLib.D3.Composer.prototype.updateInstance() - fix me")},GameLib.D3.Composer.prototype.toApiObject=function(){return new GameLib.D3.API.Composer(this.id,this.name,GameLib.Utils.IdOrNull(this.renderer),GameLib.Utils.IdOrNull(this.renderTarget),this.passes.map(function(e){return GameLib.Utils.IdOrNull(e)}),GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Composer.FromObject=function(e,t){var i=GameLib.D3.API.Composer.FromObject(t);return new GameLib.D3.Composer(e,i)},GameLib.D3.Controls=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Controls)return t;GameLib.D3.API.Controls.call(this,t.id,t.controlsType,t.name,t.domElement,t.parentEntity);var i=GameLib.Component.COMPONENT_CONTROLS,n={domElement:GameLib.DomElement},a=!1;this.controlsType===GameLib.D3.Controls.CONTROLS_TYPE_EDITOR&&(i=GameLib.Component.COMPONENT_CONTROLS_EDITOR,n.raycaster=GameLib.D3.Raycaster,n.camera=GameLib.D3.Camera,a=!0),this.controlsType===GameLib.D3.Controls.CONTROLS_TYPE_TOUCH&&(i=GameLib.Component.COMPONENT_CONTROLS_TOUCH),this.controlsType===GameLib.D3.Controls.CONTROLS_TYPE_KEYBOARD&&(i=GameLib.Component.COMPONENT_CONTROLS_KEYBOARD),this.controlsType===GameLib.D3.Controls.CONTROLS_TYPE_MOUSE&&(i=GameLib.Component.COMPONENT_CONTROLS_MOUSE),GameLib.Component.call(this,i,n,a)},GameLib.D3.Controls.prototype=Object.create(GameLib.D3.API.Controls.prototype),GameLib.D3.Controls.prototype.constructor=GameLib.D3.Controls,GameLib.D3.Controls.CONTROLS_TYPE_EDITOR=0,GameLib.D3.Controls.CONTROLS_TYPE_TOUCH=1,GameLib.D3.Controls.CONTROLS_TYPE_KEYBOARD=2,GameLib.D3.Controls.CONTROLS_TYPE_MOUSE=3,GameLib.D3.Controls.prototype.createInstance=function(){GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Controls.prototype.updateInstance=function(){console.log("default controls update instance")},GameLib.D3.Controls.prototype.toApiObject=function(){return new GameLib.D3.API.Controls(this.id,this.controlsType,this.name,GameLib.Utils.IdOrNull(this.domElement),GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Controls.FromObject=function(e,t){var i=GameLib.D3.API.Controls.FromObject(t);return new GameLib.D3.Controls(e,i)},GameLib.D3.Controls.Editor=function(e,t,i,n){this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(i)&&(i=null),this.raycaster=i,GameLib.Utils.UndefinedOrNull(n)&&(n=null),this.camera=n,this.raycaster instanceof GameLib.D3.API.Raycaster&&(this.raycaster=new GameLib.D3.Raycaster(this.graphics,this.raycaster)),this.camera instanceof GameLib.D3.API.Camera&&(this.camera=new GameLib.D3.Camera(this.graphics,this.camera)),GameLib.D3.Controls.call(this,this.graphics,t)},GameLib.D3.Controls.Editor.prototype=Object.create(GameLib.D3.Controls.prototype),GameLib.D3.Controls.Editor.prototype.constructor=GameLib.D3.Controls.Editor,GameLib.D3.Controls.Editor.prototype.createInstance=function(){if(!this.camera||!this.camera.instance)throw new Error("No camera at time of instance");if(!this.domElement||!this.domElement.instance)throw new Error("No dom element at time of instance");this.instance=new THREE.EditorControls(this.camera.instance,this.domElement.instance),GameLib.D3.Controls.prototype.createInstance.call(this)},GameLib.D3.Controls.Editor.prototype.updateInstance=function(){console.warn("an update instance was called on editor controls - which, if not called from within a running system at the right time will affect the order of input event handling and cause system instability"),GameLib.D3.Controls.prototype.updateInstance.call(this)},GameLib.D3.Controls.Editor.prototype.toApiObject=function(){var e=GameLib.D3.Controls.prototype.toApiObject.call(this);return e.raycaster=GameLib.Utils.IdOrNull(this.raycaster),e.camera=GameLib.Utils.IdOrNull(this.camera),e},GameLib.D3.Controls.Editor.FromObject=function(e,t){var i=GameLib.D3.API.Controls.FromObject(t);return new GameLib.D3.Controls.Editor(e,i,t.raycaster,t.camera)},GameLib.D3.Controls.Keyboard=function(e,t){this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.D3.Controls.call(this,this.graphics,t)},GameLib.D3.Controls.Keyboard.prototype=Object.create(GameLib.D3.Controls.prototype),GameLib.D3.Controls.Keyboard.prototype.constructor=GameLib.D3.Controls.Keyboard,GameLib.D3.Controls.Keyboard.prototype.createInstance=function(){this.instance=!0,GameLib.D3.Controls.prototype.createInstance.call(this)},GameLib.D3.Controls.Keyboard.prototype.updateInstance=function(){GameLib.D3.Controls.prototype.updateInstance.call(this)},GameLib.D3.Controls.Keyboard.prototype.toApiObject=function(){return GameLib.D3.Controls.prototype.toApiObject.call(this)},GameLib.D3.Controls.Keyboard.FromObject=function(e,t){var i=GameLib.D3.API.Controls.FromObject(t);return new GameLib.D3.Controls.Keyboard(e,i)};GameLib.D3.Controls.Mouse=function(e,t){this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.D3.Controls.call(this,this.graphics,t)},GameLib.D3.Controls.Mouse.prototype=Object.create(GameLib.D3.Controls.prototype),GameLib.D3.Controls.Mouse.prototype.constructor=GameLib.D3.Controls.Mouse,GameLib.D3.Controls.Mouse.prototype.createInstance=function(){this.instance=!0,GameLib.D3.Controls.prototype.createInstance.call(this)},GameLib.D3.Controls.Mouse.prototype.updateInstance=function(){GameLib.D3.Controls.prototype.updateInstance.call(this)},GameLib.D3.Controls.Mouse.prototype.toApiObject=function(){return GameLib.D3.Controls.prototype.toApiObject.call(this)},GameLib.D3.Controls.Mouse.FromObject=function(e,t){var i=GameLib.D3.API.Controls.FromObject(t);return new GameLib.D3.Controls.Mouse(e,i)},GameLib.D3.Controls.Touch=function(e,t,i){this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(i)&&(i=5), +this.sensitivity=i,GameLib.D3.Controls.call(this,this.graphics,t)},GameLib.D3.Controls.Touch.prototype=Object.create(GameLib.D3.Controls.prototype),GameLib.D3.Controls.Touch.prototype.constructor=GameLib.D3.Controls.Touch,GameLib.D3.Controls.Touch.prototype.createInstance=function(){this.instance=!0,GameLib.D3.Controls.prototype.createInstance.call(this)},GameLib.D3.Controls.Touch.prototype.updateInstance=function(){GameLib.D3.Controls.prototype.updateInstance.call(this)},GameLib.D3.Controls.Touch.prototype.toApiObject=function(){var e=GameLib.D3.Controls.prototype.toApiObject.call(this);return e.sensitivity=this.sensitivity,e},GameLib.D3.Controls.Touch.FromObject=function(e,t){var i=GameLib.D3.API.Controls.FromObject(t);return new GameLib.D3.Controls.Touch(e,i,t.sensitivity)},GameLib.D3.CustomCode=function(e){if(GameLib.Utils.UndefinedOrNull(e)&&(e={}),e instanceof GameLib.D3.CustomCode)return e;GameLib.D3.API.CustomCode.call(this,e.id,e.name,e.eventId,e.code,e.parentEntity),this.editor=null,GameLib.Component.call(this,GameLib.Component.COMPONENT_CUSTOM_CODE)},GameLib.D3.CustomCode.prototype=Object.create(GameLib.D3.API.CustomCode.prototype),GameLib.D3.CustomCode.prototype.constructor=GameLib.D3.CustomCode,GameLib.D3.CustomCode.prototype.createInstance=function(){try{this.instance=new Function("data",this.code).bind(this)}catch(e){this.instance=new Function("data","console.log('compilation failed for : "+this.name+"');").bind(this)}GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.CustomCode.prototype.updateInstance=function(){try{this.instance=new Function("data",this.code).bind(this),this.publish(GameLib.Event.COMPILE_SUCCESS,{component:this})}catch(e){this.instance=new Function("data","console.log('compilation update failed for : "+this.name+"');").bind(this),this.publish(GameLib.Event.COMPILE_FAILED,{component:this})}},GameLib.D3.CustomCode.prototype.toApiObject=function(){return new GameLib.D3.API.CustomCode(this.id,this.name,this.eventId,this.code,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.CustomCode.FromObject=function(e){var t=GameLib.D3.API.CustomCode.FromObject(e);return new GameLib.D3.CustomCode(t)},GameLib.D3.CustomCode.prototype.launchEditor=function(){GameLib.Event.Emit(GameLib.Event.GET_CODER_IMPLEMENTATION,null,function(e){this.coder=e,this.coder.isNotCodeMirrorThrow()}.bind(this)),this.editor=this.coder.instance(document.body,{value:this.code,mode:"javascript",lineNumbers:!0,scrollbarStyle:"overlay",indentWithTabs:!0,indentUnit:4}),this.editor.on("change",function(){this.code=this.editor.getValue(),this.updateInstance()}.bind(this))},GameLib.D3.CustomCode.prototype.closeEditor=function(){var e=this.editor.getWrapperElement();e.parentElement.removeChild(e)},GameLib.D3.Face=function(e,t){if(this.implementation=e,e instanceof GameLib.D3.Graphics)this.implementation.isNotThreeThrow();else{if(!(e instanceof GameLib.D3.Physics))throw new Error("Unhandled implementation : "+e);this.implementation.isNotCannonThrow()}if(GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Face)return t;GameLib.D3.API.Face.call(this,t.id,t.name,t.v0index,t.v1index,t.v2index,t.materialIndex,t.uvs,t.color,t.vertexColors,t.vertexNormals,t.normal),this.implementation instanceof GameLib.D3.Graphics&&(this.color=new GameLib.Color(this.implementation,this.color,this),this.vertexColors=this.vertexColors.map(function(e){return e instanceof GameLib.Color?e:e instanceof GameLib.API.Color?new GameLib.Color(this.implementation,e,this):void console.warn("unknown vertex color type",e)}.bind(this))),this.vertexNormals=this.vertexNormals.map(function(e){return e instanceof GameLib.Vector3?e:e instanceof GameLib.API.Vector3?new GameLib.Vector3(this.implementation,e,this):void console.warn("unknown vertex normal type",e)}.bind(this)),this.uvs=this.uvs.reduce(function(e,t,i){return e[i]=t.reduce(function(e,t){return t instanceof GameLib.API.Vector2?e.push(new GameLib.Vector2(this.implementation,t,this)):console.warn("unknown uv type"),e}.bind(this),[]),e}.bind(this),[]),this.normal=new GameLib.Vector3(this.implementation,this.normal,this)},GameLib.D3.Face.prototype=Object.create(GameLib.D3.API.Face.prototype),GameLib.D3.Face.prototype.constructor=GameLib.D3.Face,GameLib.D3.Face.prototype.createInstance=function(){},GameLib.D3.Face.prototype.updateInstance=function(){},GameLib.D3.Face.prototype.toApiObject=function(){return new GameLib.D3.API.Face(this.id,this.name,this.v0index,this.v1index,this.v2index,this.materialIndex,this.uvs.reduce(function(e,t,i){return e[i]=t.reduce(function(e,t){return t instanceof GameLib.Vector2?e.push(t.toApiObject()):console.warn("unknown uv type - cannot commit to API"),e}.bind(this),[]),e}.bind(this),[]),this.color.toApiObject(),this.vertexColors.map(function(e){return e.toApiObject()}),this.vertexNormals.map(function(e){return e.toApiObject()}),this.normal.toApiObject())},GameLib.D3.Face.FromObject=function(e,t){return new GameLib.D3.Face(e,GameLib.D3.API.Face.FromObject(t))},GameLib.D3.Fog=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Fog)return t;GameLib.D3.API.Fog.call(this,t.id,t.name,t.exponential,t.color,t.near,t.far,t.density,t.parentEntity),this.color=new GameLib.Color(this.graphics,this.color,this),GameLib.Component.call(this,GameLib.Component.COMPONENT_FOG)},GameLib.D3.Fog.prototype=Object.create(GameLib.D3.API.Fog.prototype),GameLib.D3.Fog.prototype.constructor=GameLib.D3.Fog,GameLib.D3.Fog.prototype.createInstance=function(){this.exponential?this.instance=new THREE.FogExp2(this.color.instance,this.density):this.instance=new THREE.Fog(this.color.instance,this.near,this.far),this.instance.name=this.name,GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Fog.prototype.updateInstance=function(e){if("exponential"===e){if(this.exponential&&!(this.instance instanceof THREE.FogExp2))return void this.createInstance();if(!(this.exponential||this.instance instanceof THREE.Fog))return void this.createInstance()}"color"===e&&(this.color.instance.setRGB(this.color.r,this.color.g,this.color.b),this.instance.color=this.color.instance),"near"!==e&&"far"!==e||this.instance instanceof THREE.Fog&&(this.instance.near=this.near,this.instance.far=this.far),"density"===e&&this.instance instanceof THREE.FogExp2&&(this.instance.density=this.density)},GameLib.D3.Fog.prototype.toApiObject=function(){return new GameLib.D3.API.Fog(this.id,this.name,this.exponential,this.color.toApiObject(),this.near,this.far,this.density,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Fog.FromObject=function(e,t){var i=GameLib.D3.API.Fog.FromObject(t);return new GameLib.D3.Fog(e,i)},GameLib.D3.Font=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Font)return t;GameLib.D3.API.Font.call(this,t.id,t.name,t.url,t.parentEntity),GameLib.Component.call(this,GameLib.Component.COMPONENT_FONT)},GameLib.D3.Font.prototype=Object.create(GameLib.D3.API.Font.prototype),GameLib.D3.Font.prototype.constructor=GameLib.D3.Font,GameLib.D3.Font.prototype.createInstance=function(){GameLib.Event.Emit(GameLib.Event.LOAD_FONT,{font:this}),this.instance=null,GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Font.prototype.updateInstance=function(){GameLib.Event.Emit(GameLib.Event.LOAD_FONT,{font:this})},GameLib.D3.Font.prototype.toApiObject=function(){return new GameLib.D3.API.Font(this.id,this.name,this.url,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Font.FromObject=function(e,t){return new GameLib.D3.Font(e,GameLib.D3.API.Font.FromObject(t))},GameLib.D3.FrictionContactMaterial=function(e,t){if(this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.FrictionContactMaterial)return t;GameLib.D3.API.FrictionContactMaterial.call(this,t.id,t.name,t.materials,t.friction,t.restitution,t.contactEquationStiffness,t.contactEquationRelaxation,t.frictionEquationStiffness,t.frictionEquationRelaxation,t.parentEntity),GameLib.Component.call(this,GameLib.Component.COMPONENT_FRICTION_CONTACT_MATERIAL,{materials:[GameLib.D3.FrictionMaterial]})},GameLib.D3.FrictionContactMaterial.prototype=Object.create(GameLib.D3.API.FrictionContactMaterial.prototype),GameLib.D3.FrictionContactMaterial.prototype.constructor=GameLib.D3.FrictionContactMaterial,GameLib.D3.FrictionContactMaterial.prototype.createInstance=function(){this.instance=new CANNON.ContactMaterial(null,null,{friction:this.friction,restitution:this.restitution,contactEquationStiffness:this.contactEquationStiffness}),this.instance.materials=this.materials.map(function(e){return e.instance}),GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.FrictionContactMaterial.prototype.updateInstance=function(){this.instance.materials=this.materials.map(function(e){return e.instance}),this.instance.friction=this.friction,this.instance.restitution=this.restitution,this.instance.contactEquationStiffness=this.contactEquationStiffness,this.instance.contactEquationRelaxation=this.contactEquationRelaxation,this.instance.frictionEquationStiffness=this.frictionEquationStiffness,this.instance.frictionEquationRelaxation=this.frictionEquationRelaxation},GameLib.D3.FrictionContactMaterial.prototype.toApiObject=function(){return new GameLib.D3.API.FrictionContactMaterial(this.id,this.name,this.materials.map(function(e){return GameLib.Utils.IdOrNull(e)}),this.friction,this.restitution,this.contactEquationStiffness,this.contactEquationRelaxation,this.frictionEquationStiffness,this.frictionEquationRelaxation,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.FrictionContactMaterial.FromObject=function(e,t){var i=GameLib.D3.API.FrictionContactMaterial.FromObject(t);return new GameLib.D3.FrictionContactMaterial(e,i)},GameLib.D3.FrictionMaterial=function(e,t){if(this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.FrictionMaterial)return t;GameLib.D3.API.FrictionMaterial.call(this,t.id,t.name,t.friction,t.restitution,t.parentEntity),GameLib.Component.call(this,GameLib.Component.COMPONENT_FRICTION_MATERIAL)},GameLib.D3.FrictionMaterial.prototype=Object.create(GameLib.D3.API.FrictionMaterial.prototype),GameLib.D3.FrictionMaterial.prototype.constructor=GameLib.D3.FrictionMaterial,GameLib.D3.FrictionMaterial.prototype.createInstance=function(){this.instance=new CANNON.Material(this.name),this.instance.friction=this.friction,this.instance.restitution=this.restitution,GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.FrictionMaterial.prototype.updateInstance=function(){this.instance.friction=this.friction,this.instance.restitution=this.restitution,this.instance.name=this.name},GameLib.D3.FrictionMaterial.prototype.toApiObject=function(){return new GameLib.D3.API.FrictionMaterial(this.id,this.name,this.friction,this.restitution,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.FrictionMaterial.FromObject=function(e,t){var i=GameLib.D3.API.FrictionMaterial.FromObject(t);return new GameLib.D3.FrictionMaterial(e,i)},GameLib.D3.Graphics=function(e,t,i){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Graphics ("+e+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=GameLib.D3.Graphics.GRAPHICS_TYPE_THREE),this.graphicsType=i,this.createInstance()},GameLib.D3.Graphics.GRAPHICS_TYPE_THREE=1,GameLib.D3.Graphics.prototype.createInstance=function(){this.instance=THREE},GameLib.D3.Graphics.prototype.updateInstance=function(){},GameLib.D3.Graphics.prototype.isThree=function(){return this.graphicsType===GameLib.D3.Graphics.GRAPHICS_TYPE_THREE},GameLib.D3.Graphics.prototype.isNotThreeThrow=function(){if(this.graphicsType!==GameLib.D3.Graphics.GRAPHICS_TYPE_THREE)throw console.warn("Only THREE supported for this function"),new Error("Only THREE supported for this function")},GameLib.D3.Helper=function(e,t,i,n,a,s){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t=GameLib.Utils.RandomId()),this.id=t,GameLib.Utils.UndefinedOrNull(i)&&(i="Helper ("+t+")"),this.name=i,GameLib.Utils.UndefinedOrNull(n))throw console.warn("Cannot create a helper for an Object which does not exist"),new Error("Cannot create a helper for an Object which does not exist");this.object=n,GameLib.Utils.UndefinedOrNull(a)&&(a=GameLib.D3.Helper.HELPER_TYPE_NONE,n instanceof GameLib.D3.Mesh&&n.meshType!==GameLib.D3.Mesh.MESH_TYPE_CURVE&&(a=GameLib.D3.Helper.HELPER_TYPE_EDGES),n instanceof GameLib.D3.Light&&(n.lightType===GameLib.D3.Light.LIGHT_TYPE_DIRECTIONAL&&(a=GameLib.D3.Helper.HELPER_TYPE_DIRECTIONAL_LIGHT),n.lightType===GameLib.D3.Light.LIGHT_TYPE_POINT&&(a=GameLib.D3.Helper.HELPER_TYPE_POINT_LIGHT),n.lightType===GameLib.D3.Light.LIGHT_TYPE_SPOT&&(a=GameLib.D3.Helper.HELPER_TYPE_SPOT_LIGHT)),n instanceof GameLib.D3.Skeleton&&(a=GameLib.D3.Helper.HELPER_TYPE_SKELETON)),this.helperType=a,GameLib.Utils.UndefinedOrNull(s)&&(s=null),this.parentEntity=s,this.createInstance()},GameLib.D3.Helper.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.Helper.prototype.constructor=GameLib.D3.Helper,GameLib.D3.Helper.HELPER_TYPE_NONE=0,GameLib.D3.Helper.HELPER_TYPE_EDGES=1,GameLib.D3.Helper.HELPER_TYPE_DIRECTIONAL_LIGHT=2,GameLib.D3.Helper.HELPER_TYPE_SPOT_LIGHT=3,GameLib.D3.Helper.HELPER_TYPE_POINT_LIGHT=4,GameLib.D3.Helper.HELPER_TYPE_WIREFRAME=5,GameLib.D3.Helper.HELPER_TYPE_SKELETON=6,GameLib.D3.Helper.prototype.createInstance=function(){this.helperType===GameLib.D3.Helper.HELPER_TYPE_EDGES&&(this.instance=new THREE.LineSegments(new THREE.EdgesGeometry(this.object.instance.geometry),new THREE.LineBasicMaterial({color:65280,linewidth:2}))),this.helperType===GameLib.D3.Helper.HELPER_TYPE_DIRECTIONAL_LIGHT&&(this.instance=new THREE.DirectionalLightHelper(this.object.instance)),this.helperType===GameLib.D3.Helper.HELPER_TYPE_POINT_LIGHT&&(this.instance=new THREE.PointLightHelper(this.object.instance,1)),this.helperType===GameLib.D3.Helper.HELPER_TYPE_SPOT_LIGHT&&(this.instance=new THREE.SpotLightHelper(this.object.instance)),this.helperType===GameLib.D3.Helper.HELPER_TYPE_WIREFRAME&&(this.instance=new THREE.WireframeGeometry(this.object.instance,65280)),this.helperType===GameLib.D3.Helper.HELPER_TYPE_SKELETON&&(this.instance=new THREE.SkeletonHelper(this.object.instance))},GameLib.D3.Helper.prototype.updateInstance=function(){this.instance.position.copy(this.object.instance.position),this.object.instance.parentMesh&&this.object.instance.parentMesh.instance&&this.instance.position.add(this.object.instance.parentMesh.instance.position),this.instance.scale.copy(this.object.instance.scale),this.instance.quaternion.copy(this.object.instance.quaternion)},GameLib.D3.Image=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Image)return t;GameLib.D3.API.Image.call(this,t.id,t.name,t.fileName,t.extension,t.path,t.contentType,t.size,t.parentEntity),GameLib.Component.call(this,GameLib.Component.COMPONENT_IMAGE,null,!0),GameLib.Event.Emit(GameLib.Event.LOAD_IMAGE,{image:this})},GameLib.D3.Image.prototype=Object.create(GameLib.D3.API.Image.prototype),GameLib.D3.Image.prototype.constructor=GameLib.D3.Image,GameLib.D3.Image.prototype.createInstance=function(){GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Image.prototype.updateInstance=function(){this.createInstance()},GameLib.D3.Image.prototype.toApiObject=function(){return new GameLib.D3.API.Image(this.id,this.name,this.fileName,this.extension,this.path,this.contentType,this.size,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Image.FromObject=function(e,t){return new GameLib.D3.Image(e,GameLib.D3.API.Image.FromObject(t))},GameLib.D3.Light=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Light)return t;GameLib.D3.API.Light.call(this,t.id,t.lightType,t.name,t.color,t.intensity,t.position,t.targetPosition,t.quaternion,t.rotation,t.scale,t.distance,t.decay,t.power,t.angle,t.penumbra,t.parentScene,t.parentEntity),this.color=new GameLib.Color(e,this.color,this),this.position=new GameLib.Vector3(e,this.position,this),this.targetPosition=new GameLib.Vector3(e,this.targetPosition,this),this.scale=new GameLib.Vector3(e,this.scale,this),this.quaternion=new GameLib.Quaternion(e,this.quaternion,this),this.rotation=new GameLib.Vector3(e,this.rotation,this),GameLib.Component.call(this,GameLib.Component.COMPONENT_LIGHT,{parentScene:GameLib.D3.Scene})},GameLib.D3.Light.prototype=Object.create(GameLib.D3.API.Light.prototype),GameLib.D3.Light.prototype.constructor=GameLib.D3.Light,GameLib.D3.Light.LIGHT_TYPE_AMBIENT=1,GameLib.D3.Light.LIGHT_TYPE_DIRECTIONAL=2,GameLib.D3.Light.LIGHT_TYPE_POINT=3,GameLib.D3.Light.LIGHT_TYPE_SPOT=4,GameLib.D3.Light.prototype.createInstance=function(){if(this.lightType===GameLib.D3.Light.LIGHT_TYPE_AMBIENT||"AmbientLight"===this.lightType)this.instance=new THREE.AmbientLight(this.color.instance,this.intensity);else if(this.lightType===GameLib.D3.Light.LIGHT_TYPE_DIRECTIONAL||"DirectionalLight"===this.lightType)this.instance=new THREE.DirectionalLight(this.color.instance,this.intensity);else if(this.lightType===GameLib.D3.Light.LIGHT_TYPE_POINT||"PointLight"===this.lightType)this.instance=new THREE.PointLight(this.color.instance,this.intensity),this.instance.distance=this.distance,this.instance.decay=this.decay;else{if(this.lightType!==GameLib.D3.Light.LIGHT_TYPE_SPOT&&"SpotLight"!==this.lightType)return void console.warn("unsupported light type: "+this.lightType);this.instance=new THREE.SpotLight(this.color.instance,this.intensity),this.instance.distance=this.distance,this.instance.angle=this.angle,this.instance.penumbra=this.penumbra,this.instance.decay=this.decay}this.instance.name=this.name,this.instance.position.x=this.position.x,this.instance.position.y=this.position.y,this.instance.position.z=this.position.z,this.instance.scale.x=this.scale.x,this.instance.scale.y=this.scale.y,this.instance.scale.z=this.scale.z,this.instance.target&&(this.instance.target.position.x=this.targetPosition.x,this.instance.target.position.y=this.targetPosition.y,this.instance.target.position.z=this.targetPosition.z),this.instance.quaternion.x=this.quaternion.x,this.instance.quaternion.y=this.quaternion.y,this.instance.quaternion.z=this.quaternion.z,this.instance.quaternion.w=this.quaternion.w,this.instance.intensity=this.intensity,this.instance.color.set(this.color.toHex()),GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Light.prototype.updateInstance=function(e){GameLib.Utils.UndefinedOrNull(e)&&console.warn("no property for light: "+this.name),"lightType"===e&&(this.parentScene.instance.remove(this.instance),this.createInstance(),this.parentScene.instance.add(this.instance)),"name"===e&&(this.instance.name=this.name),"position"===e&&(this.instance.position.x=this.position.x,this.instance.position.y=this.position.y,this.instance.position.z=this.position.z),"scale"===e&&(this.instance.scale.x=this.scale.x,this.instance.scale.y=this.scale.y,this.instance.scale.z=this.scale.z),"target"===e&&this.instance.target&&(this.instance.target.position.x=this.targetPosition.x,this.instance.target.position.y=this.targetPosition.y,this.instance.target.position.z=this.targetPosition.z),"quaternion"===e&&(this.instance.quaternion.x=this.quaternion.x,this.instance.quaternion.y=this.quaternion.y,this.instance.quaternion.z=this.quaternion.z,this.instance.quaternion.w=this.quaternion.w),"intensity"===e&&(this.instance.intensity=this.intensity),"color"===e&&this.instance.color.set(this.color.toHex())},GameLib.D3.Light.prototype.toApiObject=function(){return new GameLib.D3.API.Light(this.id,this.lightType,this.name,this.color.toApiObject(),this.intensity,this.position.toApiObject(),this.targetPosition.toApiObject(),this.quaternion.toApiObject(),this.rotation.toApiObject(),this.scale.toApiObject(),this.distance,this.decay,this.power,this.angle,this.penumbra,GameLib.Utils.IdOrNull(this.parentScene),GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Light.FromObject=function(e,t){return new GameLib.D3.Light(e,GameLib.D3.API.Light.FromObject(t))},GameLib.D3.LookAt=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.LookAt)return t;GameLib.D3.API.LookAt.call(this,t.id,t.name,t.currentComponent,t.targetComponent,t.targetPositionOffset,t.rotationSpeed,t.parentEntity),this.targetPositionOffset=new GameLib.Vector3(this.graphics,this.targetPositionOffset,this),this.lookAtMatrix=new GameLib.Matrix4(this.graphics,this.lookAtMatrix,this),this.up=new GameLib.Vector3(this.graphics,this.up,this),this.currentRotation=new GameLib.Quaternion(this.graphics,this.currentRotation,this),this.targetPosition=new GameLib.Vector3(this.graphics,this.targetPosition,this),GameLib.Component.call(this,GameLib.Component.COMPONENT_LOOK_AT,{currentComponent:GameLib.Component,targetComponent:GameLib.Component})},GameLib.D3.LookAt.prototype=Object.create(GameLib.D3.API.LookAt.prototype),GameLib.D3.LookAt.prototype.constructor=GameLib.D3.LookAt,GameLib.D3.LookAt.prototype.createInstance=function(){this.instance=!0,GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.LookAt.prototype.updateInstance=function(){},GameLib.D3.LookAt.prototype.toApiObject=function(){return new GameLib.D3.API.LookAt(this.id,this.name,GameLib.Utils.IdOrNull(this.currentComponent),GameLib.Utils.IdOrNull(this.targetComponent),this.targetPositionOffset.toApiObject(),this.rotationSpeed,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.LookAt.FromObject=function(e,t){var i=GameLib.D3.API.LookAt.FromObject(t);return new GameLib.D3.LookAt(e,i)},GameLib.D3.LookAt.prototype.update=function(e){this.currentComponent&&this.targetComponent&&(this.targetPosition.x=this.targetComponent.position.x+this.targetPositionOffset.x,this.targetPosition.y=this.targetComponent.position.y+this.targetPositionOffset.y,this.targetPosition.z=this.targetComponent.position.z+this.targetPositionOffset.z,this.targetPosition.updateInstance(),this.currentComponent.lookAt.x=this.targetPosition.x,this.currentComponent.lookAt.y=this.targetPosition.y,this.currentComponent.lookAt.z=this.targetPosition.z,this.currentComponent.lookAt.updateInstance())},GameLib.D3.Material=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Material)return t;GameLib.D3.API.Material.call(this,t.id,t.materialType,t.name,t.opacity,t.side,t.transparent,t.specular,t.lightMapIntensity,t.aoMapIntensity,t.color,t.emissive,t.emissiveIntensity,t.combine,t.shininess,t.reflectivity,t.refractionRatio,t.fog,t.wireframe,t.wireframeLineWidth,t.wireframeLineCap,t.wireframeLineJoin,t.vertexColors,t.skinning,t.morphTargets,t.morphNormals,t.lineWidth,t.lineCap,t.lineJoin,t.dashSize,t.gapWidth,t.blending,t.blendSrc,t.blendDst,t.blendEquation,t.depthTest,t.depthFunc,t.depthWrite,t.polygonOffset,t.polygonOffsetFactor,t.polygonOffsetUnits,t.alphaTest,t.clippingPlanes,t.clipShadows,t.visible,t.overdraw,t.flatShading,t.bumpScale,t.normalScale,t.displacementScale,t.displacementBias,t.roughness,t.metalness,t.pointSize,t.pointSizeAttenuation,t.spriteRotation,t.envMapIntensity,t.alphaMap,t.aoMap,t.bumpMap,t.diffuseMap,t.displacementMap,t.emissiveMap,t.environmentMap,t.lightMap,t.metalnessMap,t.normalMap,t.roughnessMap,t.specularMap,t.parentEntity),this.specular=new GameLib.Color(e,this.specular,this),this.color=new GameLib.Color(e,this.color,this),this.emissive=new GameLib.Color(e,this.emissive,this),this.alphaMap&&this.alphaMap instanceof GameLib.D3.API.Texture&&(this.alphaMap=new GameLib.D3.Texture(this.graphics,this.alphaMap)),this.aoMap&&this.aoMap instanceof GameLib.D3.API.Texture&&(this.aoMap=new GameLib.D3.Texture(this.graphics,this.aoMap)),this.bumpMap&&this.bumpMap instanceof GameLib.D3.API.Texture&&(this.bumpMap=new GameLib.D3.Texture(this.graphics,this.bumpMap)),this.diffuseMap&&this.diffuseMap instanceof GameLib.D3.API.Texture&&(this.diffuseMap=new GameLib.D3.Texture(this.graphics,this.diffuseMap)),this.displacementMap&&this.displacementMap instanceof GameLib.D3.API.Texture&&(this.displacementMap=new GameLib.D3.Texture(this.graphics,this.displacementMap)),this.emissiveMap&&this.emissiveMap instanceof GameLib.D3.API.Texture&&(this.emissiveMap=new GameLib.D3.Texture(this.graphics,this.emissiveMap)),this.environmentMap&&this.environmentMap instanceof GameLib.D3.API.Texture&&(this.environmentMap=new GameLib.D3.Texture(this.graphics,this.environmentMap)),this.lightMap&&this.lightMap instanceof GameLib.D3.API.Texture&&(this.lightMap=new GameLib.D3.Texture(this.graphics,this.lightMap)),this.metalnessMap&&this.metalnessMap instanceof GameLib.D3.API.Texture&&(this.metalnessMap=new GameLib.D3.Texture(this.graphics,this.metalnessMap)),this.normalMap&&this.normalMap instanceof GameLib.D3.API.Texture&&(this.normalMap=new GameLib.D3.Texture(this.graphics,this.normalMap)),this.roughnessMap&&this.roughnessMap instanceof GameLib.D3.API.Texture&&(this.roughnessMap=new GameLib.D3.Texture(this.graphics,this.roughnessMap)),this.specularMap&&this.specularMap instanceof GameLib.D3.API.Texture&&(this.specularMap=new GameLib.D3.Texture(this.graphics,this.specularMap)),GameLib.Component.call(this,GameLib.Component.COMPONENT_MATERIAL,{alphaMap:GameLib.D3.Texture,aoMap:GameLib.D3.Texture,bumpMap:GameLib.D3.Texture,diffuseMap:GameLib.D3.Texture,displacementMap:GameLib.D3.Texture,emissiveMap:GameLib.D3.Texture,environmentMap:GameLib.D3.Texture,lightMap:GameLib.D3.Texture,metalnessMap:GameLib.D3.Texture,normalMap:GameLib.D3.Texture,roughnessMap:GameLib.D3.Texture,specularMap:GameLib.D3.Texture})},GameLib.D3.Material.prototype=Object.create(GameLib.D3.API.Material.prototype),GameLib.D3.Material.prototype.constructor=GameLib.D3.Material,GameLib.D3.Material.TYPE_MULTIPLY_OPERATION=0,GameLib.D3.Material.TYPE_MIX_OPERATION=1,GameLib.D3.Material.TYPE_ADD_OPERATION=2,GameLib.D3.Material.TYPE_NO_COLORS=0,GameLib.D3.Material.TYPE_FACE_COLORS=1,GameLib.D3.Material.TYPE_VERTEX_COLORS=2,GameLib.D3.Material.TYPE_NO_BLENDING=0,GameLib.D3.Material.TYPE_NORMAL_BLENDING=1,GameLib.D3.Material.TYPE_ADDITIVE_BLENDING=2,GameLib.D3.Material.TYPE_SUBTRACTIVE_BLENDING=3,GameLib.D3.Material.TYPE_MULTIPLY_BLENDING=4,GameLib.D3.Material.TYPE_CUSTOM_BLENDING=5,GameLib.D3.Material.TYPE_ZERO_FACTOR=200,GameLib.D3.Material.TYPE_ONE_FACTOR=201,GameLib.D3.Material.TYPE_SRC_COLOR_FACTOR=202,GameLib.D3.Material.TYPE_ONE_MINUS_SRC_COLOR_FACTOR=203,GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR=204,GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR=205,GameLib.D3.Material.TYPE_DST_ALPHA_FACTOR=206,GameLib.D3.Material.TYPE_ONE_MINUS_DST_ALPHA_FACTOR=207,GameLib.D3.Material.TYPE_DST_COLOR_FACTOR=208,GameLib.D3.Material.TYPE_ONE_MINUS_DST_COLOR_FACTOR=209,GameLib.D3.Material.TYPE_SRC_ALPHA_SATURATE_FACTOR=210,GameLib.D3.Material.TYPE_ADD_EQUATION=100,GameLib.D3.Material.TYPE_SUBTRACT_EQUATION=101,GameLib.D3.Material.TYPE_REVERSE_SUBTRACT_EQUATION=102,GameLib.D3.Material.TYPE_MIN_EQUATION=103,GameLib.D3.Material.TYPE_MAX_EQUATION=104,GameLib.D3.Material.TYPE_NEVER_DEPTH=0,GameLib.D3.Material.TYPE_ALWAYS_DEPTH=1,GameLib.D3.Material.TYPE_LESS_DEPTH=2,GameLib.D3.Material.TYPE_LESS_EQUAL_DEPTH=3,GameLib.D3.Material.TYPE_EQUAL_DEPTH=4,GameLib.D3.Material.TYPE_GREATER_EQUAL_DEPTH=5,GameLib.D3.Material.TYPE_GREATER_DEPTH=6,GameLib.D3.Material.TYPE_NOT_EQUAL_DEPTH=7,GameLib.D3.Material.TYPE_FRONT_SIDE=0,GameLib.D3.Material.TYPE_BACK_SIDE=1,GameLib.D3.Material.TYPE_DOUBLE_SIDE=2,GameLib.D3.Material.TYPE_FLAT_SHADING=1,GameLib.D3.Material.TYPE_SMOOTH_SHADING=2,GameLib.D3.Material.MATERIAL_TYPE_LINE_BASIC=1,GameLib.D3.Material.MATERIAL_TYPE_LINE_DASHED=2,GameLib.D3.Material.MATERIAL_TYPE_BASIC=3,GameLib.D3.Material.MATERIAL_TYPE_DEPTH=4,GameLib.D3.Material.MATERIAL_TYPE_LAMBERT=5,GameLib.D3.Material.MATERIAL_TYPE_NORMAL=6,GameLib.D3.Material.MATERIAL_TYPE_PHONG=7,GameLib.D3.Material.MATERIAL_TYPE_STANDARD=8,GameLib.D3.Material.MATERIAL_TYPE_POINTS=9,GameLib.D3.Material.MATERIAL_TYPE_SPRITE=10,GameLib.D3.Material.LINE_CAP_BUTT=1,GameLib.D3.Material.LINE_CAP_ROUND=2,GameLib.D3.Material.LINE_CAP_SQUARE=3,GameLib.D3.Material.LINE_JOIN_ROUND=1,GameLib.D3.Material.LINE_JOIN_BEVEL=2,GameLib.D3.Material.LINE_JOIN_MITER=3,GameLib.D3.Material.prototype.createStandardMaterialInstance=function(){return new THREE.MeshStandardMaterial({name:this.name,opacity:this.opacity,transparent:this.transparent,blending:this.blending,blendSrc:this.blendSrc,blendDst:this.blendDst,blendEquation:this.blendEquation,depthTest:this.depthTest,depthFunc:this.depthFunc,depthWrite:this.depthWrite,polygonOffset:this.polygonOffset,polygonOffsetFactor:this.polygonOffsetFactor,polygonOffsetUnits:this.polygonOffsetUnits,alphaTest:this.alphaTest,clippingPlanes:this.clippingPlanes,clipShadows:this.clipShadows,overdraw:this.overdraw,visible:this.visible,side:this.side,color:this.color.instance,roughness:this.roughness,metalness:this.metalness,lightMapIntensity:this.lightMapIntensity,aoMapIntensity:this.aoMapIntensity,emissive:this.emissive.instance,emissiveIntensity:this.emissiveIntensity,bumpScale:this.bumpScale,normalScale:this.normalScale,displacementScale:this.displacementScale,refractionRatio:this.refractionRatio,fog:this.fog,flatShading:this.flatShading,wireframe:this.wireframe,wireframeLinewidth:this.wireframeLineWidth,wireframeLinecap:this.wireframeLineCap,wireframeLinejoin:this.wireframeLineJoin,vertexColors:GameLib.D3.Material.TYPE_VERTEX_COLORS,skinning:this.skinning,morphTargets:this.morphTargets,morphNormals:this.morphNormals})},GameLib.D3.Material.prototype.createPointsMaterialInstance=function(){return new THREE.PointsMaterial({name:this.name,opacity:this.opacity,transparent:this.transparent,depthTest:this.depthTest,depthFunc:this.depthFunc,depthWrite:this.depthWrite,visible:this.visible,side:this.side,color:this.color.instance,size:this.pointSize,sizeAttenuation:this.pointSizeAttenuation})},GameLib.D3.Material.prototype.createLineBasicMaterialInstance=function(){var e="round";this.lineCap===GameLib.D3.Material.LINE_CAP_BUTT&&(e="butt"),this.lineCap===GameLib.D3.Material.LINE_CAP_SQUARE&&(e="square");var t="round";return this.lineJoin===GameLib.D3.Material.LINE_JOIN_BEVEL&&(t="bevel"),this.lineJoin===GameLib.D3.Material.LINE_JOIN_MITER&&(t="miter"),new THREE.LineBasicMaterial({name:this.name,opacity:this.opacity,transparent:this.transparent,depthTest:this.depthTest,depthFunc:this.depthFunc,depthWrite:this.depthWrite,visible:this.visible,side:this.side,color:this.color.instance,linewidth:this.lineWidth,linecap:e,linejoin:t})},GameLib.D3.Material.prototype.createPhongMaterialInstance=function(){return new THREE.MeshPhongMaterial({name:this.name,opacity:this.opacity,transparent:this.transparent,blending:this.blending,blendSrc:this.blendSrc,blendDst:this.blendDst,blendEquation:this.blendEquation,depthTest:this.depthTest,depthFunc:this.depthFunc,depthWrite:this.depthWrite,polygonOffset:this.polygonOffset,polygonOffsetFactor:this.polygonOffsetFactor,polygonOffsetUnits:this.polygonOffsetUnits,alphaTest:this.alphaTest,clippingPlanes:this.clippingPlanes,clipShadows:this.clipShadows,overdraw:this.overdraw,visible:this.visible,side:this.side,color:this.color.instance,specular:this.specular.instance,shininess:this.shininess,lightMapIntensity:this.lightMapIntensity,aoMapIntensity:this.aoMapIntensity,emissive:this.emissive.instance,emissiveIntensity:this.emissiveIntensity,bumpScale:this.bumpScale,normalScale:this.normalScale,displacementScale:this.displacementScale,combine:this.combine,refractionRatio:this.refractionRatio,fog:this.fog,flatShading:this.flatShading,wireframe:this.wireframe,wireframeLinewidth:this.wireframeLineWidth, +wireframeLinecap:this.wireframeLineCap,wireframeLinejoin:this.wireframeLineJoin,vertexColors:GameLib.D3.Material.TYPE_VERTEX_COLORS,skinning:this.skinning,morphTargets:this.morphTargets,morphNormals:this.morphNormals})},GameLib.D3.Material.prototype.createMeshBasicMaterialInstance=function(){return new THREE.MeshBasicMaterial({name:this.name,opacity:this.opacity,transparent:this.transparent,blending:this.blending,blendSrc:this.blendSrc,blendDst:this.blendDst,blendEquation:this.blendEquation,depthTest:this.depthTest,depthFunc:this.depthFunc,depthWrite:this.depthWrite,polygonOffset:this.polygonOffset,polygonOffsetFactor:this.polygonOffsetFactor,polygonOffsetUnits:this.polygonOffsetUnits,alphaTest:this.alphaTest,clippingPlanes:this.clippingPlanes,clipShadows:this.clipShadows,overdraw:this.overdraw,visible:this.visible,side:this.side,color:this.color.instance,vertexColors:GameLib.D3.Material.TYPE_VERTEX_COLORS,fog:this.fog})},GameLib.D3.Material.prototype.checkTexture=function(e,t){var i=!1;return this[e]&&this[e].instance?this.instance[t]!==this[e].instance&&(this.instance[t]=this[e].instance,i=!0):null!==this.instance[t]&&(this.instance[t]=null,i=!0),i},GameLib.D3.Material.prototype.updateTextures=function(){var e=!1;return this.checkTexture("alphaMap","alphaMap")&&(e=!0),this.checkTexture("aoMap","aoMap")&&(e=!0),this.checkTexture("bumpMap","bumpMap")&&(e=!0),this.checkTexture("diffuseMap","map")&&(e=!0),this.checkTexture("displacementMap","displacementMap")&&(e=!0),this.checkTexture("emissiveMap","emissiveMap")&&(e=!0),this.checkTexture("environmentMap","envMap")&&(e=!0),this.checkTexture("lightMap","lightMap")&&(e=!0),this.checkTexture("metalnessMap","metalnessMap")&&(e=!0),this.checkTexture("normalMap","normalMap")&&(e=!0),this.checkTexture("roughnessMap","roughnessMap")&&(e=!0),this.checkTexture("specularMap","specularMap")&&(e=!0),e&&this.publish(GameLib.Event.MATERIAL_TEXTURES_UPDATED,{material:this}),e},GameLib.D3.Material.prototype.updateStandardMaterialInstance=function(e){this.instance.name=this.name,this.instance.opacity=this.opacity,this.instance.transparent=this.transparent,this.instance.blending=this.blending,this.instance.blendSrc=this.blendSrc,this.instance.blendDst=this.blendDst,this.instance.blendEquation=this.blendEquation,this.instance.depthTest=this.depthTest,this.instance.depthFunc=this.depthFunc,this.instance.depthWrite=this.depthWrite,this.instance.polygonOffset=this.polygonOffset,this.instance.polygonOffsetFactor=this.polygonOffsetFactor,this.instance.polygonOffsetUnits=this.polygonOffsetUnits,this.instance.alphaTest=this.alphaTest,this.instance.clippingPlanes=this.clippingPlanes,this.instance.clipShadows=this.clipShadows,this.instance.overdraw=this.overdraw,this.instance.visible=this.visible,this.instance.side=this.side,this.instance.color=this.color.instance,this.instance.envMapIntensity=this.envMapIntensity,this.instance.roughness=this.roughness,this.instance.metalness=this.metalness,this.instance.lightMapIntensity=this.lightMapIntensity,this.instance.aoMapIntensity=this.aoMapIntensity,this.instance.emissive=this.emissive.instance,this.instance.emissiveIntensity=this.emissiveIntensity,this.instance.bumpScale=this.bumpScale,this.instance.normalScale=this.normalScale,this.instance.displacementScale=this.displacementScale,this.instance.refractionRatio=this.refractionRatio,this.instance.fog=this.fog,this.instance.flatShading=this.flatShading,this.instance.wireframe=this.wireframe,this.instance.wireframeLinewidth=this.wireframeLineWidth,this.instance.wireframeLinecap=this.wireframeLineCap,this.instance.wireframeLinejoin=this.wireframeLineJoin,this.instance.vertexColors=GameLib.D3.Material.TYPE_VERTEX_COLORS,this.instance.skinning=this.skinning,this.instance.morphTargets=this.morphTargets,this.instance.morphNormals=this.morphNormals},GameLib.D3.Material.prototype.updatePointsMaterialInstance=function(e){this.instance.name=this.name,this.instance.opacity=this.opacity,this.instance.transparent=this.transparent,this.instance.depthFunc=this.depthFunc,this.instance.depthWrite=this.depthWrite,this.instance.visible=this.visible,this.instance.side=this.side,this.instance.color=this.color.instance,this.instance.size=this.pointSize,this.instance.sizeAttenuation=this.pointSizeAttenuation},GameLib.D3.Material.prototype.updateLineBasicMaterialInstance=function(e){var t="round";this.lineCap===GameLib.D3.Material.LINE_CAP_BUTT&&(t="butt"),this.lineCap===GameLib.D3.Material.LINE_CAP_SQUARE&&(t="square");var i="round";this.lineJoin===GameLib.D3.Material.LINE_JOIN_BEVEL&&(i="bevel"),this.lineJoin===GameLib.D3.Material.LINE_JOIN_MITER&&(i="miter"),this.instance.name=this.name,this.instance.opacity=this.opacity,this.instance.transparent=this.transparent,this.instance.depthFunc=this.depthFunc,this.instance.depthWrite=this.depthWrite,this.instance.visible=this.visible,this.instance.side=this.side,this.instance.color=this.color.instance,this.instance.linewidth=this.lineWidth,this.instance.linecap=t,this.instance.linejoin=i},GameLib.D3.Material.prototype.updatePhongMaterialInstance=function(e){this.instance.name=this.name,this.instance.opacity=this.opacity,this.instance.transparent=this.transparent,this.instance.blending=this.blending,this.instance.blendSrc=this.blendSrc,this.instance.blendDst=this.blendDst,this.instance.blendEquation=this.blendEquation,this.instance.depthTest=this.depthTest,this.instance.depthFunc=this.depthFunc,this.instance.depthWrite=this.depthWrite,this.instance.polygonOffset=this.polygonOffset,this.instance.polygonOffsetFactor=this.polygonOffsetFactor,this.instance.polygonOffsetUnits=this.polygonOffsetUnits,this.instance.alphaTest=this.alphaTest,this.instance.clippingPlanes=this.clippingPlanes,this.instance.clipShadows=this.clipShadows,this.instance.overdraw=this.overdraw,this.instance.visible=this.visible,this.instance.side=this.side,this.instance.color=this.color.instance,this.instance.specular=this.specular.instance,this.instance.shininess=this.shininess,this.instance.lightMapIntensity=this.lightMapIntensity,this.instance.aoMapIntensity=this.aoMapIntensity,this.instance.emissive=this.emissive.instance,this.instance.emissiveIntensity=this.emissiveIntensity,this.instance.envMapIntensity=this.envMapIntensity,this.instance.bumpScale=this.bumpScale,this.instance.normalScale=this.normalScale,this.instance.displacementScale=this.displacementScale,this.instance.combine=this.combine,this.instance.refractionRatio=this.refractionRatio,this.instance.fog=this.fog,this.instance.flatShading=this.flatShading,this.instance.wireframe=this.wireframe,this.instance.wireframeLinewidth=this.wireframeLineWidth,this.instance.wireframeLinecap=this.wireframeLineCap,this.instance.wireframeLinejoin=this.wireframeLineJoin,this.instance.vertexColors=GameLib.D3.Material.TYPE_VERTEX_COLORS,this.instance.skinning=this.skinning,this.instance.morphTargets=this.morphTargets,this.instance.morphNormals=this.morphNormals},GameLib.D3.Material.prototype.updateMeshBasicMaterialInstance=function(e){this.instance.name=this.name,this.instance.opacity=this.opacity,this.instance.transparent=this.transparent,this.instance.blending=this.blending,this.instance.blendSrc=this.blendSrc,this.instance.blendDst=this.blendDst,this.instance.blendEquation=this.blendEquation,this.instance.depthTest=this.depthTest,this.instance.depthFunc=this.depthFunc,this.instance.depthWrite=this.depthWrite,this.instance.polygonOffset=this.polygonOffset,this.instance.polygonOffsetFactor=this.polygonOffsetFactor,this.instance.polygonOffsetUnits=this.polygonOffsetUnits,this.instance.alphaTest=this.alphaTest,this.instance.clippingPlanes=this.clippingPlanes,this.instance.clipShadows=this.clipShadows,this.instance.overdraw=this.overdraw,this.instance.visible=this.visible,this.instance.side=this.side,this.instance.color=this.color.instance,this.instance.vertexColors=GameLib.D3.Material.TYPE_VERTEX_COLORS,this.instance.fog=this.fog},GameLib.D3.Material.prototype.createInstance=function(){this.materialType===GameLib.D3.Material.MATERIAL_TYPE_STANDARD?this.instance=this.createStandardMaterialInstance():this.materialType===GameLib.D3.Material.MATERIAL_TYPE_POINTS?this.instance=this.createPointsMaterialInstance():this.materialType===GameLib.D3.Material.MATERIAL_TYPE_PHONG?this.instance=this.createPhongMaterialInstance():this.materialType===GameLib.D3.Material.MATERIAL_TYPE_BASIC?this.instance=this.createMeshBasicMaterialInstance():this.materialType===GameLib.D3.Material.MATERIAL_TYPE_LINE_BASIC?this.instance=this.createLineBasicMaterialInstance():console.warn("material type is not implemented yet: "+this.materialType),this.instance.needsUpdate=!0,this.updateTextures(),GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Material.prototype.updateInstance=function(e){return this.instance?"materialType"===e?(this.createInstance(),void this.publish(GameLib.Event.MATERIAL_TYPE_CHANGED,{material:this})):("alphaMap"!==e&&"aoMap"!==e&&"bumpMap"!==e&&"diffuseMap"!==e&&"displacementMap"!==e&&"emissiveMap"!==e&&"environmentMap"!==e&&"lightMap"!==e&&"metalnessMap"!==e&&"normalMap"!==e&&"roughnessMap"!==e&&"specularMap"!==e||this.updateTextures(),this.materialType===GameLib.D3.Material.MATERIAL_TYPE_STANDARD?this.updateStandardMaterialInstance(e):this.materialType===GameLib.D3.Material.MATERIAL_TYPE_POINTS?this.updatePointsMaterialInstance(e):this.materialType===GameLib.D3.Material.MATERIAL_TYPE_PHONG?this.updatePhongMaterialInstance(e):this.materialType===GameLib.D3.Material.MATERIAL_TYPE_BASIC?this.updateMeshBasicMaterialInstance(e):this.materialType===GameLib.D3.Material.MATERIAL_TYPE_LINE_BASIC?this.updateLineBasicMaterialInstance(e):console.warn("not yet implemented (material type = "+this.materialType+")"),void(this.instance.needsUpdate=!0)):void console.warn("Attempt to update a non-existent instance")},GameLib.D3.Material.prototype.toApiObject=function(e){GameLib.Utils.UndefinedOrNull(e)&&(e=!1);var t=null;this.alphaMap&&(e&&this.alphaMap.save(),t=this.alphaMap.id);var i=null;this.aoMap&&(e&&this.aoMap.save(),i=this.aoMap.id);var n=null;this.bumpMap&&(e&&this.bumpMap.save(),n=this.bumpMap.id);var a=null;this.diffuseMap&&(e&&this.diffuseMap.save(),a=this.diffuseMap.id);var s=null;this.displacementMap&&(e&&this.displacementMap.save(),s=this.displacementMap.id);var o=null;this.emissiveMap&&(e&&this.emissiveMap.save(),o=this.emissiveMap.id);var r=null;this.environmentMap&&(e&&this.environmentMap.save(),r=this.environmentMap.id);var c=null;this.lightMap&&(e&&this.lightMap.save(),c=this.lightMap.id);var h=null;this.metalnessMap&&(e&&this.metalnessMap.save(),h=this.metalnessMap.id);var m=null;this.normalMap&&(this.normalMap.save(),m=this.normalMap.id);var l=null;this.roughnessMap&&(e&&this.roughnessMap.save(),l=this.roughnessMap.id);var p=null;return this.specularMap&&(e&&this.specularMap.save(),p=this.specularMap.id),new GameLib.D3.API.Material(this.id,this.materialType,this.name,this.opacity,this.side,this.transparent,this.specular.toApiObject(),this.lightMapIntensity,this.aoMapIntensity,this.color.toApiObject(),this.emissive.toApiObject(),this.emissiveIntensity,this.combine,this.shininess,this.reflectivity,this.refractionRatio,this.fog,this.wireframe,this.wireframeLineWidth,this.wireframeLineCap,this.wireframeLineJoin,this.vertexColors,this.skinning,this.morphTargets,this.morphNormals,this.lineWidth,this.lineCap,this.lineJoin,this.dashSize,this.gapWidth,this.blending,this.blendSrc,this.blendDst,this.blendEquation,this.depthTest,this.depthFunc,this.depthWrite,this.polygonOffset,this.polygonOffsetFactor,this.polygonOffsetUnits,this.alphaTest,this.clippingPlanes,this.clipShadows,this.visible,this.overdraw,this.flatShading,this.bumpScale,this.normalScale,this.displacementScale,this.displacementBias,this.roughness,this.metalness,this.pointSize,this.pointSizeAttenuation,this.spriteRotation,this.envMapIntensity,t,i,n,a,s,o,r,c,h,m,l,p,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Material.prototype.getTextures=function(){var e=[];return this.alphaMap&&e.push(this.alphaMap),this.aoMap&&e.push(this.aoMap),this.bumpMap&&e.push(this.bumpMap),this.diffuseMap&&e.push(this.diffuseMap),this.displacementMap&&e.push(this.displacementMap),this.emissiveMap&&e.push(this.emissiveMap),this.environmentMap&&e.push(this.environmentMap),this.lightMap&&e.push(this.lightMap),this.metalnessMap&&e.push(this.metalnessMap),this.normalMap&&e.push(this.normalMap),this.roughnessMap&&e.push(this.roughnessMap),this.specularMap&&e.push(this.specularMap),e},GameLib.D3.Material.FromObject=function(e,t){return new GameLib.D3.Material(e,GameLib.D3.API.Material.FromObject(t))},GameLib.D3.Mesh=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Mesh)return t;GameLib.D3.API.Mesh.call(this,t.id,t.meshType,t.name,t.vertices,t.faces,t.materials,t.parentMesh,t.parentScene,t.skeleton,t.skinIndices,t.skinWeights,t.position,t.quaternion,t.rotation,t.scale,t.up,t.modelMatrix,t.parentEntity,t.renderOrder,t.isBufferMesh,t.useQuaternion,t.visible),this.faces=this.faces.map(function(e){return e instanceof GameLib.D3.API.Face?new GameLib.D3.Face(this.graphics,e):e}.bind(this)),this.materials=this.materials.map(function(e){return e instanceof GameLib.D3.API.Material?new GameLib.D3.Material(this.graphics,e):e}.bind(this)),this.skeleton&&(this.skeleton=new GameLib.D3.Skeleton(this.graphics,this.skeleton)),this.vertices=this.vertices.map(function(e){return new GameLib.D3.Vertex(this.graphics,e)}.bind(this)),this.position=new GameLib.Vector3(this.graphics,this.position,this),this.quaternion=new GameLib.Quaternion(this.graphics,this.quaternion,this),this.rotation=new GameLib.Vector3(this.graphics,this.rotation,this),this.scale=new GameLib.Vector3(this.graphics,this.scale,this),this.up=new GameLib.Vector3(this.graphics,this.up,this),this.modelMatrix=new GameLib.Matrix4(this.graphics,this.modelMatrix,this),this.dimensions=new GameLib.Vector3(this.graphics,new GameLib.API.Vector3,this);var i={parentMesh:GameLib.D3.Mesh,parentScene:GameLib.D3.Scene,materials:[GameLib.D3.Material],skeleton:GameLib.D3.Skeleton},n=GameLib.Component.COMPONENT_MESH;this.meshType===GameLib.D3.Mesh.MESH_TYPE_PLANE&&(n=GameLib.Component.COMPONENT_MESH_PLANE),this.meshType===GameLib.D3.Mesh.MESH_TYPE_BOX&&(n=GameLib.Component.COMPONENT_MESH_BOX),this.meshType===GameLib.D3.Mesh.MESH_TYPE_CYLINDER&&(n=GameLib.Component.COMPONENT_MESH_CYLINDER),this.meshType===GameLib.D3.Mesh.MESH_TYPE_SPHERE&&(n=GameLib.Component.COMPONENT_MESH_SPHERE),this.meshType===GameLib.D3.Mesh.MESH_TYPE_LINE&&(n=GameLib.Component.COMPONENT_MESH_LINE),this.meshType===GameLib.D3.Mesh.MESH_TYPE_TEXT&&(n=GameLib.Component.COMPONENT_MESH_TEXT,i.font=GameLib.D3.Font),this.helper=null,this.updateRotationFromAxisAngle=!0,GameLib.Component.call(this,n,i)},GameLib.D3.Mesh.prototype=Object.create(GameLib.D3.API.Mesh.prototype),GameLib.D3.Mesh.prototype.constructor=GameLib.D3.Mesh,GameLib.D3.Mesh.MESH_TYPE_NORMAL=0,GameLib.D3.Mesh.MESH_TYPE_SKINNED=1,GameLib.D3.Mesh.MESH_TYPE_CURVE=2,GameLib.D3.Mesh.MESH_TYPE_SPHERE=3,GameLib.D3.Mesh.MESH_TYPE_PLANE=4,GameLib.D3.Mesh.MESH_TYPE_BOX=5,GameLib.D3.Mesh.MESH_TYPE_CYLINDER=6,GameLib.D3.Mesh.MESH_TYPE_TEXT=7,GameLib.D3.Mesh.MESH_TYPE_LINE=8,GameLib.D3.Mesh.prototype.lookAt=function(e){this.instance.lookAt(new THREE.Vector3(e.x,e.y,e.z)),this.rotation.x=this.instance.rotation.x,this.rotation.y=this.instance.rotation.y,this.rotation.z=this.instance.rotation.z,this.quaternion.x=this.instance.quaternion.x,this.quaternion.y=this.instance.quaternion.y,this.quaternion.z=this.instance.quaternion.z,this.quaternion.w=this.instance.quaternion.w},GameLib.D3.Mesh.prototype.createInstanceGeometry=function(e){if(e instanceof THREE.Geometry&&(this.computeBoundingBox(e),this.isBufferMesh))return(new THREE.BufferGeometry).fromGeometry(e);this.faces.sort(function(e,t){return e.materialIndext.materialIndex?1:0});var t=new Float32Array(this.faces.reduce(function(e,t){return e.push(this.vertices[t.v0index].position.x),e.push(this.vertices[t.v0index].position.y),e.push(this.vertices[t.v0index].position.z),e.push(this.vertices[t.v1index].position.x),e.push(this.vertices[t.v1index].position.y),e.push(this.vertices[t.v1index].position.z),e.push(this.vertices[t.v2index].position.x),e.push(this.vertices[t.v2index].position.y),e.push(this.vertices[t.v2index].position.z),e}.bind(this),[])),i=null;if(this.isBufferMesh){i=new THREE.BufferGeometry,i.addAttribute("position",new THREE.BufferAttribute(t,3));var n=Float32Array.from(this.faces.reduce(function(e,t){return e.push(1,1,1,1,1,1,1,1,1),e}.bind(this),[]));i.addAttribute("color",new THREE.BufferAttribute(n,3,!0));var a=Float32Array.from(this.faces.reduce(function(e,t){return t.uvs[0].map(function(t){e.push(t.x),e.push(t.y)}),e},[]));i.addAttribute("uv",new THREE.BufferAttribute(a,2));this.faces.reduce(function(e,t){var i=e.pop();return i.index!==t.materialIndex?(e.push(i),e.push({index:t.materialIndex,count:3})):(i.count+=3,e.push(i)),e},[{index:0,count:0}]).reduce(function(e,t){return i.addGroup(e,t.count,t.index),e+t.count},0)}else{i=new THREE.Geometry;var s=[];i.faces=this.faces.map(function(e){e.uvs[0].length>0&&s.push(e.uvs[0].map(function(e){return new THREE.Vector2(e.x,e.y)}));var t=new THREE.Face3(e.v0index,e.v1index,e.v2index);return e.normal&&(t.normal=new THREE.Vector3(e.normal.x,e.normal.y,e.normal.z)),e.color&&(t.color=new THREE.Color(e.color.r,e.color.g,e.color.b)),t.materialIndex=e.materialIndex,t}),i.vertices=this.vertices.map(function(e){return new THREE.Vector3(e.position.x,e.position.y,e.position.z)}),i.verticesNeedUpdate=!0,s.length>0&&(i.faceVertexUvs=[s]),i.computeFaceNormals(),i.computeVertexNormals()}return this.computeBoundingBox(i),i},GameLib.D3.Mesh.prototype.createInstance=function(){var e=this.createInstanceGeometry();this.skeleton?(1===this.materials.length?this.instance=new THREE.SkinnedMesh(e,this.materials[0].instance):this.instance=new THREE.SkinnedMesh(e,this.materials.map(function(e){return e.instance})),this.instance.add(this.skeleton.rootBoneInstance),this.instance.bind(this.skeleton.instance)):1===this.materials.length?this.instance=new THREE.Mesh(e,this.materials[0].instance):this.instance=new THREE.Mesh(e,this.materials.map(function(e){return e.instance})),this.instance.name=this.name,this.parentMesh&&this.parentMesh.instance&&this.parentMesh.add(this.instance,this),this.instance.position.x=this.position.x,this.instance.position.y=this.position.y,this.instance.position.z=this.position.z,this.useQuaternion?(this.instance.quaternion.x=this.quaternion.x,this.instance.quaternion.y=this.quaternion.y,this.instance.quaternion.z=this.quaternion.z,this.instance.quaternion.w=this.quaternion.w,this.instance.quaternion.setFromAxisAngle(new THREE.Vector3(this.quaternion.axis.x,this.quaternion.axis.y,this.quaternion.axis.z),this.quaternion.angle)):(this.instance.rotation.x=this.rotation.x,this.instance.rotation.y=this.rotation.y,this.instance.rotation.z=this.rotation.z),this.instance.scale.x=this.scale.x,this.instance.scale.y=this.scale.y,this.instance.scale.z=this.scale.z,this.instance.up.x=this.up.x,this.instance.up.y=this.up.y,this.instance.up.z=this.up.z,this.instance.renderOrder=this.renderOrder,this.instance.visible=this.visible,GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Mesh.prototype.updateInstance=function(e){(this.isBufferMesh&&!(this.instance.geometry instanceof THREE.BufferGeometry)||!this.isBufferMesh&&this.instance.geometry instanceof THREE.BufferGeometry)&&(this.instance.geometry=this.createInstanceGeometry(this.instance.geometry)),this.useQuaternion?this.updateRotationFromAxisAngle?this.updateInstanceRotationFromAxisAngle():(this.instance.quaternion.x=this.quaternion.x,this.instance.quaternion.y=this.quaternion.y,this.instance.quaternion.z=this.quaternion.z,this.instance.quaternion.w=this.quaternion.w):(this.instance.rotation.x=this.rotation.x,this.instance.rotation.y=this.rotation.y,this.instance.rotation.z=this.rotation.z),this.parentMesh&&this.parentMesh.instance&&this.instance.parent!==this.parentMesh.instance&&(this.instance.parent=this.parentMesh.instance),this.instance.scale.x=this.scale.x,this.instance.scale.y=this.scale.y,this.instance.scale.z=this.scale.z,this.instance.position.x=this.position.x,this.instance.position.y=this.position.y,this.instance.position.z=this.position.z,this.instance.up.x=this.up.x,this.instance.up.y=this.up.y,this.instance.up.z=this.up.z,this.instance.name=this.name,1===this.materials.length&&this.materials[0].instance&&(this.instance.material=this.materials[0].instance),this.instance.renderOrder=this.renderOrder,this.helper&&(this.removeHelper(),this.createHelper()),"visible"===e&&(this.instance.visible=this.visible)},GameLib.D3.Mesh.prototype.updateVerticesFromGeometryInstance=function(e){if(this.vertices=[],this.faces=[],e instanceof THREE.BufferGeometry){var t=e.getAttribute("position").array,i=e.getAttribute("uv").array;e.groups.map(function(e){for(var n=e.materialIndex,a=e.start,s=e.count,o=[],r=[],c=a;cthis.maxSpeed&&(this.currentSpeed=this.maxSpeed),this.grain=this.currentSpeed/100;var t=this.spline.getPointAt(this.currentPathValue);this.currentPosition.x=t.x,this.currentPosition.y=t.y,this.currentPosition.z=t.z,this.currentPathValue+=this.grain,this.currentPathValue>=1&&(this.currentPathValue=this.currentPathValue-1),this.currentPathValue<0&&(this.currentPathValue=0);var i=this.spline.getPointAt(this.currentPathValue);this.futurePosition.x=i.x,this.futurePosition.y=i.y,this.futurePosition.z=i.z,this.raycaster.setPosition(this.currentPosition),this.raycaster.setDirection({x:-this.up.x,y:-this.up.y,z:-this.up.z});var n=this.raycaster.getFaceNormal(this.raytraceMesh);n&&(this.up.x=this.mx(n.x),this.up.y=this.my(n.y),this.up.z=this.mz(n.z)),this.rotationMatrix.lookAt(this.currentPosition,this.futurePosition,this.up),this.rotationVector.setFromRotationMatrix(this.rotationMatrix),this.mesh.position.x=this.futurePosition.x,this.mesh.position.y=this.futurePosition.y,this.mesh.position.z=this.futurePosition.z,this.mesh.quaternion.x=this.rotationVector.x,this.mesh.quaternion.y=this.rotationVector.y,this.mesh.quaternion.z=this.rotationVector.z,this.mesh.quaternion.w=this.rotationVector.w}},GameLib.D3.PhysicsWorld=function(e,t){if(this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.PhysicsWorld)return t;GameLib.D3.API.PhysicsWorld.call(this,t.id,t.name,t.gravity,t.broadphase,t.solver,t.rigidBodies,t.contactMaterials,t.allowSleep,t.defaultContactMaterial,t.parentEntity),this.gravity instanceof GameLib.API.Vector3&&(this.gravity=new GameLib.Vector3(this.physics,this.gravity,this)),this.broadphase instanceof GameLib.D3.API.Broadphase&&(this.broadphase=new GameLib.D3.Broadphase(this.physics,this.broadphase)),this.solver instanceof GameLib.D3.API.Solver&&(this.solver=new GameLib.D3.Solver(this.physics,this.solver)),this.rigidBodies=this.rigidBodies.map(function(e){return e instanceof GameLib.D3.API.RigidBody?new GameLib.D3.RigidBody(this.physics,e):e}.bind(this)),this.contactMaterials=this.contactMaterials.map(function(e){return e instanceof GameLib.D3.API.FrictionContactMaterial?new GameLib.D3.FrictionContactMaterial(this.physics,e):e}.bind(this)),this.defaultContactMaterial instanceof GameLib.D3.API.FrictionContactMaterial&&(this.defaultContactMaterial=new GameLib.D3.FrictionContactMaterial(this.physics,this.defaultContactMaterial)),GameLib.Component.call(this,GameLib.Component.COMPONENT_PHYSICS_WORLD,{broadphase:GameLib.D3.Broadphase,solver:GameLib.D3.Solver,rigidBodies:[GameLib.D3.RigidBody],contactMaterials:[GameLib.D3.FrictionContactMaterial],defaultContactMaterial:GameLib.D3.FrictionContactMaterial})},GameLib.D3.PhysicsWorld.prototype=Object.create(GameLib.D3.API.PhysicsWorld.prototype),GameLib.D3.PhysicsWorld.prototype.constructor=GameLib.D3.PhysicsWorld,GameLib.D3.PhysicsWorld.prototype.createInstance=function(){if(GameLib.Utils.UndefinedOrNull(this.broadphase))throw new Error("no broadphase");if(GameLib.Utils.UndefinedOrNull(this.broadphase.instance))throw new Error("no broadphase instance");if(GameLib.Utils.UndefinedOrNull(this.solver))throw new Error("no solver");if(GameLib.Utils.UndefinedOrNull(this.solver.instance))throw new Error("no solver instance");this.instance=new CANNON.World,this.instance.broadphase=this.broadphase.instance,this.instance.solver=this.solver.instance,this.instance.gravity=this.gravity.instance,this.instance.allowSleep=this.allowSleep,this.contactMaterials.map(function(e){if(GameLib.Utils.UndefinedOrNull(e))throw new Error("no contact material");if(GameLib.Utils.UndefinedOrNull(e.instance))throw new Error("no contact material instance");this.instance.addContactMaterial(e.instance)}.bind(this)),this.rigidBodies.map(function(e){if(GameLib.Utils.UndefinedOrNull(e))throw new Error("no rigidbody");if(GameLib.Utils.UndefinedOrNull(e.instance))throw new Error("no rigidbody instance");e.parentWorld=this,this.instance.add(e.instance)}.bind(this)),this.instance.defaultContactMaterial.friction=this.defaultContactMaterial.friction,this.instance.defaultContactMaterial.restitution=this.defaultContactMaterial.restitution,this.instance.defaultContactMaterial.contactEquationStiffness=this.defaultContactMaterial.contactEquationStiffness,this.instance.defaultContactMaterial.contactEquationRelaxation=this.defaultContactMaterial.contactEquationRelaxation,this.instance.defaultContactMaterial.frictionEquationStiffness=this.defaultContactMaterial.frictionEquationStiffness,this.instance.defaultContactMaterial.frictionEquationRelaxation=this.defaultContactMaterial.frictionEquationRelaxation,GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.PhysicsWorld.prototype.addRigidBody=function(e){e&&e.instance?(this.instance.add(e.instance),e.parentWorld=this,GameLib.Utils.PushUnique(this.rigidBodies,e)):console.warn("Attempt to add rigidBody "+e.name+" without an instance")},GameLib.D3.PhysicsWorld.prototype.removeRigidBody=function(e){if(!e instanceof GameLib.D3.RigidBody)return void console.warn("not a rigid body");e.instance?this.instance.remove(e.instance):console.warn("Attempt to remove rigidBody "+e.name+" without an instance"),e.parentWorld=null;var t=this.rigidBodies.indexOf(e);-1!==t?this.rigidBodies.splice(t,1):console.warn("could not remove a rigidbody from an array where it should have existed")},GameLib.D3.PhysicsWorld.prototype.updateInstance=function(){if(!this.instance)return void console.log("no world instance");this.instance.broadphase=this.broadphase.instance,this.instance.solver=this.solver.instance,this.instance.gravity=this.gravity.instance,this.instance.allowSleep=this.allowSleep,this.instance.defaultContactMaterial.friction=this.defaultContactMaterial.friction,this.instance.defaultContactMaterial.restitution=this.defaultContactMaterial.restitution,this.instance.defaultContactMaterial.contactEquationStiffness=this.defaultContactMaterial.contactEquationStiffness,this.instance.defaultContactMaterial.contactEquationRelaxation=this.defaultContactMaterial.contactEquationRelaxation,this.instance.defaultContactMaterial.frictionEquationStiffness=this.defaultContactMaterial.frictionEquationStiffness,this.instance.defaultContactMaterial.frictionEquationRelaxation=this.defaultContactMaterial.frictionEquationRelaxation},GameLib.D3.PhysicsWorld.prototype.toApiObject=function(){return new GameLib.D3.API.PhysicsWorld(this.id,this.name,this.gravity.toApiObject(),GameLib.Utils.IdOrNull(this.broadphase),GameLib.Utils.IdOrNull(this.solver),this.rigidBodies.map(function(e){return GameLib.Utils.IdOrNull(e)}),this.contactMaterials.map(function(e){return GameLib.Utils.IdOrNull(e)}),this.allowSleep,GameLib.Utils.IdOrNull(this.defaultContactMaterial),GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.PhysicsWorld.FromObject=function(e,t){var i=GameLib.D3.API.PhysicsWorld.FromObject(t);return new GameLib.D3.PhysicsWorld(e,i)},GameLib.D3.Physics=function(e,t,i){GameLib.Utils.UndefinedOrNull(e)&&(e=GameLib.Utils.RandomId()),this.id=e,GameLib.Utils.UndefinedOrNull(t)&&(t="Physics ("+e+")"),this.name=t,GameLib.Utils.UndefinedOrNull(i)&&(i=GameLib.D3.Physics.PHYSICS_TYPE_CANNON),this.physicsType=i,this.createInstance()},GameLib.D3.Physics.PHYSICS_TYPE_CANNON=1,GameLib.D3.Physics.prototype.createInstance=function(){this.instance=CANNON},GameLib.D3.Physics.prototype.updateInstance=function(){},GameLib.D3.Physics.prototype.isNotCannonThrow=function(){if(this.physicsType!==GameLib.D3.Physics.PHYSICS_TYPE_CANNON)throw console.warn("Only CANNON supported for this function"),new Error("Only CANNON supported for this function")},GameLib.D3.PolyVertex=function(e,t,i,n,a){this.localIndex=e,this.mvertIndex=t,this.uv=i,this.materialIndex=n,this.edgeIndex=a},GameLib.D3.PolyVertex.prototype.clone=function(){return new GameLib.D3.PolyVertex(this.localIndex,this.mvertIndex,this.uv.copy(),this.materialIndex,this.edgeIndex)},GameLib.D3.RaycastVehicle=function(e,t){if(this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.RaycastVehicle)return t;GameLib.D3.API.RaycastVehicle.call(this,t.id,t.name,t.chassis,t.wheels,t.raycastWheels,t.parentWorld,t.parentEntity),this.chassis instanceof GameLib.D3.API.RaycastVehicle&&(this.chassis=new GameLib.D3.RaycastVehicle(this.physics,this.chassis)),this.wheels=this.wheels.map(function(e){return e instanceof GameLib.D3.API.RigidBody?new GameLib.D3.RigidBody(this.physics,e):e}.bind(this)),this.raycastWheels=this.raycastWheels.map(function(e){return e instanceof GameLib.D3.API.RaycastWheel?new GameLib.D3.RaycastWheel(this.physics,e):e}.bind(this)),GameLib.Component.call(this,GameLib.Component.COMPONENT_RAYCAST_VEHICLE,{chassis:GameLib.D3.RigidBody,wheels:[GameLib.D3.RigidBody],raycastWheels:[GameLib.D3.RaycastWheel],parentWorld:GameLib.D3.PhysicsWorld})},GameLib.D3.RaycastVehicle.prototype=Object.create(GameLib.D3.API.RaycastVehicle.prototype),GameLib.D3.RaycastVehicle.prototype.constructor=GameLib.D3.RaycastVehicle,GameLib.D3.RaycastVehicle.prototype.createInstance=function(){if(GameLib.Utils.UndefinedOrNull(this.chassis))throw new Error("no chassis");if(GameLib.Utils.UndefinedOrNull(this.chassis.instance))throw new Error("no chassis instance");if(GameLib.Utils.UndefinedOrNull(this.parentWorld))throw new Error("no parent world");if(GameLib.Utils.UndefinedOrNull(this.parentWorld.instance))throw new Error("no parent world instance");this.instance=new CANNON.RaycastVehicle({chassisBody:this.chassis.instance}),this.raycastWheels.map(function(e){if(GameLib.Utils.UndefinedOrNull(e))throw new Error("no wheel");if(GameLib.Utils.UndefinedOrNull(e.instance))throw new Error("no wheel instance");this.instance.addWheel(e.instance)}.bind(this)),this.instance.addToWorld(this.parentWorld.instance),GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.RaycastVehicle.prototype.updateInstance=function(){console.log("TODO: update raycast vehicle instance")},GameLib.D3.RaycastVehicle.prototype.toApiObject=function(){return new GameLib.D3.API.RaycastVehicle(this.id,this.name,GameLib.Utils.IdOrNull(this.chassis),this.wheels.map(function(e){return GameLib.Utils.IdOrNull(e)}),this.raycastWheels.map(function(e){return GameLib.Utils.IdOrNull(e)}),GameLib.Utils.IdOrNull(this.parentWorld),GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.RaycastVehicle.FromObject=function(e,t){var i=GameLib.D3.API.RaycastVehicle.FromObject(t);return new GameLib.D3.RaycastVehicle(e,i)},GameLib.D3.RaycastWheel=function(e,t){if(this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.RaycastWheel)return t;GameLib.D3.API.RaycastWheel.call(this,t.id,t.name,t.radius,t.directionLocal,t.suspensionStiffness,t.suspensionRestLength,t.frictionSlip,t.dampingRelaxation,t.dampingCompression,t.maxSuspensionForce,t.rollInfluence,t.axleLocal,t.chassisConnectionPointLocal,t.maxSuspensionTravel,t.customSlidingRotationalSpeed,t.useCustomSlidingRotationalSpeed,t.parentEntity,t.parentMesh),this.directionLocal=new GameLib.Vector3(this.physics,this.directionLocal,this),this.axleLocal=new GameLib.Vector3(this.physics,this.axleLocal,this),this.chassisConnectionPointLocal=new GameLib.Vector3(this.physics,this.chassisConnectionPointLocal,this),GameLib.Component.call(this,GameLib.Component.COMPONENT_RAYCAST_WHEEL,{parentMesh:GameLib.D3.Mesh})},GameLib.D3.RaycastWheel.prototype=Object.create(GameLib.D3.API.RaycastWheel.prototype),GameLib.D3.RaycastWheel.prototype.constructor=GameLib.D3.RaycastWheel,GameLib.D3.RaycastWheel.prototype.createInstance=function(){this.instance={radius:this.radius,directionLocal:this.directionLocal.instance,suspensionStiffness:this.suspensionStiffness,suspensionRestLength:this.suspensionRestLength,frictionSlip:this.frictionSlip,dampingRelaxation:this.dampingRelaxation,dampingCompression:this.dampingCompression,maxSuspensionForce:this.maxSuspensionForce,rollInfluence:this.rollInfluence,axleLocal:this.axleLocal.instance,chassisConnectionPointLocal:this.chassisConnectionPointLocal.instance,maxSuspensionTravel:this.maxSuspensionTravel,customSlidingRotationalSpeed:this.customSlidingRotationalSpeed,useCustomSlidingRotationalSpeed:this.useCustomSlidingRotationalSpeed},GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.RaycastWheel.prototype.updateInstance=function(){this.instance.radius=this.radius,this.instance.directionLocal=this.directionLocal.instance,this.instance.suspensionStiffness=this.suspensionStiffness,this.instance.suspensionRestLength=this.suspensionRestLength,this.instance.frictionSlip=this.frictionSlip,this.instance.dampingRelaxation=this.dampingRelaxation,this.instance.dampingCompression=this.dampingCompression,this.instance.maxSuspensionForce=this.maxSuspensionForce,this.instance.rollInfluence=this.rollInfluence,this.instance.axleLocal=this.axleLocal.instance,this.instance.chassisConnectionPointLocal=this.chassisConnectionPointLocal.instance,this.instance.maxSuspensionTravel=this.maxSuspensionTravel,this.instance.customSlidingRotationalSpeed=this.customSlidingRotationalSpeed,this.instance.useCustomSlidingRotationalSpeed=this.useCustomSlidingRotationalSpeed},GameLib.D3.RaycastWheel.prototype.toApiObject=function(){return new GameLib.D3.API.RaycastWheel(this.id,this.name,this.radius,this.directionLocal.toApiObject(),this.suspensionStiffness,this.suspensionRestLength,this.frictionSlip,this.dampingRelaxation,this.dampingCompression,this.maxSuspensionForce,this.rollInfluence,this.axleLocal.toApiObject(),this.chassisConnectionPointLocal.toApiObject(),this.maxSuspensionTravel,this.customSlidingRotationalSpeed,this.useCustomSlidingRotationalSpeed,GameLib.Utils.IdOrNull(this.parentEntity),GameLib.Utils.IdOrNull(this.parentMesh))},GameLib.D3.RaycastWheel.FromObject=function(e,t){var i=GameLib.D3.API.RaycastWheel.FromObject(t);return new GameLib.D3.RaycastWheel(e,i)},GameLib.D3.RaycastWheel.prototype.setChassisLocalConnectionPoint=function(){this.parentMesh||console.log("you need to set the parent mesh first"),this.chassisConnectionPointLocal.x=this.parentMesh.position.x,this.chassisConnectionPointLocal.y=this.parentMesh.position.y,this.chassisConnectionPointLocal.z=this.parentMesh.position.z},GameLib.D3.Raycaster=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Raycaster)return t;GameLib.D3.API.Raycaster.call(this,t.id,t.name,t.position,t.direction),this.position=new GameLib.Vector3(this.graphics,this.position,this),this.direction=new GameLib.Vector3(this.graphics,this.direction,this),GameLib.Component.call(this,GameLib.Component.COMPONENT_RAYCASTER)},GameLib.D3.Raycaster.prototype=Object.create(GameLib.D3.API.Raycaster.prototype),GameLib.D3.Raycaster.prototype.constructor=GameLib.D3.Raycaster,GameLib.D3.Raycaster.prototype.createInstance=function(){this.instance=new THREE.Raycaster,this.instance.set(this.position.instance,this.direction.instance),GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Raycaster.prototype.updateInstance=function(){this.position.instance.x=this.position.x,this.position.instance.y=this.position.y,this.position.instance.z=this.position.z,this.direction.instance.x=this.direction.x,this.direction.instance.y=this.direction.y,this.direction.instance.z=this.direction.z,this.instance.set(this.position.instance,this.direction.instance)},GameLib.D3.Raycaster.prototype.toApiObject=function(){return new GameLib.D3.API.Raycaster(this.id,this.name,this.position.toApiObject(),this.direction.toApiObject())},GameLib.D3.Raycaster.FromObject=function(e,t){var i=GameLib.D3.API.Raycaster.FromObject(t);return new GameLib.D3.Raycaster(e,i)},GameLib.D3.Raycaster.prototype.set=function(e,t){this.position.x=e.x,this.position.y=e.y,this.position.z=e.z,this.direction.x=t.x,this.direction.y=t.y,this.direction.z=t.z,this.position.updateInstance(),this.direction.updateInstance()},GameLib.D3.Raycaster.prototype.setDirection=function(e){this.direction.x=e.x,this.direction.y=e.y,this.direction.z=e.z,this.direction.updateInstance()},GameLib.D3.Raycaster.prototype.setPosition=function(e){this.position.x=e.x,this.position.y=e.y,this.position.z=e.z,this.position.updateInstance()},GameLib.D3.Raycaster.prototype.setFromCamera=function(e,t){this.instance.setFromCamera(e,t.instance),this.position.x=this.instance.ray.origin.x,this.position.y=this.instance.ray.origin.y,this.position.z=this.instance.ray.origin.z,this.direction.x=this.instance.ray.direction.x,this.direction.y=this.instance.ray.direction.y,this.direction.z=this.instance.ray.direction.z},GameLib.D3.Raycaster.prototype.getIntersectedObjects=function(e){return e.reduce(function(e,t){var i=this.instance.intersectObject(t.instance);return i.length>0&&e.push({mesh:t,distance:i[0].distance}),e}.bind(this),[])},GameLib.D3.Raycaster.prototype.getFaceNormal=function(e){var t=null,i=this.instance.intersectObject(e.instance);return i&&i.length>0&&(t=new GameLib.Vector3(this.graphics,new GameLib.API.Vector3(i[0].face.normal.x,i[0].face.normal.y,i[0].face.normal.z),this)),t},GameLib.D3.Raycaster.prototype.getIntersectPoint=function(e){var t=null,i=this.instance.intersectObject(e.instance);return i&&i.length>0&&(t=new GameLib.Vector3(this.graphics,new GameLib.API.Vector3(i[0].point.x,i[0].point.y,i[0].point.z),this)),t},GameLib.D3.RenderTarget=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.RenderTarget)return t;GameLib.D3.API.RenderTarget.call(this,t.id,t.name,t.width,t.height,t.stencilBuffer,t.texture),GameLib.Component.call(this,GameLib.Component.COMPONENT_RENDER_TARGET,{texture:GameLib.D3.Texture})},GameLib.D3.RenderTarget.prototype=Object.create(GameLib.D3.API.RenderTarget.prototype),GameLib.D3.RenderTarget.prototype.constructor=GameLib.D3.RenderTarget,GameLib.D3.RenderTarget.prototype.createInstance=function(){if(GameLib.Utils.UndefinedOrNull(this.texture))throw new Error("no texture");if(GameLib.Utils.UndefinedOrNull(this.texture.instance))throw new Error("no texture instance");this.instance=new THREE.WebGLRenderTarget(this.width,this.height,{stencilBuffer:this.stencilBuffer}),this.instance.texture=this.texture.instance,GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.RenderTarget.prototype.updateInstance=function(){if(this.instance)this.instance.setSize(this.width,this.height),this.instance.stencilBuffer=this.stencilBuffer,this.texture&&this.texture.instance?(this.instance.texture=this.texture.instance,this.instance.texture.needsUpdate=!0):this.instance.texture=null;else try{this.createInstance()}catch(e){console.error(e)}},GameLib.D3.RenderTarget.prototype.toApiObject=function(){return new GameLib.D3.API.RenderTarget(this.id,this.name,this.width,this.height,this.stencilBuffer,GameLib.Utils.IdOrNull(this.texture),GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.RenderTarget.FromObject=function(e,t){var i=GameLib.D3.API.RenderTarget.FromObject(t);return new GameLib.D3.RenderTarget(e,i)},GameLib.D3.Renderer=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Renderer)return t;GameLib.D3.API.Renderer.call(this,t.id,t.name,t.autoClear,t.localClipping,t.width,t.height,t.preserveDrawingBuffer,t.domElement,t.clearColor,t.camera,t.scenes,t.viewports,t.clippingPlanes,t.bufferScene,t.bufferCamera,t.renderTarget,t.defaultScene,t.sortObjects,t.parentEntity),this.clearColor=new GameLib.Color(this.graphics,this.clearColor,this),this.domElement instanceof GameLib.API.DomElement&&(this.domElement=new GameLib.DomElement(this.domElement)),this.camera instanceof GameLib.D3.API.Camera&&(this.camera=new GameLib.D3.Camera(this.graphics,this.camera)),this.scenes=this.scenes.map(function(e){return e instanceof GameLib.D3.API.Scene?new GameLib.D3.Scene(this.graphics,e):e}.bind(this)),this.viewports=this.viewports.map(function(e){return e instanceof GameLib.D3.API.Viewport?new GameLib.D3.Viewport(this.graphics,e):e}.bind(this)),this.clippingPlanes=this.clippingPlanes.map(function(e){return e instanceof GameLib.D3.API.Mesh?new GameLib.D3.Mesh.Plane(this.graphics,e,e.width,e.height,e.widthSegments,e.heightSegments,e.heightMapScale,e.isHeightMap,e.isClippingPlane,e.distanceFromOrigin):e}.bind(this)),this.bufferScene instanceof GameLib.D3.API.Scene&&(this.bufferScene=new GameLib.D3.Scene(this.graphics,this.bufferScene)),this.bufferCamera instanceof GameLib.D3.API.Camera&&(this.bufferCamera=new GameLib.D3.Camera(this.graphics,this.bufferCamera)),this.renderTarget instanceof GameLib.D3.API.RenderTarget&&(this.renderTarget=new GameLib.D3.RenderTarget(this.graphics,this.renderTarget)),GameLib.Component.call(this,GameLib.Component.COMPONENT_RENDERER,{domElement:GameLib.DomElement,camera:GameLib.D3.Camera,scenes:[GameLib.D3.Scene],viewports:[GameLib.D3.Viewport],clippingPlanes:[GameLib.D3.Mesh.Plane],bufferScene:GameLib.D3.Scene,bufferCamera:GameLib.D3.Camera,renderTarget:GameLib.D3.RenderTarget,defaultScene:GameLib.D3.Scene})},GameLib.D3.Renderer.prototype=Object.create(GameLib.D3.API.Renderer.prototype),GameLib.D3.Renderer.prototype.constructor=GameLib.D3.Renderer,GameLib.D3.Renderer.prototype.createInstance=function(){if(GameLib.Utils.UndefinedOrNull(this.domElement))throw new Error("no dom element");if(GameLib.Utils.UndefinedOrNull(this.domElement.instance))throw new Error("no dom element instance");this.instance=new THREE.WebGLRenderer({canvas:this.domElement.instance}),this.clippingPlanes.length>0&&(this.instance.clippingPlanes=this.clippingPlanes.map(function(e){if(!e.isClippingPlane||!e.instance||!e.instance.clipping)throw new Error("is not a clipping plane or no clipping plane instance");return e.instance.clipping})),this.instance.localClippingEnabled=this.localClipping,this.instance.setSize(this.width,this.height),this.instance.setClearColor(new THREE.Color(this.clearColor.r,this.clearColor.g,this.clearColor.b),1-this.clearColor.a),this.instance.domElement.width=this.width,this.instance.domElement.height=this.height,this.instance.autoClear=this.autoClear,this.instance.preserveDrawingBuffer=this.preserveDrawingBuffer,this.instance.sortObjects=this.sortObjects,GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Renderer.prototype.updateInstance=function(e){if(this.instance)e||console.error("no property for renderer"),"localClipping"===e&&(this.instance.localClippingEnabled=this.localClipping),this.instance.setSize(this.width,this.height),this.instance.domElement.width=this.width,this.instance.domElement.height=this.height,"clearColor"===e&&this.instance.setClearColor(new THREE.Color(this.clearColor.r,this.clearColor.g,this.clearColor.b),1-this.clearColor.a),"autoClear"===e&&(this.instance.autoClear=this.autoClear),"preserveDrawingBuffer"===e&&(this.instance.preserveDrawingBuffer=this.preserveDrawingBuffer),this.clippingPlanes.length>0?this.instance.clippingPlanes=this.clippingPlanes.map(function(e){if(!e.isClippingPlane||!e.instance||!e.instance.clipping)throw new Error("is not a clipping plane or no clipping plane instance");return e.instance.clipping}):this.instance.clippingPlanes=[],"sortObjects"===e&&(this.instance.sortObjects=this.sortObjects);else try{this.createInstance()}catch(e){console.error(e.message)}},GameLib.D3.Renderer.prototype.toApiObject=function(){return new GameLib.D3.API.Renderer(this.id,this.name,this.autoClear,this.localClipping,this.width,this.height,this.preserveDrawingBuffer,GameLib.Utils.IdOrNull(this.domElement),this.clearColor.toApiObject(),GameLib.Utils.IdOrNull(this.camera),this.scenes.map(function(e){return GameLib.Utils.IdOrNull(e)}),this.viewports.map(function(e){return GameLib.Utils.IdOrNull(e)}),this.clippingPlanes.map(function(e){return GameLib.Utils.IdOrNull(e)}),GameLib.Utils.IdOrNull(this.bufferScene),GameLib.Utils.IdOrNull(this.bufferCamera),GameLib.Utils.IdOrNull(this.renderTarget),GameLib.Utils.IdOrNull(this.defaultScene),this.sortObjects,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Renderer.FromObject=function(e,t){var i=GameLib.D3.API.Renderer.FromObject(t);return new GameLib.D3.Renderer(e,i)},GameLib.D3.Renderer.prototype.render=function(e,t){this.instance&&(GameLib.Utils.UndefinedOrNull(t)&&(t=this.scenes),this.viewports.length>1&&(this.instance.autoClear=!1),t.length>1&&(this.instance.autoClear=!1),this.instance.clear(),this.bufferScene&&this.bufferScene.instance&&this.bufferCamera&&this.bufferCamera.instance&&this.renderTarget&&this.renderTarget.instance&&this.instance.render(this.bufferScene.instance,this.bufferCamera.instance,this.renderTarget.instance),this.viewports.map(function(e){this.instance.setViewport(e.x*this.width,e.y*this.height,e.width*this.width,e.height*this.height),t.map(function(e){e.instance&&(this.camera.instance||e.renderCamera||e.renderCamera.instance)&&(e.renderCamera&&e.renderCamera.instance?this.instance.render(e.instance,e.renderCamera.instance):this.instance.render(e.instance,this.camera.instance))}.bind(this))}.bind(this)))},GameLib.D3.Renderer.prototype.setSize=function(e,t){this.width=e,this.height=t,this.instance?this.instance.setSize(this.width,this.height):console.log("renderer not ready to set size")},GameLib.D3.RigidBody=function(e,t){if(this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.RigidBody)return t;GameLib.D3.API.RigidBody.call(this,t.id,t.name,t.mass,t.friction,t.position,t.quaternion,t.velocity,t.angularVelocity,t.linearDamping,t.angularDamping,t.allowSleep,t.sleepSpeedLimit,t.sleepTimeLimit,t.collisionFilterGroup,t.collisionFilterMask,t.fixedRotation,t.shapes,t.kinematic,t.parentMesh,t.parentWorld,t.parentEntity),this.position=new GameLib.Vector3(this.physics,this.position,this),this.quaternion=new GameLib.Quaternion(this.physics,this.quaternion,this),this.velocity=new GameLib.Vector3(this.physics,this.velocity,this),this.angularVelocity=new GameLib.Vector3(this.physics,this.angularVelocity,this),this.force=new GameLib.Vector3(this.physics),this.forcePoint=new GameLib.Vector3(this.physics),GameLib.Component.call(this,GameLib.Component.COMPONENT_RIGID_BODY,{shapes:[GameLib.D3.Shape],parentMesh:GameLib.D3.Mesh,parentWorld:GameLib.D3.PhysicsWorld})},GameLib.D3.RigidBody.prototype=Object.create(GameLib.D3.API.RigidBody.prototype),GameLib.D3.RigidBody.prototype.constructor=GameLib.D3.RigidBody,GameLib.D3.RigidBody.prototype.createInstance=function(){this.instance=new CANNON.Body({mass:this.mass,friction:this.friction,position:this.position.instance,quaternion:this.quaternion.instance,velocity:this.velocity.instance,angularVelocity:this.angularVelocity.instance,linearDamping:this.linearDamping,angularDamping:this.angularDamping,allowSleep:this.allowSleep,sleepSpeedLimit:this.sleepSpeedLimit,sleepTimeLimit:this.sleepTimeLimit,collisionFilterGroup:this.collisionFilterGroup,collisionFilterMask:this.collisionFilterMask,fixedRotation:this.fixedRotation,kinematic:this.kinematic}),this.instance.addEventListener("sleepy",function(){console.log(this.name+" is feeling sleepy...")}.bind(this)),this.instance.addEventListener("sleep",function(){console.log(this.name+" fell asleep!")}.bind(this)),this.instance.addEventListener("wakeup",function(){console.log(this.name+" woke up!")}.bind(this)),this.shapes.map(function(e){if(GameLib.Utils.UndefinedOrNull(e))throw new Error("no shape");if(GameLib.Utils.UndefinedOrNull(e.instance))throw new Error("no shape instance");this.instance.addShape(e.instance)}.bind(this)),GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.RigidBody.prototype.updateInstance=function(){this.instance.mass=this.mass,this.instance.friction=this.friction,this.instance.position.x=this.position.x,this.instance.position.y=this.position.y,this.instance.position.z=this.position.z,this.quaternion.axis.instance.x=this.quaternion.axis.x,this.quaternion.axis.instance.y=this.quaternion.axis.y,this.quaternion.axis.instance.z=this.quaternion.axis.z,this.instance.quaternion.setFromAxisAngle(this.quaternion.axis.instance,this.quaternion.angle),this.quaternion.x=this.instance.quaternion.x,this.quaternion.y=this.instance.quaternion.y,this.quaternion.z=this.instance.quaternion.z,this.quaternion.w=this.instance.quaternion.w,this.parentMesh.position.setFrom(this.position),this.parentMesh.quaternion.setFrom(this.quaternion),this.parentMesh.updateInstance(),this.instance.velocity.x=this.velocity.x,this.instance.velocity.y=this.velocity.y,this.instance.velocity.z=this.velocity.z,this.instance.angularVelocity.x=this.angularVelocity.x,this.instance.angularVelocity.y=this.angularVelocity.y,this.instance.angularVelocity.z=this.angularVelocity.z,this.instance.linearDamping=this.linearDamping,this.instance.angularDamping=this.angularDamping,this.instance.allowSleep=this.allowSleep,this.instance.sleepSpeedLimit=this.sleepSpeedLimit,this.instance.sleepTimeLimit=this.sleepTimeLimit,this.instance.collisionFilterGroup=this.collisionFilterGroup,this.instance.collisionFilterMask=this.collisionFilterMask,this.instance.fixedRotation=this.fixedRotation,this.instance.kinematic=this.kinematic},GameLib.D3.RigidBody.prototype.setFromParentMesh=function(){ +this.parentMesh&&this.parentMesh.instance||console.log("no parent mesh or instance"),this.instance.position.x=this.parentMesh.position.x,this.instance.position.y=this.parentMesh.position.y,this.instance.position.z=this.parentMesh.position.z,this.instance.quaternion.x=this.parentMesh.quaternion.x,this.instance.quaternion.y=this.parentMesh.quaternion.y,this.instance.quaternion.z=this.parentMesh.quaternion.z,this.instance.quaternion.w=this.parentMesh.quaternion.w},GameLib.D3.RigidBody.prototype.toApiObject=function(){return new GameLib.D3.API.RigidBody(this.id,this.name,this.mass,this.friction,this.position.toApiObject(),this.quaternion.toApiObject(),this.velocity.toApiObject(),this.angularVelocity.toApiObject(),this.linearDamping,this.angularDamping,this.allowSleep,this.sleepSpeedLimit,this.sleepTimeLimit,this.collisionFilterGroup,this.collisionFilterMask,this.fixedRotation,this.shapes.map(function(e){return GameLib.Utils.IdOrNull(e)}),this.kinematic,GameLib.Utils.IdOrNull(this.parentMesh),GameLib.Utils.IdOrNull(this.parentWorld),GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.RigidBody.FromObject=function(e,t){var i=GameLib.D3.API.RigidBody.FromObject(t);return new GameLib.D3.RigidBody(e,i)},GameLib.D3.RigidBody.prototype.applyForce=function(){this.instance.applyForce(this.force.instance,this.forcePoint.instance)},GameLib.D3.RigidBody.prototype.applyLocalForce=function(){this.instance.applyLocalForce(this.force.instance,this.forcePoint.instance)},GameLib.D3.Scene=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Scene)return t;GameLib.D3.API.Scene.call(this,t.id,t.name,t.meshes,t.lights,t.textures,t.materials,t.images,t.fog,t.renderCamera,t.showGrid,t.showAxis,t.gridSize,t.gridColor,t.parentEntity),this.meshes=this.meshes.map(function(e){return e instanceof GameLib.D3.API.Mesh?(e.parentScene=this,new GameLib.D3.Mesh(this.graphics,e)):e}.bind(this)),this.lights=this.lights.map(function(e){return e instanceof GameLib.D3.API.Light?new GameLib.D3.Light(this.graphics,e):e}.bind(this)),this.textures=this.textures.map(function(e){if(e instanceof GameLib.D3.API.Texture){return new GameLib.D3.Texture(this.graphics,e)}return e}.bind(this)),this.materials=this.materials.map(function(e){if(e instanceof GameLib.D3.API.Material){return new GameLib.D3.Material(this.graphics,e)}return e}.bind(this)),this.images=this.images.map(function(e){if(e instanceof GameLib.D3.API.Image){return new GameLib.D3.Image(this.graphics,e)}return e}.bind(this)),this.fog instanceof GameLib.D3.API.Fog&&(this.fog=new GameLib.D3.Fog(this.graphics,this.fog)),this.renderCamera instanceof GameLib.D3.API.Camera&&(this.renderCamera=new GameLib.D3.Camera(this.graphics,this.renderCamera)),this.gridColor instanceof GameLib.API.Color&&(this.gridColor=new GameLib.Color(this.graphics,this.gridColor,this)),this.helpers=[],this.clones=[],this.grid=[],this.axis=[],this.storeClones=!1,GameLib.Component.call(this,GameLib.Component.COMPONENT_SCENE,{meshes:[GameLib.D3.Mesh],lights:[GameLib.D3.Light],textures:[GameLib.D3.Texture],materials:[GameLib.D3.Material],images:[GameLib.D3.Image],fog:GameLib.D3.Fog,renderCamera:GameLib.D3.Camera})},GameLib.D3.Scene.prototype=Object.create(GameLib.D3.API.Scene.prototype);GameLib.D3.Scene.prototype.constructor=GameLib.D3.Scene,GameLib.D3.Scene.prototype.createInstance=function(){this.instance=new THREE.Scene,this.instance.name=this.name,this.fog&&this.fog.instance&&(this.instance.fog=this.fog.instance),this.meshes.map(function(e){if(GameLib.Utils.UndefinedOrNull(e))throw new Error("no mesh");if(GameLib.Utils.UndefinedOrNull(e.instance))throw new Error("no mesh instance");this.instance.add(e.instance),e.parentScene=this}.bind(this)),this.lights.map(function(e){if(GameLib.Utils.UndefinedOrNull(e))throw new Error("no light");if(GameLib.Utils.UndefinedOrNull(e.instance))throw new Error("no light instance");this.instance.add(e.instance),e.parentScene=this}.bind(this)),this.showGrid&&this.drawGrid(),this.showAxis&&this.drawAxis(),GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Scene.prototype.updateInstance=function(e){if("name"===e)return void(this.instance.name=this.name);this.fog&&this.fog.instance!==this.instance.fog&&(this.instance.fog=this.fog.instance),this.meshes.map(function(e){this.instance.children.indexOf(-1===e.instance)&&this.instance.add(e.instance)}.bind(this)),this.lights.map(function(e){-1===this.instance.children.indexOf(e.instance)&&this.instance.add(e.instance)}.bind(this)),this.instance.children.map(function(e){var t=this.meshes.map(function(e){return e.instance}),i=this.lights.map(function(e){return e.instance});(e instanceof THREE.Mesh||e instanceof THREE.Light)&&-1===i.indexOf(e)&&-1===t.indexOf(e)&&this.instance.remove(e)}.bind(this)),"showGrid"!==e&&"gridSize"!==e&&"gridColor"!==e||(this.showGrid?this.drawGrid():this.removeGrid()),"showAxis"===e&&(this.showAxis?this.drawAxis():this.removeAxis())},GameLib.D3.Scene.prototype.toApiObject=function(){var e=this.meshes.reduce(function(e,t){return(-1===this.clones.indexOf(t)||this.storeClones)&&e.push(GameLib.Utils.IdOrNull(t)),e}.bind(this),[]),t=this.lights.reduce(function(e,t){return(-1===this.clones.indexOf(t)||this.storeClones)&&e.push(GameLib.Utils.IdOrNull(t)),e}.bind(this),[]),i=this.textures.map(function(e){return GameLib.Utils.IdOrNull(e)}),n=this.materials.map(function(e){return GameLib.Utils.IdOrNull(e)}),a=this.images.map(function(e){return GameLib.Utils.IdOrNull(e)});return new GameLib.D3.API.Scene(this.id,this.name,e,t,i,n,a,GameLib.Utils.IdOrNull(this.fog),GameLib.Utils.IdOrNull(this.renderCamera),this.showGrid,this.showAxis,this.gridSize,this.gridColor.toApiObject(),GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Scene.FromObject=function(e,t){var i=GameLib.D3.API.Scene.FromObject(t);return new GameLib.D3.Scene(e,i)},GameLib.D3.Scene.prototype.addObject=function(e){e instanceof GameLib.D3.Mesh?-1===this.meshes.indexOf(e)&&this.meshes.push(e):e instanceof GameLib.D3.API.Mesh&&(e=new GameLib.D3.Mesh(this.graphics,e),this.meshes.push(e)),e instanceof GameLib.D3.Light?-1===this.lights.indexOf(e)&&this.lights.push(e):e instanceof GameLib.D3.API.Light&&(e=new GameLib.D3.Light(this.graphics,e),this.lights.push(e)),e.parentScene=this,this.instance&&e.instance&&-1===this.instance.children.indexOf(e.instance)&&this.instance.add(e.instance)},GameLib.D3.Scene.prototype.addClone=function(e){(e instanceof GameLib.D3.Mesh||e instanceof GameLib.D3.Light)&&(this.instance&&e.instance&&this.instance.add(e.instance),GameLib.Utils.PushUnique(this.clones,e),e.parentScene=this)},GameLib.D3.Scene.prototype.removeObject=function(e){var t=-1;if(e instanceof GameLib.D3.Mesh)t=this.meshes.indexOf(e),-1!==t&&this.meshes.splice(t,1),-1!==(t=this.clones.indexOf(e))&&this.clones.splice(t,1);else{if(!(e instanceof GameLib.D3.Light))return void console.warn("Cannot remove this object - what is this ?"+e.toString());t=this.lights.indexOf(e),-1!==t&&this.lights.splice(t,1),-1!==(t=this.clones.indexOf(e))&&this.clones.splice(t,1)}-1!==this.instance.children.indexOf(e.instance)?this.instance.remove(e.instance):console.warn("no scene instance"),e.parentScene===this&&(e.parentScene=null)},GameLib.D3.Scene.prototype.drawGrid=function(){this.removeGrid();for(var e=new THREE.LineBasicMaterial({color:this.gridColor.toHex(),linewidth:1}),t=-this.gridSize;t<=this.gridSize;t+=1){var i=new THREE.Geometry;i.vertices.push(new THREE.Vector3(t,0,-1*this.gridSize),new THREE.Vector3(t,0,this.gridSize));var n=new THREE.Line(i,e);this.instance.add(n),this.grid.push(n);var a=new THREE.Geometry;a.vertices.push(new THREE.Vector3(-1*this.gridSize,0,t),new THREE.Vector3(this.gridSize,0,t));var s=new THREE.Line(a,e);this.instance.add(s),this.grid.push(s)}},GameLib.D3.Scene.prototype.removeGrid=function(){this.grid.map(function(e){this.instance.remove(e)}.bind(this))},GameLib.D3.Scene.prototype.drawAxis=function(){this.removeAxis();var e=new THREE.LineBasicMaterial({color:16711680,linewidth:2}),t=new THREE.Geometry;t.vertices.push(new THREE.Vector3(0,0,0),new THREE.Vector3(100,0,0));var i=new THREE.Line(t,e);this.instance.add(i),this.axis.push(i);var n=new THREE.LineBasicMaterial({color:65280,linewidth:2}),a=new THREE.Geometry;a.vertices.push(new THREE.Vector3(0,0,0),new THREE.Vector3(0,100,0));var s=new THREE.Line(a,n);this.instance.add(s),this.axis.push(s);var o=new THREE.LineBasicMaterial({color:255,linewidth:2}),r=new THREE.Geometry;r.vertices.push(new THREE.Vector3(0,0,0),new THREE.Vector3(0,0,100));var c=new THREE.Line(r,o);this.instance.add(c),this.axis.push(c)},GameLib.D3.Scene.prototype.removeAxis=function(){this.axis.map(function(e){this.instance.remove(e)}.bind(this))},GameLib.D3.Shape=function(e,t){if(this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Shape)return t;GameLib.D3.API.Shape.call(this,t.id,t.name,t.boundingSphereRadius,t.collisionResponse,t.frictionMaterial,t.parentMesh,t.parentEntity);var i=GameLib.Component.COMPONENT_SHAPE,n={frictionMaterial:GameLib.D3.FrictionMaterial,parentMesh:GameLib.D3.Mesh};this instanceof GameLib.D3.Shape.Box&&(i=GameLib.Component.COMPONENT_SHAPE_BOX),this instanceof GameLib.D3.Shape.ConvexHull&&(i=GameLib.Component.COMPONENT_SHAPE_CONVEX_HULL),this instanceof GameLib.D3.Shape.ConvexHull.Cylinder&&(i=GameLib.Component.COMPONENT_SHAPE_CONVEX_HULL_CYLINDER),this instanceof GameLib.D3.Shape.Sphere&&(i=GameLib.Component.COMPONENT_SHAPE_SPHERE),this instanceof GameLib.D3.Shape.TriMesh&&(i=GameLib.Component.COMPONENT_SHAPE_TRI_MESH),this instanceof GameLib.D3.Shape.Plane&&(i=GameLib.Component.COMPONENT_SHAPE_PLANE),this instanceof GameLib.D3.Shape.HeightMap&&(i=GameLib.Component.COMPONENT_SHAPE_HEIGHT_MAP),GameLib.Component.call(this,i,n)},GameLib.D3.Shape.prototype=Object.create(GameLib.D3.API.Shape.prototype),GameLib.D3.Shape.prototype.constructor=GameLib.D3.Shape,GameLib.D3.Shape.prototype.createInstance=function(){GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Shape.prototype.updateInstance=function(){throw new Error("Do not instantiate this class directly - use a child class instead")},GameLib.D3.Shape.prototype.toApiObject=function(){return new GameLib.D3.API.Shape(this.id,this.name,this.boundingSphereRadius,this.collisionResponse,GameLib.Utils.IdOrNull(this.frictionMaterial),GameLib.Utils.IdOrNull(this.parentMesh),GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Shape.FromObject=function(e,t){throw"not implemented"},GameLib.D3.Shape.prototype.stopVisualize=function(){GameLib.Event.Emit(GameLib.Event.STOP_VISUALIZE,{mesh:this.mesh})},GameLib.D3.Shape.prototype.visualize=function(){GameLib.Event.Emit(GameLib.Event.VISUALIZE,{shape:this})},GameLib.D3.Shape.Box=function(e,t,i){this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(i)?i=new GameLib.Vector3(e,new GameLib.API.Vector3(1,1,1)):i instanceof GameLib.API.Vector3&&(i=new GameLib.Vector3(this.physics,i,this)),this.halfExtents=i,GameLib.D3.Shape.call(this,this.physics,t)},GameLib.D3.Shape.Box.prototype=Object.create(GameLib.D3.Shape.prototype),GameLib.D3.Shape.Box.prototype.constructor=GameLib.D3.Shape.Box,GameLib.D3.Shape.Box.prototype.createInstance=function(){if(GameLib.Utils.UndefinedOrNull(this.halfExtents))throw new Error("no halfExtents");if(GameLib.Utils.UndefinedOrNull(this.halfExtents.instance))throw new Error("no halfExtents instance");this.instance=new CANNON.Box(this.halfExtents.instance),GameLib.D3.Shape.prototype.createInstance.call(this)},GameLib.D3.Shape.Box.prototype.updateInstance=function(){this.instance.halfExtents.x=this.halfExtents.x,this.instance.halfExtents.y=this.halfExtents.y,this.instance.halfExtents.z=this.halfExtents.z,this.instance.updateBoundingSphereRadius(),this.instance.updateConvexPolyhedronRepresentation()},GameLib.D3.Shape.Box.prototype.toApiObject=function(){var e=GameLib.D3.Shape.prototype.toApiObject.call(this);return e.halfExtents=this.halfExtents.toApiObject(),e},GameLib.D3.Shape.Box.prototype.setFromMesh=function(){if(null===this.parentMesh)return void console.log("select a mesh first");var e=this.parentMesh.getBoundingBox();this.halfExtents.x=e.x/2,this.halfExtents.y=e.y/2,this.halfExtents.z=e.z/2,this.halfExtents.updateInstance()},GameLib.D3.Shape.Box.FromObject=function(e,t){var i=GameLib.D3.API.Shape.FromObject(t);return i.halfExtents=GameLib.API.Vector3.FromObject(t.halfExtents),new GameLib.D3.Shape.Box(e,i,i.halfExtents)},GameLib.D3.Shape.ConvexHull=function(e,t,i,n,a,s){if(this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Shape.ConvexHull)return t;GameLib.Utils.UndefinedOrNull(i)&&(i=[]),this.vertices=i,GameLib.Utils.UndefinedOrNull(n)&&(n=[]),this.faces=n,GameLib.Utils.UndefinedOrNull(a)&&(a=[]),this.uniqueAxes=a,GameLib.Utils.UndefinedOrNull(s)&&(s=[]),this.uniqueEdges=s,this.vertices=this.vertices.map(function(e){return e instanceof GameLib.D3.API.Vertex?new GameLib.D3.Vertex(this.physics,e):e}.bind(this)),this.faces=this.faces.map(function(e){return e instanceof GameLib.D3.API.Face?new GameLib.D3.Face(this.physics,e):e}.bind(this)),this.uniqueAxes=this.uniqueAxes.map(function(e){return e instanceof GameLib.API.Vector3?new GameLib.Vector3(this.physics,e,this):e}.bind(this)),this.uniqueEdges=this.uniqueEdges.map(function(e){return e instanceof GameLib.API.Vector3?new GameLib.Vector3(this.physics,e,this):e}.bind(this)),GameLib.D3.Shape.call(this,this.physics,t)},GameLib.D3.Shape.ConvexHull.prototype=Object.create(GameLib.D3.Shape.prototype),GameLib.D3.Shape.ConvexHull.prototype.constructor=GameLib.D3.Shape.ConvexHull,GameLib.D3.Shape.ConvexHull.prototype.createInstance=function(){var e=[];this.instance=new CANNON.ConvexPolyhedron(this.vertices.map(function(e){if(GameLib.Utils.UndefinedOrNull(e))throw new Error("no vertex");if(GameLib.Utils.UndefinedOrNull(e.position))throw new Error("no vertex position");if(GameLib.Utils.UndefinedOrNull(e.position.instance))throw new Error("no vertex position instance");return e.position.instance}),this.faces.map(function(t){if(GameLib.Utils.UndefinedOrNull(t))throw new Error("no face");if(GameLib.Utils.UndefinedOrNull(t.normal))throw new Error("no face normal");if(GameLib.Utils.UndefinedOrNull(t.normal.instance))throw new Error("no face normal instance");if(GameLib.Utils.UndefinedOrNull(t.v0index))throw new Error("no face v0index");if(GameLib.Utils.UndefinedOrNull(t.v1index))throw new Error("no face v1index");if(GameLib.Utils.UndefinedOrNull(t.v2index))throw new Error("no face v2index");return e.push(t.normal.instance),[t.v0index,t.v1index,t.v2index]})),this.instance.faceNormals=e,GameLib.D3.Shape.prototype.createInstance.call(this)},GameLib.D3.Shape.ConvexHull.prototype.updateInstance=function(){console.log("todo: update convex hull instance")},GameLib.D3.Shape.ConvexHull.prototype.loadFromInstance=function(){console.log("todo: eventually load the faces and vertices from the instance faces and vertices and normals"),console.log("todo: this way we can nicely visualize them with our gamelib classes :)")},GameLib.D3.Shape.ConvexHull.prototype.toApiObject=function(){var e=GameLib.D3.Shape.prototype.toApiObject.call(this);return e.vertices=this.vertices.map(function(e){return e instanceof GameLib.D3.Vertex?e.toApiObject():e}),e.faces=this.faces.map(function(e){return e instanceof GameLib.D3.Face?e.toApiObject():e}),e.uniqueAxes=this.uniqueAxes.map(function(e){return e instanceof GameLib.Vector3?e.toApiObject():e}),e.uniqueEdges=this.uniqueEdges.map(function(e){return e instanceof GameLib.Vector3?e.toApiObject():e}),e},GameLib.D3.Shape.ConvexHull.prototype.setFromMesh=function(){console.log("todo: set convex hull from mesh"),this.updateInstance()},GameLib.D3.Shape.ConvexHull.InheritableProperties=function(e,t){return{vertices:t.vertices.map(function(t){return GameLib.D3.Vertex.FromObject(e,t)}),faces:t.faces.map(function(t){return GameLib.D3.Face.FromObject(e,t)}),uniqueAxes:t.uniqueAxes.map(function(e){return GameLib.API.Vector3.FromObject(e)}),uniqueEdges:t.uniqueEdges.map(function(e){return GameLib.API.Vector3.FromObject(e)})}},GameLib.D3.Shape.ConvexHull.FromObject=function(e,t){var i=GameLib.D3.API.Shape.FromObject(t),n=GameLib.D3.Shape.ConvexHull.InheritableProperties(e,t);return new GameLib.D3.Shape.ConvexHull.call(this,e,i,n.vertices,n.faces,n.uniqueAxes,n.uniqueEdges)},GameLib.D3.Shape.ConvexHull.Cylinder=function(e,t,i,n,a,s){this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(i)&&(i=1),this.radiusTop=i,GameLib.Utils.UndefinedOrNull(n)&&(n=1),this.radiusBottom=n,GameLib.Utils.UndefinedOrNull(a)&&(a=n/2),this.height=a,GameLib.Utils.UndefinedOrNull(s)&&(s=20),this.numSegments=s,GameLib.D3.Shape.ConvexHull.call(this,this.physics,t)},GameLib.D3.Shape.ConvexHull.Cylinder.prototype=Object.create(GameLib.D3.Shape.ConvexHull.prototype),GameLib.D3.Shape.ConvexHull.Cylinder.prototype.constructor=GameLib.D3.Shape.ConvexHull.Cylinder,GameLib.D3.Shape.ConvexHull.Cylinder.prototype.createInstance=function(){this.instance=new CANNON.Cylinder(this.radiusTop,this.radiusBottom,this.height,this.numSegments),GameLib.D3.Shape.prototype.createInstance.call(this)},GameLib.D3.Shape.ConvexHull.Cylinder.prototype.updateInstance=function(){console.log("todo : update cylinder instance")},GameLib.D3.Shape.ConvexHull.Cylinder.prototype.setFromMesh=function(){this.radiusTop=this.parentMesh.dimensions.x/2,this.radiusBottom=this.parentMesh.dimensions.x/2,this.height=this.parentMesh.dimensions.z},GameLib.D3.Shape.ConvexHull.Cylinder.prototype.toApiObject=function(){var e=GameLib.D3.Shape.ConvexHull.prototype.toApiObject.call(this);return e.radiusTop=this.radiusTop,e.radiusBottom=this.radiusBottom,e.height=this.height,e.numSegments=this.numSegments,e},GameLib.D3.Shape.ConvexHull.Cylinder.FromObject=function(e,t){var i=GameLib.D3.API.Shape.FromObject(t),n=GameLib.D3.Shape.ConvexHull.InheritableProperties(e,t);for(var a in n)n.hasOwnProperty(a)&&(i[a]=n[a]);return new GameLib.D3.Shape.ConvexHull.Cylinder(e,i,t.radiusTop,t.radiusBottom,t.height,t.numSegments)},GameLib.D3.Shape.HeightMap=function(e,t,i,n,a,s){this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(i)&&(i=[[10,10,10],[10,10,10],[10,10,10]]),this.heightData=i,GameLib.Utils.UndefinedOrNull(n)&&(n=0),this.minValue=n,GameLib.Utils.UndefinedOrNull(a)&&(a=10),this.maxValue=a,GameLib.Utils.UndefinedOrNull(s)&&(s=1),this.elementSize=s,GameLib.D3.Shape.call(this,this.physics,t)},GameLib.D3.Shape.HeightMap.prototype=Object.create(GameLib.D3.Shape.prototype),GameLib.D3.Shape.HeightMap.prototype.constructor=GameLib.D3.Shape.HeightMap,GameLib.D3.Shape.HeightMap.prototype.createInstance=function(){this.instance=new CANNON.Heightfield(this.heightData,{elemSize:this.elementSize}),GameLib.D3.Shape.prototype.createInstance.call(this)},GameLib.D3.Shape.HeightMap.prototype.updateInstance=function(){this.instance.data=this.heightData,this.instance.elemSize=this.elemSize,this.instance.update()},GameLib.D3.Shape.HeightMap.prototype.toApiObject=function(){var e=GameLib.D3.Shape.prototype.toApiObject.call(this);return e.heightData=this.heightData,e.minValue=this.minValue,e.maxValue=this.maxValue,e.elemSize=this.elemSize,e},GameLib.D3.Shape.HeightMap.prototype.setFromMesh=function(){if(null===this.parentMesh)return void console.log("select a mesh first");if(!this.parentMesh.isHeightMap)return void console.log("not a heightmap mesh");var e=Array.prototype.slice.call(this.parentMesh.getHeightData());this.heightData=[];for(var t=0;t<=this.parentMesh.widthSegments;t++){this.heightData[t]=[];for(var i=0;i<=this.parentMesh.heightSegments;i++)this.heightData[t][i]=e[t*(this.parentMesh.widthSegments+1)+i]}this.updateInstance()},GameLib.D3.Shape.HeightMap.FromObject=function(e,t){var i=GameLib.D3.API.Shape.FromObject(t);return new GameLib.D3.Shape.HeightMap(e,i,t.heightData,t.minValue,t.maxValue,t.elemSize)},GameLib.D3.Shape.Plane=function(e,t){this.physics=e,this.physics.isNotCannonThrow(),GameLib.D3.Shape.call(this,this.physics,t)},GameLib.D3.Shape.Plane.prototype=Object.create(GameLib.D3.Shape.prototype),GameLib.D3.Shape.Plane.prototype.constructor=GameLib.D3.Shape.Plane,GameLib.D3.Shape.Plane.prototype.createInstance=function(){this.instance=new CANNON.Plane,GameLib.D3.Shape.prototype.createInstance.call(this)},GameLib.D3.Shape.Plane.prototype.updateInstance=function(){},GameLib.D3.Shape.Plane.FromObject=function(e,t){var i=GameLib.D3.API.Shape.FromObject(t);return new GameLib.D3.Shape.Plane(e,i)},GameLib.D3.Shape.Sphere=function(e,t,i){this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(i)&&(i=1),this.radius=i,GameLib.D3.Shape.call(this,this.physics,t)},GameLib.D3.Shape.Sphere.prototype=Object.create(GameLib.D3.Shape.prototype),GameLib.D3.Shape.Sphere.prototype.constructor=GameLib.D3.Shape.Sphere,GameLib.D3.Shape.Sphere.prototype.createInstance=function(){this.instance=new CANNON.Sphere(this.radius),GameLib.D3.Shape.prototype.createInstance.call(this)},GameLib.D3.Shape.Sphere.prototype.updateInstance=function(){this.instance.radius=this.radius,this.instance.updateBoundingSphereRadius()},GameLib.D3.Shape.Sphere.prototype.toApiObject=function(){var e=GameLib.D3.Shape.prototype.toApiObject.call(this);return e.radius=this.radius,e},GameLib.D3.Shape.Sphere.FromObject=function(e,t){var i=GameLib.D3.API.Shape.FromObject(t);return new GameLib.D3.Shape.Sphere(e,i,t.radius)},GameLib.D3.Shape.TriMesh=function(e,t,i,n){this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(i)&&(i=[]),this.vertices=i,GameLib.Utils.UndefinedOrNull(n)&&(n=[]),this.indices=n,GameLib.D3.Shape.call(this,this.physics,t)},GameLib.D3.Shape.TriMesh.prototype=Object.create(GameLib.D3.Shape.prototype),GameLib.D3.Shape.TriMesh.prototype.constructor=GameLib.D3.Shape.TriMesh,GameLib.D3.Shape.TriMesh.prototype.createInstance=function(){this.instance=new CANNON.TriMesh(this.vertices,this.indices),GameLib.D3.Shape.prototype.createInstance.call(this)},GameLib.D3.Shape.TriMesh.prototype.updateInstance=function(){this.instance.vertices=this.vertices,this.instance.indices=this.indices,this.instance.updateAABB(),this.instance.updateBoundingSphereRadius(),this.instance.updateEdges(),this.instance.updateNormals(),this.instance.updateTree()},GameLib.D3.Skeleton=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Skeleton)return t;GameLib.D3.API.Skeleton.call(this,t.id,t.name,t.bones,t.boneInverses,t.useVertexTexture,t.boneTextureWidth,t.boneTextureHeight,t.boneMatrices,t.boneTexture,t.parentEntity),this.bones=this.bones.map(function(e){if(e instanceof GameLib.D3.API.Bone)return new GameLib.D3.Bone(this.graphics,e);throw console.warn("apiBone not an instance of API.Bone"),new Error("apiBone not an instance of API.Bone")}.bind(this)),this.boneInverses=this.boneInverses.map(function(e){if(e instanceof GameLib.API.Matrix4)return new GameLib.Matrix4(this.graphics,e,this);throw console.warn("boneInverse not an instance of API.Matrix4"),new Error("boneInverse not an instance of API.Matrix4")}.bind(this)),this.boneMatrices=this.boneMatrices.map(function(e){if(e instanceof GameLib.API.Matrix4)return new GameLib.Matrix4(this.graphics,e,this);throw console.warn("boneMatrices not an instance of API.Matrix4"),new Error("boneMatrices not an instance of API.Matrix4")}.bind(this)),GameLib.Component.call(this,GameLib.Component.COMPONENT_SKELETON,{bones:[GameLib.D3.Bone]})},GameLib.D3.Skeleton.prototype=Object.create(GameLib.D3.API.Skeleton.prototype),GameLib.D3.Skeleton.prototype.constructor=GameLib.D3.Skeleton,GameLib.D3.Skeleton.prototype.createInstance=function(e){var t=this.bones.map(function(e){if(GameLib.Utils.UndefinedOrNull(e))throw new Error("no bone");if(GameLib.Utils.UndefinedOrNull(e.instance))throw new Error("no bone instance");return e.instance}),i=this.bones.reduce(function(e,t){return e||(0===t.parentBoneIds.length?t.instance:null)},null);if(GameLib.Utils.UndefinedOrNull(i))throw new Error("could not find parent bone instance");this.instance=new THREE.Skeleton(t),this.rootBoneInstance=i,this.instance.useVertexTexture=this.useVertexTexture,this.boneIdToBone={},this.bones.map(function(e){this.boneIdToBone[e.id]=e}.bind(this)),this.bones.map(function(e){return function(t){t.childBoneIds.map(function(t){e.add(this.boneIdToBone[t].instance)}.bind(this))}}(i).bind(this)),this.instance.update(),this.instance.calculateInverses(),GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Skeleton.prototype.updateInstance=function(){},GameLib.D3.Skeleton.prototype.toApiObject=function(){return new GameLib.D3.API.Skeleton(this.id,this.name,this.bones.map(function(e){return e.toApiObject()}),this.boneInverses.map(function(e){return e.toApiObject()}),this.useVertexTexture,this.boneTextureWidth,this.boneTextureHeight,this.boneMatrices.map(function(e){return e.toApiObject()}),this.boneTexture,this.parentEntity)},GameLib.D3.Skeleton.FromObject=function(e,t){if(!t)return null;var i=GameLib.D3.API.Skeleton.FromObject(t);return new GameLib.D3.Skeleton(e,i)},GameLib.D3.Solver=function(e,t){if(this.physics=e,this.physics.isNotCannonThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Solver)return t;GameLib.D3.API.Solver.call(this,t.id,t.name,t.solverType,t.iterations,t.tolerance,t.parentEntity),GameLib.Component.call(this,GameLib.Component.COMPONENT_SOLVER)},GameLib.D3.Solver.prototype=Object.create(GameLib.D3.API.Solver.prototype),GameLib.D3.Solver.prototype.constructor=GameLib.D3.Solver,GameLib.D3.Solver.prototype.createInstance=function(){if(this.solverType===GameLib.D3.Solver.GS_SOLVER)this.instance=new CANNON.GSSolver;else{if(this.solverType!==GameLib.D3.Solver.SPLIT_SOLVER)throw new Error("unsupported solver type: "+this.solverType);this.instance=new CANNON.SplitSolver}this.instance.tolerance=this.tolerance,this.instance.iterations=this.iterations,GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Solver.prototype.updateInstance=function(){this.solverType===GameLib.D3.Solver.GS_SOLVER&&(this.instance instanceof CANNON.GSSolver||(this.instance=new CANNON.GSSolver)),this.solverType===GameLib.D3.Solver.SPLIT_SOLVER&&(this.instance instanceof CANNON.SplitSolver||(this.instance=new CANNON.SplitSolver)),this.instance.iterations=this.iterations,this.instance.tolerance=this.tolerance},GameLib.D3.Solver.prototype.toApiObject=function(){return new GameLib.D3.API.Solver(this.id,this.name,this.solverType,this.iterations,this.tolerance,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Solver.FromObject=function(e,t){var i=GameLib.D3.API.Solver.FromObject(t);return new GameLib.D3.Solver(e,i)},GameLib.D3.Solver.GS_SOLVER=1,GameLib.D3.Solver.SPLIT_SOLVER=2,GameLib.D3.Spline=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Spline)return t;GameLib.D3.API.Spline.call(this,t.id,t.name,t.vertices,t.parentEntity),this.vertices=this.vertices.map(function(t){return new GameLib.Vector3(e,t,this)}),GameLib.Component.call(this,GameLib.Component.COMPONENT_SPLINE)},GameLib.D3.Spline.prototype=Object.create(GameLib.D3.API.Spline.prototype),GameLib.D3.Spline.prototype.constructor=GameLib.D3.Spline,GameLib.D3.Spline.prototype.createInstance=function(){var e=this.vertices.map(function(e){if(GameLib.Utils.UndefinedOrNull(e))throw new Error("no vertex");if(GameLib.Utils.UndefinedOrNull(e.instance))throw new Error("no vertex instance");return e.instance});this.instance=THREE.CatmullRomCurve3(e),GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Spline.prototype.updateInstance=function(){var e=this.vertices.map(function(e){if(GameLib.Utils.UndefinedOrNull(e))throw new Error("no vertex");if(GameLib.Utils.UndefinedOrNull(e.instance))throw new Error("no vertex instance");return e.instance});this.instance=new THREE.CatmullRomCurve3(e)},GameLib.D3.Spline.prototype.toApiObject=function(){return new GameLib.D3.API.Spline(this.id,this.name,this.vertices.map(function(e){return e.toApiObject()}),GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Spline.FromObject=function(e,t){var i=GameLib.D3.API.Spline.FromObject(t);return new GameLib.D3.Spline(e,i)},GameLib.D3.Spline.prototype.getPointAt=function(e){var t=this.instance.getPointAt(e);return new GameLib.Vector3(this.graphics,new GameLib.API.Vector3(t.x,t.y,t.z),this,.1)},GameLib.D3.Stats=function(e,t,i,n,a){if(GameLib.Utils.UndefinedOrNull(e))throw new Error("Need Stats object");if(this.stats=e,GameLib.Utils.UndefinedOrNull(t)&&(t=GameLib.Utils.RandomId()),this.id=t,GameLib.Utils.UndefinedOrNull(i)&&(i="Stats ("+t+")"),this.name=i,GameLib.Utils.UndefinedOrNull(n))throw console.warn("Need a DOM element for stats"),new Error("Need a DOM element for stats");this.domElement=n,GameLib.Utils.UndefinedOrNull(a)&&(a=null),this.parentEntity=a,GameLib.Component.call(this,GameLib.Component.COMPONENT_STATS,{domElement:GameLib.DomElement})},GameLib.D3.Stats.prototype=Object.create(GameLib.Component.prototype),GameLib.D3.Stats.prototype.constructor=GameLib.D3.Stats,GameLib.D3.Stats.prototype.resize=function(){console.log("override stats resize per implementation")},GameLib.D3.Stats.prototype.createInstance=function(){this.instance=this.stats(),this.resize(),this.domElement.instance.parentElement.appendChild(this.instance.dom),GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Stats.prototype.updateInstance=function(){this.instance=new this.stats},GameLib.D3.Stats.prototype.start=function(){this.instance.begin()},GameLib.D3.Stats.prototype.end=function(){this.instance.end()},GameLib.D3.Texture=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Texture)return t;GameLib.D3.API.Texture.call(this,t.id,t.typeId,t.name,t.image,t.images,t.wrapS,t.wrapT,t.repeat,t.data,t.format,t.mapping,t.magFilter,t.minFilter,t.textureType,t.anisotropy,t.offset,t.generateMipmaps,t.flipY,t.mipmaps,t.unpackAlignment,t.premultiplyAlpha,t.encoding,t.canvas,t.animated,t.reverseAnimation,t.forward,t.parentEntity),this.offset=new GameLib.Vector2(this.graphics,this.offset,this),this.repeat=new GameLib.Vector2(this.graphics,this.repeat,this),this.image instanceof GameLib.D3.API.Image&&(this.image=new GameLib.D3.Image(this.graphics,this.image)),this.images=this.images.map(function(e){return e instanceof GameLib.D3.API.Image?new GameLib.D3.Image(this.graphics,e):e}.bind(this)),this.canvas instanceof GameLib.D3.API.Canvas&&(this.canvas=new GameLib.D3.Canvas(this.graphics,this.canvas)),GameLib.Component.call(this,GameLib.Component.COMPONENT_TEXTURE,{image:GameLib.D3.Image,images:[GameLib.D3.Image],canvas:GameLib.D3.Canvas})},GameLib.D3.Texture.prototype=Object.create(GameLib.D3.API.Texture.prototype),GameLib.D3.Texture.prototype.constructor=GameLib.D3.Texture,GameLib.D3.Texture.TYPE_ALPHA_FORMAT=1019,GameLib.D3.Texture.TYPE_RGB_FORMAT=1020,GameLib.D3.Texture.TYPE_RGBA_FORMAT=1021,GameLib.D3.Texture.TYPE_LUMINANCE_FORMAT=1022,GameLib.D3.Texture.TYPE_LUMINANCE_ALPHA_FORMAT=1023,GameLib.D3.Texture.TYPE_DEPTH_FORMAT=1026,GameLib.D3.Texture.TYPE_UV_MAPPING=300,GameLib.D3.Texture.TYPE_CUBE_REFLECTION_MAPPING=301,GameLib.D3.Texture.TYPE_CUBE_REFRACTION_MAPPING=302,GameLib.D3.Texture.TYPE_EQUI_RECTANGULAR_REFLECTION_MAPPING=303,GameLib.D3.Texture.TYPE_EQUI_RECTANGULAR_REFRACTION_MAPPING=304,GameLib.D3.Texture.TYPE_SPHERICAL_REFLECTION_MAPPING=305,GameLib.D3.Texture.TYPE_CUBE_UV_REFLECTION_MAPPING=306,GameLib.D3.Texture.TYPE_CUBE_UV_REFRACTION_MAPPING=307,GameLib.D3.Texture.TYPE_REPEAT_WRAPPING=1e3,GameLib.D3.Texture.TYPE_CLAMP_TO_EDGE_WRAPPING=1001,GameLib.D3.Texture.TYPE_MIRRORED_REPEAT_WRAPPING=1002,GameLib.D3.Texture.TYPE_NEAREST_FILTER=1003,GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_NEAREST_FILTER=1004, +GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_LINEAR_FILTER=1005,GameLib.D3.Texture.TYPE_LINEAR_FILTER=1006,GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_NEAREST_FILTER=1007,GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER=1008,GameLib.D3.Texture.TYPE_UNSIGNED_BYTE=1009,GameLib.D3.Texture.TYPE_BYTE=1010,GameLib.D3.Texture.TYPE_SHORT=1011,GameLib.D3.Texture.TYPE_UNSIGNED_SHORT=1012,GameLib.D3.Texture.TYPE_INT=1013,GameLib.D3.Texture.TYPE_UNSIGNED_INT=1014,GameLib.D3.Texture.TYPE_FLOAT=1015,GameLib.D3.Texture.TYPE_HALF_FLOAT=1025,GameLib.D3.Texture.TYPE_LINEAR_ENCODING=3e3,GameLib.D3.Texture.TYPE_SRGB_ENCODING=3001,GameLib.D3.Texture.TYPE_GAMMA_ENCODING=3007,GameLib.D3.Texture.TYPE_RGBE_ENCODING=3002,GameLib.D3.Texture.TYPE_LOG_LUV_ENCODING=3003,GameLib.D3.Texture.TYPE_RGBM7_ENCODING=3004,GameLib.D3.Texture.TYPE_RGBM16_ENCODING=3005,GameLib.D3.Texture.TYPE_RGBD_ENCODING=3006,GameLib.D3.Texture.TEXTURE_TYPE_NORMAL=1,GameLib.D3.Texture.TEXTURE_TYPE_CUBE=2,GameLib.D3.Texture.TEXTURE_TYPE_CANVAS=3,GameLib.D3.Texture.prototype.createInstance=function(){if(this.typeId===GameLib.D3.Texture.TEXTURE_TYPE_CUBE){if(6!==this.images.length)throw new Error("not enough images for cube texture");var e=this.images.map(function(e){if(GameLib.Utils.UndefinedOrNull(e))throw new Error("no image");if(GameLib.Utils.UndefinedOrNull(e.instance))throw new Error("no image instance");return e.instance});this.instance=new THREE.CubeTexture(e)}else if(this.typeId===GameLib.D3.Texture.TEXTURE_TYPE_NORMAL)GameLib.Utils.UndefinedOrNull(this.image)||GameLib.Utils.UndefinedOrNull(this.image.instance)?this.instance=new THREE.Texture:this.instance=new THREE.Texture(this.image.instance);else if(this.typeId===GameLib.D3.Texture.TEXTURE_TYPE_CANVAS)if(GameLib.Utils.UndefinedOrNull(this.canvas))this.instance=new THREE.Texture;else{if(GameLib.Utils.UndefinedOrNull(this.canvas.instance))throw new Error("no canvas instance");this.instance=new THREE.Texture(this.canvas.instance)}this.mapping=this.instance.mapping,this.encoding=this.instance.encoding,this.format=this.instance.format,this.instance.name=this.name,this.instance.flipY=this.flipY,this.instance.offset.x=this.offset.x,this.instance.offset.y=this.offset.y,this.instance.repeat.x=this.repeat.x,this.instance.repeat.y=this.repeat.y,this.instance.wrapS=this.wrapS,this.instance.wrapT=this.wrapT,this.instance.needsUpdate=!0,GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Texture.prototype.updateInstance=function(e){if(GameLib.Utils.UndefinedOrNull(this.instance))try{return void this.createInstance()}catch(e){console.error(e)}if(GameLib.Utils.UndefinedOrNull(e))throw new Error("need to specify a property");if("image"===e){if(this.typeId===GameLib.D3.Texture.TEXTURE_TYPE_NORMAL){if(GameLib.Utils.UndefinedOrNull(this.image)&&this.instance.image)try{this.createInstance()}catch(e){console.error(e)}if(this.image&&this.image.instance&&this.instance.image!==this.image.instance)try{this.createInstance()}catch(e){console.error(e)}}else if(this.typeId===GameLib.D3.Texture.TEXTURE_TYPE_CANVAS){if(GameLib.Utils.UndefinedOrNull(this.canvas)&&this.instance.canvas)try{this.createInstance()}catch(e){console.error(e)}if(this.canvas&&this.canvas.instance&&this.instance.image!==this.canvas.instance)try{this.createInstance()}catch(e){console.error(e)}}else this.typeId===GameLib.D3.Texture.TEXTURE_TYPE_CUBE&&console.log("todo : cube images change check here");this.publish(GameLib.Event.IMAGE_CHANGED,{texture:this}),this.instance.needsUpdate=!0}"name"===e&&(this.instance.name=this.name),"flipY"===e&&(this.instance.flipY=this.flipY),"encoding"===e&&(this.instance.encoding=this.encoding),"offset"===e&&(this.instance.offset.x=this.offset.x,this.instance.offset.y=this.offset.y),"repeat"===e&&(this.instance.repeat.x=this.repeat.x,this.instance.repeat.y=this.repeat.y),"mapping"===e&&(this.instance.mapping=this.mapping),"format"===e&&(this.instance.format=this.format),"wrapS"===e&&(this.instance.wrapS=this.wrapS),"wrapT"===e&&(this.instance.wrapT=this.wrapT),"animated"===e&&GameLib.Event.Emit(GameLib.Event.TEXTURE_ANIMATED_CHANGE,{texture:this})},GameLib.D3.Texture.prototype.toApiObject=function(){return new GameLib.D3.API.Texture(this.id,this.typeId,this.name,GameLib.Utils.IdOrNull(this.image),this.images.map(function(e){return GameLib.Utils.IdOrNull(e)}),this.wrapS,this.wrapT,this.repeat.toApiObject(),this.data,this.format,this.mapping,this.magFilter,this.minFilter,this.textureType,this.anisotropy,this.offset.toApiObject(),this.generateMipmaps,this.flipY,this.mipmaps,this.unpackAlignment,this.premultiplyAlpha,this.encoding,GameLib.Utils.IdOrNull(this.canvas),this.animated,this.reverseAnimation,this.forward,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Texture.FromObject=function(e,t){var i=GameLib.D3.API.Texture.FromObject(t);return new GameLib.D3.Texture(e,i)},GameLib.D3.TriangleEdge=function(e,t){this.triangle=e,this.edge=t},GameLib.D3.Vertex=function(e,t){if(this.implementation=e,e instanceof GameLib.D3.Graphics)this.implementation.isNotThreeThrow();else{if(!(e instanceof GameLib.D3.Physics))throw new Error("Unhandled implementation : "+e);this.implementation.isNotCannonThrow()}if(GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Vertex)return t;GameLib.D3.API.Vertex.call(this,t.position,t.boneWeights),this.position=new GameLib.Vector3(this.implementation,this.position,null),e instanceof GameLib.D3.Graphics&&(this.boneWeights=this.boneWeights.map(function(e){return new GameLib.D3.BoneWeight(this.implementation,e)}.bind(this)))},GameLib.D3.Vertex.prototype=Object.create(GameLib.D3.API.Vertex.prototype),GameLib.D3.Vertex.prototype.constructor=GameLib.D3.Vertex,GameLib.D3.Vertex.prototype.toApiObject=function(){return new GameLib.D3.API.Vertex(this.position.toApiObject(),this.boneWeights.map(function(e){return e.toApiObject()}))},GameLib.D3.Vertex.FromObject=function(e,t){var i=GameLib.D3.API.Vertex.FromObject(t);return new GameLib.D3.Vertex(e,i)},GameLib.D3.Viewport=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.D3.Viewport)return t;GameLib.D3.API.Viewport.call(this,t.id,t.name,t.width,t.height,t.x,t.y,t.parentEntity),GameLib.Component.call(this,GameLib.Component.COMPONENT_VIEWPORT)},GameLib.D3.Viewport.prototype=Object.create(GameLib.D3.API.Viewport.prototype),GameLib.D3.Viewport.prototype.constructor=GameLib.D3.Viewport,GameLib.D3.Viewport.prototype.createInstance=function(){this.instance=!0,GameLib.Component.prototype.createInstance.call(this)},GameLib.D3.Viewport.prototype.updateInstance=function(){},GameLib.D3.Viewport.prototype.toApiObject=function(){return new GameLib.D3.API.Viewport(this.id,this.name,this.width,this.height,this.x,this.y,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.D3.Viewport.FromObject=function(e,t){var i=GameLib.D3.API.Viewport.FromObject(t);return new GameLib.D3.Viewport(e,i)},GameLib.DomElement=function(e){if(GameLib.Utils.UndefinedOrNull(e)&&(e={}),e instanceof GameLib.DomElement)return e;GameLib.API.DomElement.call(this,e.id,e.name,e.domElementId,e.parentEntity),GameLib.Component.call(this,GameLib.Component.COMPONENT_DOM_ELEMENT)},GameLib.DomElement.prototype=Object.create(GameLib.API.DomElement.prototype),GameLib.DomElement.prototype.constructor=GameLib.DomElement,GameLib.DomElement.prototype.createInstance=function(){this.instance=document.getElementById(this.domElementId),GameLib.Component.prototype.createInstance.call(this)},GameLib.DomElement.prototype.updateInstance=function(){this.instance=document.getElementById(this.domElementId)},GameLib.DomElement.prototype.toApiObject=function(){return new GameLib.API.DomElement(this.id,this.name,this.domElementId,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.DomElement.prototype.append=function(e){this.instance.appendChild(e)},GameLib.DomElement.prototype.clear=function(){this.instance.innerHTML=""},GameLib.DomElement.FromObject=function(e){var t=GameLib.API.DomElement.FromObject(e);return new GameLib.DomElement(t)},GameLib.Dom=function(e,t){this.document=e,this.window=t},GameLib.EntityManager=function(e){if(GameLib.Utils.UndefinedOrNull(e)&&(e={}),e instanceof GameLib.EntityManager)return e;GameLib.API.EntityManager.call(this,e.id,e.name,e.entities,e.defaultEntity,e.defaultRenderer),this.register=[],GameLib.Event.Subscribe(GameLib.Event.COMPONENT_REGISTER,this.registerComponent.bind(this)),GameLib.Event.Subscribe(GameLib.Event.REMOVE_COMPONENT,this.removeComponent.bind(this)),GameLib.Component.call(this,GameLib.Component.COMPONENT_ENTITY_MANAGER,{entities:[GameLib.Entity],defaultEntity:GameLib.Entity,defaultRenderer:GameLib.D3.Renderer})},GameLib.EntityManager.prototype=Object.create(GameLib.API.EntityManager.prototype),GameLib.EntityManager.prototype.constructor=GameLib.EntityManager,GameLib.EntityManager.prototype.createInstance=function(){this.instance=GameLib.EntityManager.Instance,GameLib.Component.prototype.createInstance.call(this)},GameLib.EntityManager.prototype.registerComponent=function(e){var t=this.register.length;GameLib.Utils.PushUnique(this.register,e.component),t!==this.register.length&&GameLib.Event.Emit(GameLib.Event.REGISTER_UPDATE,{register:this.register})},GameLib.EntityManager.prototype.removeComponent=function(e){var t=this.register.indexOf(e.component);-1!==t&&(this.register.splice(t,1),GameLib.Event.Emit(GameLib.Event.REGISTER_UPDATE,{register:this.register}))},GameLib.EntityManager.prototype.createEntity=function(e){var t=new GameLib.API.Entity(null,e,null,null,this),i=new GameLib.Entity(t);return this.entities.push(i),this.defaultEntity=i,GameLib.Event.Emit(GameLib.Event.NEW_ENTITY,{entity:i}),i},GameLib.EntityManager.prototype.findEntityById=function(e){return this.entities.reduce(function(t,i){return i.id===e&&(t=i),t},null)},GameLib.EntityManager.prototype.findComponentById=function(e){return this.register.reduce(function(t,i){return i.id===e&&(t=i),t},null)},GameLib.EntityManager.prototype.findHelperByObject=function(e){return this.register.reduce(function(t,i){return i instanceof GameLib.D3.Helper&&i.object===e&&(t=i),t},null)},GameLib.EntityManager.prototype.findSceneByObject=function(e){return this.register.reduce(function(t,i){return i instanceof GameLib.D3.Scene&&(-1!==i.meshes.indexOf(e)&&(t=i),-1!==i.lights.indexOf(e)&&(t=i)),t},null)},GameLib.EntityManager.prototype.addEntity=function(e){e.parentEntityManager=this,this.entities.push(e)},GameLib.EntityManager.prototype.queryByName=function(e){return this.entities.reduce(function(t,i){return i.name===e&&(t=i),t},null)},GameLib.EntityManager.prototype.removeEntity=function(e){var t=this.entities.indexOf(e);return-1===t?(console.log("failed to remove entity : ",e),!1):(this.entities.splice(t,1),e.parentEntityManager=null,!0)},GameLib.EntityManager.prototype.findEntities=function(e){return this.entities.reduce(function(t,i){return e.reduce(function(e,t){return i.hasComponent(t)||(e=!1),e},!0)&&t.push(i),t},[])},GameLib.EntityManager.prototype.queryComponents=function(e){return this.register.reduce(function(t,i){return e instanceof Array?e.map(function(e){i instanceof e&&-1===t.indexOf(i)&&t.push(i)}):i instanceof e&&-1===t.indexOf(i)&&t.push(i),t},[])},GameLib.EntityManager.prototype.toApiObject=function(){var e=this.entities.map(function(e){return GameLib.Utils.IdOrNull(e)});return new GameLib.API.EntityManager(this.id,this.name,e,GameLib.Utils.IdOrNull(this.defaultEntity),GameLib.Utils.IdOrNull(this.defaultRenderer))},GameLib.EntityManager.FromObject=function(e){var t=GameLib.API.EntityManager.FromObject(e);return new GameLib.EntityManager(t)},GameLib.Entity=function(e){if(GameLib.Utils.UndefinedOrNull(e)&&(e={}),e instanceof GameLib.Entity)return e;GameLib.API.Entity.call(this,e.id,e.name,e.components,e.parentEntity,e.parentEntityManager),this.componentToCreate=0,GameLib.Component.call(this,GameLib.Component.COMPONENT_ENTITY,{components:[GameLib.Component],activeComponent:GameLib.Component})},GameLib.Entity.prototype=Object.create(GameLib.API.Entity.prototype),GameLib.Entity.prototype.constructor=GameLib.Entity,GameLib.Entity.prototype.createInstance=function(){this.instance=!0,GameLib.Component.prototype.createInstance.call(this)},GameLib.Entity.prototype.addComponent=function(e){if(GameLib.Utils.PushUnique(this.components,e),e instanceof GameLib.D3.Mesh)e.getChildrenComponents().map(function(e){GameLib.Utils.PushUnique(this.components,e),e.parentEntity=this}.bind(this));else{e.buildIdToObject();for(var t in e.idToObject)e.idToObject.hasOwnProperty(t)&&e.idToObject[t]!==e&&e.idToObject[t]instanceof GameLib.Component&&(GameLib.Utils.PushUnique(this.components,e.idToObject[t]),e.idToObject[t].parentEntity=this)}e.parentEntity=this};GameLib.Entity.prototype.getComponents=function(e){return this.components.reduce(function(t,i){return i instanceof e&&t.push(i),t},[])},GameLib.Entity.prototype.getFirstComponent=function(e){var t=this.getComponents(e);return t.length>0?t[0]:null},GameLib.Entity.prototype.hasComponent=function(e){return this.components.reduce(function(t,i){return i instanceof e&&(t=!0),t},!1)},GameLib.Entity.prototype.removeComponent=function(e){GameLib.Utils.UndefinedOrNull(e)&&(e=this.activeComponent);var t=this.components.indexOf(e);return-1!==t?this.components.splice(t,1):console.error("component not found"),e.parentEntity=null,!0},GameLib.Entity.prototype.updateInstance=function(){console.log("entity update instance called")},GameLib.Entity.prototype.toApiObject=function(){var e=this.components.map(function(e){return GameLib.Utils.IdOrNull(e)});return new GameLib.API.Entity(this.id,this.name,e,GameLib.Utils.IdOrNull(this.parentEntity),GameLib.Utils.IdOrNull(this.parentEntityManager))},GameLib.Entity.FromObject=function(e,t){var i=GameLib.API.Entity.FromObject(e),n=new GameLib.Entity(i);return GameLib.Utils.UndefinedOrNull(t)?n:(t.addEntity(n),n)},GameLib.GUI=function(e,t,i,n,a,s){if(GameLib.Utils.UndefinedOrNull(e))throw new Error("Need GUI object");if(this.gui=e,GameLib.Utils.UndefinedOrNull(t)&&(t=GameLib.Utils.RandomId()),this.id=t,GameLib.Utils.UndefinedOrNull(i)&&(i="GUI ("+t+")"),this.name=i,GameLib.Utils.UndefinedOrNull(n))throw console.warn("Need a DOM element for stats"),new Error("Need a DOM element for stats");this.domElement=n,GameLib.Utils.UndefinedOrNull(a)&&(a=[]),this.objects=a,GameLib.Utils.UndefinedOrNull(s)&&(s=null),this.parentEntity=s,GameLib.Component.call(this,GameLib.Component.COMPONENT_GUI,{domElement:GameLib.DomElement})},GameLib.GUI.prototype=Object.create(GameLib.Component.prototype),GameLib.GUI.prototype.constructor=GameLib.GUI,GameLib.GUI.prototype.createInstance=function(){this.instance=new dat.GUI({autoPlace:!1}),GameLib.Component.prototype.createInstance.call(this)},GameLib.GUI.prototype.updateInstance=function(){this.instance=new dat.GUI({autoPlace:!1})},GameLib.GUI.prototype.removeEmtpyFolders=function(){this.instance.removeEmptyFolders()},GameLib.GUI.prototype.removeAllFolders=function(){this.instance.removeAllFolders()},GameLib.GUI.prototype.addFolder=function(e){try{return this.instance.addFolder(e)}catch(t){try{return e+=" duplicate ("+GameLib.Utils.RandomId()+")",this.instance.addFolder(e)}catch(e){return console.log(e.message),null}}},GameLib.Matrix4=function(e,t,i,n){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.Matrix4)return t;GameLib.API.Matrix4.call(this,t.rows[0],t.rows[1],t.rows[2],t.rows[3]),GameLib.Utils.UndefinedOrNull(i)&&(i=null),this.parentObject=i,GameLib.Utils.UndefinedOrNull(n)&&(n=.001),this.grain=n,this.rows=this.rows.map(function(e){if(e instanceof GameLib.API.Vector4)return new GameLib.Vector4(this.graphics,e,this,this.grain);throw console.warn("Attempted conversion of wrong instance"),new Error("Attempted conversion of wrong instance")}.bind(this)),this.forward=new GameLib.Vector4(this.graphics,this.forward,this,this.grain),this.left=new GameLib.Vector4(this.graphics,this.left,this,this.grain),this.up=new GameLib.Vector4(this.graphics,this.up,this,this.grain),this.createInstance()},GameLib.Matrix4.prototype=Object.create(GameLib.API.Matrix4.prototype),GameLib.Matrix4.prototype.constructor=GameLib.Matrix4,GameLib.Matrix4.prototype.createInstance=function(e){this.instance=new THREE.Matrix4,this.instance.set(this.rows[0].x,this.rows[1].x,this.rows[2].x,this.rows[3].x,this.rows[0].y,this.rows[1].y,this.rows[2].y,this.rows[3].y,this.rows[0].z,this.rows[1].z,this.rows[2].z,this.rows[3].z,this.rows[0].w,this.rows[1].w,this.rows[2].w,this.rows[3].w)},GameLib.Matrix4.prototype.updateInstance=function(){this.instance.set(this.rows[0].x,this.rows[1].x,this.rows[2].x,this.rows[3].x,this.rows[0].y,this.rows[1].y,this.rows[2].y,this.rows[3].y,this.rows[0].z,this.rows[1].z,this.rows[2].z,this.rows[3].z,this.rows[0].w,this.rows[1].w,this.rows[2].w,this.rows[3].w),this.parentObject&&this.parentObject.updateInstance&&this.parentObject.updateInstance()},GameLib.Matrix4.prototype.toApiObject=function(){return new GameLib.API.Matrix4(this.rows[0].toApiObject(),this.rows[1].toApiObject(),this.rows[2].toApiObject(),this.rows[3].toApiObject())},GameLib.Matrix4.FromObject=function(e,t,i){var n=new GameLib.API.Matrix4.FromObject(t);return new GameLib.Matrix4(e,i,n)},GameLib.Matrix4.prototype.lookAt=function(e,t,i){var n=new GameLib.API.Vector3(e.x,e.y,e.z),a=n.subtract(t).normalize();0===a.squared()&&(a.z=1);var s=i.cross(a).normalize();0===s.squared()&&(a.x+=1e-4,s=i.cross(a).normalize());var o=a.cross(s);return this.rows[0].x=s.x,this.rows[0].y=s.y,this.rows[0].z=s.z,this.rows[1].x=o.x,this.rows[1].y=o.y,this.rows[1].z=o.z,this.rows[2].x=a.x,this.rows[2].y=a.y,this.rows[2].z=a.z,this.forward.x=a.x,this.forward.y=a.y,this.forward.z=a.z,this.left.x=s.x,this.left.y=s.y,this.left.z=s.z,this.up.x=o.x,this.up.y=o.y,this.up.z=o.z,this.updateInstance(),this},GameLib.Matrix4.prototype.identity=function(){this.rows=[new GameLib.Vector4(this.graphics,new GameLib.API.Vector4(1,0,0,0),this,this.grain),new GameLib.Vector4(this.graphics,new GameLib.API.Vector4(0,1,0,0),this,this.grain),new GameLib.Vector4(this.graphics,new GameLib.API.Vector4(0,0,1,0),this,this.grain),new GameLib.Vector4(this.graphics,new GameLib.API.Vector4(0,0,0,1),this,this.grain)]},GameLib.Matrix4.prototype.transpose=function(){return this.temp[0].x=this.rows[0].x,this.temp[0].y=this.rows[1].x,this.temp[0].z=this.rows[2].x,this.temp[0].w=this.rows[3].x,this.temp[1].x=this.rows[0].y,this.temp[1].y=this.rows[1].y,this.temp[1].z=this.rows[2].y,this.temp[1].w=this.rows[3].y,this.temp[2].x=this.rows[0].z,this.temp[2].y=this.rows[1].z,this.temp[2].z=this.rows[2].z,this.temp[2].w=this.rows[3].z,this.temp[3].x=this.rows[0].w,this.temp[3].y=this.rows[1].w,this.temp[3].z=this.rows[2].w,this.temp[3].w=this.rows[3].w,this.rows[0].x=this.temp[0].x,this.rows[0].y=this.temp[0].y,this.rows[0].z=this.temp[0].z,this.rows[0].w=this.temp[0].w,this.rows[1].x=this.temp[1].x,this.rows[1].y=this.temp[1].y,this.rows[1].z=this.temp[1].z,this.rows[1].w=this.temp[1].w,this.rows[2].x=this.temp[2].x,this.rows[2].y=this.temp[2].y,this.rows[2].z=this.temp[2].z,this.rows[2].w=this.temp[2].w,this.rows[3].x=this.temp[3].x,this.rows[3].y=this.temp[3].y,this.rows[3].z=this.temp[3].z,this.rows[3].w=this.temp[3].w,this},GameLib.Mouse=function(e,t){if(this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.Mouse)return t;GameLib.API.Mouse.call(this,t.id,t.name,t.x,t.y,t.parentEntity),GameLib.Component.call(this,GameLib.Component.COMPONENT_MOUSE)},GameLib.Mouse.prototype=Object.create(GameLib.API.Mouse.prototype),GameLib.Mouse.prototype.constructor=GameLib.Mouse,GameLib.Mouse.prototype.createInstance=function(e){this.instance=!0,GameLib.Component.prototype.createInstance.call(this)},GameLib.Mouse.prototype.updateInstance=function(){},GameLib.Mouse.prototype.toApiObject=function(){return new GameLib.API.Mouse(this.id,this.name,this.x,this.y,this.parentEntity)},GameLib.Quaternion=function(e,t,i,n){if(this.implementation=e,e instanceof GameLib.D3.Graphics)this.physics=null,this.graphics=e,this.graphics.isNotThreeThrow();else{if(!(e instanceof GameLib.D3.Physics))throw new Error("Unhandled implementation : "+e);this.graphics=null,this.physics=e,this.physics.isNotCannonThrow()}if(GameLib.Utils.UndefinedOrNull(t)&&(t={}),t instanceof GameLib.Quaternion)return t;GameLib.API.Quaternion.call(this,t.x,t.y,t.z,t.w,t.axis,t.angle),GameLib.Utils.UndefinedOrNull(i)&&(i=null),this.parentObject=i,this.axis=new GameLib.Vector3(this.implementation,this.axis,this,this.grain),Object.defineProperty(this,"angle",GameLib.Utils.LimitToPI("angle",this.angle)),GameLib.Utils.UndefinedOrNull(n)&&(n=.001),this.grain=n,this.createInstance()},GameLib.Quaternion.prototype=Object.create(GameLib.API.Quaternion.prototype),GameLib.Quaternion.prototype.constructor=GameLib.Quaternion,GameLib.Quaternion.prototype.createInstance=function(){this.graphics&&(this.instance=new THREE.Quaternion(this.x,this.y,this.z,this.w)),this.physics&&(this.instance=new CANNON.Quaternion(this.x,this.y,this.z,this.w))},GameLib.Quaternion.prototype.updateInstance=function(e){this.instance.x=this.x,this.instance.y=this.y,this.instance.z=this.z,this.instance.w=this.w,this.parentObject&&this.parentObject.updateInstance&&this.parentObject.updateInstance(e)},GameLib.Quaternion.prototype.toApiObject=function(){return new GameLib.API.Quaternion(this.x,this.y,this.z,this.w,this.axis.toApiObject(),this.angle)},GameLib.Quaternion.prototype.equals=function(e){return this.x===e.x&&this.y===e.y&&this.z===e.z&&this.w===e.w&&this.axis.equals(e.axis)&&this.angle===e.angle},GameLib.Quaternion.prototype.setFrom=function(e){this.x=e.x,this.y=e.y,this.z=e.z,this.w=e.w,this.axis.setFrom(e.axis),this.angle=e.angle},GameLib.Quaternion.prototype.copy=function(e){console.log("todo")},GameLib.System=function(e){if(GameLib.Utils.UndefinedOrNull(e)&&(e={}),e instanceof GameLib.System)return e;GameLib.API.System.call(this,e.id,e.name,e.systemType,e.parentEntity),this.started=!1,this.paused=!1;var t=GameLib.Component.COMPONENT_SYSTEM,i={};e.systemType===GameLib.System.SYSTEM_TYPE_ANIMATION&&(t=GameLib.Component.COMPONENT_SYSTEM_ANIMATION),e.systemType===GameLib.System.SYSTEM_TYPE_CUSTOM&&(t=GameLib.Component.COMPONENT_SYSTEM_CUSTOM_CODE),e.systemType===GameLib.System.SYSTEM_TYPE_GUI&&(t=GameLib.Component.COMPONENT_SYSTEM_GUI),e.systemType===GameLib.System.SYSTEM_TYPE_INPUT&&(t=GameLib.Component.COMPONENT_SYSTEM_INPUT,i.mouseControls=[GameLib.D3.Controls.Mouse],i.keyboardControls=[GameLib.D3.Controls.Keyboard],i.touchControls=[GameLib.D3.Controls.Touch],i.editorControls=[GameLib.D3.Controls.Editor]),e.systemType===GameLib.System.SYSTEM_TYPE_LINKING&&(t=GameLib.Component.COMPONENT_SYSTEM_LINKING),e.systemType===GameLib.System.SYSTEM_TYPE_PHYSICS&&(t=GameLib.Component.COMPONENT_SYSTEM_PHYSICS),e.systemType===GameLib.System.SYSTEM_TYPE_RENDER&&(t=GameLib.Component.COMPONENT_SYSTEM_RENDER),e.systemType===GameLib.System.SYSTEM_TYPE_STORAGE&&(t=GameLib.Component.COMPONENT_SYSTEM_STORAGE),e.systemType===GameLib.System.SYSTEM_TYPE_VISUALIZATION&&(t=GameLib.Component.COMPONENT_SYSTEM_VISUALIZATION),e.systemType===GameLib.System.SYSTEM_TYPE_PARTICLE&&(t=GameLib.Component.COMPONENT_SYSTEM_PARTICLE),e.systemType===GameLib.System.SYSTEM_TYPE_AUDIO&&(t=GameLib.Component.COMPONENT_SYSTEM_AUDIO,i.audioComponents=[GameLib.D3.Audio]),GameLib.Component.call(this,t)},GameLib.System.prototype=Object.create(GameLib.API.System.prototype),GameLib.System.prototype.constructor=GameLib.System,GameLib.System.SYSTEM_TYPE_NONE=0,GameLib.System.SYSTEM_TYPE_RENDER=1,GameLib.System.SYSTEM_TYPE_ANIMATION=2,GameLib.System.SYSTEM_TYPE_INPUT=4,GameLib.System.SYSTEM_TYPE_STORAGE=8,GameLib.System.SYSTEM_TYPE_GUI=16,GameLib.System.SYSTEM_TYPE_PHYSICS=32,GameLib.System.SYSTEM_TYPE_LINKING=64,GameLib.System.SYSTEM_TYPE_CUSTOM=128,GameLib.System.SYSTEM_TYPE_VISUALIZATION=256,GameLib.System.SYSTEM_TYPE_PARTICLE=512,GameLib.System.SYSTEM_TYPE_AUDIO=1024,GameLib.System.SYSTEM_TYPE_ALL=65535,GameLib.System.prototype.createInstance=function(){this.instance=!0,GameLib.Component.prototype.createInstance.call(this)},GameLib.System.prototype.start=function(){this.started=!0,console.log("starting "+this.name)},GameLib.System.prototype.stop=function(){this.started=!1,console.log("stopping "+this.name)},GameLib.System.prototype.toApiObject=function(){return new GameLib.API.System(this.id,this.name,this.systemType,GameLib.Utils.IdOrNull(this.parentEntity))},GameLib.System.prototype.restart=function(){console.log("restarting system : "+this.name),this.stop(),this.start()},GameLib.System.Animation=function(e){GameLib.System.call(this,e),this.animations={},this.latest={},this.textures={},this.textureIds=[],this.animationMeshAddedSubscription=null,this.animationMeshRemovedSubscription=null,this.instanceCreatedSubscription=null,this.removeComponentSubscription=null,this.textureAnimatedSubscription=null,this.animateTextureInstanceSubscription=null},GameLib.System.Animation.prototype=Object.create(GameLib.System.prototype),GameLib.System.Animation.prototype.constructor=GameLib.System.Animation,GameLib.System.Animation.prototype.start=function(){GameLib.System.prototype.start.call(this),this.beforeRenderSubscription=GameLib.Event.Subscribe(GameLib.Event.BEFORE_RENDER,this.beforeRender.bind(this)),GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Animation).map(function(e){e.meshes.map(function(t){this.attachAnimation(e,t)}.bind(this))}.bind(this)),this.animationMeshAddedSubscription=GameLib.Event.Subscribe(GameLib.Event.ANIMATION_MESH_ADDED,function(e){this.attachAnimation(e.animation,e.mesh)}.bind(this)),this.animationMeshRemovedSubscription=GameLib.Event.Subscribe(GameLib.Event.ANIMATION_MESH_REMOVED,function(e){this.detachAnimation(e.mesh)}.bind(this)),this.instanceCreatedSubscription=GameLib.Event.Subscribe(GameLib.Event.INSTANCE_CREATED,this.instanceCreated.bind(this)),this.removeComponentSubscription=GameLib.Event.Subscribe(GameLib.Event.REMOVE_COMPONENT,this.removeComponent.bind(this)),this.textureAnimatedSubscription=GameLib.Event.Subscribe(GameLib.Event.TEXTURE_ANIMATED_CHANGE,this.textureAnimatedChange.bind(this)),this.animateTextureInstanceSubscription=GameLib.Event.Subscribe(GameLib.Event.ANIMATE_TEXTURE_INSTANCE,this.animateTextureInstance.bind(this))},GameLib.System.Animation.prototype.instanceCreated=function(e){if(e.component instanceof GameLib.D3.Texture&&e.component.animated){if(e.component.repeat.x>1||e.component.repeat.x<0)return console.warn("cannot animate a texture with repeat.x greater than 1 or less than 0"),void(e.component.animated=!1);if(e.component.repeat.y>1||e.component.repeat.y<0)return console.warn("cannot animate a texture with repeat.y greater than 1 or less than 0"),void(e.component.animated=!1);this.textures[e.component.id]=e.component,this.textureIds=Object.keys(this.textures)}},GameLib.System.Animation.prototype.removeComponent=function(e){e.component instanceof GameLib.D3.Texture&&e.component.animated&&(GameLib.Utils.UndefinedOrNull(this.textures[e.component.id])?console.warn("tried to remove an animated texture, which should have been in the list but isnt: "+e.component.name):(delete this.textures[e.component.id],this.textureIds=Object.keys(this.textures)))},GameLib.System.Animation.prototype.textureAnimatedChange=function(e){if(e.texture.animated){if(e.texture.repeat.x>1||e.texture.repeat.x<0)return console.warn("cannot animate a texture with repeat.x greater than 1 or less than 0"),void(e.texture.animated=!1);if(e.texture.repeat.y>1||e.texture.repeat.y<0)return console.warn("cannot animate a texture with repeat.y greater than 1 or less than 0"),void(e.texture.animated=!1);this.textures[e.texture.id]=e.texture,this.textureIds=Object.keys(this.textures)}else GameLib.Utils.UndefinedOrNull(this.textures[e.texture.id])?console.warn("tried to remove an animated texture, which should have been in the list but isnt: "+e.texture.name):(delete this.textures[e.texture.id],this.textureIds=Object.keys(this.textures))},GameLib.System.Animation.prototype.animateTextureInstance=function(e){return e.texture.repeat.x>1||e.texture.repeat.x<0?(console.warn("cannot animate a texture with repeat.x greater than 1 or less than 0"),void(e.texture.userData.animated=!1)):e.texture.repeat.y>1||e.texture.repeat.y<0?(console.warn("cannot animate a texture with repeat.y greater than 1 or less than 0"),void(e.texture.userData.animated=!1)):(e.texture.userData.animated=!0,this.textures[e.texture.id]=e.texture,void(this.textureIds=Object.keys(this.textures)))},GameLib.System.Animation.prototype.beforeRender=function(e){if(!this.paused){var t=e.delta;for(var i in this.animations)if(this.animations.hasOwnProperty(i)){var n=[];if(this.animations[i].length>0)for(var a=!1,s=0;s=1-t.repeat.x&&(t.offset.y>=1-t.repeat.y?(t.offset.x=1-t.repeat.x,t.offset.y=1-t.repeat.y,t.userData?t.userData.forward=!1:t.forward=!1):(t.offset.x=0,t.offset.y+=t.repeat.y))),(!1===t.forward||t.userData&&!1===t.userData.forward)&&(t.offset.x-=t.repeat.x,t.offset.x<=0&&(t.offset.x=0,t.offset.y=1-t.repeat.x&&(t.offset.y>=1-t.repeat.y?(t.offset.x=0,t.offset.y=0):(t.offset.x=0,t.offset.y+=t.repeat.y))),t.userData||t.updateInstance("offset")}.bind(this))}},GameLib.System.Animation.prototype.detachAnimation=function(e){var t=!1;e.backupQuaternionAngleDescriptor&&(Object.defineProperty(e.quaternion,"angle",e.backupQuaternionAngleDescriptor),delete e.backupQuaternionAngleDescriptor,t=!0),e.backupQuaternionAxisXDescriptor&&(Object.defineProperty(e.quaternion.axis,"x",e.backupQuaternionAxisXDescriptor),delete e.backupQuaternionAxisXDescriptor,t=!0),e.backupQuaternionAxisYDescriptor&&(Object.defineProperty(e.quaternion.axis,"y",e.backupQuaternionAxisYDescriptor),delete e.backupQuaternionAxisYDescriptor,t=!0),e.backupQuaternionAxisZDescriptor&&(Object.defineProperty(e.quaternion.axis,"z",e.backupQuaternionAxisZDescriptor),delete e.backupQuaternionAxisXDescriptor,t=!0),e.backupRotationXDescriptor&&(Object.defineProperty(e.rotation,"x",e.backupRotationXDescriptor),delete e.backupRotationXDescriptor,t=!0),e.backupRotationYDescriptor&&(Object.defineProperty(e.rotation,"y",e.backupRotationYDescriptor),delete e.backupRotationYDescriptor,t=!0),e.backupRotationZDescriptor&&(Object.defineProperty(e.rotation,"z",e.backupRotationZDescriptor),delete e.backupRotationZDescriptor,t=!0),e.backupPositionXDescriptor&&(Object.defineProperty(e.position,"x",e.backupPositionXDescriptor),delete e.backupPositionXDescriptor,t=!0),e.backupPositionYDescriptor&&(Object.defineProperty(e.position,"y",e.backupPositionYDescriptor),delete e.backupPositionYDescriptor,t=!0),e.backupPositionZDescriptor&&(Object.defineProperty(e.position,"z",e.backupPositionZDescriptor),delete e.backupPositionZDescriptor,t=!0), +e.backupScaleXDescriptor&&(Object.defineProperty(e.scale,"x",e.backupScaleXDescriptor),delete e.backupScaleXDescriptor,t=!0),e.backupScaleYDescriptor&&(Object.defineProperty(e.scale,"y",e.backupScaleYDescriptor),delete e.backupScaleYDescriptor,t=!0),e.backupScaleZDescriptor&&(Object.defineProperty(e.scale,"z",e.backupScaleZDescriptor),delete e.backupScaleZDescriptor,t=!0),this.latest[e.id]&&(e.rotation.x=this.latest[e.id].rotation.x,e.rotation.y=this.latest[e.id].rotation.y,e.rotation.z=this.latest[e.id].rotation.z,e.position.x=this.latest[e.id].position.x,e.position.y=this.latest[e.id].position.y,e.position.z=this.latest[e.id].position.z,e.scale.x=this.latest[e.id].scale.x,e.scale.y=this.latest[e.id].scale.y,e.scale.z=this.latest[e.id].scale.z,e.quaternion.axis.x=this.latest[e.id].quaternion.axis.x,e.quaternion.axis.y=this.latest[e.id].quaternion.axis.y,e.quaternion.axis.z=this.latest[e.id].quaternion.axis.z,e.quaternion.angle=this.latest[e.id].quaternion.angle,delete this.latest[e.id],t=!0),this.animations[e.id]&&(delete this.animations[e.id],t=!0),t&&e.updateInstance()},GameLib.System.Animation.prototype.attachAnimation=function(e,t){if(this.latest[t.id]={rotation:{x:t.rotation.x,y:t.rotation.y,z:t.rotation.z},position:{x:t.position.x,y:t.position.y,z:t.position.z},scale:{x:t.scale.x,y:t.scale.y,z:t.scale.z},quaternion:{axis:{x:t.quaternion.axis.x,y:t.quaternion.axis.y,z:t.quaternion.axis.z},angle:t.quaternion.angle}},this.animations[t.id]=[],t.backupRotationXDescriptor)throw new Error("already a backed up x descriptor");t.backupQuaternionAngleDescriptor=Object.getOwnPropertyDescriptor(t.quaternion,"angle"),t.backupQuaternionAxisXDescriptor=Object.getOwnPropertyDescriptor(t.quaternion.axis,"x"),t.backupQuaternionAxisYDescriptor=Object.getOwnPropertyDescriptor(t.quaternion.axis,"y"),t.backupQuaternionAxisZDescriptor=Object.getOwnPropertyDescriptor(t.quaternion.axis,"z"),t.backupRotationXDescriptor=Object.getOwnPropertyDescriptor(t.rotation,"x"),t.backupRotationYDescriptor=Object.getOwnPropertyDescriptor(t.rotation,"y"),t.backupRotationZDescriptor=Object.getOwnPropertyDescriptor(t.rotation,"z"),t.backupPositionXDescriptor=Object.getOwnPropertyDescriptor(t.position,"x"),t.backupPositionYDescriptor=Object.getOwnPropertyDescriptor(t.position,"y"),t.backupPositionZDescriptor=Object.getOwnPropertyDescriptor(t.position,"z"),t.backupScaleXDescriptor=Object.getOwnPropertyDescriptor(t.scale,"x"),t.backupScaleYDescriptor=Object.getOwnPropertyDescriptor(t.scale,"y"),t.backupScaleZDescriptor=Object.getOwnPropertyDescriptor(t.scale,"z"),Object.defineProperty(t.quaternion,"angle",{get:this.getProperty(t,"angle","quaternion"),set:this.setProperty(t,e,"angle","quaternion"),configurable:!0}),Object.defineProperty(t.quaternion.axis,"x",{get:this.getSubProperty(t,"x","quaternion","axis"),set:this.setSubProperty(t,e,"x","quaternion","axis"),configurable:!0}),Object.defineProperty(t.quaternion.axis,"y",{get:this.getSubProperty(t,"y","quaternion","axis"),set:this.setSubProperty(t,e,"y","quaternion","axis"),configurable:!0}),Object.defineProperty(t.quaternion.axis,"z",{get:this.getSubProperty(t,"z","quaternion","axis"),set:this.setSubProperty(t,e,"z","quaternion","axis"),configurable:!0}),Object.defineProperty(t.rotation,"x",{get:this.getProperty(t,"x","rotation"),set:this.setProperty(t,e,"x","rotation"),configurable:!0}),Object.defineProperty(t.rotation,"y",{get:this.getProperty(t,"y","rotation"),set:this.setProperty(t,e,"y","rotation"),configurable:!0}),Object.defineProperty(t.rotation,"z",{get:this.getProperty(t,"z","rotation"),set:this.setProperty(t,e,"z","rotation"),configurable:!0}),Object.defineProperty(t.scale,"x",{get:this.getProperty(t,"x","scale"),set:this.setProperty(t,e,"x","scale"),configurable:!0}),Object.defineProperty(t.scale,"y",{get:this.getProperty(t,"y","scale"),set:this.setProperty(t,e,"y","scale"),configurable:!0}),Object.defineProperty(t.scale,"z",{get:this.getProperty(t,"z","scale"),set:this.setProperty(t,e,"z","scale"),configurable:!0}),Object.defineProperty(t.position,"x",{get:this.getProperty(t,"x","position"),set:this.setProperty(t,e,"x","position"),configurable:!0}),Object.defineProperty(t.position,"y",{get:this.getProperty(t,"y","position"),set:this.setProperty(t,e,"y","position"),configurable:!0}),Object.defineProperty(t.position,"z",{get:this.getProperty(t,"z","position"),set:this.setProperty(t,e,"z","position"),configurable:!0})},GameLib.System.Animation.prototype.getSubProperty=function(e,t,i,n){return function(){return this.latest[e.id][i][n][t]}.bind(this)},GameLib.System.Animation.prototype.setSubProperty=function(e,t,i,n,a){return function(s){var o=Number(this.latest[e.id][n][a][i]);this.latest[e.id][n][a][i]=s,this.animations[e.id].push({type:n,axis:i,from:o,to:s,animation:t,mesh:e})}.bind(this)},GameLib.System.Animation.prototype.getProperty=function(e,t,i){return function(){return this.latest[e.id][i][t]}.bind(this)},GameLib.System.Animation.prototype.setProperty=function(e,t,i,n){return function(a){var s=Number(this.latest[e.id][n][i]);this.latest[e.id][n][i]=a,this.animations[e.id].push({type:n,axis:i,from:s,to:a,animation:t,mesh:e})}.bind(this)},GameLib.System.Animation.prototype.stop=function(){GameLib.System.prototype.stop.call(this),this.beforeRenderSubscription.remove(),this.animationMeshAddedSubscription.remove(),this.animationMeshRemovedSubscription.remove(),this.animations={},GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Mesh).map(function(e){for(var t in this.latest)this.latest.hasOwnProperty(t)&&t===e.id&&this.detachAnimation(e)}.bind(this)),this.instanceCreatedSubscription.remove(),this.removeComponentSubscription.remove(),this.textureAnimatedSubscription.remove(),this.animateTextureInstanceSubscription.remove()},GameLib.System.Audio=function(e){GameLib.System.call(this,e),this.instanceCreatedSubscription=null,this.removeComponentSubscription=null,this.playAudioSubscription=null,this.pauseAudioSubscription=null,this.stopAudioSubscription=null,this.stopAllAudioSubscription=null,this.audioComponents=[],this.toPlay=[]},GameLib.System.Audio.prototype=Object.create(GameLib.System.prototype),GameLib.System.Audio.prototype.constructor=GameLib.System.Audio,GameLib.System.Audio.prototype.start=function(){GameLib.System.prototype.start.call(this),this.instanceCreatedSubscription=GameLib.Event.Subscribe(GameLib.Event.INSTANCE_CREATED,this.instanceCreated.bind(this)),this.removeComponentSubscription=GameLib.Event.Subscribe(GameLib.Event.REMOVE_COMPONENT,this.removeComponent.bind(this)),this.playAudioSubscription=GameLib.Event.Subscribe(GameLib.Event.PLAY_AUDIO,this.playAudio.bind(this)),this.pauseAudioSubscription=GameLib.Event.Subscribe(GameLib.Event.PAUSE_AUDIO,this.pauseAudio.bind(this)),this.stopAudioSubscription=GameLib.Event.Subscribe(GameLib.Event.STOP_AUDIO,this.stopAudio.bind(this)),this.stopAllAudioSubscription=GameLib.Event.Subscribe(GameLib.Event.STOP_ALL_AUDIO,this.stopAllAudio.bind(this))},GameLib.System.Audio.prototype.instanceCreated=function(e){if(e.component instanceof GameLib.D3.Audio){GameLib.Utils.PushUnique(this.audioComponents,e.component);-1!==this.toPlay.indexOf(e.component.name)&&GameLib.Event.Emit(GameLib.Event.PLAY_AUDIO,{name:e.component.name})}},GameLib.System.Audio.prototype.playAudio=function(e){var t=!1;this.audioComponents.map(function(i){i.name===e.name&&(t=!0,i.instance||console.log("audio not ready yet"),i.instance.isPlaying&&i.overplay&&i.instance.stop(),i.instance.isPlaying||(i.instance.play(),i.instance.onEnded=function(){this.isPlaying=!1,GameLib.Event.Emit(GameLib.Event.AUDIO_ENDED,{audio:i})}))}),t||(console.log("delaying audio play until loaded for: "+e.name),this.toPlay.push(e.name))},GameLib.System.Audio.prototype.pauseAudio=function(e){},GameLib.System.Audio.prototype.stopAllAudio=function(e){this.audioComponents.map(function(e){e.instance.isPlaying&&e.instance.stop()})},GameLib.System.Audio.prototype.stopAudio=function(e){this.audioComponents.map(function(t){t.name===e.name&&t.instance.isPlaying&&t.instance.stop()})},GameLib.System.Audio.prototype.removeComponent=function(e){},GameLib.System.Audio.prototype.stop=function(){GameLib.System.prototype.stop.call(this),this.instanceCreatedSubscription.remove(),this.removeComponentSubscription.remove(),this.playAudioSubscription.remove(),this.pauseAudioSubscription.remove(),this.stopAudioSubscription.remove(),this.stopAllAudioSubscription.remove()},GameLib.System.CustomCode=function(e){GameLib.System.call(this,e),this.instanceCreatedSubscription=null,this.removeComponentSubscription=null,this.compileSuccessSubscription=null,this.compileFailedSubscription=null,this.subscriptions={}},GameLib.System.CustomCode.prototype=Object.create(GameLib.System.prototype),GameLib.System.CustomCode.prototype.constructor=GameLib.System.CustomCode,GameLib.System.CustomCode.prototype.start=function(){GameLib.System.prototype.start.call(this),GameLib.EntityManager.Instance.queryComponents(GameLib.D3.CustomCode).map(function(e){this.subscriptions[e.id]=GameLib.Event.Subscribe(e.eventId,e.instance)}.bind(this)),this.instanceCreatedSubscription=GameLib.Event.Subscribe(GameLib.Event.INSTANCE_CREATED,this.instanceCreated.bind(this)),this.removeComponentSubscription=GameLib.Event.Subscribe(GameLib.Event.REMOVE_COMPONENT,this.removeComponent.bind(this)),this.compileSuccessSubscription=GameLib.Event.Subscribe(GameLib.Event.COMPILE_SUCCESS,this.compileSuccess.bind(this)),this.compileFailedSubscription=GameLib.Event.Subscribe(GameLib.Event.COMPILE_FAILED,this.compileFailed.bind(this))},GameLib.System.CustomCode.prototype.instanceCreated=function(e){e.component instanceof GameLib.D3.CustomCode&&(this.subscriptions[e.component.id]&&(console.warn("a component already existed"),this.subscriptions[e.component.id].remove()),this.subscriptions[e.component.id]=GameLib.Event.Subscribe(e.component.eventId,e.component.instance))},GameLib.System.CustomCode.prototype.removeComponent=function(e){e.component instanceof GameLib.D3.CustomCode&&this.subscriptions[e.component.id]&&(this.subscriptions[e.component.id].remove(),delete this.subscriptions[e.component.id])},GameLib.System.CustomCode.prototype.compileSuccess=function(e){this.subscriptions[e.component.id]&&this.subscriptions[e.component.id].remove(),this.subscriptions[e.component.id]=GameLib.Event.Subscribe(e.component.eventId,e.component.instance)},GameLib.System.CustomCode.prototype.compileFailed=function(e){this.subscriptions[e.component.id]&&(this.subscriptions[e.component.id].remove(),delete this.subscriptions[e.component.id])},GameLib.System.CustomCode.prototype.stop=function(){GameLib.System.prototype.stop.call(this),this.instanceCreatedSubscription&&(this.instanceCreatedSubscription.remove(),this.instanceCreatedSubscription=null),this.removeComponentSubscription&&(this.removeComponentSubscription.remove(),this.removeComponentSubscription=null),this.compileSuccessSubscription&&(this.compileSuccessSubscription.remove(),this.compileSuccessSubscription=null),this.compileFailedSubscription&&(this.compileFailedSubscription.remove(),this.compileFailedSubscription=null),Object.keys(this.subscriptions).map(function(e){this.subscriptions[e]&&(this.subscriptions[e].remove(),delete this.subscriptions[e])}.bind(this))},GameLib.System.GUI=function(e){GameLib.System.call(this,e),this.guis=[],this.components=[],this.backupComponents=[],this.exclusiveMode=!1,this.buildGUISubscription=null,this.meshDeletedSubscription=null,this.meshSelectedSubscription=null,this.meshDeselectedSubscription=null,this.newEntitySubscription=null,this.meshSelectionObjects={}},GameLib.System.GUI.prototype=Object.create(GameLib.System.prototype),GameLib.System.GUI.prototype.constructor=GameLib.System.GUI,GameLib.System.GUI.prototype.start=function(){GameLib.System.prototype.start.call(this),this.guis=GameLib.EntityManager.Instance.queryComponents(GameLib.GUI),dat.GUI.prototype.removeEmtpyFolders=function(){for(var e in this.__folders)if(this.__folders.hasOwnProperty(e)){var t=this.__folders[e];0===t.__listening.length&&(t.close(),this.__ul.removeChild(t.domElement.parentNode),delete this.__folders[e],this.onResize())}},dat.GUI.prototype.listen=function(e){this.__listening.length;this.__listening.push(e),delete this.closed,Object.defineProperty(this,"closed",{get:function(){return this.params.closed},set:function(e){this.params.closed=e,this.params.closed?(this.dom.addClass(this.__ul,"closed"),cancelAnimationFrame(this.animationId)):(this.dom.removeClass(this.__ul,"closed"),this.updateDisplaysCallback=function(){this.animationId=requestAnimationFrame(this.updateDisplaysCallback.bind(this)),this.__listening.map(function(e){e.updateDisplay()})}.bind(this),this.animationId=requestAnimationFrame(this.updateDisplaysCallback)),this.onResize(),this.__closeButton&&(this.__closeButton.innerHTML=e?"Open Controls":"Close Controls")},configurable:!0})},dat.GUI.prototype.removeAllFolders=function(){for(var e in this.__folders)if(this.__folders.hasOwnProperty(e)){var t=this.__folders[e];cancelAnimationFrame(t.animationId),t.__controllers.map(function(e){e.remove()}),t.__controllers=[],t.__listening=[],t.close(),this.__ul.removeChild(t.domElement.parentNode),delete this.__folders[e],this.onResize()}},this.guis.map(function(e){e.domElement.instance.parentElement.appendChild(e.instance.domElement)}),this.buildGUISubscription=this.subscribe(GameLib.Event.BUILD_GUI,this.buildGUI),this.meshDeletedSubscription=this.subscribe(GameLib.Event.REMOVE_MESH,this.meshDeleted),this.meshSelectedSubscription=this.subscribe(GameLib.Event.MESH_SELECTED,this.meshSelected),this.meshDeselectedSubscription=this.subscribe(GameLib.Event.MESH_DESELECTED,this.meshDeslected),this.newEntitySubscription=this.subscribe(GameLib.Event.NEW_ENTITY,this.newEntity),this.componentRemovedSubscription=this.subscribe(GameLib.Event.REMOVE_COMPONENT,this.removeComponent)},GameLib.System.GUI.prototype.onChange=function(e,t,i){return function(n){i.map(function(i){i[e][t]=n,i instanceof GameLib.D3.Mesh&&"rotation"===e&&(i.useQuaternion=!1),i instanceof GameLib.D3.Mesh&&"quaternion"===e&&(i.useQuaternion=!0),"function"==typeof i[e].updateInstance?i[e].updateInstance(e):"function"==typeof i[e][t].updateInstance?i[e][t].updateInstance(t):i.updateInstance(e)})}},GameLib.System.GUI.prototype.controller=function(e,t,i,n,a,s,o,r,c){GameLib.Utils.UndefinedOrNull(r)&&(r=-1e3),GameLib.Utils.UndefinedOrNull(c)&&(c=1e3),"axleLocal"!==i&&"directionLocal"!==i||(r=-1,c=1,a=1),"offset"!==i&&"repeat"!==i||(r=-1e3,c=1e3,a=1e-5);var h=e.add(t[i],n,r,c,a).name(i+"."+n);return h.onChange(this.onChange(i,n,o)),s&&h.listen(),h},GameLib.System.GUI.prototype.buildQuaternionControl=function(e,t,i){var n=t.template,a=!1;1===t.affected.length&&(n=t.affected[0],a=!0);var s=t.affected;this.controller(e,n,i,"x",.1,a,s),this.controller(e,n,i,"y",.1,a,s),this.controller(e,n,i,"z",.1,a,s),this.controller(e,n,i,"w",.1,a,s),this.controller(e,n,i,"angle",.001,a,s,-Math.PI,Math.PI),e.add(n[i].axis,"x",-1,1,.01).name("quaternion.axis.x").onChange(function(e){s.map(function(t){t.useQuaternion=!0,t[i].axis.x=Number(e),t.updateInstance("x")})}),e.add(n[i].axis,"y",-1,1,.01).name("quaternion.axis.y").onChange(function(e){s.map(function(t){t.useQuaternion=!0,t[i].axis.y=Number(e),t.updateInstance("y")})}),e.add(n[i].axis,"z",-1,1,.01).name("quaternion.axis.z").onChange(function(e){s.map(function(t){t.useQuaternion=!0,t[i].axis.z=Number(e),t.updateInstance("z")})})},GameLib.System.GUI.prototype.buildVectorControl=function(e,t,i){var n=t.template,a=!1;1===t.affected.length&&(n=t.affected[0],a=!0);var s=t.affected,o=[];GameLib.Utils.isVector4(n[i])&&o.push(this.controller(e,n,i,"w",.01,a,s)),o.push(this.controller(e,n,i,"x",.01,a,s)),o.push(this.controller(e,n,i,"y",.01,a,s)),(GameLib.Utils.isVector3(n[i])||GameLib.Utils.isVector4(n[i]))&&o.push(this.controller(e,n,i,"z",.01,a,s))},GameLib.System.GUI.prototype.buildParentSelectionControl=function(e,t,i){var n=null;"parentEntity"===i&&(n=GameLib.Entity),"parentMesh"===i&&(n=GameLib.D3.Mesh),"parentWorld"===i&&(n=GameLib.D3.PhysicsWorld),"parentScene"===i&&(n=GameLib.D3.Scene);var a=GameLib.EntityManager.Instance.queryComponents(n).reduce(function(e,t){return e[t.name]=t,e},{none:null}),s=t.template,o=t.affected;e.add(s,i,a).listen().onChange(function(e){var t=null;"null"!==e&&(t=GameLib.EntityManager.Instance.findComponentById(e)),o.map(function(e){e[i]=t,"parentEntity"===i&&GameLib.Event.Emit(GameLib.Event.PARENT_ENTITY_CHANGE,{originalEntity:this.initialValue,newEntity:t,object:e}),"parentWorld"===i&&GameLib.Event.Emit(GameLib.Event.PARENT_WORLD_CHANGE,{originalWorld:this.initialValue,newWorld:t,object:e}),"parentScene"===i&&GameLib.Event.Emit(GameLib.Event.PARENT_SCENE_CHANGE,{originalScene:this.initialValue,newScene:t,object:e})}.bind(this)),"parentEntity"===i&&GameLib.Event.Emit(GameLib.Event.BUILD_GUI,null),this.initialValue=t})},GameLib.System.GUI.prototype.buildArrayManagerControl=function(e,t,i){var n=t.template.linkedObjects[i];if(!(n instanceof Array))return void console.error("data mismatch - something not an array");var a=t.template,s=a[i],o=function(n,a){var s="invalid item";n&&n.name&&(s=n.name);var o=e.add({remove:function(){t.affected.map(function(t){t[i].splice(a,1),e.remove(o)})}},"remove").name("remove "+i+"["+a+"] - "+s);e.updateDisplay()};s.map(o);var r={},c=GameLib.EntityManager.Instance.queryComponents(n).reduce(function(e,t){return e[t.name]=t,r[t.id]=t,e},{none:null}),h={component:null,add:function(){t.affected.map(function(e){-1===e[i].indexOf(h.component)&&(e[i].push(h.component),GameLib.Event.Emit(GameLib.Event.ARRAY_ITEM_ADDED,{component:e,property:i,item:h.component}))}),GameLib.Event.Emit(GameLib.Event.BUILD_GUI)}};e.add(h,"component",c).name("select "+i).onChange(function(e){h.component="null"===e?null:r[e]}).listen(),e.add(h,"add").name("add to "+i)},GameLib.System.GUI.prototype.buildColorControl=function(e,t,i){var n=t.template,a={hexColor:n[i].toHex()};e.addColor(a,"hexColor").name(i).listen().onChange(function(e){t.affected.map(function(t){t[i].fromHex(e),t[i].updateInstance(i)})}),e.add(a,"hexColor").name(i).listen().onChange(function(e){t.affected.map(function(t){t[i].fromHex(e),t[i].updateInstance(i)})})},GameLib.System.GUI.prototype.buildSelectControl=function(e,t,i){var n=null;t.template[i]?n=t.template[i].constructor:t.template.linkedObjects[i]&&(n=t.template.linkedObjects[i]);var a=t.template,s=GameLib.EntityManager.Instance.queryComponents(n),o={},r=s.reduce(function(e,t){return e[t.name]=t,o[t.id]=t,e},{none:null});e.add(a,i,r).name(i).listen().onChange(function(e){var n=null;"null"!==e&&(n=o[e]),t.affected.map(function(e){e[i]=n,e.updateInstance(i)}),this.initialValue=n})},GameLib.System.GUI.prototype.buildControl=function(e,t,i){var n=t.template,a=!1;1===t.affected.length&&(n=t.affected[0],a=!0);var s=t.componentType,o=[];if((GameLib.Utils.isString(n[i])||GameLib.Utils.isBoolean(n[i]))&&o.push(e.add(n,i)),GameLib.Utils.isNumber(n[i])){if(n.grain&&n.grain,"systemType"===i)o.push(e.add(n,i,{animation:GameLib.System.SYSTEM_TYPE_ANIMATION,gui:GameLib.System.SYSTEM_TYPE_GUI,input:GameLib.System.SYSTEM_TYPE_INPUT,render:GameLib.System.SYSTEM_TYPE_RENDER,storage:GameLib.System.SYSTEM_TYPE_STORAGE,linking:GameLib.System.SYSTEM_TYPE_LINKING,physics:GameLib.System.SYSTEM_TYPE_PHYSICS,"custom code":GameLib.System.SYSTEM_TYPE_CUSTOM}));else if("opacityType"===i)o.push(e.add(n,i,{constant:GameLib.D3.Particle.OPACITY_TYPE_CONSTANT,decrease:GameLib.D3.Particle.OPACITY_TYPE_DECREASE_LINEAR,increase:GameLib.D3.Particle.OPACITY_TYPE_INCREASE_LINEAR}));else if("positionOffsetType"===i)o.push(e.add(n,i,{constant:GameLib.D3.Particle.POSITION_OFFSET_TYPE_CONSTANT,random:GameLib.D3.Particle.POSITION_OFFSET_TYPE_RANDOM,function:GameLib.D3.Particle.POSITION_OFFSET_TYPE_FUNCTION}));else if("directionType"===i)o.push(e.add(n,i,{constant:GameLib.D3.Particle.DIRECTION_TYPE_CONSTANT,random:GameLib.D3.Particle.DIRECTION_TYPE_RANDOM,"random normalized":GameLib.D3.Particle.DIRECTION_TYPE_RANDOM_NORMALIZED,function:GameLib.D3.Particle.DIRECTION_TYPE_FUNCTION}));else if("speedType"===i)o.push(e.add(n,i,{constant:GameLib.D3.Particle.SPEED_TYPE_CONSTANT,linear:GameLib.D3.Particle.SPEED_TYPE_LINEAR,exponential:GameLib.D3.Particle.SPEED_TYPE_EXPONENTIAL,logarithmic:GameLib.D3.Particle.SPEED_TYPE_LOGARITHMIC,"1 / log":GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_LOG,exp:GameLib.D3.Particle.SPEED_TYPE_EXP,"1 / exp":GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_EXP}));else if("scaleType"===i)o.push(e.add(n,i,{constant:GameLib.D3.Particle.SCALE_TYPE_CONSTANT,linear:GameLib.D3.Particle.SCALE_TYPE_LINEAR,exponential:GameLib.D3.Particle.SCALE_TYPE_EXPONENTIAL,random:GameLib.D3.Particle.SCALE_TYPE_RANDOM,"random (x = y)":GameLib.D3.Particle.SCALE_TYPE_RANDOM_X_EQUALS_Y,function:GameLib.D3.Particle.SCALE_TYPE_FUNCTION}));else if("rotationType"===i)o.push(e.add(n,i,{constant:GameLib.D3.Particle.ROTATION_TYPE_CONSTANT,random:GameLib.D3.Particle.ROTATION_TYPE_RANDOM,function:GameLib.D3.Particle.ROTATION_TYPE_FUNCTION}));else if("broadphaseType"===i)o.push(e.add(n,i,{naive:GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE,grid:GameLib.D3.Image.BROADPHASE_TYPE_GRID,sap:GameLib.D3.Image.BROADPHASE_TYPE_SAP}));else if("solverType"===i)o.push(e.add(n,i,{gs:GameLib.D3.Solver.GS_SOLVER,split:GameLib.D3.Solver.SPLIT_SOLVER}));else if("meshType"===i)o.push(e.add(n,i,{normal:GameLib.D3.Mesh.MESH_TYPE_NORMAL,curve:GameLib.D3.Mesh.MESH_TYPE_CURVE,skinned:GameLib.D3.Mesh.MESH_TYPE_SKINNED,plane:GameLib.D3.Mesh.MESH_TYPE_PLANE,sphere:GameLib.D3.Mesh.MESH_TYPE_SPHERE,box:GameLib.D3.Mesh.MESH_TYPE_BOX,cylinder:GameLib.D3.Mesh.MESH_TYPE_CYLINDER,text:GameLib.D3.Mesh.MESH_TYPE_TEXT}));else if("cameraType"===i)o.push(e.add(n,i,{perspective:GameLib.D3.Camera.CAMERA_TYPE_PERSPECTIVE,orthographic:GameLib.D3.Camera.CAMERA_TYPE_ORTHOGONAL}));else if("materialType"===i)o.push(e.add(n,i,{standard:GameLib.D3.Material.MATERIAL_TYPE_STANDARD,basic:GameLib.D3.Material.MATERIAL_TYPE_BASIC,phong:GameLib.D3.Material.MATERIAL_TYPE_PHONG,points:GameLib.D3.Material.MATERIAL_TYPE_POINTS,"line basic":GameLib.D3.Material.MATERIAL_TYPE_LINE_BASIC}));else if("side"===i)o.push(e.add(n,i,{double:GameLib.D3.Material.TYPE_DOUBLE_SIDE,front:GameLib.D3.Material.TYPE_FRONT_SIDE,back:GameLib.D3.Material.TYPE_BACK_SIDE}));else if("combine"===i)o.push(e.add(n,i,{multiply:GameLib.D3.Material.TYPE_MULTIPLY_OPERATION,mix:GameLib.D3.Material.TYPE_MIX_OPERATION,add:GameLib.D3.Material.TYPE_ADD_OPERATION}));else if("vertexColors"===i)o.push(e.add(n,i,{none:GameLib.D3.Material.TYPE_NO_COLORS,face:GameLib.D3.Material.TYPE_FACE_COLORS,vertex:GameLib.D3.Material.TYPE_VERTEX_COLORS}));else if("blending"===i)o.push(e.add(n,i,{none:GameLib.D3.Material.TYPE_NO_BLENDING,normal:GameLib.D3.Material.TYPE_NORMAL_BLENDING,additive:GameLib.D3.Material.TYPE_ADDITIVE_BLENDING,subtractive:GameLib.D3.Material.TYPE_SUBTRACTIVE_BLENDING,multiply:GameLib.D3.Material.TYPE_MULTIPLY_BLENDING,custom:GameLib.D3.Material.TYPE_CUSTOM_BLENDING}));else if("blendSrc"===i)o.push(e.add(n,i,{zero:GameLib.D3.Material.TYPE_ZERO_FACTOR,one:GameLib.D3.Material.TYPE_ONE_FACTOR,"source color":GameLib.D3.Material.TYPE_SRC_COLOR_FACTOR,"one minus source color":GameLib.D3.Material.TYPE_ONE_MINUS_SRC_COLOR_FACTOR,"source alpha":GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR,"one minus source alpha":GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR,"destination alpha":GameLib.D3.Material.TYPE_DST_ALPHA_FACTOR,"one minus destination alpha":GameLib.D3.Material.TYPE_ONE_MINUS_DST_ALPHA_FACTOR,"destination color":GameLib.D3.Material.TYPE_DST_COLOR_FACTOR,"one minus destination color":GameLib.D3.Material.TYPE_ONE_MINUS_DST_COLOR_FACTOR,"source alpha saturate":GameLib.D3.Material.TYPE_SRC_ALPHA_SATURATE_FACTOR}));else if("blendDst"===i)o.push(e.add(n,i,{zero:GameLib.D3.Material.TYPE_ZERO_FACTOR,one:GameLib.D3.Material.TYPE_ONE_FACTOR,"source color":GameLib.D3.Material.TYPE_SRC_COLOR_FACTOR,"one minus source color":GameLib.D3.Material.TYPE_ONE_MINUS_SRC_COLOR_FACTOR,"source alpha":GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR,"one minus source alpha":GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR,"destination alpha":GameLib.D3.Material.TYPE_DST_ALPHA_FACTOR,"one minus destination alpha":GameLib.D3.Material.TYPE_ONE_MINUS_DST_ALPHA_FACTOR,"destination color":GameLib.D3.Material.TYPE_DST_COLOR_FACTOR,"one minus destination color":GameLib.D3.Material.TYPE_ONE_MINUS_DST_COLOR_FACTOR,"source alpha saturate":GameLib.D3.Material.TYPE_SRC_ALPHA_SATURATE_FACTOR}));else if("blendEquation"===i)o.push(e.add(n,i,{add:GameLib.D3.Material.TYPE_ADD_EQUATION,subtract:GameLib.D3.Material.TYPE_SUBTRACT_EQUATION,"reverse subtract":GameLib.D3.Material.TYPE_REVERSE_SUBTRACT_EQUATION,min:GameLib.D3.Material.TYPE_MIN_EQUATION,max:GameLib.D3.Material.TYPE_MAX_EQUATION}));else if("depthFunc"===i)o.push(e.add(n,i,{never:GameLib.D3.Material.TYPE_NEVER_DEPTH,always:GameLib.D3.Material.TYPE_ALWAYS_DEPTH,"less depth":GameLib.D3.Material.TYPE_LESS_DEPTH,"less equal depth":GameLib.D3.Material.TYPE_LESS_EQUAL_DEPTH,"equal depth":GameLib.D3.Material.TYPE_EQUAL_DEPTH,"greated equal depth":GameLib.D3.Material.TYPE_GREATER_EQUAL_DEPTH,"greated depth":GameLib.D3.Material.TYPE_GREATER_DEPTH,"not equal depth":GameLib.D3.Material.TYPE_NOT_EQUAL_DEPTH}));else if("wrapS"===i)o.push(e.add(n,i,{repeat:GameLib.D3.Texture.TYPE_REPEAT_WRAPPING,clamp:GameLib.D3.Texture.TYPE_CLAMP_TO_EDGE_WRAPPING,"mirrored repeat":GameLib.D3.Texture.TYPE_MIRRORED_REPEAT_WRAPPING}));else if("wrapT"===i)o.push(e.add(n,i,{repeat:GameLib.D3.Texture.TYPE_REPEAT_WRAPPING,clamp:GameLib.D3.Texture.TYPE_CLAMP_TO_EDGE_WRAPPING,"mirrored repeat":GameLib.D3.Texture.TYPE_MIRRORED_REPEAT_WRAPPING}));else if("format"===i)o.push(e.add(n,i,{alpha:GameLib.D3.Texture.TYPE_ALPHA_FORMAT,rgb:GameLib.D3.Texture.TYPE_RGB_FORMAT,rgba:GameLib.D3.Texture.TYPE_RGBA_FORMAT,luminance:GameLib.D3.Texture.TYPE_LUMINANCE_FORMAT,"luminance alpha":GameLib.D3.Texture.TYPE_LUMINANCE_ALPHA_FORMAT,depth:GameLib.D3.Texture.TYPE_DEPTH_FORMAT}));else if("mapping"===i)o.push(e.add(n,i,{uv:GameLib.D3.Texture.TYPE_UV_MAPPING,"cube reflection":GameLib.D3.Texture.TYPE_CUBE_REFLECTION_MAPPING,"cube refraction":GameLib.D3.Texture.TYPE_CUBE_REFRACTION_MAPPING,"equi rectangular reflection":GameLib.D3.Texture.TYPE_EQUI_RECTANGULAR_REFLECTION_MAPPING,"equi rectangular refraction":GameLib.D3.Texture.TYPE_EQUI_RECTANGULAR_REFRACTION_MAPPING,"spherical reflection":GameLib.D3.Texture.TYPE_SPHERICAL_REFLECTION_MAPPING,"cube uv reflection":GameLib.D3.Texture.TYPE_CUBE_UV_REFLECTION_MAPPING,"cube uv refraction":GameLib.D3.Texture.TYPE_CUBE_UV_REFRACTION_MAPPING}));else if("magFilter"===i)o.push(e.add(n,i,{nearest:GameLib.D3.Texture.TYPE_NEAREST_FILTER,"nearest mipmap nearest":GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_NEAREST_FILTER,"nearest mipmap linear":GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_LINEAR_FILTER,linear:GameLib.D3.Texture.TYPE_LINEAR_FILTER,"linear mipmap nearest":GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_NEAREST_FILTER,"linear mipmap linear":GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER}));else if("minFilter"===i)o.push(e.add(n,i,{nearest:GameLib.D3.Texture.TYPE_NEAREST_FILTER,"nearest mipmap nearest":GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_NEAREST_FILTER,"nearest mipmap linear":GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_LINEAR_FILTER,linear:GameLib.D3.Texture.TYPE_LINEAR_FILTER,"linear mipmap nearest":GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_NEAREST_FILTER,"linear mipmap linear":GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER}));else if(s===GameLib.Component.COMPONENT_TEXTURE&&"typeId"===i)o.push(e.add(n,i,{normal:GameLib.D3.Texture.TEXTURE_TYPE_NORMAL,cube:GameLib.D3.Texture.TEXTURE_TYPE_CUBE,canvas:GameLib.D3.Texture.TEXTURE_TYPE_CANVAS}));else if("textureType"===i)o.push(e.add(n,i,{"unsigned byte":GameLib.D3.Texture.TYPE_UNSIGNED_BYTE,byte:GameLib.D3.Texture.TYPE_BYTE,short:GameLib.D3.Texture.TYPE_SHORT,"unsigned short":GameLib.D3.Texture.TYPE_UNSIGNED_SHORT,int:GameLib.D3.Texture.TYPE_INT,"unsigned int":GameLib.D3.Texture.TYPE_UNSIGNED_INT,float:GameLib.D3.Texture.TYPE_FLOAT,"half float":GameLib.D3.Texture.TYPE_HALF_FLOAT}));else if("encoding"===i)o.push(e.add(n,i,{linear:GameLib.D3.Texture.TYPE_LINEAR_ENCODING,srgb:GameLib.D3.Texture.TYPE_SRGB_ENCODING,gamma:GameLib.D3.Texture.TYPE_GAMMA_ENCODING,rgbe:GameLib.D3.Texture.TYPE_RGBE_ENCODING,"log luv":GameLib.D3.Texture.TYPE_LOG_LUV_ENCODING,rgbm7:GameLib.D3.Texture.TYPE_RGBM7_ENCODING,rgbm16:GameLib.D3.Texture.TYPE_RGBM16_ENCODING,rgbd:GameLib.D3.Texture.TYPE_RGBD_ENCODING}));else if("lightType"===i)o.push(e.add(n,i,{ambient:GameLib.D3.Light.LIGHT_TYPE_AMBIENT,directional:GameLib.D3.Light.LIGHT_TYPE_DIRECTIONAL,spot:GameLib.D3.Light.LIGHT_TYPE_SPOT,point:GameLib.D3.Light.LIGHT_TYPE_POINT}));else if("eventId"===i){for(var r={},c=0;c<200;c++)try{r[GameLib.Event.GetEventName(c)]=c}catch(e){}o.push(e.add(n,i,r))}else"functionType"===i?o.push(e.add(n,i,{rotation:GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_ROTATION,translation:GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_TRANSLATION,scale:GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_SCALE})):"opacity"===i||"opacityFactor"===i||"metalness"===i||"roughness"===i||"volume"===i?o.push(e.add(n,i,0,1,.001)):"shininess"===i||"fov"===i?o.push(e.add(n,i,-255,255,1)):"aspect"===i||"wireframeLineWidth"===i||"lineWidth"===i?o.push(e.add(n,i,0,5,.001)):"bumpScale"===i||"normalScale"===i||"displacementScale"===i||"heightMapScale"===i||"intensity"===i?o.push(e.add(n,i,-10,10,.001)):"minX"===i||"minY"===i||"minZ"===i||"maxX"===i||"maxY"===i||"maxZ"===i||"offsetX"===i?o.push(e.add(n,i,-1e3,1e3,.01)):"widthSegments"===i||"radiusSegments"===i||"heightSegments"===i||"particlesPerSecond"===i?o.push(e.add(n,i,1,1e3,1)):"width"===i||"height"===i||"depth"===i||"radius"===i?o.push(e.add(n,i,0,1e3,.1)):"near"===i||"distanceGrain"===i||"envMapIntensity"===i?o.push(e.add(n,i,-10,100,.001)):"bumpScale"===i?o.push(e.add(n,i,0,20,.001)):"heightOffset"===i||"rotationFactor"===i?o.push(e.add(n,i,-100,100,.001)):"friction"===i?o.push(e.add(n,i,0,1e3,.01)):"radiusTop"===i||"radiusBottom"===i?o.push(e.add(n,i,0,100,.1)):"mass"===i?o.push(e.add(n,i,0,1e3,.1)):"sensitivity"===i?o.push(e.add(n,i,1,50,1)):"density"===i?o.push(e.add(n,i,0,1,1e-6)):"thetaLength"===i||"angle"===i?o.push(e.add(n,i,2*-Math.PI,2*Math.PI,.01)):o.push(e.add(n,i,-1e3,1e3,.1))}o.map(function(n){"name"===i?n.onFinishChange(function(e,n){return function(e){t.affected.map(function(t){t[i]=e,t.updateInstance(i)}),n.domElement.getElementsByClassName("title")[0].innerHTML=e}}(0,e)):n.onChange(function(e){"number"==typeof this.initialValue&&(e=Number(e)),t.affected.map(function(t){t[i]=e,t.updateInstance(i)})}),a&&n.listen()})},GameLib.System.GUI.prototype.meshSelected=function(e){this.exclusiveMode?GameLib.Utils.PushUnique(this.backupComponents,e.mesh):GameLib.Utils.PushUnique(this.components,e.mesh)},GameLib.System.GUI.prototype.meshDeslected=function(e){var t=-1;this.exclusiveMode?-1!==(t=this.backupComponents.indexOf(e.mesh))&&this.backupComponents.splice(t,1):-1!==(t=this.components.indexOf(e.mesh))&&this.components.splice(t,1)},GameLib.System.GUI.prototype.buildGUI=function(e){this.guis.map(function(t){if(t.instance.destroy(),t.removeAllFolders(),e&&(e.components?(this.exclusiveMode||(this.exclusiveMode=!0,this.backupComponents=this.components.map(function(e){return e})),this.components=e.components.map(function(e){return e})):this.exclusiveMode?(this.exclusiveMode=!1,this.components=this.backupComponents.map(function(e){return e})):console.log("we are already not in mesh select mode - not doing anything with the backup")),this.exclusiveMode||(this.components=this.components.filter(function(e){return e instanceof GameLib.D3.Mesh})),!(GameLib.Utils.UndefinedOrNull(this.components.length)||this.components.length<1)){this.exclusiveMode||(this.components=this.components.reduce(function(e,t){var i=t.getChildrenComponents() +;return GameLib.Utils.PushUnique(e,t),i.map(function(t){GameLib.Utils.PushUnique(e,t)}),e}.bind(this),[])),this.components.sort(function(e,t){return e.componentType>t.componentType?1:e.componentType0?console.log("ignoring multiple editor controls"):(this.editorControls.push(e.component),this.registerEditorControls())),e.component instanceof GameLib.D3.Controls.Touch&&(this.touchControls.length>0?console.log("ignoring multiple touch controls"):(this.touchControls.push(e.component),this.registerTouchControls())),e.component instanceof GameLib.D3.Controls.Keyboard&&(this.keyboardControls.length>0?console.log("ignoring multiple keyboard controls"):(this.keyboardControls.push(e.component),this.registerKeyboardControls())),e.component instanceof GameLib.D3.Controls.Mouse&&(this.mouseControls.length>0?console.log("ignoring multiple mouse controls"):(this.mouseControls.push(e.component),this.registerMouseControls()))},GameLib.System.Input.prototype.removeComponent=function(e){if(e.component instanceof GameLib.D3.Controls.Editor){var t=this.editorControls.indexOf(e.component);-1!==t?(console.log("removing editor controls from system"),this.deRegisterEditorControls(),this.editorControls.splice(t,1)):console.log("failed to find the editor controls in the system - probably it was ignored - "+e.component.name)}},GameLib.System.Input.prototype.delayedInstanceEncountered=function(e){e.component instanceof GameLib.D3.Controls.Editor&&(0===this.editorControls.length?(this.editorControls.push(e.component),this.registerEditorControls()):e.component.createInstance())},GameLib.System.Input.prototype.registerTouchControls=function(){if(1===this.touchControls.length){var e=this.touchControls[0];this.touchSensitivity=e.sensitivity,this.touchStart=this.onTouchStart.bind(this),this.touchMove=this.onTouchMove.bind(this),this.touchEnd=this.onTouchEnd.bind(this),this.touchCancel=this.onTouchCancel.bind(this),e.domElement.instance.addEventListener("touchstart",this.touchStart,!1),e.domElement.instance.addEventListener("touchmove",this.touchMove,!1),e.domElement.instance.addEventListener("touchend",this.touchEnd,!1),e.domElement.instance.addEventListener("touchcancel",this.touchCancel,!1)}},GameLib.System.Input.prototype.registerKeyboardControls=function(){if(1===this.keyboardControls.length){var e=this.keyboardControls[0];this.keyboardKeyUp=this.onKeyboardKeyUp.bind(this),this.keyboardKeyDown=this.onKeyboardKeyDown.bind(this),e.domElement.instance.addEventListener("keyup",this.keyboardKeyUp,!1),e.domElement.instance.addEventListener("keydown",this.keyboardKeyDown,!1)}},GameLib.System.Input.prototype.registerMouseControls=function(){if(1===this.mouseControls.length){var e=this.mouseControls[0];this.mouseDown=this.onMouseDown.bind(this),this.mouseMove=this.onMouseMove.bind(this),this.mouseWheel=this.onMouseWheel.bind(this),this.mouseUp=this.onMouseUp.bind(this),e.domElement.instance.addEventListener("mousedown",this.mouseDown,!1),e.domElement.instance.addEventListener("mousemove",this.mouseMove,!1),e.domElement.instance.addEventListener("wheel",this.mouseWheel,!1),e.domElement.instance.addEventListener("mouseup",this.mouseUp,!1)}},GameLib.System.Input.prototype.registerEditorControls=function(){if(1===this.editorControls.length){var e=this.editorControls[0];this.mouseDownEdit=this.onMouseDownEdit.bind(this),this.mouseMoveEdit=this.onMouseMoveEdit.bind(this),e.domElement.instance.addEventListener("mousedown",this.mouseDownEdit,!1),e.domElement.instance.addEventListener("mousemove",this.mouseMoveEdit,!1),this.keyboardControls.length>0||(this.keyDown=this.onKeyDown.bind(this),this.keyUp=this.onKeyUp.bind(this),e.domElement.instance.addEventListener("keydown",this.keyDown,!1),e.domElement.instance.addEventListener("keyup",this.keyUp,!1)),e.createInstance(),this.mouseWheelEdit=this.onMouseWheelEdit.bind(this),this.mouseUpEdit=this.onMouseUpEdit.bind(this),e.domElement.instance.addEventListener("wheel",this.mouseWheelEdit,!1),e.domElement.instance.addEventListener("mouseup",this.mouseUpEdit,!1)}},GameLib.System.Input.prototype.deRegisterEditorControls=function(){if(1===this.editorControls.length){var e=this.editorControls[0];e.domElement.instance.removeEventListener("mousedown",this.mouseDownEdit,!1),e.domElement.instance.removeEventListener("mousemove",this.mouseMoveEdit,!1),this.keyboardControls.length<1&&(e.domElement.instance.removeEventListener("keydown",this.keyDown,!1),e.domElement.instance.removeEventListener("keyup",this.keyUp,!1)),e.instance.dispose(),e.domElement.instance.removeEventListener("wheel",this.mouseWheelEdit,!1),e.domElement.instance.removeEventListener("mouseup",this.mouseUpEdit,!1)}},GameLib.System.Input.prototype.deRegisterTouchControls=function(){if(1===this.touchControls.length){var e=this.touchControls[0];e.domElement.instance.removeEventListener("touchstart",this.touchStart,!1),e.domElement.instance.removeEventListener("touchmove",this.touchMove,!1),e.domElement.instance.removeEventListener("touchend",this.touchEnd,!1),e.domElement.instance.removeEventListener("touchcancel",this.touchCancel,!1)}},GameLib.System.Input.prototype.deRegisterKeyboardControls=function(){if(1===this.keyboardControls.length){var e=this.keyboardControls[0];e.domElement.instance.removeEventListener("keydown",this.keyboardKeyDown,!1),e.domElement.instance.removeEventListener("keyup",this.keyboardKeyUp,!1)}},GameLib.System.Input.prototype.deRegisterMouseControls=function(){if(1===this.mouseControls.length){var e=this.mouseControls[0];e.domElement.instance.removeEventListener("mousedown",this.mouseDown,!1),e.domElement.instance.removeEventListener("mousemove",this.mouseMove,!1),e.domElement.instance.removeEventListener("wheel",this.mouseWheel,!1),e.domElement.instance.removeEventListener("mouseup",this.mouseUp,!1)}},GameLib.System.Input.prototype.onKeyboardKeyUp=function(e){GameLib.Event.Emit(GameLib.Event.KEY_DOWN,{code:e.code})},GameLib.System.Input.prototype.onKeyboardKeyDown=function(e){GameLib.Event.Emit(GameLib.Event.KEY_UP,{code:e.code})},GameLib.System.Input.prototype.onTouchStart=function(e){this.sensitivityCounter=0,this.touches={};for(var t=0;te.changedTouches[a].pageX&&(r+=s),this.touches[t].lastTouchY>e.changedTouches[a].pageY&&(h+=o),this.touches[t].lastTouchY=this.touchSensitivity&&(this.sensitivityCounter=0,GameLib.Event.Emit(GameLib.Event.TOUCH_MOVE,this.touches))},GameLib.System.Input.prototype.onTouchCancel=function(e){this.sensitivityCounter=0;for(var t=0;tt.distance?1:0});var a=n.map(function(e){return e.mesh}),s=a[0];s&&(e.preventDefault(),e.stopImmediatePropagation(),s.selected?this.deSelectMesh(s):this.selectMesh(s),GameLib.Event.Emit(GameLib.Event.BUILD_GUI,null))}}.bind(this))},GameLib.System.Input.prototype.onMouseMoveEdit=function(e){},GameLib.System.Input.prototype.onMouseUpEdit=function(e){this.editorControls.map(function(e){e.camera.position.x=e.camera.instance.position.x,e.camera.position.y=e.camera.instance.position.y,e.camera.position.z=e.camera.instance.position.z,e.camera.quaternion.x=e.camera.instance.quaternion.x,e.camera.quaternion.y=e.camera.instance.quaternion.y,e.camera.quaternion.z=e.camera.instance.quaternion.z,e.camera.quaternion.w=e.camera.instance.quaternion.w,e.camera.lookAt.x=e.instance.center.x,e.camera.lookAt.y=e.instance.center.y,e.camera.lookAt.z=e.instance.center.z,e.camera.lookAt.instance.copy(e.instance.center)})},GameLib.System.Input.prototype.onMouseWheelEdit=function(e){this.editorControls.map(function(e){e.camera.position.x=e.camera.instance.position.x,e.camera.position.y=e.camera.instance.position.y,e.camera.position.z=e.camera.instance.position.z})},GameLib.System.Input.prototype.selectMesh=function(e){!0!==e.selected&&(e.selected=!0,e.createHelper(),GameLib.Event.Emit(GameLib.Event.MESH_SELECTED,{mesh:e}))},GameLib.System.Input.prototype.deSelectMesh=function(e){e.selected=!1,e.removeHelper(),GameLib.Event.Emit(GameLib.Event.MESH_DESELECTED,{mesh:e})},GameLib.System.Linking=function(e){GameLib.System.call(this,e),this.dependencies={},this.resolved=[],this.componentCreatedSubscription=null,this.componentClonedSubscription=null,this.registerDependenciesSubscription=null,this.componentRemoveSubscription=null,this.parentSceneChangeSubscription=null,this.parentWorldChangeSubscription=null,this.parentEntityChangeSubscription=null,this.instanceCreatedSubscription=null,this.instanceClonedSubscription=null,this.removeMeshSubscription=null,this.imageChangedSubscription=null,this.materialTypeChangedSubscription=null,this.arrayItemAddedSubscription=null},GameLib.System.Linking.prototype=Object.create(GameLib.System.prototype),GameLib.System.Linking.prototype.constructor=GameLib.System.Linking,GameLib.System.Linking.prototype.start=function(){GameLib.System.prototype.start.call(this),this.componentCreatedSubscription=this.subscribe(GameLib.Event.COMPONENT_CREATED,this.componentCreated.bind(this)),this.componentClonedSubscription=this.subscribe(GameLib.Event.COMPONENT_CLONED,this.componentCloned.bind(this)),this.registerDependenciesSubscription=this.subscribe(GameLib.Event.REGISTER_DEPENDENCIES,this.registerDependenciesDirect),this.componentRemoveSubscription=this.subscribe(GameLib.Event.REMOVE_COMPONENT,this.removeComponent),this.parentSceneChangeSubscription=this.subscribe(GameLib.Event.PARENT_SCENE_CHANGE,this.onParentSceneChange),this.parentWorldChangeSubscription=this.subscribe(GameLib.Event.PARENT_WORLD_CHANGE,this.onParentWorldChange),this.parentEntityChangeSubscription=this.subscribe(GameLib.Event.PARENT_ENTITY_CHANGE,this.onParentEntityChange),this.instanceCreatedSubscription=this.subscribe(GameLib.Event.INSTANCE_CREATED,this.instanceCreated),this.instanceClonedSubscription=this.subscribe(GameLib.Event.INSTANCE_CLONED,this.instanceCloned),this.removeMeshSubscription=this.subscribe(GameLib.Event.REMOVE_MESH,this.removeMesh),this.imageChangedSubscription=this.subscribe(GameLib.Event.IMAGE_CHANGED,this.imageChanged),this.materialTypeChangedSubscription=this.subscribe(GameLib.Event.MATERIAL_TYPE_CHANGED,this.materialTypeChanged),this.arrayItemAddedSubscription=this.subscribe(GameLib.Event.ARRAY_ITEM_ADDED,this.arrayItemAdded)},GameLib.System.Linking.prototype.link=function(e,t){for(var i in e.linkedObjects)if(e.linkedObjects.hasOwnProperty(i))if(e.linkedObjects[i]instanceof Array){var n=[];e[i]=e[i].map(function(a){return a===t.component.id?(n.push({parent:e,property:i,child:t.component}),t.component):a}),n.map(function(e){GameLib.Event.Emit(GameLib.Event.COMPONENT_LINKED,e)})}else e[i]&&e[i]===t.component.id&&(e[i]=t.component,GameLib.Event.Emit(GameLib.Event.COMPONENT_LINKED,{parent:e,property:i,child:t.component}))},GameLib.System.Linking.prototype.resolveDependencies=function(e){if(!e.loaded)return!1;var t=this.dependencies[e.id];if(GameLib.Utils.UndefinedOrNull(t))return!1;t.map(function(t){if(this.link(t,{component:e}),GameLib.Utils.PushUnique(this.resolved,e),GameLib.Utils.UndefinedOrNull(t.dependencies)||t.dependencies instanceof Array&&0===t.dependencies.length){if(!t.loaded||GameLib.Utils.UndefinedOrNull(t.instance))try{t.performInstanceCreation()}catch(e){console.error(e)}}else{var i=t.dependencies.indexOf(e.id);-1!==i&&t.dependencies.splice(i,1),0===t.dependencies.length&&t.performInstanceCreation()}}.bind(this)),delete this.dependencies[e.id],GameLib.Event.Emit(GameLib.Event.UNRESOLVED_DEPENDENCIES_UPDATE,{dependencies:this.dependencies}),GameLib.Utils.IsEmpty(this.dependencies)&&(GameLib.Event.Emit(GameLib.Event.COMPONENTS_LINKED,{components:this.resolved.map(function(e){return e})}),this.resolved=[])},GameLib.System.Linking.prototype.registerDependencies=function(e){e.dependencies&&e.dependencies.length>0&&(e.dependencies=e.dependencies.reduce(function(t,i){var n=GameLib.EntityManager.Instance.findComponentById(i);return n&&n.loaded?(this.link(e,{component:n}),GameLib.Utils.PushUnique(this.resolved,n)):(GameLib.Utils.UndefinedOrNull(this.dependencies[i])&&(this.dependencies[i]=[]),-1===this.dependencies[i].indexOf(e)&&(this.dependencies[i].push(e),GameLib.Event.Emit(GameLib.Event.UNRESOLVED_DEPENDENCIES_UPDATE,{dependencies:this.dependencies})),t.push(i)),t}.bind(this),[]),0===e.dependencies.length&&e.performInstanceCreation())},GameLib.System.Linking.prototype.componentCreated=function(e){var t=e.component;this.registerDependencies(t),this.resolveDependencies(t)},GameLib.System.Linking.prototype.componentCloned=function(e){if(this.componentCreated(e),e.component instanceof GameLib.D3.Mesh){if(!(e.parent instanceof GameLib.D3.Mesh))throw new Error("no scene parent");e.parent.parentScene&&e.parent.parentScene.addClone(e.component)}},GameLib.System.Linking.prototype.registerDependenciesDirect=function(e){this.registerDependencies(e.component)},GameLib.System.Linking.prototype.removeComponent=function(e){if(!e.component)return void console.error("no component to remove");var t=e.component;t.parentEntity instanceof GameLib.Entity&&t.parentEntity.removeComponent(t),t instanceof GameLib.D3.Mesh&&t.parentScene instanceof GameLib.D3.Scene&&(t.removeHelper(),t.parentScene.removeObject(t)),t instanceof GameLib.D3.Light&&t.parentScene instanceof GameLib.D3.Scene&&t.parentScene.removeObject(t),t instanceof GameLib.Entity&&GameLib.EntityManager.Instance.removeEntity(t)},GameLib.System.Linking.prototype.imageChanged=function(e){GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Material).map(function(t){-1!==t.getTextures().indexOf(e.texture)&&t.updateInstance()})},GameLib.System.Linking.prototype.arrayItemAdded=function(e){e.component instanceof GameLib.D3.PhysicsWorld&&e.item instanceof GameLib.D3.RigidBody&&e.component.addRigidBody(e.item),e.component instanceof GameLib.D3.Mesh&&e.item instanceof GameLib.D3.Material&&e.component.addMaterial(e.item)},GameLib.System.Linking.prototype.instanceCloned=function(e){},GameLib.System.Linking.prototype.instanceCreated=function(e){this.resolveDependencies(e.component),e.component instanceof GameLib.D3.Image&&GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Texture).map(function(t){t.image!==e.component&&-1===t.images.indexOf(e.component)||t.updateInstance("image")}),e.component instanceof GameLib.D3.Scene&&GameLib.EntityManager.Instance.register.map(function(t){t.parentScene===e.component.id&&(t.parentScene=e.component)}),e.component.parentScene&&"string"==typeof e.component.parentScene&&GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Scene).map(function(t){e.component.parentScene===t.id&&(e.component.parentScene=t,t.addObject(e.component))}),e.component.parentEngine&&"string"==typeof e.component.parentEngine&&GameLib.EntityManager.Instance.queryComponents(GameLib.D3.ParticleEngine).map(function(t){e.component.parentEngine===t.id&&(e.component.parentEngine=t)}),e.component instanceof GameLib.D3.Mesh&&(e.preventParentMeshCheck||GameLib.EntityManager.Instance.register.map(function(t){t.parentMesh&&t.parentMesh===e.component.id&&(t.parentMesh=e.component,t instanceof GameLib.D3.Mesh&&t.setParentMesh(e.component))})),e.component.parentMesh&&"string"==typeof e.component.parentMesh&&GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Mesh).map(function(t){e.component.parentMesh===t.id&&(e.component.parentMesh=t,e.component instanceof GameLib.D3.Mesh&&e.component.setParentMesh(t))}),e.component.parentWorld&&"string"==typeof e.component.parentWorld&&GameLib.EntityManager.Instance.queryComponents(GameLib.D3.PhysicsWorld).map(function(t){e.component.parentWorld===t.id&&(e.component.parentWorld=t,"function"==typeof e.component.instance.addToWorld&&(e.component.instance.addToWorld(t.instance),console.log("instance added to physics world")))})},GameLib.System.Linking.prototype.materialTypeChanged=function(e){GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Mesh).map(function(t){t.materials.reduce(function(t,i){return i===e.material&&(t=!0),t},!1)&&(1===t.materials.length?t.instance.material=t.materials[0].instance:t.instance.material=t.materials.map(function(e){return e.instance}),t.instance.geometry.uvsNeedUpdate=!0,t.instance.material.needsUpdate=!0)})},GameLib.System.Linking.prototype.onParentWorldChange=function(e){e.object instanceof GameLib.D3.RigidBody&&(e.originalWorld instanceof GameLib.D3.PhysicsWorld&&e.originalWorld.removeRigidBody(e.object),e.newWorld instanceof GameLib.D3.PhysicsWorld&&e.newWorld.addRigidBody(e.object))},GameLib.System.Linking.prototype.onParentSceneChange=function(e){if(e.object instanceof GameLib.D3.Mesh||e.object instanceof GameLib.D3.Light){var t=GameLib.EntityManager.Instance.findHelperByObject(e.object);t&&(e.originalScene&&e.originalScene.instance&&e.originalScene.instance.remove(t.instance),e.newScene.instance.add(t.instance)),e.originalScene&&e.originalScene.removeObject&&e.originalScene.removeObject(e.object),e.newScene&&e.newScene.addObject(e.object)}},GameLib.System.Linking.prototype.onParentEntityChange=function(e){e.originalEntity instanceof GameLib.Entity&&e.originalEntity.removeComponent(e.object),e.newEntity instanceof GameLib.Entity&&e.newEntity.addComponent(e.object),GameLib.Event.Emit(GameLib.Event.PARENT_ENTITY_CHANGED,{originalEntity:e.originalEntity,newEntity:e.newEntity,component:e.object})},GameLib.System.Linking.prototype.removeMesh=function(e){var t=e.meshes.reduce(function(e,t){return e.push(t),t.getChildrenComponents().map(function(t){e.push(t)}),e},[]),i=GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Mesh);i=i.filter(function(t){return-1===e.meshes.indexOf(t)});var n=i.reduce(function(e,t){return e.push(t),t.getChildrenComponents().map(function(t){e.push(t)}),e},[]);t=t.filter(function(e){return-1===n.indexOf(e)}),t.map(function(e){e.remove()})},GameLib.System.Linking.prototype.stop=function(){GameLib.System.prototype.stop.call(this),this.componentCreatedSubscription.remove(),this.componentClonedSubscription.remove(),this.registerDependenciesSubscription.remove(),this.componentRemoveSubscription.remove(),this.parentSceneChangeSubscription.remove(),this.parentWorldChangeSubscription.remove(),this.parentEntityChangeSubscription.remove(),this.instanceCreatedSubscription.remove(),this.instanceClonedSubscription.remove(),this.removeMeshSubscription.remove(),this.imageChangedSubscription.remove(),this.materialTypeChangedSubscription.remove(),this.arrayItemAddedSubscription.remove()},GameLib.System.Particle=function(e,t,i){this.graphics=e,this.graphics.isNotThreeThrow(),GameLib.System.call(this,i),this.engines=[],this.camera=t,this.totalTime=0,this.instanceCreatedSubscription=null,this.removeComponentSubscription=null,this.beforeRenderSubscription=null},GameLib.System.Particle.prototype=Object.create(GameLib.System.prototype),GameLib.System.Particle.prototype.constructor=GameLib.System.Particle,GameLib.System.Particle.prototype.start=function(){GameLib.System.prototype.start.call(this),this.particleEngines=GameLib.EntityManager.Instance.queryComponents(GameLib.D3.ParticleEngine),this.instanceCreatedSubscription=GameLib.Event.Subscribe(GameLib.Event.INSTANCE_CREATED,this.instanceCreated.bind(this)),this.removeComponentSubscription=GameLib.Event.Subscribe(GameLib.Event.REMOVE_COMPONENT,this.removeComponent.bind(this)),this.beforeRenderSubscription=GameLib.Event.Subscribe(GameLib.Event.BEFORE_RENDER,this.beforeRender.bind(this))},GameLib.System.Particle.prototype.instanceCreated=function(e){e.component instanceof GameLib.D3.ParticleEngine&&(console.log("new particle engine"),this.particleEngines.push(e.component)),e.component instanceof GameLib.D3.Camera&&(console.log("new camera"),this.camera=e.component)},GameLib.System.Particle.prototype.removeComponent=function(e){if(e.component instanceof GameLib.D3.ParticleEngine){var t=this.particleEngines.indexOf(e.component);-1!==t?(console.log("removing particle engine from system"+e.component.name),this.particleEngines.splice(t,1)):console.log("failed to find the particle engine in the system : "+e.component.name)}},GameLib.System.Particle.prototype.beforeRender=function(e){this.totalTime+=e.delta,this.particleEngines.map(function(t){if(!(GameLib.Utils.UndefinedOrNull(t.camera)||GameLib.Utils.UndefinedOrNull(t.templateParticle)||GameLib.Utils.UndefinedOrNull(t.templateParticle.mesh)||GameLib.Utils.UndefinedOrNull(t.templateParticle.mesh.parentScene)||GameLib.Utils.UndefinedOrNull(t.templateParticle.mesh.parentScene.instance))&&(t.elapsed+=e.delta,t.particles=t.particles.reduce(function(i,n){var a=n.userData.speed;return n.userData.speedType===GameLib.D3.Particle.SPEED_TYPE_CONSTANT&&(a=e.delta*n.userData.speed),n.userData.speedType===GameLib.D3.Particle.SPEED_TYPE_LINEAR&&(a=e.delta*n.userData.speed,n.userData.speed+=a),n.userData.speedType===GameLib.D3.Particle.SPEED_TYPE_EXPONENTIAL&&(a=Math.pow(n.userData.speed,2)*e.delta,n.userData.speed+=a),n.userData.speedType===GameLib.D3.Particle.SPEED_TYPE_LOGARITHMIC&&(a=Math.log(n.userData.speed)*e.delta,n.userData.speed+=a),n.userData.speedType===GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_LOG&&(a=1/Math.log(n.userData.speed)*e.delta,n.userData.speed+=a),n.userData.speedType===GameLib.D3.Particle.SPEED_TYPE_EXP&&(a=Math.exp(n.userData.speed)*e.delta,n.userData.speed+=a),n.userData.speedType===GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_EXP&&(a=1/Math.exp(n.userData.speed)*e.delta,n.userData.speed+=a),n.position.x+=n.userData.direction.x*a,n.position.y+=n.userData.direction.y*a,n.position.z+=n.userData.direction.z*a,t.templateParticle.scaleType,GameLib.D3.Particle.SCALE_TYPE_CONSTANT,t.templateParticle.scaleType===GameLib.D3.Particle.SCALE_TYPE_LINEAR&&(n.scale.x+=n.userData.scale.x*e.delta,n.scale.y+=n.userData.scale.x*e.delta,n.scale.z+=n.userData.scale.x*e.delta),n.quaternion.copy(t.camera.instance.quaternion),t.templateParticle.opacityType===GameLib.D3.Particle.OPACITY_TYPE_INCREASE_LINEAR&&(n.material.opacity+=t.templateParticle.opacityFactor),t.templateParticle.opacityType===GameLib.D3.Particle.OPACITY_TYPE_DECREASE_LINEAR&&(n.material.opacity-=t.templateParticle.opacityFactor), +n.userData.elapsed+=e.delta,n.userData.elapsed>n.userData.lifeTime||n.material.opacity<0?(n.userData.scene.remove(n),n.geometry.dispose(),n.material.dispose()):i.push(n),i},[]),t.disabledForRemoval&&0===t.particles.length&&GameLib.Event.Emit(GameLib.Event.REMOVE_PARTICLE_ENGINE,{component:t}),t.enabled&&!t.disabledForRemoval)){var i=null;if(t.pulse){if(0===t.particles.length){t.elapsed=0;for(var n=0;nt.frequency&&(t.elapsed=0,i=t.templateParticle.cloneInstance(),t.particles.push(i))}}.bind(this))},GameLib.System.Particle.prototype.stop=function(){GameLib.System.prototype.stop.call(this),this.instanceCreatedSubscription.remove(),this.removeComponentSubscription.remove(),this.beforeRenderSubscription.remove()},GameLib.System.Physics=function(e){GameLib.System.call(this,e),this.worlds=[],this.beforeRenderSubscription=null,this.afterRenderSubscription=null},GameLib.System.Physics.prototype=Object.create(GameLib.System.prototype),GameLib.System.Physics.prototype.constructor=GameLib.System.Physics,GameLib.System.Physics.prototype.start=function(){GameLib.System.prototype.start.call(this),this.worlds=GameLib.EntityManager.Instance.queryComponents(GameLib.D3.PhysicsWorld),this.beforeRenderSubscription=this.subscribe(GameLib.Event.BEFORE_RENDER,this.beforeRender)},GameLib.System.Physics.prototype.beforeRender=function(e){this.worlds.map(function(t){t.instance&&(t.instance.step(e.delta),t.rigidBodies.map(function(e){e.position.x=e.instance.position.x,e.position.y=e.instance.position.y,e.position.z=e.instance.position.z,e.quaternion.x=e.instance.quaternion.x,e.quaternion.y=e.instance.quaternion.y,e.quaternion.z=e.instance.quaternion.z,e.quaternion.w=e.instance.quaternion.w,e.parentMesh.position.x=e.instance.position.x,e.parentMesh.position.y=e.instance.position.y,e.parentMesh.position.z=e.instance.position.z,e.parentMesh.quaternion.x=e.instance.quaternion.x,e.parentMesh.quaternion.y=e.instance.quaternion.y,e.parentMesh.quaternion.z=e.instance.quaternion.z,e.parentMesh.quaternion.w=e.instance.quaternion.w,e.instance.getVelocityAtWorldPoint(new CANNON.Vec3(0,0,0),e.velocity.instance),e.velocity.x=e.velocity.instance.x,e.velocity.y=e.velocity.instance.y,e.velocity.z=e.velocity.instance.z,e.parentMesh.updateRotationFromAxisAngle=!1,e.parentMesh.updateInstance(),e.parentMesh.updateRotationFromAxisAngle=!0}))}.bind(this))},GameLib.System.Physics.prototype.stop=function(){GameLib.System.prototype.stop.call(this),this.worlds=[],this.rigidBodies=[],this.wheels=[],this.vehicles=[],this.beforeRenderSubscription&&this.beforeRenderSubscription.remove(),this.afterRenderSubscription&&this.afterRenderSubscription.remove()},GameLib.System.Render=function(e){GameLib.System.call(this,e),this.renderSubscription=null},GameLib.System.Render.prototype=Object.create(GameLib.System.prototype),GameLib.System.Render.prototype.constructor=GameLib.System.Render,GameLib.System.Render.prototype.start=function(){GameLib.System.prototype.start.call(this),this.renderers=GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Renderer),this.statistics=GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Stats),this.instanceCreatedSubscription=GameLib.Event.Subscribe(GameLib.Event.INSTANCE_CREATED,this.instanceCreated.bind(this)),this.removeComponentSubscription=GameLib.Event.Subscribe(GameLib.Event.REMOVE_COMPONENT,this.removeComponent.bind(this)),this.renderSubscription=this.subscribe(GameLib.Event.RENDER,this.render)},GameLib.System.Render.prototype.instanceCreated=function(e){e.component instanceof GameLib.D3.Renderer&&(console.log("new renderer"),this.renderers.push(e.component))},GameLib.System.Render.prototype.removeComponent=function(e){if(e.component instanceof GameLib.D3.Renderer){var t=this.renderers.indexOf(e.component);-1!==t?(console.log("removing renderer from system"),this.renderers.splice(t,1)):console.log("failed to find the renderer in the system : "+e.component.name)}},GameLib.System.Render.prototype.render=function(e){if(this.statistics&&this.statistics.map(function(e){e.start()}),GameLib.Event.Emit(GameLib.Event.BEFORE_RENDER,e),this.renderers.length<1);else if(1===this.renderers.length)this.renderers[0].render(e.delta);else{var t=this.renderers.reduce(function(e,t){return t.scenes.map(function(t){e.push(t)}),e},[]),i=GameLib.EntityManager.Instance.defaultRenderer;GameLib.Utils.UndefinedOrNull(i)&&(i=this.renderers[0]),i.render(e.delta,t)}GameLib.Event.Emit(GameLib.Event.AFTER_RENDER,e),this.statistics&&this.statistics.map(function(e){e.end()})},GameLib.System.Render.prototype.stop=function(){GameLib.System.prototype.stop.call(this),this.instanceCreatedSubscription.remove(),this.removeComponentSubscription.remove(),this.renderSubscription.remove(),this.renderers.map(function(e){e.statistics&&(e.statistics.resize(),e.domElement.instance.parentElement.removeChild(e.statistics.instance.dom))}),this.renderers=[]},GameLib.System.Storage=function(e,t,i,n,a,s,o,r,c,h){GameLib.System.call(this,t),GameLib.Utils.UndefinedOrNull(i)&&(i=null),this.token=i,GameLib.Utils.UndefinedOrNull(n)&&(console.warn("Need an API Upload URL for a storage system"),n=""),this.apiUploadUrl=n,GameLib.Utils.UndefinedOrNull(a)&&(a=null),this.onImageLoaded=a,GameLib.Utils.UndefinedOrNull(s)&&(s=null),this.onImageProgress=s,GameLib.Utils.UndefinedOrNull(o)&&(o=null),this.onImageError=o,GameLib.Utils.UndefinedOrNull(r)&&(r=null),this.onComponentLoaded=r,GameLib.Utils.UndefinedOrNull(c)&&(c=null),this.onComponentProgress=c,GameLib.Utils.UndefinedOrNull(h)&&(h=null),this.onComponentError=h,this.loaded=[],this.loading=[],this.failed=[],this.otherDependencies=[],this.loginSubscription=null,this.saveSubscription=null,this.loadSubscription=null,this.loadImageSubscription=null,this.blenderDataSubscription=null,this.imageUploadCompleteSubscription=null,this.fetchComponentTypesSubscription=null,this.fetchComponentsSubscription=null},GameLib.System.Storage.prototype=Object.create(GameLib.System.prototype),GameLib.System.Storage.prototype.constructor=GameLib.System.Storage,GameLib.System.Storage.prototype.start=function(){GameLib.System.prototype.start.call(this),GameLib.Event.Emit(GameLib.Event.GET_GRAPHICS_IMPLEMENTATION,null,function(e){this.graphics=e}.bind(this),function(){this.graphics=null}.bind(this)),GameLib.Event.Emit(GameLib.Event.GET_PHYSICS_IMPLEMENTATION,null,function(e){this.physics=e}.bind(this),function(){this.physics=null}.bind(this)),GameLib.Event.Emit(GameLib.Event.GET_CODER_IMPLEMENTATION,null,function(e){this.coder=e}.bind(this),function(){this.coder=null}.bind(this)),this.loginSubscription=this.subscribe(GameLib.Event.LOGGED_IN,function(e){this.token=e.token}),this.saveSubscription=this.subscribe(GameLib.Event.SAVE_COMPONENT,this.save),this.loadSubscription=this.subscribe(GameLib.Event.LOAD_COMPONENT,this.load),this.deleteSubscription=this.subscribe(GameLib.Event.DELETE_COMPONENT,this.delete),this.loadImageSubscription=this.subscribe(GameLib.Event.LOAD_IMAGE,this.loadImage),this.loadFontSubscription=this.subscribe(GameLib.Event.LOAD_FONT,this.loadFont),this.blenderDataSubscription=this.subscribe(GameLib.Event.BLENDER_DATA_RECEIVED,this.processBlenderData),this.imageUploadCompleteSubscription=this.subscribe(GameLib.Event.IMAGE_UPLOAD_COMPLETE,this.imageUploadComplete),this.fetchComponentTypesSubscription=this.subscribe(GameLib.Event.FETCH_COMPONENT_TYPES,this.fetchComponentTypes),this.fetchComponentsSubscription=this.subscribe(GameLib.Event.FETCH_COMPONENTS,this.fetchComponents)},GameLib.System.Storage.prototype.delete=function(e){this.publish(GameLib.Event.GET_API_URL,null,function(t){if("undefined"==typeof XMLHttpRequest)return void console.log("Implement server side delete here");e.ids.map(function(e){var i=new XMLHttpRequest;i.open("POST",t.apiUrl+"/component/delete/"+e),i.setRequestHeader("Accept","application/json"),i.setRequestHeader("Content-Type","application/json"),i.setRequestHeader("x-authorization",t.passwoid),i.onreadystatechange=function(){if(4===this.readyState){try{var e=JSON.parse(this.responseText)}catch(e){GameLib.Event.Emit(GameLib.Event.DELETE_COMPONENT_ERROR,{message:this.responseText})}"success"===e.result?GameLib.Event.Emit(GameLib.Event.COMPONENT_DELETED,{message:e.message||"Successfully saved the component"}):GameLib.Event.Emit(GameLib.Event.DELETE_COMPONENT_ERROR,{message:e.message||"The server responded but failed to save the component"})}},i.send(JSON.stringify({session:this.token}))}.bind(this))}.bind(this),function(e){throw console.error(e.message),new Error(e.message)})},GameLib.System.Storage.prototype.save=function(e){var t=GameLib.Event.GET_API_URL;e.remote&&(t=GameLib.Event.GET_REMOTE_API_URL),this.publish(t,null,function(t){if("undefined"==typeof XMLHttpRequest)return void console.log("Implement server side save here");var i=new XMLHttpRequest;i.open("POST",t.apiUrl+"/component/create"),i.setRequestHeader("Accept","application/json"),i.setRequestHeader("Content-Type","application/json"),i.setRequestHeader("x-authorization",t.passwoid),i.onreadystatechange=function(){if(4===this.readyState){try{var t=JSON.parse(this.responseText)}catch(t){GameLib.Event.Emit(GameLib.Event.SAVE_COMPONENT_ERROR,{message:this.responseText,component:e.apiObject})}"success"===t.result?GameLib.Event.Emit(GameLib.Event.COMPONENT_SAVED,{message:t.message||"Successfully saved the component",component:e.apiObject}):GameLib.Event.Emit(GameLib.Event.SAVE_COMPONENT_ERROR,{message:t.message||"The server responded but failed to save the component",component:e.apiObject})}},i.send(JSON.stringify({component:e.apiObject,session:this.token}))})};GameLib.System.Storage.prototype.createRuntimeObject=function(responseText,clientErrorCallback){try{var object=JSON.parse(responseText)}catch(e){return this.onComponentError&&this.onComponentError(e),clientErrorCallback&&clientErrorCallback({message:e.message||"JSON parse error"}),GameLib.Event.Emit(GameLib.Event.LOAD_COMPONENT_ERROR,{error:e}),null}if("success"!==object.result)return this.onComponentError&&this.onComponentError(id,object),clientErrorCallback&&clientErrorCallback({message:object.message||"Server load error"}),GameLib.Event.Emit(GameLib.Event.LOAD_COMPONENT_ERROR,{error:object}),null;var runtimeComponent=null,component=object.component[0],componentName=GameLib.Component.GetComponentName(component.componentType),componentClass=eval(componentName),fn=componentClass.FromObject;if(component.componentType===GameLib.Component.COMPONENT_ENTITY)runtimeComponent=fn(component,GameLib.EntityManager.Instance);else{try{runtimeComponent=fn(component)}catch(e){if(this.coder)try{runtimeComponent=fn(this.coder,component)}catch(e){}if(!runtimeComponent&&this.graphics)try{runtimeComponent=fn(this.graphics,component)}catch(e){}if(!runtimeComponent&&this.physics)try{runtimeComponent=fn(this.physics,component)}catch(e){}}runtimeComponent||clientErrorCallback&&clientErrorCallback({result:"failure",message:"Could not create a runtime component: "+component.name})}return runtimeComponent},GameLib.System.Storage.prototype.loadComponent=function(e,t,i,n,a){t.map(function(e){GameLib.Utils.PushUnique(this.loading,e);var t=GameLib.EntityManager.Instance.findComponentById(e);t&&t.remove()}.bind(this)),t.map(function(t){var s=new XMLHttpRequest;s.onload=function(s){return function(){var o=s.createRuntimeObject.bind(s)(this.responseText);if(!o)return void s.failed.push(t);if(o.parentEntity&&"string"==typeof o.parentEntity&&GameLib.EntityManager.Instance.queryComponents(GameLib.Entity).map(function(e){o.parentEntity===e.id&&(o.parentEntity=e)}),GameLib.Event.Emit(GameLib.Event.COMPONENT_CREATED,{component:o}),s.loaded.push(o.id),i){var r=o.getDependencies();s.otherDependencies.map(function(e){var t=r.indexOf(e);-1!==t&&r.splice(t,1)}),r.map(function(e){GameLib.Utils.PushUnique(this.otherDependencies,e)}.bind(s)),r=r.reduce(function(e,t){return-1===s.failed.indexOf(t)?e.push(t):console.log("ignoring failed component : "+t),e}.bind(s),[]),r=r.reduce(function(e,t){return GameLib.EntityManager.Instance.findComponentById(t)||e.push(t),e},[]),r=r.reduce(function(e,t){return-1===s.loaded.indexOf(t)&&e.push(t),e},[]),r.map(function(e){GameLib.Utils.PushUnique(s.loading,e)}),s.loadComponent(e,r,i,n,a),GameLib.Event.Emit(GameLib.Event.LOAD_PROGRESS,{loaded:s.loaded.length,toProcess:r.length})}s.onComponentLoaded&&s.onComponentLoaded(o)}}(this),s.onprogress=function(e){return function(t){var i=0;0!==t.total&&(i=Math.round(100*Number(t.loaded/t.total))),this.onComponentProgress&&this.onComponentProgress(e,i)}.bind(this)}(t),s.onerror=function(e){return function(t){console.warn("component load failed for component ID "+e),this.onComponentError&&this.onComponentError(e,t),a&&a({message:"xhr request failure"})}.bind(this)}(t),s.open("GET",e+"/component/load/"+t),s.send()}.bind(this))},GameLib.System.Storage.prototype.load=function(e,t,i){this.publish(GameLib.Event.GET_API_URL,null,function(n){if("undefined"==typeof XMLHttpRequest)return void console.log("Implement server side load here");e.ids&&e.ids.length>0?this.loadComponent(n.apiUrl,e.ids,e.includeDependencies,t,i):console.log("No components selected")}.bind(this),function(e){throw console.error(e.message),new Error(e.message)})},GameLib.System.Storage.prototype.xhrLoad=function(e,t,i){if("undefined"==typeof XMLHttpRequest)return void console.log("Implement server side load here");console.log("Loading...","success");var n=new XMLHttpRequest;n.open("GET",e),n.setRequestHeader("Accept","application/json"),n.setRequestHeader("Content-Type","application/json"),n.onreadystatechange=function(){if(4===n.readyState){if(!n.responseText)return console.log("Invalid response from server"),void i({message:"Invalid response from server"});try{var e=JSON.parse(n.responseText)}catch(e){e.message="Could not parse JSON",i(e)}if("success"!==e.result)return i({message:e.message||"Unknown Error Occurred"});t(e)}},n.onerror=i,n.send()},GameLib.System.Storage.prototype.fetchComponentTypes=function(e,t,i){this.xhrLoad(e.url,function(e){t({ids:e.ids})},i)},GameLib.System.Storage.prototype.fetchComponents=function(e,t,i){this.xhrLoad(e.url,function(e){t({components:e.component})},i)},GameLib.System.Storage.prototype.imageUploadComplete=function(e){var t=GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Image);e.images.map(function(e){var i=null;e?GameLib.D3.Image.FromObject(this.graphics,e):(i=t.reduce(function(t,i){return e.id===i.id&&(t=i),t},null),i.updateInstance())}.bind(this))},GameLib.System.Storage.prototype.processBlenderData=function(e){console.log("loading blender data"),e.images.map(function(e){var t=GameLib.D3.Image.FromObject(this.graphics,e);GameLib.Event.Emit(GameLib.Event.COMPONENT_CREATED,{component:t})}.bind(this)),e.textures.map(function(e){var t=GameLib.D3.Texture.FromObject(this.graphics,e);GameLib.Event.Emit(GameLib.Event.COMPONENT_CREATED,{component:t})}.bind(this)),e.materials.map(function(e){var t=GameLib.D3.Material.FromObject(this.graphics,e);GameLib.Event.Emit(GameLib.Event.COMPONENT_CREATED,{component:t})}.bind(this)),e.meshes.map(function(e){var t=GameLib.D3.Mesh.FromObject(this.graphics,e);GameLib.Event.Emit(GameLib.Event.COMPONENT_CREATED,{component:t})}.bind(this))},GameLib.System.Storage.prototype.loadFont=function(e){console.log("loading font : "+e.font.name),this.publish(GameLib.Event.GET_API_URL,null,function(t){var i=t.apiUrl+"/fonts/"+e.font.url+"?ts="+Date.now();(new THREE.FontLoader).load(i,function(t){GameLib.Utils.IsEmpty(t.data)?GameLib.Event.Emit(GameLib.Event.FONT_NOT_FOUND,{font:e.font}):(e.font.instance=t,e.font.createInstance())})}.bind(this),function(e){throw console.error(e.message),new Error(e.message)})},GameLib.System.Storage.prototype.loadImage=function(e){console.log("loading image : "+e.image.name),this.publish(GameLib.Event.GET_API_URL,null,function(t){var i=this.onImageLoaded,n=this.onImageProgress,a=this.onImageError,s=e.image,o=t.apiUrl+s.path+s.fileName+s.extension+"?ts="+Date.now(),r=new XMLHttpRequest;r.withCredentials=!0,r.open("OPTIONS",o),r.setRequestHeader("Content-Type","application/json"),r.onload=function(){var t=new XMLHttpRequest;t.withCredentials=!0,t.open("GET",o),t.setRequestHeader("Content-Type",s.contentType),t.responseType="blob",t.onload=function(){var t=!1,n="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QoWEQMQBXD4hQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAABRSURBVGje7c8xDQAwCAAwmA3koA/PU8FB0jpo1nRc9uI4AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBgX0fjEoBa8xN1z4AAAAASUVORK5CYII=";try{"application/json"!==this.response.type&&(n=window.URL.createObjectURL(this.response),t=!0)}catch(e){}var a=document.createElement("img");a.onload=function(){t&&window.URL.revokeObjectURL(n),s.instance=a,s.createInstance(),i&&i(s,e.createTexture)},a.src=n},t.onprogress=function(e){var t=0;0!==e.total&&(t=Math.round(100*Number(e.loaded/e.total))),n&&n(s,t),s.size=e.total},t.onerror=function(e){console.warn("image load failed for image "+s.name),a&&a(s,e)},t.send()},r.onerror=function(e){console.warn("image pre-flight request failed for image "+s.name),a&&a(s,e)},r.send()}.bind(this),function(e){throw console.error(e.message),new Error(e.message)})},GameLib.System.Storage.prototype.stop=function(){GameLib.System.prototype.stop.call(this),this.loginSubscription.remove(),this.loadSubscription.remove(),this.saveSubscription.remove(),this.loadImageSubscription.remove(),this.loadFontSubscription.remove(),this.blenderDataSubscription.remove(),this.imageUploadCompleteSubscription.remove(),this.deleteSubscription.remove(),this.fetchComponentTypesSubscription.remove(),this.fetchComponentsSubscription.remove()},GameLib.System.Visualization=function(e,t,i){GameLib.System.call(this,e),this.graphics=t,this.graphics.isNotThreeThrow(),this.physics=i,this.physics.isNotCannonThrow(),this.visualizationSubscription=null,this.stopVisualizationSubscription=null},GameLib.System.Visualization.prototype=Object.create(GameLib.System.prototype),GameLib.System.Visualization.prototype.constructor=GameLib.System.Visualization,GameLib.System.Visualization.prototype.start=function(){GameLib.System.prototype.start.call(this),this.visualizationSubscription=this.subscribe(GameLib.Event.VISUALIZE,this.visualize),this.stopVisualizationSubscription=this.subscribe(GameLib.Event.STOP_VISUALIZE,this.stopVisualize)},GameLib.System.Visualization.prototype.visualize=function(e){var t=e.shape;t.parentMesh;t.setFromMesh();var i=new GameLib.D3.API.Mesh;if(i.name="Visualization Mesh for Shape "+t.name,t instanceof GameLib.D3.Shape.HeightMap)for(var n=new CANNON.Vec3,a=new CANNON.Vec3,s=new CANNON.Vec3,o=0;o Math.PI) { + value -= (Math.PI * 2); + } + + while (value < -(Math.PI)) { + value += (Math.PI * 2); + } + + store = value; + } + }; +}; + +/** + * Returns an array of IDs representing the objects + * @param array + * @returns [] + * @constructor + */ +GameLib.Utils.IdArrayOrEmptyArray = function (array) { + if (GameLib.Utils.UndefinedOrNull(array)) { + return []; + } else { + + return array.map(function(item) { + + if (GameLib.Utils.UndefinedOrNull(item.id)) { + throw new Error('No ID found while trying to store IDs to array'); + } + + return item.id + }); + } +}; + +/** + * Links an object to its parent through idToObject array + * @param propertyString + * @param idToObject + * @param parentObject + * @param id + * @constructor + */ +GameLib.Utils.Link = function(propertyString, idToObject, parentObject, id) { + + if (!GameLib.Utils.UndefinedOrNull(parentObject[propertyString])) { + + if (!idToObject.hasOwnProperty(id)) { + console.warn('Linking failed for object:' + parentObject.name); + } + + parentObject[propertyString] = idToObject[id]; + } +}; + +/** + * Generates a random ID + * @returns {string} + * @constructor + */ +GameLib.Utils.RandomId = function(length) { + + if (GameLib.Utils.UndefinedOrNull(length)) { + length = 10; + } + + return Math.random().toString(36).substr(2, length); +}; + +GameLib.Utils.InvertWindingOrder = function(triangles) { + + for (var i = 0; i < triangles.length; i++) { + var v1 = triangles[i].v1; + triangles[i].v1 = triangles[i].v2; + triangles[i].v2 = v1; + + var backupUV = triangles[i].triangle.v1uv; + triangles[i].triangle.v1uv = triangles[i].triangle.v2uv; + triangles[i].triangle.v2uv = backupUV; + } + + return triangles; +}; + +/** + * Inverts a mesh winding order (and its instance) + * @param mesh GameLib.D3.Mesh + * @returns {*} + * @constructor + */ +GameLib.Utils.InvertMeshWindingOrder = function(mesh) { + + mesh.faces.forEach( + function (face) { + + var tmpV1 = face.v1; + face.v1 = face.v2; + face.v2 = tmpV1; + + var tmpV1uv = face.v1uv; + face.v1uv = face.v2uv; + face.v2uv = tmpV1uv; + + }.bind(this) + ); + + mesh.computeNormals = true; + mesh.createInstance(); +}; + +/** + * This function resets a the winding order of a mesh from a reference point V (the average center of the mesh) + */ +GameLib.Utils.ResetWindingOrder = function(faces, vertices) { + + var vertexList = new GameLib.API.Vector3.Points(); + + for (var v = 0; v < vertices.length; v++) { + vertexList.add(new GameLib.API.Vector3( + vertices[v].position.x, + vertices[v].position.y, + vertices[v].position.z + )); + } + + var V = vertexList.average(); + + var triangles = []; + + for (var s = 0; s < faces.length; s += 3) { + + var v0 = faces[s]; + var v1 = faces[s+1]; + var v2 = faces[s+2]; + + triangles.push( + { + v0 : v0, + v1 : v1, + v2 : v2, + edges : [ + {v0: v0, v1: v1}, + {v0: v1, v1: v2}, + {v0: v2, v1: v0} + ], + winding : 0, + edgeIndex : -1, + processed : false + } + ); + } + + for (var i = 0; i < triangles.length; i++) { + if ( + GameLib.API.Vector3.clockwise( + vertices[triangles[i].v0].position, + vertices[triangles[i].v1].position, + vertices[triangles[i].v2].position, + V + ) + ) { + console.log('clockwise'); + var bv1 = triangles[i].v1; + triangles[i].v1 = triangles[i].v2; + triangles[i].v2 = bv1; + } else { + console.log('not clockwise'); + } + } + + return triangles; +}; + +/** + * This function resets the winding order for triangles in faces, given an initial triangle and orientation edge + * used pseudocode from + * http://stackoverflow.com/questions/17036970/how-to-correct-winding-of-triangles-to-counter-clockwise-direction-of-a-3d-mesh + * We need to use a graph traversal algorithm, + * lets assume we have method that returns neighbor of triangle on given edge + * + * neighbor_on_egde( next_tria, edge ) + * + * to_process = set of pairs triangle and orientation edge, initial state is one good oriented triangle with any edge on it + * processed = set of processed triangles; initial empty + * + * while to_process is not empty: + * next_tria, orientation_edge = to_process.pop() + * add next_tria in processed + * if next_tria is not opposite oriented than orientation_edge: + * change next_tria (ABC) orientation (B<->C) + * for each edge (AB) in next_tria: + * neighbor_tria = neighbor_on_egde( next_tria, edge ) + * if neighbor_tria exists and neighbor_tria not in processed: + * to_process add (neighbor_tria, edge opposite oriented (BA)) + * @param faces GameLib.D3.Face[] + * @param orientationEdge GameLib.API.Vector2 + * @returns {Array} + */ +GameLib.Utils.FixWindingOrder = function(faces, orientationEdge) { + + /** + * Checks if a Face belonging to a TriangleEdge has already been processed + * @param processed TriangleEdge[] + * @param triangle Face + * @returns {boolean} + */ + function inProcessed(processed, triangle) { + + for (var i = 0; i < processed.length; i++) { + if (processed[i].triangle.equals(triangle)) { + return true; + } + } + + return false; + } + + /** + * Returns a neighbouring triangle on a specific edge - preserving the edge orientation + * @param edge GameLib.API.Vector2 + * @param faces GameLib.D3.Face[] + * @param currentTriangle + * @returns {*} + */ + function neighbourOnEdge(edge, faces, currentTriangle) { + + for (var i = 0; i < faces.length; i++) { + if ( + (faces[i].v0 === edge.x && faces[i].v1 === edge.y) || + (faces[i].v1 === edge.x && faces[i].v2 === edge.y) || + (faces[i].v2 === edge.x && faces[i].v0 === edge.y) || + (faces[i].v0 === edge.y && faces[i].v1 === edge.x) || + (faces[i].v1 === edge.y && faces[i].v2 === edge.x) || + (faces[i].v2 === edge.y && faces[i].v0 === edge.x) + ) { + + var triangle = new GameLib.D3.API.Face( + null, + null, + faces[i].v0index, + faces[i].v1index, + faces[i].v2index, + faces[i].materialIndex, + faces[i].uvs + ); + + if (triangle.equals(currentTriangle)) { + continue; + } + + return new GameLib.D3.TriangleEdge( + triangle, + edge + ); + } + } + + return null; + } + + var toProcess = [ + new GameLib.D3.TriangleEdge( + new GameLib.D3.API.Face( + null, + null, + faces[0].v0index, + faces[0].v1index, + faces[0].v2index, + faces[0].materialIndex, + faces[0].uvs + ), + orientationEdge + ) + ]; + + var processed = []; + + while (toProcess.length > 0) { + + var triangleEdge = toProcess.pop(); + + /** + * If edge is the same orientation (i.e. the edge order is the same as the given triangle edge) it needs to be reversed + * to have the same winding order) + */ + if ( + (triangleEdge.triangle.v0index === triangleEdge.edge.x && + triangleEdge.triangle.v1index === triangleEdge.edge.y) || + (triangleEdge.triangle.v1index === triangleEdge.edge.x && + triangleEdge.triangle.v2index === triangleEdge.edge.y) || + (triangleEdge.triangle.v2index === triangleEdge.edge.x && + triangleEdge.triangle.v0index === triangleEdge.edge.y) + ) { + var backupV = triangleEdge.triangle.v1index; + triangleEdge.triangle.v1index = triangleEdge.triangle.v2index; + triangleEdge.triangle.v2index = backupV; + + // var backupUV = triangleEdge.triangle.v1uv; + // triangleEdge.triangle.v1uv = triangleEdge.triangle.v2uv; + // triangleEdge.triangle.v2uv = backupUV; + // + var backupUV = triangleEdge.triangle.uvs[0][1]; + triangleEdge.triangle.uvs[0][1] = triangleEdge.triangle.uvs[0][2]; + triangleEdge.triangle.uvs[0][2] = backupUV; + } + + processed.push(triangleEdge); + + var edges = [ + new GameLib.API.Vector2( + triangleEdge.triangle.v0index, + triangleEdge.triangle.v1index + ), + new GameLib.API.Vector2( + triangleEdge.triangle.v1index, + triangleEdge.triangle.v2index + ), + new GameLib.API.Vector2( + triangleEdge.triangle.v2index, + triangleEdge.triangle.v0index + ) + ]; + + for (var j = 0; j < edges.length; j++) { + var neighbour = neighbourOnEdge(edges[j], faces, triangleEdge.triangle); + if (neighbour && !inProcessed(processed, neighbour.triangle)) { + toProcess.push(neighbour); + } + } + } + + /** + * In processed - we will have some duplicates - only add the unique ones + * @type {Array} + */ + var triangles = []; + for (var i = 0; i < processed.length; i++) { + var found = false; + for (var k = 0; k < triangles.length; k++) { + if (triangles[k].equals(processed[i].triangle)){ + found = true; + break; + } + } + if (!found) { + triangles.push(processed[i].triangle); + } + } + + return triangles; +}; + +/** + * This is a work-around function to fix polys which don't triangulate because + * they could lie on Z-plane (XZ or YZ)) - we translate the poly to the origin, systematically rotate the poly around + * Z then Y axis + * @param verticesFlat [] + * @param grain is the amount to systematically rotate the poly by - a finer grain means a more accurate maximum XY + * @return [] + */ +GameLib.Utils.FixPolyZPlane = function(verticesFlat, grain) { + + if ((verticesFlat.length % 3) !== 0 && !(verticesFlat.length > 9)) { + console.log("The vertices are not in the right length : " + verticesFlat.length); + } + + var vertices = []; + + var points = new GameLib.API.Quaternion.Points(); + + for (var i = 0; i < verticesFlat.length; i += 3) { + points.add(new GameLib.API.Vector3( + verticesFlat[i], + verticesFlat[i + 1], + verticesFlat[i + 2] + )); + } + + points.toOrigin(); + + points.maximizeXDistance(grain); + + points.maximizeYDistance(grain); + + for (i = 0; i < points.vectors.length; i++) { + vertices.push( + [ + points.vectors[i].x, + points.vectors[i].y + ] + ); + } + + return vertices; +}; + +GameLib.Utils.MovingAverage = function(period) { + var nums = []; + return function(num) { + nums.push(num); + if (nums.length > period) + nums.splice(0,1); // remove the first element of the array + var sum = 0; + for (var i in nums) + sum += nums[i]; + var n = period; + if (nums.length < period) + n = nums.length; + return(sum/n); + } +}; + +GameLib.Utils.Intersect = function (a, b) { + + var t; + + /** + * Loop over shortest array + */ + if (b.length > a.length) { + t = b; + b = a; + a = t; + } + + return a.filter( + /** + * Check if exists + * @param e + * @returns {boolean} + */ + function (e) { + return (b.indexOf(e) > -1); + } + ).filter( + /** + * Remove Duplicates + * @param e + * @param i + * @param c + * @returns {boolean} + */ + function (e, i, c) { + return c.indexOf(e) === i; + } + ); +}; + +GameLib.Utils.Difference = function (a, b) { + + var t; + + /** + * Loop over shortest array + */ + if (b.length > a.length) { + t = b; + b = a; + a = t; + } + + return a.filter( + /** + * Check if exists + * @param e + * @returns {boolean} + */ + function (e) { + return (b.indexOf(e) === -1); + } + ).filter( + /** + * Remove Duplicates + * @param e + * @param i + * @param c + * @returns {boolean} + */ + function (e, i, c) { + return c.indexOf(e) === i; + } + ); +}; + +/** + * Push only if not in there already + * @param array + * @param object + * @constructor + */ +GameLib.Utils.PushUnique = function(array, object) { + + if (array.indexOf(object) === -1) { + array.push(object); + } +}; + +/** + * Checks whether or not the object is empty + * @param obj + * @returns {boolean} + * @constructor + */ +GameLib.Utils.IsEmpty = function(obj) { + return (Object.keys(obj).length === 0 && obj.constructor === Object); +}; + +GameLib.Utils.isString = function(member) { + return (typeof member === 'string'); +}; + +GameLib.Utils.isBoolean = function(member) { + return (member === true || member === false); +}; + +GameLib.Utils.isColor = function(member) { + return (member instanceof GameLib.Color); +}; + +GameLib.Utils.isNumber = function(member) { + return (typeof member === 'number'); +}; + +GameLib.Utils.isVector2 = function(member) { + return ( + member instanceof GameLib.API.Vector2 || + member instanceof GameLib.Vector2 + ); +}; + +GameLib.Utils.isVector3 = function(member) { + return ( + member instanceof GameLib.API.Vector3 || + member instanceof GameLib.Vector3 + ); +}; + +GameLib.Utils.isVector4 = function(member) { + return ( + member instanceof GameLib.API.Vector4 || + member instanceof GameLib.Vector4 || + member instanceof GameLib.API.Quaternion || + member instanceof GameLib.Quaternion + ); +}; + +/** + * @return {string} + */ +GameLib.Utils.LowerUnderscore = function(name) { + return name.toLowerCase().replace(/\s+/, '_'); +}; + +GameLib.Utils.UpperCaseWordsSpaces = function(word) { + return word.replace(/[-_]/g, ' ').split(' ').reduce( + function(result, word) { + result += word[0].toUpperCase() + word.substr(1); + return result + ' '; + }, + '' + ).trim(); +}; +/** + * API Component Interface - Do not construct objects of this type directly + * @param componentType + * @param parentEntity + * @constructor + */ +GameLib.API.Component = function( + componentType, + parentEntity +) { + this.componentType = componentType; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + +}; + +GameLib.API.Component.prototype = Object.create(GameLib.Event.prototype); +GameLib.API.Component.prototype.constructor = GameLib.API.Component; +/** + * Component Interface + * @constructor + * @param componentType + * @param linkedObjects + * @param delayed + */ +GameLib.Component = function( + componentType, + linkedObjects, + delayed +) { + if (GameLib.Utils.UndefinedOrNull(linkedObjects)) { + linkedObjects = {}; + } + this.linkedObjects = linkedObjects; + this.linkedObjects.parentEntity = GameLib.Entity; + + GameLib.API.Component.call( + this, + componentType, + this.parentEntity + ); + + this.idToObject = {}; + + this.selected = false; + + this.building = false; + + this.loaded = false; + + this.linked = false; + + this.cloneNumber = 0; + + this.isClone = false; + + if (GameLib.Utils.UndefinedOrNull(delayed)) { + delayed = false; + } + this.delayed = delayed; + + this.dependencies = this.getDependencies(); + + GameLib.Event.Emit( + GameLib.Event.COMPONENT_REGISTER, + { + component : this + } + ); + + if (this.dependencies.length === 0) { + + this.performInstanceCreation(); + + } else { + GameLib.Event.Emit( + GameLib.Event.REGISTER_DEPENDENCIES, + { + component : this + } + ); + } + + +}; + +GameLib.Component.prototype = Object.create(GameLib.API.Component.prototype); +GameLib.Component.prototype.constructor = GameLib.Component; + +/** + * This function, performs standard instance creation steps for all our components, which means + * Ensure we have no dependencies + * Build a list of all child components - if they are all linked, we are ready to create an instance + * Ensure we are linked + * Ensure we are not delayed + * Try to create the instance + * Error Log if failed + * Don't do anything if we are not fully linked + */ +GameLib.Component.prototype.performInstanceCreation = function() { + + var dependencies = true; + + if (GameLib.Utils.UndefinedOrNull(this.dependencies)) { + dependencies = false; + } + + if (this.dependencies && this.dependencies instanceof Array && this.dependencies.length === 0) { + dependencies = false; + } + + if (dependencies) { + throw new Error('performInstanceCreation called while this object still has dependencies'); + } + + delete this.dependencies; + + /** + * Build ID to object should run through all sub components - + * if one is found which is not linked, this component is not linked fully + */ + this.buildIdToObject(); + + /** + * Don't try to create an instance of this object until it is fully linked + */ + if (this.linked) { + if (!this.delayed) { + try { + this.createInstance(); + } catch (error) { + console.error(error); + } + } else { + /** + * Some systems require a restart in order to create the delayed components (like System.Input for + * Edit Controls) - we need to give them the opportunity to restart + */ + GameLib.Event.Emit( + GameLib.Event.DELAYED_INSTANCE_ENCOUNTERED, + { + component : this + } + ) + } + } +}; + +GameLib.Component.prototype.createInstance = function() { + + // console.log('create instance : '+ this.name); + + /** + * When you do actually call 'createInstance' - it is wise to state we are no longer delayed - we assume the caller + * knows when to call createInstance, so we do the housekeeping here + * @type {boolean} + */ + this.delayed = false; + + if (this.instance) { + + this.loaded = true; + + GameLib.Event.Emit( + GameLib.Event.INSTANCE_CREATED, + { + component: this + } + ) + } + + if (this instanceof GameLib.Entity) { + GameLib.Event.Emit( + GameLib.Event.ENTITY_LOADED, + { + entity:this + } + ) + } +}; + +/** + * Dependencies are everything which is either a string or an object with an id which is linked to this object + * @returns {Array} + */ +GameLib.Component.prototype.getDependencies = function() { + + var dependencies = []; + + for (var property in this.linkedObjects) { + + if ( + this.linkedObjects.hasOwnProperty(property) && + property.indexOf('parent') !== 0 && + this.hasOwnProperty(property) + ){ + if (typeof this[property] === 'string') { + GameLib.Utils.PushUnique(dependencies, this[property]); + } + + if (this[property] instanceof Array) { + this[property].map( + function(arrayProperty) { + + if (typeof arrayProperty === 'string') { + GameLib.Utils.PushUnique(dependencies, arrayProperty); + } + + if (arrayProperty && + arrayProperty instanceof GameLib.Component + ) { + GameLib.Utils.PushUnique(dependencies, arrayProperty.id); + } + } + ); + } + + if (this[property] && + this[property] instanceof GameLib.Component + ) { + GameLib.Utils.PushUnique(dependencies, this[property].id); + } + } + } + + return dependencies; +}; + +GameLib.Component.prototype.toString = function() { + return this.id; +}; + +GameLib.Component.COMPONENT_PATH_FOLLOWING = 0x1; +GameLib.Component.COMPONENT_MATERIAL = 0x2; +GameLib.Component.COMPONENT_RENDERER = 0x3; +GameLib.Component.COMPONENT_LOOK_AT = 0x4; +GameLib.Component.COMPONENT_CAMERA = 0x5; +GameLib.Component.COMPONENT_FOLLOW = 0x6; +GameLib.Component.COMPONENT_MESH = 0x7; +GameLib.Component.COMPONENT_SPLINE = 0x8; +GameLib.Component.COMPONENT_LIGHT = 0x9; +GameLib.Component.COMPONENT_INPUT_DRIVE = 0xa; +GameLib.Component.COMPONENT_COMPOSER = 0xb; +GameLib.Component.COMPONENT_RENDER_TARGET = 0xc; +GameLib.Component.COMPONENT_PASS = 0xd; +GameLib.Component.COMPONENT_SCENE = 0xe; +GameLib.Component.COMPONENT_RAYCASTER = 0xf; +GameLib.Component.COMPONENT_INPUT_EDITOR = 0x10; +GameLib.Component.COMPONENT_EDITOR = 0x11; +GameLib.Component.COMPONENT_VIEWPORT = 0x12; +GameLib.Component.COMPONENT_SYSTEM = 0x13; +GameLib.Component.COMPONENT_GRAPHICS = 0x14; +GameLib.Component.COMPONENT_HELPER = 0x15; +GameLib.Component.COMPONENT_CUSTOM_CODE = 0x16; +GameLib.Component.COMPONENT_MOUSE = 0x17; +GameLib.Component.COMPONENT_SKELETON = 0x18; +GameLib.Component.COMPONENT_TEXTURE = 0x19; +GameLib.Component.COMPONENT_ENTITY_MANAGER = 0x1a; +GameLib.Component.COMPONENT_DOM_ELEMENT = 0x1b; +GameLib.Component.COMPONENT_IMAGE_FACTORY = 0x1c; +GameLib.Component.COMPONENT_STATS = 0x1d; +GameLib.Component.COMPONENT_GUI = 0x1e; +GameLib.Component.COMPONENT_IMAGE = 0x1f; +GameLib.Component.COMPONENT_ENTITY = 0x20; +GameLib.Component.COMPONENT_MESH_SPHERE = 0x21; +GameLib.Component.COMPONENT_MESH_PLANE = 0x22; +GameLib.Component.COMPONENT_MESH_CURVE = 0x23; +GameLib.Component.COMPONENT_PHYSICS_WORLD = 0x24; +GameLib.Component.COMPONENT_BROADPHASE = 0x25; +GameLib.Component.COMPONENT_SOLVER = 0x26; +GameLib.Component.COMPONENT_RIGID_BODY = 0x27; +GameLib.Component.COMPONENT_SHAPE = 0x28; +GameLib.Component.COMPONENT_SHAPE_BOX = 0x29; +GameLib.Component.COMPONENT_SHAPE_SPHERE = 0x2a; +GameLib.Component.COMPONENT_SHAPE_TRI_MESH = 0x2b; +GameLib.Component.COMPONENT_SHAPE_CONVEX_HULL = 0x2c; +GameLib.Component.COMPONENT_SHAPE_CONVEX_HULL_CYLINDER = 0x2d; +GameLib.Component.COMPONENT_SHAPE_HEIGHT_MAP = 0x2e; +GameLib.Component.COMPONENT_SHAPE_PLANE = 0x2f; +GameLib.Component.COMPONENT_CONTROLS = 0x30; +GameLib.Component.COMPONENT_CONTROLS_EDITOR = 0x31; +GameLib.Component.COMPONENT_CONTROLS_TOUCH = 0x32; +GameLib.Component.COMPONENT_FRICTION_MATERIAL = 0x33; +GameLib.Component.COMPONENT_FRICTION_CONTACT_MATERIAL = 0x34; +GameLib.Component.COMPONENT_RAYCAST_VEHICLE = 0x35; +GameLib.Component.COMPONENT_RAYCAST_WHEEL = 0x36; +GameLib.Component.COMPONENT_CLOCK = 0x37; +GameLib.Component.COMPONENT_ANIMATION = 0x38; +GameLib.Component.COMPONENT_CONTROLS_KEYBOARD = 0x39; +GameLib.Component.COMPONENT_CONTROLS_MOUSE = 0x3a; +GameLib.Component.COMPONENT_MESH_TEXT = 0x3b; +GameLib.Component.COMPONENT_FONT = 0x3c; +GameLib.Component.COMPONENT_CANVAS = 0x3d; +GameLib.Component.COMPONENT_BONE = 0x3e; +GameLib.Component.COMPONENT_MESH_BOX = 0x3f; +GameLib.Component.COMPONENT_MESH_CYLINDER = 0x40; +GameLib.Component.COMPONENT_SYSTEM_ANIMATION = 0x41; +GameLib.Component.COMPONENT_SYSTEM_CUSTOM_CODE = 0x42; +GameLib.Component.COMPONENT_SYSTEM_GUI = 0x43; +GameLib.Component.COMPONENT_SYSTEM_INPUT = 0x44; +GameLib.Component.COMPONENT_SYSTEM_LINKING = 0x45; +GameLib.Component.COMPONENT_SYSTEM_PHYSICS = 0x46; +GameLib.Component.COMPONENT_SYSTEM_RENDER = 0x47; +GameLib.Component.COMPONENT_SYSTEM_STORAGE = 0x48; +GameLib.Component.COMPONENT_SYSTEM_VISUALIZATION = 0x49; +GameLib.Component.COMPONENT_FOG = 0x50; +GameLib.Component.COMPONENT_MESH_LINE = 0x51; +GameLib.Component.COMPONENT_PARTICLE_ENGINE = 0x52; +GameLib.Component.COMPONENT_SYSTEM_PARTICLE = 0x53; +GameLib.Component.COMPONENT_PARTICLE = 0x54; +GameLib.Component.COMPONENT_AUDIO = 0x55; +GameLib.Component.COMPONENT_SYSTEM_AUDIO = 0x56; + +/** + * Returns string name for component number + * @param number + * @returns {*} + * @constructor + */ +GameLib.Component.GetComponentName = function(number) { + switch(number) { + case 0x1 : return 'GameLib.D3.PathFollowing'; + case 0x2 : return 'GameLib.D3.Material'; + case 0x3 : return 'GameLib.D3.Renderer'; + case 0x4 : return 'GameLib.D3.LookAt'; + case 0x5 : return 'GameLib.D3.Camera'; + case 0x6 : return 'GameLib.D3.Follow'; + case 0x7 : return 'GameLib.D3.Mesh'; + case 0x8 : return 'GameLib.D3.Spline'; + case 0x9 : return 'GameLib.D3.Light'; + case 0xa : return 'GameLib.D3.InputDrive'; + case 0xb : return 'GameLib.D3.Composer'; + case 0xc : return 'GameLib.D3.RenderTarget'; + case 0xd : return 'GameLib.D3.Pass'; + case 0xe : return 'GameLib.D3.Scene'; + case 0xf : return 'GameLib.D3.Raycaster'; + case 0x10 : return 'GameLib.D3.InputEditor'; + case 0x11 : return 'GameLib.D3.Editor'; + case 0x12 : return 'GameLib.D3.Viewport'; + case 0x13 : return 'GameLib.System'; + case 0x14 : return 'GameLib.D3.Graphics'; + case 0x15 : return 'GameLib.D3.Helper'; + case 0x16 : return 'GameLib.D3.CustomCode'; + case 0x17 : return 'GameLib.Mouse'; + case 0x18 : return 'GameLib.D3.Skeleton'; + case 0x19 : return 'GameLib.D3.Texture'; + case 0x1a : return 'GameLib.EntityManager'; + case 0x1b : return 'GameLib.DomElement'; + case 0x1c : return 'GameLib.D3.ImageFactory'; + case 0x1d : return 'GameLib.D3.Stats'; + case 0x1e : return 'GameLib.GUI'; + case 0x1f : return 'GameLib.D3.Image'; + case 0x20 : return 'GameLib.Entity'; + case 0x21 : return 'GameLib.D3.Mesh.Sphere'; + case 0x22 : return 'GameLib.D3.Mesh.Plane'; + case 0x23 : return 'GameLib.D3.Mesh.Curve'; + case 0x24 : return 'GameLib.D3.PhysicsWorld'; + case 0x25 : return 'GameLib.D3.Broadphase'; + case 0x26 : return 'GameLib.D3.Solver'; + case 0x27 : return 'GameLib.D3.RigidBody'; + case 0x28 : return 'GameLib.D3.Shape'; + case 0x29 : return 'GameLib.D3.Shape.Box'; + case 0x2a : return 'GameLib.D3.Shape.Sphere'; + case 0x2b : return 'GameLib.D3.Shape.TriMesh'; + case 0x2c : return 'GameLib.D3.Shape.ConvexHull'; + case 0x2d : return 'GameLib.D3.Shape.ConvexHull.Cylinder'; + case 0x2e : return 'GameLib.D3.Shape.HeightMap'; + case 0x2f : return 'GameLib.D3.Shape.Plane'; + case 0x30 : return 'GameLib.D3.Controls'; + case 0x31 : return 'GameLib.D3.Controls.Editor'; + case 0x32 : return 'GameLib.D3.Controls.Touch'; + case 0x33 : return 'GameLib.D3.FrictionMaterial'; + case 0x34 : return 'GameLib.D3.FrictionContactMaterial'; + case 0x35 : return 'GameLib.D3.RaycastVehicle'; + case 0x36 : return 'GameLib.D3.RaycastWheel'; + case 0x37 : return 'GameLib.Clock'; + case 0x38 : return 'GameLib.D3.Animation'; + case 0x39 : return 'GameLib.D3.Controls.Keyboard'; + case 0x3a : return 'GameLib.D3.Controls.Mouse'; + case 0x3b : return 'GameLib.D3.Mesh.Text'; + case 0x3c : return 'GameLib.D3.Font'; + case 0x3d : return 'GameLib.D3.Canvas'; + case 0x3e : return 'GameLib.D3.Bone'; + case 0x3f : return 'GameLib.D3.Mesh.Box'; + case 0x40 : return 'GameLib.D3.Mesh.Cylinder'; + case 0x41 : return 'GameLib.D3.System.Animation'; + case 0x42 : return 'GameLib.D3.System.CustomCode'; + case 0x43 : return 'GameLib.D3.System.GUI'; + case 0x44 : return 'GameLib.D3.System.Input'; + case 0x45 : return 'GameLib.D3.System.Linking'; + case 0x46 : return 'GameLib.D3.System.Physics'; + case 0x47 : return 'GameLib.D3.System.Render'; + case 0x48 : return 'GameLib.D3.System.Storage'; + case 0x49 : return 'GameLib.D3.System.Visualization'; + case 0x50 : return 'GameLib.D3.Fog'; + case 0x51 : return 'GameLib.D3.Mesh.Line'; + case 0x52 : return 'GameLib.D3.ParticleEngine'; + case 0x53 : return 'GameLib.D3.System.Particle'; + case 0x54 : return 'GameLib.D3.Particle'; + case 0x55 : return 'GameLib.D3.Audio'; + case 0x56 : return 'GameLib.D3.System.Audio'; + break; + } + + throw new Error('Unknown component type: ' + number ); +}; + +/** + * Components are linked at runtime - for storing, we just store the ID + * @returns {*} + */ +GameLib.Component.prototype.toApiObject = function() { + return this.id; +}; + +GameLib.Component.prototype.processComponent = function(object) { + if (object instanceof GameLib.Component) { + + object.buildIdToObject(); + + if (!object.linked) { + this.linked = false; + } + + var idToObject = object.idToObject; + + for (var objectProperty in idToObject) { + if (idToObject.hasOwnProperty(objectProperty)) { + this.idToObject[objectProperty] = idToObject[objectProperty]; + } + } + + if (object.id) { + this.idToObject[object.id] = object; + } else { + console.warn('Object with no ID passed: ' + object) + } + + } else if (typeof object === 'string') { + this.linked = false; + } else { + console.warn('Unhandled type of object: ', object); + } +}; + +/** + * This function - builds an 'id to object' object - which contains the ids which point directly + * to its corresponding object, for all the objects contained inside this object + */ +GameLib.Component.prototype.buildIdToObject = function() { + + if (this.building) { + return; + } + + /** + * If this component 'building' flag is true - it is in the process of building idToObject up the callstack and the + * caller should know to not try to build idToObject again (prevent infinite recursion) + */ + this.building = true; + + /** + * If any child component is not fully linked, this component will show as not linked + * @type {boolean} + */ + this.linked = true; + + this.idToObject = {}; + + for (var property in this.linkedObjects) { + if ( + this.linkedObjects.hasOwnProperty(property) && + this.hasOwnProperty(property) && + this[property] && + property.indexOf('parent') !== 0 + ) { + + if (this.linkedObjects[property] instanceof Array) { + + /** + * Remove null objects (can happen) + */ + this[property] = this[property].filter( + function (object) { + if (object === null) { + console.log('null object found and removed'); + return false; + } + return true; + } + ); + + this[property].map( + function (object) { + this.processComponent(object); + }.bind(this) + ); + + } else { + this.processComponent(this[property]); + } + } + } + + if (this instanceof GameLib.D3.Scene) { + if (!this.storeClones) { + this.clones.map( + function (clone) { + if (this.idToObject.hasOwnProperty(clone.id)) { + delete this.idToObject[clone.id]; + } + }.bind(this) + ) + } + } + + this.idToObject[this.id] = this; + + this.building = false; +}; + +GameLib.Component.prototype.generateNewIds = function() { + + this.buildIdToObject(); + + var codeComponents = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.CustomCode); + + for (var property in this.idToObject) { + if (this.idToObject.hasOwnProperty(property)) { + + var oldId = this.idToObject[property].id; + var newId = GameLib.Utils.RandomId(); + + this.idToObject[property].id = newId; + this.idToObject[property].name = this.idToObject[property].name.replace(oldId,newId); + codeComponents.map(function(codeComponent){ + codeComponent.code = codeComponent.code.replace(oldId,newId); + }); + } + } + +}; + +GameLib.Component.prototype.remove = function() { + + this.buildIdToObject(); + + var dependencies = this.getDependencies(); + + dependencies.map( + function(objectId) { + + var childComponent = this.idToObject[objectId]; + + if (childComponent instanceof GameLib.Component) { + childComponent.remove(); + } + + }.bind(this) + ); + + GameLib.Event.Emit( + GameLib.Event.REMOVE_COMPONENT, + { + component : this + } + ) + +}; + +GameLib.Component.prototype.clone = function() { + + var apiObject = this.toApiObject(); + + this.cloneNumber += 1; + + apiObject.id = GameLib.Utils.RandomId(); + + apiObject.name = this.name + ' Clone (' + this.cloneNumber + ')'; + + var runtimeObject = null; + + try { + runtimeObject = new this.constructor(this.graphics, apiObject); + } catch (e){ + console.log(e); + try { + runtimeObject = new this.constructor(this.physics, apiObject); + } catch (e) { + console.log(e); + try { + runtimeObject = new this.constructor(this.coder, apiObject); + } catch (e) { + console.log(e); + console.log('failed to construct a runtime component'); + return; + } + } + } + + runtimeObject.isClone = true; + + GameLib.Event.Emit( + GameLib.Event.COMPONENT_CLONED, + { + parent : this, + component : runtimeObject + } + ); + + runtimeObject.parentEntity = null; + + // if (this.parentEntity instanceof GameLib.Entity) { + // this.parentEntity.addComponent(runtimeObject); + // } + + return runtimeObject; + +}; + +/** + * Clones only the instance + */ +GameLib.Component.prototype.cloneInstance = function() { + + var clone = null; + + if ( + this.instance && + this.instance.clone && + typeof (this.instance.clone === 'function')) { + + clone = this.instance.clone(); + + GameLib.Event.Emit( + GameLib.Event.INSTANCE_CLONED, + { + component : this, + instance : clone + } + ) + } + + return clone; +}; + +GameLib.Component.prototype.saveToRemoteAPI = function() { + this.save(true); +}; + +GameLib.Component.prototype.save = function(remote) { + + var toSave = []; + var saved = []; + var failed = []; + + this.buildIdToObject(); + + if (this.saveSubscription || this.saveErrorSubscription) { + console.warn('another save is in progress'); + return; + } + + GameLib.Event.Emit( + GameLib.Event.SAVING, + { + component: this + } + ); + + this.saveSubscription = GameLib.Event.Subscribe( + GameLib.Event.COMPONENT_SAVED, + function(data) { + + saved.push(data.component); + + if (failed.length + saved.length === toSave.length) { + + this.saveSubscription.remove(); + + this.saveSubscription = null; + + this.saveErrorSubscription.remove(); + + this.saveErrorSubscription = null; + + GameLib.Event.Emit( + GameLib.Event.DONE_SAVING, + { + failed: failed, + saved: saved + } + ) + } + + }.bind(this) + ); + + this.saveErrorSubscription = GameLib.Event.Subscribe( + GameLib.Event.SAVE_COMPONENT_ERROR, + function(data) { + + failed.push(data.component); + + if (failed.length + saved.length === toSave.length) { + + this.saveSubscription.remove(); + + this.saveSubscription = null; + + this.saveErrorSubscription.remove(); + + this.saveErrorSubscription = null; + + GameLib.Event.Emit( + GameLib.Event.DONE_SAVING, + { + failed: failed, + saved: saved + } + ) + } + + }.bind(this) + ); + + for (var property in this.idToObject) { + if ( + this.idToObject.hasOwnProperty(property) && + this.idToObject[property] instanceof GameLib.Component + ) { + + var apiObject = this.idToObject[property].toApiObject(); + + apiObject.componentType = this.idToObject[property].componentType; + + toSave.push(apiObject); + + this.publish( + GameLib.Event.SAVE_COMPONENT, + { + apiObject: apiObject, + remote: remote + } + ); + } + } + +}; +/** + * Raw Clock API object - should always correspond with the Clock Schema + * @constructor + * @param id + * @param name + * @param parentEntity + */ +GameLib.API.Clock = function( + id, + name, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Clock (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.API.Clock.prototype = Object.create(GameLib.Component.prototype); +GameLib.API.Clock.prototype.constructor = GameLib.API.Clock; + +/** + * Creates an API camera from an Object camera + * @param objectClock + * @constructor + */ +GameLib.API.Clock.FromObject = function(objectClock) { + + return new GameLib.API.Clock( + objectClock.id, + objectClock.name, + objectClock.parentEntity + ); + +}; + +/** + * API Color + * @param r + * @param g + * @param b + * @param a + * @constructor + */ +GameLib.API.Color = function (r, g, b, a) { + + if (GameLib.Utils.UndefinedOrNull(r)) { + r = 1; + } + this.r = r; + + if (GameLib.Utils.UndefinedOrNull(g)) { + g = 1; + } + this.g = g; + + if (GameLib.Utils.UndefinedOrNull(b)) { + b = 1; + } + this.b = b; + + if (GameLib.Utils.UndefinedOrNull(a)) { + a = 0; + } + this.a = a; + +}; + +/** + * Returns an API color from an Object color + * @param objectColor + * @constructor + */ +GameLib.API.Color.FromObject = function(objectColor) { + + if (GameLib.Utils.UndefinedOrNull(objectColor)){ + objectColor = {}; + } + + return new GameLib.API.Color( + objectColor.r, + objectColor.g, + objectColor.b, + objectColor.a + ); + +}; + +/** + * Converts the current color to HTML hex format (ex. #ffffff) + * @returns {string} + */ +GameLib.API.Color.prototype.toHex = function() { + + if (this.r < 0) { + this.r = 0; + } + + if (this.g < 0) { + this.g = 0; + } + + if (this.b < 0) { + this.b = 0; + } + + if (this.r > 1) { + this.r = 1; + } + + if (this.g > 1) { + this.g = 1; + } + + if (this.b > 1) { + this.b = 1; + } + + var rf = Math.floor(this.r >= 1? 255 : this.r * 256.0).toString(16); + var gf = Math.floor(this.g >= 1? 255 : this.g * 256.0).toString(16); + var bf = Math.floor(this.b >= 1? 255 : this.b * 256.0).toString(16); + + if (rf.length < 2) { + rf = '0' + rf; + } + + if (gf.length < 2) { + gf = '0' + gf; + } + + if (bf.length < 2) { + bf = '0' + bf; + } + + return '#' + rf + gf + bf; +}; + +/** + * Sets this object color to what the hex value is + * @param hex + * @returns {string} + */ +GameLib.API.Color.prototype.fromHex = function(hex) { + + var matches = hex.match(new RegExp('#+(..)(..)(..)')); + + this.r = parseInt(matches[1], 16) / 255.0; + this.g = parseInt(matches[2], 16) / 255.0; + this.b = parseInt(matches[3], 16) / 255.0; +}; + +/** + * API DomElement + * @param id + * @param name + * @param domElementId + * @param parentEntity + * @constructor + */ +GameLib.API.DomElement = function( + id, + name, + domElementId, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'DOM Element (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(domElementId)) { + domElementId = ''; + } + this.domElementId = domElementId; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.API.DomElement.prototype = Object.create(GameLib.Component.prototype); +GameLib.API.DomElement.prototype.constructor = GameLib.API.DomElement; + +/** + * Returns an API domElement from an Object domElement + * @param objectDomElement + * @constructor + */ +GameLib.API.DomElement.FromObject = function (objectDomElement) { + return new GameLib.API.DomElement( + objectDomElement.id, + objectDomElement.name, + objectDomElement.domElementId, + objectDomElement.parentEntity + ) +}; + +/** + * Entity API Object (for storing / loading entities to and from API) + * @constructor + * @param id + * @param name + * @param entities GameLib.API.Entity[] + * @param defaultEntity + * @param defaultRenderer + */ +GameLib.API.EntityManager = function( + id, + name, + entities, + defaultEntity, + defaultRenderer +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Entity Manager (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(entities)) { + entities = []; + } + this.entities = entities; + + if (GameLib.Utils.UndefinedOrNull(defaultEntity)) { + defaultEntity = null; + } + this.defaultEntity = defaultEntity; + + if (GameLib.Utils.UndefinedOrNull(defaultRenderer)) { + defaultRenderer = null; + } + this.defaultRenderer = defaultRenderer; +}; + +GameLib.API.EntityManager.prototype = Object.create(GameLib.Component.prototype); +GameLib.API.EntityManager.prototype.constructor = GameLib.API.EntityManager; + +/** + * Creates an API entity manager from an Object entity manager + * @param objectEntityManager + * @constructor + */ +GameLib.API.EntityManager.FromObject = function(objectEntityManager) { + + var apiEntities = objectEntityManager.entities.map( + function (objectEntity) { + return GameLib.API.Entity.FromObject(objectEntity); + } + ); + + return new GameLib.API.EntityManager( + objectEntityManager.id, + objectEntityManager.name, + apiEntities, + objectEntityManager.defaultEntity, + objectEntityManager.defaultRenderer + ); +}; + +/** + * Entity API Object (for storing / loading entities to and from API) + * @param id + * @param name + * @param components GameLib.Component[] + * @param parentEntity GameLib.Entity + * @param parentEntityManager + * @constructor + */ +GameLib.API.Entity = function( + id, + name, + components, + parentEntity, + parentEntityManager +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Entity (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(components)) { + components = []; + } + this.components = components; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + + if (GameLib.Utils.UndefinedOrNull(parentEntityManager)) { + parentEntityManager = null; + } + this.parentEntityManager = parentEntityManager; + + this.activeComponent = null; +}; + +GameLib.API.Entity.prototype = Object.create(GameLib.Component.prototype); +GameLib.API.Entity.prototype.constructor = GameLib.API.Entity; + +/** + * Returns an API entity from an Object entity + * @param objectEntity + * @constructor + */ +GameLib.API.Entity.FromObject = function(objectEntity) { + return new GameLib.API.Entity( + objectEntity.id, + objectEntity.name, + objectEntity.components, + objectEntity.parentEntity, + objectEntity.parentEntityManager + ) +}; + +/** + * Api Matrix 4 + * @param row0 GameLib.API.Vector4 + * @param row1 GameLib.API.Vector4 + * @param row2 GameLib.API.Vector4 + * @param row3 GameLib.API.Vector4 + * @constructor + */ +GameLib.API.Matrix4 = function ApiMatrix4( + row0, + row1, + row2, + row3 +) { + this.rows = []; + + if (GameLib.Utils.UndefinedOrNull(row0)) { + row0 = new GameLib.API.Vector4(1, 0, 0, 0); + } + this.rows[0] = row0; + + if (GameLib.Utils.UndefinedOrNull(row1)) { + row1 = new GameLib.API.Vector4(0, 1, 0, 0); + } + this.rows[1] = row1; + + if (GameLib.Utils.UndefinedOrNull(row2)) { + row2 = new GameLib.API.Vector4(0, 0, 1, 0); + } + this.rows[2] = row2; + + if (GameLib.Utils.UndefinedOrNull(row3)) { + row3 = new GameLib.API.Vector4(0, 0, 0, 1); + } + this.rows[3] = row3; + + this.temp = []; + this.temp.push( + new GameLib.API.Vector4() + ); + + this.temp.push( + new GameLib.API.Vector4() + ); + + this.temp.push( + new GameLib.API.Vector4() + ); + + this.temp.push( + new GameLib.API.Vector4() + ); + + this.forward = new GameLib.API.Vector4(); + this.left = new GameLib.API.Vector4(); + this.up = new GameLib.API.Vector4(); +}; + +/** + * Returns an API matrix from an Object matrix + * @param objectMatrix + * @constructor + */ +GameLib.API.Matrix4.FromObject = function(objectMatrix) { + + if (objectMatrix.rows) { + return new GameLib.API.Matrix4( + GameLib.API.Vector4.FromObject(objectMatrix.rows[0]), + GameLib.API.Vector4.FromObject(objectMatrix.rows[1]), + GameLib.API.Vector4.FromObject(objectMatrix.rows[2]), + GameLib.API.Vector4.FromObject(objectMatrix.rows[3]) + ); + } else if (objectMatrix instanceof Array) { + return new GameLib.API.Matrix4( + GameLib.API.Vector4.FromObject(objectMatrix[0]), + GameLib.API.Vector4.FromObject(objectMatrix[1]), + GameLib.API.Vector4.FromObject(objectMatrix[2]), + GameLib.API.Vector4.FromObject(objectMatrix[3]) + ); + } else { + console.warn('Unsupported object matrix type - whats your DB version?'); + throw new Error('Unsupported object matrix type - whats your DB version?'); + } +}; + +GameLib.API.Matrix4.prototype.rotationMatrixX = function (radians) { + this.identity(); + this.rows[1] = new GameLib.API.Vector4(0, Math.cos(radians), -1 * Math.sin(radians), 0); + this.rows[2] = new GameLib.API.Vector4(0, Math.sin(radians), Math.cos(radians), 0); + return this; +}; + +GameLib.API.Matrix4.prototype.rotationMatrixY = function (radians) { + this.identity(); + this.rows[0] = new GameLib.API.Vector4( + Math.cos(radians), + 0, + Math.sin(radians), + 0 + ); + this.rows[2] = new GameLib.API.Vector4( + -1 * Math.sin(radians), + 0, + Math.cos(radians), + 0 + ); + return this; +}; + +GameLib.API.Matrix4.prototype.rotationMatrixZ = function (radians) { + this.identity(); + this.rows[0] = new GameLib.API.Vector4(Math.cos(radians), -1 * Math.sin(radians), 0, 0); + this.rows[1] = new GameLib.API.Vector4(Math.sin(radians), Math.cos(radians), 0, 0); + return this; +}; + +GameLib.API.Matrix4.prototype.rotateX = function (radians, point) { + this.identity(); + this.rotationMatrixX(radians); + return this.multiply(point); +}; + +GameLib.API.Matrix4.prototype.rotateY = function (radians, point) { + this.identity(); + this.rotationMatrixY(radians); + return this.multiply(point); +}; + +GameLib.API.Matrix4.prototype.rotateZ = function (radians, point) { + this.identity(); + this.rotationMatrixZ(radians); + return this.multiply(point); +}; + +GameLib.API.Matrix4.prototype.multiply = function (mvp) { + if (mvp instanceof GameLib.API.Quaternion || mvp instanceof GameLib.API.Vector4) { + return new GameLib.API.Quaternion( + this.rows[0].x * mvp.x + this.rows[0].y * mvp.y + this.rows[0].z * mvp.z + this.rows[0].w * mvp.w, + this.rows[1].x * mvp.x + this.rows[1].y * mvp.y + this.rows[1].z * mvp.z + this.rows[1].w * mvp.w, + this.rows[2].x * mvp.x + this.rows[2].y * mvp.y + this.rows[2].z * mvp.z + this.rows[2].w * mvp.w, + this.rows[3].x * mvp.x + this.rows[3].y * mvp.y + this.rows[3].z * mvp.z + this.rows[3].w * mvp.w + ); + } else if (mvp instanceof GameLib.API.Vector3) { + return new GameLib.API.Vector3( + this.rows[0].x * mvp.x + this.rows[0].y * mvp.y + this.rows[0].z * mvp.z, + this.rows[1].x * mvp.x + this.rows[1].y * mvp.y + this.rows[1].z * mvp.z, + this.rows[2].x * mvp.x + this.rows[2].y * mvp.y + this.rows[2].z * mvp.z + ); + } +}; + +GameLib.API.Matrix4.prototype.identity = function () { + this.rows = [ + new GameLib.API.Vector4(1, 0, 0, 0), + new GameLib.API.Vector4(0, 1, 0, 0), + new GameLib.API.Vector4(0, 0, 1, 0), + new GameLib.API.Vector4(0, 0, 0, 1) + ]; +}; + +/** + * API Mouse + * @param id + * @param name + * @param x + * @param y + * @param parentEntity + * @constructor + */ +GameLib.API.Mouse = function( + id, + name, + x, + y, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Mouse (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(x)) { + x = 0; + } + this.x = x; + + if (GameLib.Utils.UndefinedOrNull(y)) { + y = 0; + } + this.y = y; + +}; + +GameLib.API.Mouse.prototype = Object.create(GameLib.Component.prototype); +GameLib.API.Mouse.prototype.constructor = GameLib.API.Mouse; + +/** + * Returns an API mouse from an Object mouse + * @param objectMouse + * @constructor + */ +GameLib.API.Mouse.FromObject = function (objectMouse) { + return new GameLib.API.Mouse( + objectMouse.id, + objectMouse.name, + objectMouse.x, + objectMouse.y, + objectMouse.parentEntity + ) +}; + +/** + * Quaternion + * @param x + * @param y + * @param z + * @param w + * @param axis + * @param angle + * @constructor + */ +GameLib.API.Quaternion = function ( + x, + y, + z, + w, + axis, + angle +) { + + if (GameLib.Utils.UndefinedOrNull(x)) { + x = 0; + } + this.x = x; + + if (GameLib.Utils.UndefinedOrNull(y)) { + y = 0; + } + this.y = y; + + if (GameLib.Utils.UndefinedOrNull(z)) { + z = 0; + } + this.z = z; + + if (GameLib.Utils.UndefinedOrNull(w)) { + w = 1; + } + this.w = w; + + if (GameLib.Utils.UndefinedOrNull(axis)) { + axis = new GameLib.API.Vector3(); + } + this.axis = axis; + + if (GameLib.Utils.UndefinedOrNull(angle)) { + angle = 0; + } + this.angle = angle; +}; + +GameLib.API.Quaternion.prototype.translate = function (v) { + this.x += v.x; + this.y += v.y; + this.z += v.z; + return this; +}; + +GameLib.API.Quaternion.prototype.copy = function () { + return new GameLib.API.Quaternion( + this.x, + this.y, + this.z, + this.w + ); +}; + +/** + * Note, this normalize function leaves 'w' component untouched + */ +GameLib.API.Quaternion.prototype.normalize = function () { + + var EPSILON = 0.000001; + + var v2 = this.x * this.x + this.y * this.y + this.z * this.z; + + if (v2 < EPSILON) { + return this; //do nothing for zero vector + } + + var invLength = 1 / Math.sqrt(v2); + + this.x *= invLength; + this.y *= invLength; + this.z *= invLength; +}; + +GameLib.API.Quaternion.prototype.multiply = function (q) { + + var x, y, z, w; + var a = q; + var b = this; + + if (q instanceof GameLib.API.Matrix4) { + + x = a.rows[0].x * b.x + a.rows[0].y * b.y + a.rows[0].z * b.z + a.rows[0].w * b.w; + y = a.rows[1].x * b.x + a.rows[1].y * b.y + a.rows[1].z * b.z + a.rows[1].w * b.w; + z = a.rows[2].x * b.x + a.rows[2].y * b.y + a.rows[2].z * b.z + a.rows[2].w * b.w; + w = a.rows[3].x * b.x + a.rows[3].y * b.y + a.rows[3].z * b.z + a.rows[3].w * b.w; + + this.x = x; + this.y = y; + this.z = z; + this.w = w; + + return this; + + } else if (q instanceof GameLib.API.Quaternion) { + + x = ((a.x * b.x) - (a.y * b.y) - (a.z * b.z) - (a.w * a.w)); + y = ((a.x * b.y) + (a.y * b.x) - (a.z * b.w) + (a.w * a.z)); + z = ((a.x * b.z) + (a.y * b.w) + (a.z * b.x) - (a.w * a.y)); + w = ((a.x * b.w) - (a.y * b.z) + (a.z * b.y) + (a.w * a.x)); + + this.x = x; + this.y = y; + this.z = z; + this.w = w; + + return this; + + } else { + console.log("This functionality not implemented - please do this"); + throw new Error("This functionality not implemented - please do this"); + } +}; + +GameLib.API.Quaternion.prototype.setFromAngle = function (angle) { + + this.instance.setFromAxisAngle(this.axis.instance, angle); + + this.x = this.instance.x; + this.y = this.instance.y; + this.z = this.instance.z; + this.w = this.instance.w; + + return this; +}; + +GameLib.API.Quaternion.prototype.subtract = function (v) { + + if (v instanceof GameLib.API.Vector3) { + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + } + + if (v instanceof GameLib.API.Quaternion) { + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + this.w -= v.w; + } + + return this; +}; + +GameLib.API.Quaternion.prototype.magnitude = function () { + return Math.sqrt( + (this.x * this.x) + + (this.y * this.y) + + (this.z * this.z) + + (this.w * this.w) + ); +}; + +GameLib.API.Quaternion.prototype.normalize = function () { + + var magnitude = this.magnitude(); + + if (magnitude < 0.000001) { + return this; //do nothing for zero vector + } + + this.x *= magnitude; + this.y *= magnitude; + this.z *= magnitude; + this.w *= magnitude; + + return this; +}; + +/** + * + * @param matrix4 GameLib.Matrix4 + */ +GameLib.API.Quaternion.prototype.setFromRotationMatrix = function(matrix4) { + + this.instance.setFromRotationMatrix(matrix4.instance); + + this.x = this.instance.x; + this.y = this.instance.y; + this.z = this.instance.z; + this.w = this.instance.w; +}; + +/** + * + * @param quaternion GameLib.Quaternion + * @param t + * @returns {GameLib.Quaternion} + */ +GameLib.API.Quaternion.prototype.slerp = function (quaternion, t) { + + this.updateInstance(); + + this.instance.slerp(quaternion.instance, t); + + this.x = this.instance.x; + this.y = this.instance.y; + this.z = this.instance.z; + this.w = this.instance.w; + + return this; +}; + +/** + * Returns an API quaternion from an Object quaternion + * @param objectQuaternion + * @constructor + */ +GameLib.API.Quaternion.FromObject = function (objectQuaternion) { + + var apiAxis = null; + + if (objectQuaternion.axis) { + apiAxis = GameLib.API.Vector3.FromObject(objectQuaternion.axis); + } + + return new GameLib.API.Quaternion( + objectQuaternion.x, + objectQuaternion.y, + objectQuaternion.z, + objectQuaternion.w, + apiAxis, + objectQuaternion.angle + ) +}; +GameLib.API.Quaternion.Points = function () { + this.vectors = []; +}; + +GameLib.API.Quaternion.Points.prototype.add = function (vector) { + + if (vector instanceof GameLib.API.Vector3) { + vector = new GameLib.API.Quaternion( + vector.x, + vector.y, + vector.z, + 1 + ) + } + + if (!vector instanceof GameLib.API.Quaternion) { + console.warn("Vector needs to be of type Quaternion"); + throw new Error("Vector needs to be of type Quaternion"); + } + + this.vectors.push(vector); + + return this; +}; + +GameLib.API.Quaternion.Points.prototype.copy = function () { + + var vectors = []; + + for (var i = 0; i < this.vectors.length; i++) { + vectors.push(this.vectors[i].copy()); + } + + return vectors; +}; + +GameLib.API.Quaternion.Points.prototype.maximizeXDistance = function (grain) { + +// console.log("vectors (before): " + JSON.stringify(this.vectors, null, 2)); + + var multiplier = 0; + + var rotationMatrixY = new GameLib.API.Matrix4().rotationMatrixY(grain); + + var totalRadians = 0; + + var backupVectors = this.copy(); + + var maxXDistance = 0; + + for (var i = 0; i < Math.PI * 2; i += grain) { + + multiplier++; + + for (var j = 0; j < this.vectors.length; j++) { + this.vectors[j] = rotationMatrixY.multiply(this.vectors[j]); + } + + var distances = this.distances(); + + if (distances.x > maxXDistance) { + + maxXDistance = distances.x; + totalRadians = multiplier * grain; + } + } + + this.vectors = backupVectors; + +// console.log("distance: " + maxXDistance + " radians : " + totalRadians); + + var maxRotationMatrix = new GameLib.API.Matrix4().rotationMatrixY(totalRadians); + + for (var k = 0; k < this.vectors.length; k++) { + this.vectors[k] = maxRotationMatrix.multiply(this.vectors[k]); + } + +// console.log("vectors (after): " + JSON.stringify(this.vectors, null, 2)); + +}; + +GameLib.API.Quaternion.Points.prototype.maximizeYDistance = function (grain) { + +// console.log("vectors (before): " + JSON.stringify(this.vectors, null, 2)); + + var multiplier = 0; + + var rotationMatrixX = new GameLib.API.Matrix4().rotationMatrixX(grain); + + var totalRadians = 0; + + var backupVectors = this.copy(); + + var maxYDistance = 0; + + for (var i = 0; i < Math.PI * 2; i += grain) { + + multiplier++; + + for (var j = 0; j < this.vectors.length; j++) { + this.vectors[j] = rotationMatrixX.multiply(this.vectors[j]); + } + + var distances = this.distances(); + + if (distances.y > maxYDistance) { + maxYDistance = distances.y; + totalRadians = multiplier * grain; + } + } + + this.vectors = backupVectors; + +// console.log("distance: " + maxYDistance + " radians : " + totalRadians); + + var maxRotationMatrix = new GameLib.API.Matrix4().rotationMatrixX(totalRadians); + + for (var k = 0; k < this.vectors.length; k++) { + this.vectors[k] = maxRotationMatrix.multiply(this.vectors[k]); + } + +// console.log("vectors (after): " + JSON.stringify(this.vectors, null, 2)); + +}; + + +GameLib.API.Quaternion.Points.prototype.lookAt = function (at, up) { + + var polyCenter = this.average(); + + console.log("poly center : " + JSON.stringify(polyCenter)); + + var lookAtMatrix = new GameLib.API.Matrix4().lookAt(polyCenter, at, up); + + lookAtMatrix.rows[0] = new GameLib.API.Quaternion(1, 0, 0, 0); + lookAtMatrix.rows[1] = new GameLib.API.Quaternion(0, 0, 1, 0); + lookAtMatrix.rows[2] = new GameLib.API.Quaternion(0, 1, 0, 0); + + console.log("look at matrix : " + JSON.stringify(lookAtMatrix, null, 2)); + + for (var i = 0; i < this.vectors.length; i++) { + console.log("vector " + i + " (before): " + JSON.stringify(this.vectors[i])); + this.vectors[i] = lookAtMatrix.multiply(this.vectors[i]); + console.log("vector " + i + " (after) : " + JSON.stringify(this.vectors[i])); + } +}; + +GameLib.API.Quaternion.Points.prototype.distances = function () { + + var minX = this.vectors[0].x; + var minY = this.vectors[0].y; + var minZ = this.vectors[0].z; + + var maxX = this.vectors[0].x; + var maxY = this.vectors[0].y; + var maxZ = this.vectors[0].z; + + for (var i = 0; i < this.vectors.length; i++) { + if (this.vectors[i].x < minX) { + minX = this.vectors[i].x; + } + if (this.vectors[i].y < minY) { + minY = this.vectors[i].y; + } + if (this.vectors[i].z < minZ) { + minZ = this.vectors[i].z; + } + + if (this.vectors[i].x > maxX) { + maxX = this.vectors[i].x; + } + if (this.vectors[i].y > maxY) { + maxY = this.vectors[i].y; + } + if (this.vectors[i].z > maxZ) { + maxZ = this.vectors[i].z; + } + } + + return new GameLib.API.Vector3( + Math.abs(maxX - minX), + Math.abs(maxY - minY), + Math.abs(maxY - minZ) + ) +}; + +GameLib.API.Quaternion.Points.prototype.average = function () { + var averageX = 0; + var averageY = 0; + var averageZ = 0; + + for (var i = 0; i < this.vectors.length; i++) { + averageX += this.vectors[i].x; + averageY += this.vectors[i].y; + averageZ += this.vectors[i].z; + } + + return new GameLib.API.Vector3( + averageX / this.vectors.length, + averageY / this.vectors.length, + averageZ / this.vectors.length + ); +}; + +GameLib.API.Quaternion.Points.prototype.negate = function () { + + for (var i = 0; i < this.vectors.length; i++) { + this.vectors[i].x *= -1; + this.vectors[i].y *= -1; + this.vectors[i].z *= -1; + } + + return this; +}; + + +GameLib.API.Quaternion.Points.prototype.toOrigin = function () { + + var distanceFromOrigin = this.average().negate(); + + for (var i = 0; i < this.vectors.length; i++) { + this.vectors[i].translate(distanceFromOrigin); + } +}; +/** + * This component renders a scene + * @param id String + * @param name String + * @param systemType + * @param parentEntity + * @constructor + */ +GameLib.API.System = function ( + id, + name, + systemType, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = "System (" + this.id + ")"; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(systemType)) { + systemType = GameLib.System.SYSTEM_TYPE_RENDER; + } + this.systemType = systemType; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + +}; + +GameLib.API.System.prototype = Object.create(GameLib.Component.prototype); +GameLib.API.System.prototype.constructor = GameLib.API.System; + +/** + * Object to GameLib.D3.API.System + * @param objectComponent + * @constructor + */ +GameLib.API.System.FromObject = function(objectComponent) { + return new GameLib.API.System( + objectComponent.id, + objectComponent.name, + objectComponent.systemType, + objectComponent.parentEntity + ); +}; + +GameLib.API.Vector2 = function (x, y) { + + if (GameLib.Utils.UndefinedOrNull(x)) { + x = 0; + } + this.x = x; + + if (GameLib.Utils.UndefinedOrNull(y)) { + y = 0; + } + this.y = y; + +}; + +GameLib.API.Vector2.prototype.copy = function () { + return new GameLib.API.Vector2( + this.x, + this.y + ); +}; + +GameLib.API.Vector2.prototype.equals = function (v) { + return this.x === v.x && this.y === v.y; +}; + +/** + * Returns an API vector from an Object vector + * @param objectVector + * @constructor + */ +GameLib.API.Vector2.FromObject = function (objectVector) { + return new GameLib.API.Vector2( + objectVector.x, + objectVector.y + ) +}; + +GameLib.API.Vector3 = function (x, y, z) { + + if (GameLib.Utils.UndefinedOrNull(x)) { + x = 0; + } + this.x = x; + + if (GameLib.Utils.UndefinedOrNull(y)) { + y = 0; + } + this.y = y; + + if (GameLib.Utils.UndefinedOrNull(z)) { + z = 0; + } + this.z = z; + +}; + +GameLib.API.Vector3.prototype.negate = function() { + this.x = -this.x; + this.y = -this.y; + this.z = -this.z; + return this; +}; + +GameLib.API.Vector3.prototype.subtract = function (v) { + return new GameLib.API.Vector3( + this.x - v.x, + this.y - v.y, + this.z - v.z + ); +}; + +GameLib.API.Vector3.prototype.sub = function (v) { + return new GameLib.API.Vector3( + this.x - v.x, + this.y - v.y, + this.z - v.z + ); +}; + +GameLib.API.Vector3.prototype.equals = function (v) { + return this.x === v.x && this.y === v.y && this.z === v.z; +}; + +GameLib.API.Vector3.prototype.cross = function (v) { + return new GameLib.API.Vector3( + this.y * v.z - this.z * v.y, + this.z * v.x - this.x * v.z, + this.x * v.y - this.y * v.x + ); +}; + +GameLib.API.Vector3.clockwise = function (u, v, w, viewPoint) { + var normal = GameLib.API.Vector3.normal(u, v, w); + var uv = u.copy(); + var winding = normal.dot(uv.subtract(viewPoint)); + return (winding > 0); +}; + +GameLib.API.Vector3.normal = function (u, v, w) { + var vv = v.copy(); + var wv = w.copy(); + return vv.subtract(u).cross(wv.subtract(u)); +}; + +GameLib.API.Vector3.prototype.lookAt = function (at, up) { + var lookAtMatrix = GameLib.API.Matrix4.lookAt(this, at, up); + return this.multiply(lookAtMatrix); +}; + +GameLib.API.Vector3.prototype.translate = function (v) { + this.x += v.x; + this.y += v.y; + this.z += v.z; + return this; +}; + +GameLib.API.Vector3.prototype.add = function (v) { + this.x += v.x; + this.y += v.y; + this.z += v.z; + return this; +}; + +GameLib.API.Vector3.prototype.squared = function () { + return this.x * this.x + this.y * this.y + this.z * this.z; +}; + +GameLib.API.Vector3.prototype.copy = function () { + return new GameLib.API.Vector3( + this.x, + this.y, + this.z + ); +}; + +GameLib.API.Vector3.prototype.set = function (x, y, z) { + this.x = x; + this.y = y; + this.z = z; +}; + +GameLib.API.Vector3.prototype.lerp = function ( v, alpha ) { + return new GameLib.API.Vector3( + this.x + ( v.x - this.x ) * alpha, + this.y + ( v.y - this.y ) * alpha, + this.z + ( v.z - this.z ) * alpha + ); +}; + +GameLib.API.Vector3.prototype.distanceTo = function(v) { + var dx = this.x - v.x, + dy = this.y - v.y, + dz = this.z - v.z; + return Math.sqrt(dx * dx + dy * dy + dz * dz); +}; + +/** + * @return {number} + */ +GameLib.API.Vector3.AngleDirection = function(forward, directionToCheck, up) { + var perp = forward.cross(directionToCheck); + var dir = perp.dot(up); + + if (dir > 0.0) { + return 1.0; + } else if (dir < 0.0) { + return -1.0; + } else { + return 0.0; + } +}; + +/** + * Multiplies this vector with a scalar, vector or matrix. If you want a copy, copy() it first + * @param object {Number | GameLib.API.Vector3 | GameLib.API.Vector4 | GameLib.API.Matrix3 | GameLib.API.Matrix4} + * @param cross boolean true if you want the cross product, otherwise returns the scalar (dot or inner) product + * @returns {GameLib.API.Vector3 | Number} + */ +GameLib.API.Vector3.prototype.multiply = function (object, cross) { + + var x, y, z; + + var a = object; + var b = this; + + if (GameLib.Utils.UndefinedOrNull(cross)) { + cross = false; + } + + if (typeof object === 'number') { + + if (cross) { + this.x *= object; + this.y *= object; + this.z *= object; + return this; + } else { + return ((this.x * object) + (this.y * object) + (this.z * object)); + } + + } + + if (object instanceof GameLib.API.Vector3) { + + if (cross) { + + x = (a.y * b.z) - (a.z * b.y); + y = (a.z * b.x) - (a.x * b.z); + z = (a.x * b.y) - (a.y * b.x); + + this.x = x; + this.y = y; + this.z = z; + + return this; + + } else { + return ((this.x * object.x) + (this.y * object.y) + (this.z * object.z)); + } + + } else { + console.log("functionality not implemented - please do this"); + throw new Error("not implemented"); + } +}; + + +GameLib.API.Vector3.prototype.dot = function (v) { + return (this.x * v.x) + (this.y * v.y) + (this.z * v.z); +}; + +GameLib.API.Vector3.prototype.normalize = function () { + var EPSILON = 0.000001; + var v2 = this.squared(); + + if (v2 < EPSILON) { + return this; //do nothing for zero vector + } + + var invLength = 1.0 / Math.sqrt(v2); + return new GameLib.API.Vector3( + this.x * invLength, + this.y * invLength, + this.z * invLength + ); +}; + +GameLib.API.Vector3.prototype.clone = function () { + return new GameLib.API.Vector3( + this.x, + this.y, + this.z + ); +}; + +GameLib.API.Vector3.prototype.applyQuaternion = function(q) { + var x = this.x, y = this.y, z = this.z; + var qx = q.x, qy = q.y, qz = q.z, qw = q.w; + + // calculate quat * vector + + var ix = qw * x + qy * z - qz * y; + var iy = qw * y + qz * x - qx * z; + var iz = qw * z + qx * y - qy * x; + var iw = - qx * x - qy * y - qz * z; + + // calculate result * inverse quat + + this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy; + this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz; + this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx; + + return this; +}; + +GameLib.API.Vector3.prototype.clamp = function(min, max) { + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); + + return this; +}; + +GameLib.API.Vector3.prototype.length = function() { + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); +}; + +GameLib.API.Vector3.prototype.reflect = function(normal) { + return this.sub( v1.copy( normal ).multiply( 2 * this.dot( normal ) ) ); +}; + +GameLib.API.Vector3.prototype.angleTo = function (v) { + var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) ); + return Math.acos( exports.Math.clamp( theta, - 1, 1 ) ); +}; + +/** + * Returns an API vector from an Object vector + * @param objectVector + * @constructor + */ +GameLib.API.Vector3.FromObject = function (objectVector) { + return new GameLib.API.Vector3( + objectVector.x, + objectVector.y, + objectVector.z + ) +}; + +GameLib.API.Vector4 = function (x, y, z, w) { + + if (GameLib.Utils.UndefinedOrNull(x)) { + x = 0; + } + this.x = x; + + if (GameLib.Utils.UndefinedOrNull(y)) { + y = 0; + } + this.y = y; + + if (GameLib.Utils.UndefinedOrNull(z)) { + z = 0; + } + this.z = z; + + if (GameLib.Utils.UndefinedOrNull(w)) { + w = 1; + } + this.w = w; +}; + +GameLib.API.Vector4.prototype.equals = function (v) { + return this.x === v.x && this.y === v.y && this.z === v.z && this.w === v.w; +}; + +/** + * Returns an API vector from an Object vector + * @param objectVector + * @constructor + */ +GameLib.API.Vector4.FromObject = function (objectVector) { + return new GameLib.API.Vector4( + objectVector.x, + objectVector.y, + objectVector.z, + objectVector.w + ) +}; + +/** + * Creates a camera object + * @param implementation + * @param apiClock GameLib.API.Clock + * @constructor + */ +GameLib.Clock = function( + implementation, + apiClock +) { + + this.implementation = implementation; + this.implementation.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiClock)) { + apiClock = {}; + } + + if (apiClock instanceof GameLib.Clock) { + return apiClock; + } + + GameLib.API.Clock.call( + this, + apiClock.id, + apiClock.name, + apiClock.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_CLOCK + ); + +} ; + +GameLib.Clock.prototype = Object.create(GameLib.API.Clock.prototype); +GameLib.Clock.prototype.constructor = GameLib.Clock; + +/** + * Creates a camera instance of 'graphics' type (only THREE for now) + * @returns {THREE.Clock} + */ +GameLib.Clock.prototype.createInstance = function() { + + this.instance = new THREE.Clock(); + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +GameLib.Clock.prototype.updateInstance = function() { + +}; + +GameLib.Clock.prototype.getDelta = function() { + + var delta = this.instance.getDelta(); + + /** + * clamp the delta to 1/60 + */ + + if (delta > (1 / 30.0)) { + // console.log('clipped ' + (delta - (1/30.0)) + ' seconds - essentially lost time'); + delta = (1 / 30.0); + } + + return delta; +}; + +/** + * Converts a GameLib.Clock to a new GameLib.API.Clock + * @returns {GameLib.API.Clock} + */ +GameLib.Clock.prototype.toApiObject = function() { + + return new GameLib.API.Clock( + this.id, + this.name, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Converts from an Object camera to a GameLib.Clock + * @param graphics GameLib.Graphics + * @param objectClock Object + * @returns {GameLib.Clock} + * @constructor + */ +GameLib.Clock.FromObject = function(graphics, objectClock) { + + var apiClock = GameLib.API.Clock.FromObject(objectClock); + + return new GameLib.Clock( + graphics, + apiClock + ); + +}; + +/** + * Runtime color for updating instance objects + * @param graphics GameLib.D3.Graphics + * @param parentObject GameLib.D3.* + * @param apiColor GameLib.API.Color + * @param grain Number + * @constructor + */ +GameLib.Color = function ( + graphics, + apiColor, + parentObject, + grain +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiColor)) { + apiColor = {}; + } + + if (apiColor instanceof GameLib.Color) { + return apiColor; + } + + GameLib.API.Color.call( + this, + apiColor.r, + apiColor.g, + apiColor.b, + apiColor.a + ); + + if (GameLib.Utils.UndefinedOrNull(parentObject)) { + parentObject = null; + } + this.parentObject = parentObject; + + if (GameLib.Utils.UndefinedOrNull(grain)) { + grain = 0.001; + } + this.grain = grain; + + this.createInstance(); +}; + +GameLib.Color.prototype = Object.create(GameLib.API.Color.prototype); +GameLib.Color.prototype.constructor = GameLib.Color; + +/** + * Creates an instance color + * @returns {*} + */ +GameLib.Color.prototype.createInstance = function() { + this.instance = new THREE.Color( + this.r, + this.g, + this.b + ); +}; + +/** + * Updates the instance color, calls updateInstance on the parent object + */ +GameLib.Color.prototype.updateInstance = function(property) { + + this.instance.r = this.r; + this.instance.g = this.g; + this.instance.b = this.b; + + if (this.parentObject && + this.parentObject.updateInstance) { + this.parentObject.updateInstance(property); + } +}; + +/** + * Converts runtime color to API Color + * @returns {GameLib.API.Color} + */ +GameLib.Color.prototype.toApiObject = function() { + return new GameLib.API.Color( + this.r, + this.g, + this.b, + this.a + ); +}; + +/** + * Animation Component + * @param id + * @param name + * @param rotationSpeed + * @param translationSpeed + * @param scaleSpeed + * @param rotationFn + * @param translationFn + * @param scaleFn + * @param blocking + * @param applyToMeshWhenDone + * @param meshes + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Animation = function ( + id, + name, + rotationSpeed, + translationSpeed, + scaleSpeed, + rotationFn, + translationFn, + scaleFn, + blocking, + applyToMeshWhenDone, + meshes, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Animation (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(rotationSpeed)) { + rotationSpeed = 0; + } + this.rotationSpeed = rotationSpeed; + + if (GameLib.Utils.UndefinedOrNull(translationSpeed)) { + translationSpeed = 0; + } + this.translationSpeed = translationSpeed; + + if (GameLib.Utils.UndefinedOrNull(scaleSpeed)) { + scaleSpeed = 0; + } + this.scaleSpeed = scaleSpeed; + + if (GameLib.Utils.UndefinedOrNull(rotationFn)) { + rotationFn = null; + } + this.rotationFn = rotationFn; + + if (GameLib.Utils.UndefinedOrNull(translationFn)) { + translationFn = null; + } + this.translationFn = translationFn; + + if (GameLib.Utils.UndefinedOrNull(scaleFn)) { + scaleFn = null; + } + this.scaleFn = scaleFn; + + if (GameLib.Utils.UndefinedOrNull(blocking)) { + blocking = { + position : false, //positions can be blocked from accumulating and executing at once + rotation : true, //rotations need to execute in order + scale : false //scale can accumulate + }; + } + this.blocking = blocking; + + if (GameLib.Utils.UndefinedOrNull(applyToMeshWhenDone)) { + applyToMeshWhenDone = true; + } + this.applyToMeshWhenDone = applyToMeshWhenDone; + + if (GameLib.Utils.UndefinedOrNull(meshes)) { + meshes = []; + } + this.meshes = meshes; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Animation.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Animation.prototype.constructor = GameLib.D3.API.Animation; + +/** + * Object to GameLib.D3.API.Animation + * @param objectComponent + * @returns {GameLib.D3.API.Animation} + * @constructor + */ +GameLib.D3.API.Animation.FromObject = function(objectComponent) { + return new GameLib.D3.API.Animation( + objectComponent.id, + objectComponent.name, + objectComponent.rotationSpeed, + objectComponent.translationSpeed, + objectComponent.scaleSpeed, + objectComponent.rotationFn, + objectComponent.translationFn, + objectComponent.scaleFn, + objectComponent.blocking, + objectComponent.applyToMeshWhenDone, + objectComponent.meshes, + objectComponent.parentEntity + ); +}; + +/** + * Raw Audio API object - should always correspond with the Audio Schema + * @param id + * @param name + * @param path + * @param loop + * @param volume + * @param camera + * @param overplay + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Audio = function( + id, + name, + path, + loop, + volume, + camera, + overplay, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Audio (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(path)) { + path = ''; + } + this.path = path; + + if (GameLib.Utils.UndefinedOrNull(loop)) { + loop = false; + } + this.loop = loop; + + if (GameLib.Utils.UndefinedOrNull(volume)) { + volume = 0.5; + } + this.volume = volume; + + if (GameLib.Utils.UndefinedOrNull(camera)) { + camera = null; + } + this.camera = camera; + + if (GameLib.Utils.UndefinedOrNull(overplay)) { + overplay = false; + } + this.overplay = overplay; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Audio.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Audio.prototype.constructor = GameLib.D3.API.Audio; + +/** + * Creates an API Audio from an Object Audio + * @param objectAudio + * @constructor + */ +GameLib.D3.API.Audio.FromObject = function(objectAudio) { + + var apiCamera = null; + if (objectAudio.camera) { + if (objectAudio.camera instanceof Object) { + apiCamera = GameLib.D3.API.Camera.FromObject(objectAudio.camera); + } else { + apiCamera = objectAudio.camera; + } + } + + return new GameLib.D3.API.Audio( + objectAudio.id, + objectAudio.name, + objectAudio.path, + objectAudio.loop, + objectAudio.volume, + apiCamera, + objectAudio.overplay, + objectAudio.parentEntity + ); + +}; + +/** + * BoneWeight object - associates a vertex to a bone with some weight + * @param boneIndex int + * @param weight float + * @constructor + */ +GameLib.D3.API.BoneWeight = function ( + boneIndex, + weight +) { + this.boneIndex = boneIndex; + this.weight = weight; +}; + +/** + * Object to GameLib.D3.API.BoneWeight + * @param objectBoneWeight + * @returns {GameLib.D3.API.BoneWeight} + * @constructor + */ +GameLib.D3.API.BoneWeight.FromObject = function(objectBoneWeight) { + return new GameLib.D3.API.BoneWeight( + objectBoneWeight.boneIndex, + objectBoneWeight.weight + ) +}; + +/** + * Bone Superset + * @param id + * @param name string + * @param childBoneIds + * @param parentBoneIds + * @param quaternion GameLib.API.Quaternion + * @param position GameLib.API.Vector3 + * @param scale GameLib.API.Vector3 + * @param up GameLib.API.Vector3 + * @constructor + */ +GameLib.D3.API.Bone = function ( + id, + name, + childBoneIds, + parentBoneIds, + position, + quaternion, + scale, + up +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Bone (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(childBoneIds)) { + childBoneIds = []; + } + this.childBoneIds = childBoneIds; + + if (GameLib.Utils.UndefinedOrNull(parentBoneIds)) { + parentBoneIds = []; + } + this.parentBoneIds = parentBoneIds; + + if (GameLib.Utils.UndefinedOrNull(position)) { + position = new GameLib.API.Vector3(); + } + this.position = position; + + if (GameLib.Utils.UndefinedOrNull(quaternion)) { + quaternion = new GameLib.API.Quaternion(); + } + this.quaternion = quaternion; + + if (GameLib.Utils.UndefinedOrNull(scale)) { + scale = new GameLib.API.Vector3(1,1,1); + } + this.scale = scale; + + if (GameLib.Utils.UndefinedOrNull(up)) { + up = new GameLib.API.Vector3(0,1,0); + } + this.up = up; +}; + +/** + * Returns an API bone from an Object bone + * @param objectBone + * @constructor + */ +GameLib.D3.API.Bone.FromObject = function(objectBone) { + return new GameLib.D3.API.Bone( + objectBone.id, + objectBone.name, + objectBone.childBoneIds, + objectBone.parentBoneIds, + GameLib.API.Vector3.FromObject(objectBone.position), + GameLib.API.Quaternion.FromObject(objectBone.quaternion), + GameLib.API.Vector3.FromObject(objectBone.scale), + GameLib.API.Vector3.FromObject(objectBone.up) + ); +}; + +/** + * Raw Broadphase API object - should always correspond with the Broadphase Schema + * @param id + * @param name + * @param broadphaseType + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Broadphase = function( + id, + name, + broadphaseType, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Broadphase (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(broadphaseType)) { + broadphaseType = GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE; + } + this.broadphaseType = broadphaseType; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Broadphase.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Broadphase.prototype.constructor = GameLib.D3.API.Broadphase; + +/** + * Creates an API Broadphase from an Object Broadphase + * @param objectBroadphase + * @constructor + */ +GameLib.D3.API.Broadphase.FromObject = function(objectBroadphase) { + return new GameLib.D3.API.Broadphase( + objectBroadphase.id, + objectBroadphase.name, + objectBroadphase.broadphaseType, + objectBroadphase.parentEntity + ); +}; + + +/** + * Raw Camera API object - should always correspond with the Camera Schema + * @param id + * @param name + * @param cameraType GameLib.D3.Camera.CAMERA_TYPE_* + * @param fov + * @param aspect + * @param near + * @param far + * @param position GameLib.API.Vector3 + * @param lookAt GameLib.API.Vector3 + * @param minX + * @param maxX + * @param minY + * @param maxY + * @param minZ + * @param maxZ + * @param offsetX + * @param offsetY + * @param quaternion GameLib.Quaternion + * @param parentEntity + * @param eyeSeparation + * @param focalLength + * @constructor + */ +GameLib.D3.API.Camera = function( + id, + cameraType, + name, + fov, + aspect, + near, + far, + position, + lookAt, + minX, + maxX, + minY, + maxY, + minZ, + maxZ, + offsetX, + offsetY, + quaternion, + parentEntity, + eyeSeparation, + focalLength +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(cameraType)) { + cameraType = GameLib.D3.Camera.CAMERA_TYPE_PERSPECTIVE; + } + this.cameraType = cameraType; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Camera (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(fov)) { + fov = 75; + } + this.fov = fov; + + if (GameLib.Utils.UndefinedOrNull(aspect)) { + aspect = window.innerWidth / window.innerHeight; + } + this.aspect = aspect; + + if (GameLib.Utils.UndefinedOrNull(near)) { + near = 0.01; + } + this.near = near; + + if (GameLib.Utils.UndefinedOrNull(far)) { + far = 1000; + } + this.far = far; + + if (GameLib.Utils.UndefinedOrNull(position)) { + position = new GameLib.API.Vector3( + 15, + 15, + 15 + ); + } + this.position = position; + + if (GameLib.Utils.UndefinedOrNull(quaternion)) { + quaternion = new GameLib.API.Quaternion(); + } + this.quaternion = quaternion; + + if (GameLib.Utils.UndefinedOrNull(lookAt)) { + lookAt = new GameLib.API.Vector3( + 0, + 0, + 0 + ); + } + this.lookAt = lookAt; + + if (GameLib.Utils.UndefinedOrNull(minX)) { + minX = -100; + } + this.minX = minX; + + if (GameLib.Utils.UndefinedOrNull(maxX)) { + maxX = 100; + } + this.maxX = maxX; + + if (GameLib.Utils.UndefinedOrNull(minY)) { + minY = -100; + } + this.minY = minY; + + if (GameLib.Utils.UndefinedOrNull(maxY)) { + maxY = 100; + } + this.maxY = maxY; + + if (GameLib.Utils.UndefinedOrNull(minZ)) { + minZ = -100; + } + this.minZ = minZ; + + if (GameLib.Utils.UndefinedOrNull(maxZ)) { + maxZ = 100; + } + this.maxZ = maxZ; + + if (GameLib.Utils.UndefinedOrNull(offsetX)) { + offsetX = 0; + } + this.offsetX = offsetX; + + if (GameLib.Utils.UndefinedOrNull(offsetY)) { + offsetY = 0; + } + this.offsetY = offsetY; + + if (GameLib.Utils.UndefinedOrNull(eyeSeparation)) { + eyeSeparation = 30; + } + this.eyeSeparation = eyeSeparation; + + if (GameLib.Utils.UndefinedOrNull(focalLength)) { + focalLength = 150; + } + this.focalLength = focalLength; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Camera.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Camera.prototype.constructor = GameLib.D3.API.Camera; + +/** + * Creates an API camera from an Object camera + * @param objectCamera + * @constructor + */ +GameLib.D3.API.Camera.FromObject = function(objectCamera) { + + return new GameLib.D3.API.Camera( + objectCamera.id, + objectCamera.cameraType, + objectCamera.name, + objectCamera.fov, + objectCamera.aspect, + objectCamera.near, + objectCamera.far, + GameLib.API.Vector3.FromObject(objectCamera.position), + GameLib.API.Vector3.FromObject(objectCamera.lookAt), + objectCamera.minX, + objectCamera.maxX, + objectCamera.minY, + objectCamera.maxY, + objectCamera.minZ, + objectCamera.maxZ, + objectCamera.offsetX, + objectCamera.offsetY, + GameLib.API.Quaternion.FromObject(objectCamera.quaternion), + objectCamera.parentEntity, + objectCamera.eyeSeparation, + objectCamera.focalLength + ); + +}; + +/** + * Raw Canvas API object - should always correspond with the Canvas Schema + * @param id + * @param name + * @param width + * @param height + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Canvas = function( + id, + name, + width, + height, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Canvas (' + id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(width)) { + width = 512; + } + this.width = width; + + if (GameLib.Utils.UndefinedOrNull(height)) { + height = 512; + } + this.height = height; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)){ + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Canvas.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Canvas.prototype.constructor = GameLib.D3.API.Canvas; + +/** + * Returns an API light from an Object light + * @param objectCanvas + * @constructor + */ +GameLib.D3.API.Canvas.FromObject = function(objectCanvas) { + return new GameLib.D3.API.Canvas( + objectCanvas.id, + objectCanvas.name, + objectCanvas.width, + objectCanvas.height, + objectCanvas.parentEntity + ); +}; + +/** + * This component renders a scene + * @param id String + * @param name String + * @param renderer GameLib.D3.Renderer + * @param renderTarget GameLib.D3.API.RenderTarget + * @param passes GameLib.D3.API.Pass[] + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Composer = function ( + id, + name, + renderer, + renderTarget, + passes, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Composer (' + id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(renderer)) { + renderer = null; + } + this.renderer = renderer; + + if (GameLib.Utils.UndefinedOrNull(renderTarget)) { + renderTarget = null; + } + this.renderTarget = renderTarget; + + if (GameLib.Utils.UndefinedOrNull(passes)) { + passes = []; + } + this.passes = passes; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Composer.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Composer.prototype.constructor = GameLib.D3.API.Composer; + +/** + * Object to GameLib.D3.API.Composer + * @param objectComponent + * @constructor + */ +GameLib.D3.API.Composer.FromObject = function(objectComponent) { + return new GameLib.D3.API.Composer( + objectComponent.id, + objectComponent.name, + objectComponent.renderer, + objectComponent.renderTarget, + objectComponent.passes, + objectComponent.parentEntity + ); +}; + +/** + * Raw Controls API object + * @param id + * @param controlsType + * @param name + * @param domElement + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Controls = function( + id, + controlsType, + name, + domElement, + // fullscreen, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(controlsType)) { + + if (this instanceof GameLib.D3.Controls.Editor) { + controlsType = GameLib.D3.Controls.CONTROLS_TYPE_EDITOR; + } + + if (this instanceof GameLib.D3.Controls.Touch) { + controlsType = GameLib.D3.Controls.CONTROLS_TYPE_TOUCH; + } + + if (this instanceof GameLib.D3.Controls.Keyboard) { + controlsType = GameLib.D3.Controls.CONTROLS_TYPE_KEYBOARD; + } + + if (this instanceof GameLib.D3.Controls.Mouse) { + controlsType = GameLib.D3.Controls.CONTROLS_TYPE_MOUSE; + } + + if (GameLib.Utils.UndefinedOrNull(controlsType)) { + throw new Error('Could not determine controls type from this'); + } + } + this.controlsType = controlsType; + + if (GameLib.Utils.UndefinedOrNull(name)) { + + if (controlsType === GameLib.D3.Controls.CONTROLS_TYPE_EDITOR) { + name = 'Editing Controls'; + } + + if (controlsType === GameLib.D3.Controls.CONTROLS_TYPE_TOUCH) { + name = 'Touch Controls'; + } + + if (controlsType === GameLib.D3.Controls.CONTROLS_TYPE_KEYBOARD) { + name = 'Keyboard Controls'; + } + + if (controlsType === GameLib.D3.Controls.CONTROLS_TYPE_MOUSE) { + name = 'Mouse Controls'; + } + + name += ' (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(domElement)) { + domElement = null; + } + this.domElement = domElement; + + // if (GameLib.Utils.UndefinedOrNull(fullscreen)) { + // fullscreen = false; + // } + // this.fullscreen = fullscreen; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Controls.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Controls.prototype.constructor = GameLib.D3.API.Controls; + +/** + * Returns an API Controls from an Object + * @param objectControls + * @constructor + */ +GameLib.D3.API.Controls.FromObject = function (objectControls){ + return new GameLib.D3.API.Controls( + objectControls.id, + objectControls.controlsType, + objectControls.name, + objectControls.domElement, + objectControls.parentEntity + ); +}; + +/** + * Custom Code Component + * @param id + * @param name + * @param eventId + * @param code + * @param parentEntity + * @constructor + */ +GameLib.D3.API.CustomCode = function ( + id, + name, + eventId, + code, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'CustomCode (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(eventId)) { + eventId = 42; + } + this.eventId = eventId; + + if (GameLib.Utils.UndefinedOrNull(code)) { + code = "return null;\n//@ sourceURL=" + this.name + ".js"; + } + this.code = code; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + +}; + +GameLib.D3.API.CustomCode.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.CustomCode.prototype.constructor = GameLib.D3.API.CustomCode; + +/** + * Object to GameLib.D3.API.CustomCode + * @param objectComponent + * @returns {GameLib.D3.API.CustomCode} + * @constructor + */ +GameLib.D3.API.CustomCode.FromObject = function(objectComponent) { + return new GameLib.D3.API.CustomCode( + objectComponent.id, + objectComponent.name, + objectComponent.eventId, + objectComponent.code, + objectComponent.parentEntity + ); +}; + +/** + * Face + * @param id + * @param name + * @param v0index + * @param v1index + * @param v2index + * @param materialIndex + * @param uvs [[v0uv (GameLib.Vector2), v1uv(GameLib.Vector2), v2uv(GameLib.Vector2)]] + * @param color + * @param vertexColors + * @param vertexNormals + * @param normal + * @constructor + */ +GameLib.D3.API.Face = function( + id, + name, + v0index, + v1index, + v2index, + materialIndex, + uvs, + color, + vertexColors, + vertexNormals, + normal +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Face ' + id; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(v0index)) { + v0index = -1; + } + this.v0index = v0index; + + if (GameLib.Utils.UndefinedOrNull(v1index)) { + v1index = -1; + } + this.v1index = v1index; + + if (GameLib.Utils.UndefinedOrNull(v2index)) { + v2index = -1; + } + this.v2index = v2index; + + if (GameLib.Utils.UndefinedOrNull(materialIndex)) { + materialIndex = -1; + } + this.materialIndex = materialIndex; + + if (GameLib.Utils.UndefinedOrNull(uvs)) { + uvs = [[]]; + } + this.uvs = uvs; + + if (GameLib.Utils.UndefinedOrNull(color)) { + color = null; + } + this.color = color; + + if (GameLib.Utils.UndefinedOrNull(vertexColors)) { + vertexColors = []; + } + this.vertexColors = vertexColors; + + if (GameLib.Utils.UndefinedOrNull(vertexNormals)) { + vertexNormals = []; + } + this.vertexNormals = vertexNormals; + + if (GameLib.Utils.UndefinedOrNull(normal)) { + normal = null; + } + this.normal = normal; +}; + +/** + * We don't inherit from component - it makes the entitymanager too heavy - all faces end up in the register etc.. + */ + +// GameLib.D3.API.Face.prototype = Object.create(GameLib.Component.prototype); +// GameLib.D3.API.Face.prototype.constructor = GameLib.D3.API.Face; + +/** + * Returns an API Face from a data object + * @constructor + * @param objectFace + */ +GameLib.D3.API.Face.FromObject = function(objectFace) { + + var apiUvs = objectFace.uvs.reduce( + + function(result, uvArray, index) { + + result[index] = uvArray.reduce( + function(uvResult, uv) { + uvResult.push(GameLib.API.Vector2.FromObject(uv)); + return uvResult; + }, + [] + ); + + return result; + }, + [] + ); + + var apiVertexColors = objectFace.vertexColors.map( + function(vertexColor) { + return GameLib.API.Color.FromObject(vertexColor); + } + ); + + var apiColor = null; + if (objectFace.color) { + apiColor = GameLib.API.Color.FromObject(objectFace.color); + } + + var apiVertexNormals = objectFace.vertexNormals.map( + function(vertexNormal) { + return GameLib.API.Vector3.FromObject(vertexNormal); + } + ); + + var apiNormal = null; + if (objectFace.normal) { + apiNormal = GameLib.API.Vector3.FromObject(objectFace.normal); + } + + return new GameLib.D3.API.Face( + objectFace.id, + objectFace.name, + objectFace.v0index, + objectFace.v1index, + objectFace.v2index, + objectFace.materialIndex, + apiUvs, + apiColor, + apiVertexColors, + apiVertexNormals, + apiNormal + ); +}; + +/** + * Clone a Face + * @returns {GameLib.D3.API.Face} + */ +GameLib.D3.API.Face.prototype.clone = function(){ + return new GameLib.D3.API.Face( + this.id, + this.name, + this.v0index, + this.v1index, + this.v2index, + this.materialIndex, + this.uvs, + this.color, + this.vertexColors, + this.vertexNormals, + this.normal + ); + +}; + +/** + * Returns true if two triangles are equal (their vertex indices match in some order) + * @param triangle + * @returns {boolean} + */ +GameLib.D3.API.Face.prototype.equals = function(triangle) { + return ( + ( + (this.v0index === triangle.v0index) && + (this.v1index === triangle.v1index) && + (this.v2index === triangle.v2index) + ) + || + ( + (this.v0index === triangle.v0index) && + (this.v1index === triangle.v2index) && + (this.v2index === triangle.v1index) + ) + || + ( + (this.v0index === triangle.v1index) && + (this.v1index === triangle.v0index) && + (this.v2index === triangle.v2index) + ) + || + ( + (this.v0index === triangle.v1index) && + (this.v1index === triangle.v2index) && + (this.v2index === triangle.v0index) + ) + || + ( + (this.v0index === triangle.v2index) && + (this.v1index === triangle.v0index) && + (this.v2index === triangle.v1index) + ) + || + ( + (this.v0index === triangle.v2index) && + (this.v1index === triangle.v1index) && + (this.v2index === triangle.v0index) + ) + ); +}; + +/** + * Raw Fog API object - should always correspond with the Fog Schema + * @param id String + * @param name String + * @param exponential + * @param color + * @param near + * @param far + * @param density + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Fog = function( + id, + name, + exponential, + color, + near, + far, + density, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Fog (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(exponential)) { + exponential = false; + } + this.exponential = exponential; + + if (GameLib.Utils.UndefinedOrNull(color)) { + color = new GameLib.API.Color(1, 1, 1, 1) + } + this.color = color; + + if (GameLib.Utils.UndefinedOrNull(near)) { + near = 1; + } + this.near = near; + + if (GameLib.Utils.UndefinedOrNull(far)) { + far = 1000; + } + this.far = far; + + if (GameLib.Utils.UndefinedOrNull(density)) { + density = 0.00025; + } + this.density = density; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + +}; + +GameLib.D3.API.Fog.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Fog.prototype.constructor = GameLib.D3.API.Fog; + +/** + * Returns an API scene from an Object scene + * @param objectFog + * @constructor + */ +GameLib.D3.API.Fog.FromObject = function(objectFog) { + + return new GameLib.D3.API.Fog( + objectFog.id, + objectFog.name, + objectFog.exponential, + objectFog.color, + objectFog.near, + objectFog.far, + objectFog.density, + objectFog.parentEntity + ); + +}; + +/** + * Raw Font API object - should always correspond with the Font Schema + * @param id + * @param name + * @param url + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Font = function( + id, + name, + url, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Font (' + id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(url)) { + url = '/apiRelative/path/to/font'; + } + this.url = url; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)){ + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Font.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Font.prototype.constructor = GameLib.D3.API.Font; + +/** + * Returns an API light from an Object light + * @param objectFont + * @constructor + */ +GameLib.D3.API.Font.FromObject = function(objectFont) { + return new GameLib.D3.API.Font( + objectFont.id, + objectFont.name, + objectFont.url, + objectFont.parentEntity + ); +}; + +/** + * Raw FrictionContactMaterial API object - should always correspond with the FrictionContactMaterial Schema + * @param id + * @param name + * @param material1 + * @param material2 + * @param friction + * @param restitution + * @param contactEquationStiffness + * @param contactEquationRelaxation + * @param frictionEquationStiffness + * @param frictionEquationRelaxation + * @param parentEntity + * @constructor + */ +GameLib.D3.API.FrictionContactMaterial = function( + id, + name, + materials, + friction, + restitution, + contactEquationStiffness, + contactEquationRelaxation, + frictionEquationStiffness, + frictionEquationRelaxation, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Friction Material (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(materials)) { + materials = []; + } + this.materials = materials; + + if (GameLib.Utils.UndefinedOrNull(friction)) { + friction = 0.3; + } + this.friction = friction; + + if (GameLib.Utils.UndefinedOrNull(restitution)) { + restitution = 0.3; + } + this.restitution = restitution; + + if (GameLib.Utils.UndefinedOrNull(contactEquationStiffness)) { + contactEquationStiffness = 1e7; + } + this.contactEquationStiffness = contactEquationStiffness; + + if (GameLib.Utils.UndefinedOrNull(contactEquationRelaxation)) { + contactEquationRelaxation = 3; + } + this.contactEquationRelaxation = contactEquationRelaxation; + + if (GameLib.Utils.UndefinedOrNull(frictionEquationStiffness)) { + frictionEquationStiffness = 1e7; + } + this.frictionEquationStiffness = frictionEquationStiffness; + + if (GameLib.Utils.UndefinedOrNull(frictionEquationRelaxation)) { + frictionEquationRelaxation = 3; + } + this.frictionEquationRelaxation = frictionEquationRelaxation; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.FrictionContactMaterial.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.FrictionContactMaterial.prototype.constructor = GameLib.D3.API.FrictionContactMaterial; + +/** + * Creates an API FrictionContactMaterial from an Object FrictionContactMaterial + * @param objectFrictionContactMaterial + * @constructor + */ +GameLib.D3.API.FrictionContactMaterial.FromObject = function(objectFrictionContactMaterial) { + return new GameLib.D3.API.FrictionContactMaterial( + objectFrictionContactMaterial.id, + objectFrictionContactMaterial.name, + objectFrictionContactMaterial.materials, + objectFrictionContactMaterial.friction, + objectFrictionContactMaterial.restitution, + objectFrictionContactMaterial.contactEquationStiffness, + objectFrictionContactMaterial.contactEquationRelaxation, + objectFrictionContactMaterial.frictionEquationStiffness, + objectFrictionContactMaterial.frictionEquationRelaxation, + objectFrictionContactMaterial.parentEntity + ); +}; + + +/** + * Raw FrictionMaterial API object - should always correspond with the FrictionMaterial Schema + * @param id + * @param name + * @param friction + * @param restitution + * @param parentEntity + * @constructor + */ +GameLib.D3.API.FrictionMaterial = function( + id, + name, + friction, + restitution, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Friction Material (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(friction)) { + friction = -1; + } + this.friction = friction; + + if (GameLib.Utils.UndefinedOrNull(restitution)) { + restitution = -1; + } + this.restitution = restitution; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.FrictionMaterial.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.FrictionMaterial.prototype.constructor = GameLib.D3.API.FrictionMaterial; + +/** + * Creates an API FrictionMaterial from an Object FrictionMaterial + * @param objectFrictionMaterial + * @constructor + */ +GameLib.D3.API.FrictionMaterial.FromObject = function(objectFrictionMaterial) { + return new GameLib.D3.API.FrictionMaterial( + objectFrictionMaterial.id, + objectFrictionMaterial.name, + objectFrictionMaterial.friction, + objectFrictionMaterial.restitution, + objectFrictionMaterial.parentEntity + ); +}; + + +/** + * Raw ImageFactory API object - should always correspond with the ImageFactory Schema + * @param id + * @param name + * @param baseUrl String + * @param parentEntity + * @constructor + */ +GameLib.D3.API.ImageFactory = function( + id, + name, + baseUrl, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'ImageFactory (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(baseUrl)) { + baseUrl = ''; + console.warn('No baseURL defined for image factory'); + } + this.baseUrl = baseUrl; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.ImageFactory.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.ImageFactory.prototype.constructor = GameLib.D3.API.ImageFactory; + +/** + * Returns an API ImageFactory from an Object ImageFactory + * @param objectImageFactory + * @constructor + */ +GameLib.D3.API.ImageFactory.FromObject = function(objectImageFactory) { + return new GameLib.D3.API.ImageFactory( + objectImageFactory.id, + objectImageFactory.name, + objectImageFactory.baseUrl, + objectImageFactory.parentEntity + ); +}; + +/** + * Image + * @param id + * @param name + * @param fileName + * @param extension + * @param path + * @param contentType + * @param size + * @param parentEntity GameLib.Entity + * @constructor + */ +GameLib.D3.API.Image = function( + id, + name, + fileName, + extension, + path, + contentType, + size, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Image ' + id; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(fileName)) { + fileName = GameLib.Utils.LowerUnderscore(name); + } + this.fileName = fileName; + + if (GameLib.Utils.UndefinedOrNull(extension)) { + extension = '.unknown'; + } + this.extension = extension; + + if (GameLib.Utils.UndefinedOrNull(path)) { + path = '/'; + } + this.path = path; + + if (GameLib.Utils.UndefinedOrNull(contentType)) { + + contentType = 'application/octet-stream'; + + if (this.extension.match(/(png)$/i)) { + contentType = 'image/png'; + } + + if (this.extension.match(/(jpg|jpeg)$/i)) { + contentType = 'image/jpeg'; + } + + if (this.extension.match(/(gif)$/i)) { + contentType = 'image/gif'; + } + } + this.contentType = contentType; + + if (GameLib.Utils.UndefinedOrNull(size)) { + size = 0; + } + this.size = size; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Image.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Image.prototype.constructor = GameLib.D3.API.Image; + +/** + * Returns an API light from an Object light + * @constructor + * @param objectImage + */ +GameLib.D3.API.Image.FromObject = function(objectImage) { + return new GameLib.D3.API.Image( + objectImage.id, + objectImage.name, + objectImage.fileName, + objectImage.extension, + objectImage.path, + objectImage.contentType, + objectImage.size, + objectImage.parentEntity + ); +}; + + +/** + * Raw Light API object - should always correspond with the Light Schema + * @param id + * @param lightType + * @param name + * @param color + * @param intensity + * @param position + * @param targetPosition + * @param quaternion + * @param rotation + * @param scale + * @param distance + * @param decay + * @param power + * @param angle + * @param penumbra + * @param parentScene + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Light = function( + id, + lightType, + name, + color, + intensity, + position, + targetPosition, + quaternion, + rotation, + scale, + distance, + decay, + power, + angle, + penumbra, + parentScene, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(lightType)) { + lightType = GameLib.D3.Light.LIGHT_TYPE_AMBIENT; + } + this.lightType = lightType; + + if (GameLib.Utils.UndefinedOrNull(name)) { + + if (this.lightType === GameLib.D3.Light.LIGHT_TYPE_AMBIENT) { + name = 'Ambient '; + } + + if (this.lightType === GameLib.D3.Light.LIGHT_TYPE_DIRECTIONAL) { + name = 'Directional '; + } + + if (this.lightType === GameLib.D3.Light.LIGHT_TYPE_POINT) { + name = 'Point '; + } + + if (this.lightType === GameLib.D3.Light.LIGHT_TYPE_SPOT) { + name = 'Spot '; + } + + name += 'Light (' + id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(color)) { + color = new GameLib.API.Color(1,1,1,1); + } + this.color = color; + + if (GameLib.Utils.UndefinedOrNull(intensity)) { + intensity = 1; + } + this.intensity = intensity; + + if (GameLib.Utils.UndefinedOrNull(position)) { + position = new GameLib.API.Vector3(10,10,10); + } + this.position = position; + + if (GameLib.Utils.UndefinedOrNull(targetPosition)) { + targetPosition = new GameLib.API.Vector3(0,0,0); + } + this.targetPosition = targetPosition; + + if (GameLib.Utils.UndefinedOrNull(quaternion)){ + quaternion = new GameLib.API.Quaternion(); + } + this.quaternion = quaternion; + + if (GameLib.Utils.UndefinedOrNull(rotation)){ + rotation = new GameLib.API.Vector3(0,0,0); + } + this.rotation = rotation; + + if (GameLib.Utils.UndefinedOrNull(scale)){ + scale = new GameLib.API.Vector3(1,1,1); + } + this.scale = scale; + + if (GameLib.Utils.UndefinedOrNull(distance)){ + distance = 0; + } + this.distance = distance; + + if (GameLib.Utils.UndefinedOrNull(decay)){ + decay = 1; + } + this.decay = decay; + + if (GameLib.Utils.UndefinedOrNull(power)){ + power = 4 * Math.PI; + } + this.power = power; + + if (GameLib.Utils.UndefinedOrNull(angle)){ + angle = Math.PI / 3; + } + this.angle = angle; + + if (GameLib.Utils.UndefinedOrNull(penumbra)){ + penumbra = 0; + } + this.penumbra = penumbra; + + if (GameLib.Utils.UndefinedOrNull(parentScene)){ + parentScene = null; + } + this.parentScene = parentScene; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)){ + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Light.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Light.prototype.constructor = GameLib.D3.API.Light; + +/** + * Returns an API light from an Object light + * @param objectLight + * @constructor + */ +GameLib.D3.API.Light.FromObject = function(objectLight) { + return new GameLib.D3.API.Light( + objectLight.id, + objectLight.lightType, + objectLight.name, + GameLib.API.Color.FromObject(objectLight.color), + objectLight.intensity, + GameLib.API.Vector3.FromObject(objectLight.position), + GameLib.API.Vector3.FromObject(objectLight.targetPosition), + GameLib.API.Quaternion.FromObject(objectLight.quaternion), + GameLib.API.Vector3.FromObject(objectLight.rotation), + GameLib.API.Vector3.FromObject(objectLight.scale), + objectLight.distance, + objectLight.decay, + objectLight.power, + objectLight.angle, + objectLight.penumbra, + objectLight.parentScene, + objectLight.parentEntity + ); +}; + +/** + * Looks from currentPosition to targetPosition (default up is 0,1,0) + * @param id + * @param name + * @param currentComponent GameLib.Component + * @param targetComponent GameLib.Component + * @param targetPositionOffset GameLib.API.Vector3 + * @param rotationSpeed Number + * @param parentEntity + * @constructor + */ +GameLib.D3.API.LookAt = function ( + id, + name, + currentComponent, + targetComponent, + targetPositionOffset, + rotationSpeed, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = this.constructor.name; + } + this.name = name; + + if(GameLib.Utils.UndefinedOrNull(currentComponent)) { + currentComponent = null; + } + this.currentComponent = currentComponent; + + if(GameLib.Utils.UndefinedOrNull(targetComponent)) { + targetComponent = null; + } + this.targetComponent = targetComponent; + + if(GameLib.Utils.UndefinedOrNull(targetPositionOffset)) { + targetPositionOffset = new GameLib.API.Vector3(0, 0, 0); + } + this.targetPositionOffset = targetPositionOffset; + + if (GameLib.Utils.UndefinedOrNull(rotationSpeed)) { + rotationSpeed = 22.0; + } + this.rotationSpeed = rotationSpeed; + + this.lookAtMatrix = new GameLib.API.Matrix4(); + + this.up = new GameLib.API.Vector3(0, 1, 0); + + this.currentRotation = new GameLib.API.Quaternion(); + + this.targetPosition = new GameLib.API.Vector3(); + + if(GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.LookAt.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.LookAt.prototype.constructor = GameLib.D3.API.LookAt; + +/** + * Object to GameLib.D3.API.LookAt + * @param objectComponent + * @returns {GameLib.D3.API.LookAt} + * @constructor + */ +GameLib.D3.API.LookAt.FromObject = function(objectComponent) { + return new GameLib.D3.API.LookAt( + objectComponent.id, + objectComponent.name, + objectComponent.currentComponent, + objectComponent.targetComponent, + GameLib.API.Vector3.FromObject(objectComponent.targetPositionOffset), + objectComponent.rotationSpeed, + objectComponent.parentEntity + ); +}; + +/** + * Raw material API object - should always correspond with the Material Schema + * @param id + * @param materialType + * @param name + * @param opacity + * @param side + * @param transparent + * @param specular + * @param lightMapIntensity + * @param aoMapIntensity + * @param color + * @param emissive + * @param emissiveIntensity + * @param combine + * @param shininess + * @param reflectivity + * @param refractionRatio + * @param fog + * @param wireframe + * @param wireframeLineWidth + * @param wireframeLineCap + * @param wireframeLineJoin + * @param vertexColors + * @param skinning + * @param morphTargets + * @param morphNormals + * @param lineWidth + * @param lineCap + * @param lineJoin + * @param dashSize + * @param gapWidth + * @param blending + * @param blendSrc + * @param blendDst + * @param blendEquation + * @param depthTest + * @param depthFunc + * @param depthWrite + * @param polygonOffset + * @param polygonOffsetFactor + * @param polygonOffsetUnits + * @param alphaTest + * @param clippingPlanes + * @param clipShadows + * @param visible + * @param overdraw + * @param flatShading + * @param bumpScale + * @param normalScale + * @param displacementScale + * @param displacementBias + * @param roughness + * @param metalness + * @param pointSize + * @param pointSizeAttenuation + * @param spriteRotation + * @param envMapIntensity + * @param alphaMap + * @param aoMap + * @param bumpMap + * @param diffuseMap + * @param displacementMap + * @param emissiveMap + * @param environmentMap + * @param lightMap + * @param metalnessMap + * @param normalMap + * @param roughnessMap + * @param specularMap + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Material = function( + id, + materialType, + name, + opacity, + side, + transparent, + specular, + lightMapIntensity, + aoMapIntensity, + color, + emissive, + emissiveIntensity, + combine, + shininess, + reflectivity, + refractionRatio, + fog, + wireframe, + wireframeLineWidth, + wireframeLineCap, + wireframeLineJoin, + vertexColors, + skinning, + morphTargets, + morphNormals, + lineWidth, + lineCap, + lineJoin, + dashSize, + gapWidth, + blending, + blendSrc, + blendDst, + blendEquation, + depthTest, + depthFunc, + depthWrite, + polygonOffset, + polygonOffsetFactor, + polygonOffsetUnits, + alphaTest, + clippingPlanes, + clipShadows, + visible, + overdraw, + flatShading, + bumpScale, + normalScale, + displacementScale, + displacementBias, + roughness, + metalness, + pointSize, + pointSizeAttenuation, + spriteRotation, + envMapIntensity, + alphaMap, + aoMap, + bumpMap, + diffuseMap, + displacementMap, + emissiveMap, + environmentMap, + lightMap, + metalnessMap, + normalMap, + roughnessMap, + specularMap, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(materialType)) { + materialType = GameLib.D3.Material.MATERIAL_TYPE_STANDARD; + } + this.materialType = materialType; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Material (' + materialType + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(opacity)) { + opacity = 1.0; + } + this.opacity = opacity; + + if (GameLib.Utils.UndefinedOrNull(side)) { + side = GameLib.D3.Material.TYPE_FRONT_SIDE; + } + this.side = side; + + if (GameLib.Utils.UndefinedOrNull(transparent)) { + transparent = false; + } + this.transparent = transparent; + + if (GameLib.Utils.UndefinedOrNull(specular)) { + specular = new GameLib.API.Color(0.06, 0.06, 0.06, 0.06); + } + this.specular = specular; + + if (GameLib.Utils.UndefinedOrNull(lightMapIntensity)) { + lightMapIntensity = 1; + } + this.lightMapIntensity = lightMapIntensity; + + if (GameLib.Utils.UndefinedOrNull(aoMapIntensity)) { + aoMapIntensity = 1; + } + this.aoMapIntensity = aoMapIntensity; + + if (GameLib.Utils.UndefinedOrNull(color)) { + color = new GameLib.API.Color(1, 1, 1, 1) + } + this.color = color; + + if (GameLib.Utils.UndefinedOrNull(emissive)) { + emissive = new GameLib.API.Color(0, 0, 0, 0); + } + this.emissive = emissive; + + if (GameLib.Utils.UndefinedOrNull(emissiveIntensity)) { + emissiveIntensity = 1; + } + this.emissiveIntensity = emissiveIntensity; + + if (GameLib.Utils.UndefinedOrNull(combine)) { + combine = GameLib.D3.Material.TYPE_MULTIPLY_OPERATION; + } + this.combine = combine; + + if (GameLib.Utils.UndefinedOrNull(shininess)) { + shininess = 30; + } + this.shininess = shininess; + + if (GameLib.Utils.UndefinedOrNull(reflectivity)) { + reflectivity = 1; + } + this.reflectivity = reflectivity; + + if (GameLib.Utils.UndefinedOrNull(refractionRatio)) { + refractionRatio = 0.98; + } + this.refractionRatio = refractionRatio; + + if (GameLib.Utils.UndefinedOrNull(fog)) { + fog = true; + } + this.fog = fog; + + if (GameLib.Utils.UndefinedOrNull(wireframe)) { + wireframe = false; + } + this.wireframe = wireframe; + + if (GameLib.Utils.UndefinedOrNull(wireframeLineWidth)) { + wireframeLineWidth = 1; + } + this.wireframeLineWidth = wireframeLineWidth; + + if (GameLib.Utils.UndefinedOrNull(wireframeLineCap)) { + wireframeLineCap = 'round'; + } + this.wireframeLineCap = wireframeLineCap; + + if (GameLib.Utils.UndefinedOrNull(wireframeLineJoin)) { + wireframeLineJoin = 'round'; + } + this.wireframeLineJoin = wireframeLineJoin; + + if (GameLib.Utils.UndefinedOrNull(vertexColors)) { + vertexColors = GameLib.D3.Material.TYPE_NO_COLORS; + } + this.vertexColors = vertexColors; + + if (GameLib.Utils.UndefinedOrNull(skinning)) { + skinning = false; + } + this.skinning = skinning; + + if (GameLib.Utils.UndefinedOrNull(morphTargets)) { + morphTargets = false; + } + this.morphTargets = morphTargets; + + if (GameLib.Utils.UndefinedOrNull(morphNormals)) { + morphNormals = false; + } + this.morphNormals = morphNormals; + + if (GameLib.Utils.UndefinedOrNull(overdraw)) { + overdraw = 0; + } + this.overdraw = overdraw; + + if (GameLib.Utils.UndefinedOrNull(lineWidth)) { + lineWidth = 1; + } + this.lineWidth = lineWidth; + + if (GameLib.Utils.UndefinedOrNull(lineCap)) { + lineCap = 'round'; + } + this.lineCap = lineCap; + + if (GameLib.Utils.UndefinedOrNull(lineJoin)) { + lineJoin = 'round'; + } + this.lineJoin = lineJoin; + + if (GameLib.Utils.UndefinedOrNull(dashSize)) { + dashSize = 3; + } + this.dashSize = dashSize; + + if (GameLib.Utils.UndefinedOrNull(gapWidth)) { + gapWidth = 1; + } + this.gapWidth = gapWidth; + + if (GameLib.Utils.UndefinedOrNull(blending)) { + blending = GameLib.D3.Material.TYPE_NORMAL_BLENDING; + } + this.blending = blending; + + if (GameLib.Utils.UndefinedOrNull(blendSrc)) { + blendSrc = GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR; + } + this.blendSrc = blendSrc; + + if (GameLib.Utils.UndefinedOrNull(blendDst)) { + blendDst = GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR; + } + this.blendDst = blendDst; + + if (GameLib.Utils.UndefinedOrNull(blendEquation)) { + blendEquation = GameLib.D3.Material.TYPE_ADD_EQUATION; + } + this.blendEquation = blendEquation; + + if (GameLib.Utils.UndefinedOrNull(depthTest)) { + depthTest = true; + } + this.depthTest = depthTest; + + if (GameLib.Utils.UndefinedOrNull(depthFunc)) { + depthFunc = GameLib.D3.Material.TYPE_LESS_EQUAL_DEPTH; + } + this.depthFunc = depthFunc; + + if (GameLib.Utils.UndefinedOrNull(depthWrite)) { + depthWrite = true; + } + this.depthWrite = depthWrite; + + if (GameLib.Utils.UndefinedOrNull(polygonOffset)) { + polygonOffset = false; + } + this.polygonOffset = polygonOffset; + + if (GameLib.Utils.UndefinedOrNull(polygonOffsetFactor)) { + polygonOffsetFactor = 1; + } + this.polygonOffsetFactor = polygonOffsetFactor; + + if (GameLib.Utils.UndefinedOrNull(polygonOffsetUnits)) { + polygonOffsetUnits = 1; + } + this.polygonOffsetUnits = polygonOffsetUnits; + + if (GameLib.Utils.UndefinedOrNull(alphaTest)) { + alphaTest = 0; + } + this.alphaTest = alphaTest; + + if (GameLib.Utils.UndefinedOrNull(clippingPlanes)) { + clippingPlanes = []; + } + this.clippingPlanes = clippingPlanes; + + if (GameLib.Utils.UndefinedOrNull(clipShadows)) { + clipShadows = false; + } + this.clipShadows = clipShadows; + + if (GameLib.Utils.UndefinedOrNull(visible)) { + visible = true; + } + this.visible = visible; + + if (GameLib.Utils.UndefinedOrNull(flatShading)) { + flatShading = false; + } + this.flatShading = flatShading; + + if (GameLib.Utils.UndefinedOrNull(bumpScale)) { + bumpScale = 1; + } + this.bumpScale = bumpScale; + + if (GameLib.Utils.UndefinedOrNull(normalScale)) { + normalScale = 1; + } + this.normalScale = normalScale; + + if (GameLib.Utils.UndefinedOrNull(displacementScale)) { + displacementScale = 1; + } + this.displacementScale = displacementScale; + + if (GameLib.Utils.UndefinedOrNull(displacementBias)) { + displacementBias = 0; + } + this.displacementBias = displacementBias; + + if (GameLib.Utils.UndefinedOrNull(roughness)) { + roughness = 0.5; + } + this.roughness = roughness; + + if (GameLib.Utils.UndefinedOrNull(metalness)) { + metalness = 0.5; + } + this.metalness = metalness; + + if (GameLib.Utils.UndefinedOrNull(pointSize)) { + pointSize = 1; + } + this.pointSize = pointSize; + + if (GameLib.Utils.UndefinedOrNull(pointSizeAttenuation)) { + pointSizeAttenuation = true; + } + this.pointSizeAttenuation = pointSizeAttenuation; + + if (GameLib.Utils.UndefinedOrNull(spriteRotation)) { + spriteRotation = 0; + } + this.spriteRotation = spriteRotation; + + if (GameLib.Utils.UndefinedOrNull(envMapIntensity)) { + envMapIntensity = 1.0; + } + this.envMapIntensity = envMapIntensity; + + if (GameLib.Utils.UndefinedOrNull(alphaMap)) { + alphaMap = null; + } + this.alphaMap = alphaMap; + + if (GameLib.Utils.UndefinedOrNull(aoMap)) { + aoMap = null; + } + this.aoMap = aoMap; + + if (GameLib.Utils.UndefinedOrNull(bumpMap)) { + bumpMap = null; + } + this.bumpMap = bumpMap; + + if (GameLib.Utils.UndefinedOrNull(diffuseMap)) { + diffuseMap = null; + } + this.diffuseMap = diffuseMap; + + if (GameLib.Utils.UndefinedOrNull(displacementMap)) { + displacementMap = null; + } + this.displacementMap = displacementMap; + + if (GameLib.Utils.UndefinedOrNull(emissiveMap)) { + emissiveMap = null; + } + this.emissiveMap = emissiveMap; + + if (GameLib.Utils.UndefinedOrNull(environmentMap)) { + environmentMap = null; + } + this.environmentMap = environmentMap; + + if (GameLib.Utils.UndefinedOrNull(lightMap)) { + lightMap = null; + } + this.lightMap = lightMap; + + if (GameLib.Utils.UndefinedOrNull(metalnessMap)) { + metalnessMap = null; + } + this.metalnessMap = metalnessMap; + + if (GameLib.Utils.UndefinedOrNull(normalMap)) { + normalMap = null; + } + this.normalMap = normalMap; + + if (GameLib.Utils.UndefinedOrNull(roughnessMap)) { + roughnessMap = null; + } + this.roughnessMap = roughnessMap; + + if (GameLib.Utils.UndefinedOrNull(specularMap)) { + specularMap = null; + } + this.specularMap = specularMap; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + + this.needsUpdate = false; +}; + +GameLib.D3.API.Material.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Material.prototype.constructor = GameLib.D3.API.Material; + +/** + * Returns an API Material from an Object material + * @param objectMaterial + * @constructor + */ +GameLib.D3.API.Material.FromObject = function(objectMaterial) { + + var apiAlphaMap = null; + var apiAoMap = null; + var apiBumpMap = null; + var apiDiffuseMap = null; + var apiDisplacementMap = null; + var apiEmissiveMap = null; + var apiEnvironmentMap = null; + var apiLightMap = null; + var apiMetalnessMap = null; + var apiNormalMap = null; + var apiRoughnessMap = null; + var apiSpecularMap = null; + + if (objectMaterial.alphaMap) { + apiAlphaMap = objectMaterial.alphaMap; + } + + if (objectMaterial.aoMap) { + apiAoMap = objectMaterial.aoMap; + } + + if (objectMaterial.bumpMap) { + apiBumpMap = objectMaterial.bumpMap; + } + + if (objectMaterial.diffuseMap) { + apiDiffuseMap = objectMaterial.diffuseMap; + } + + if (objectMaterial.displacementMap) { + apiDisplacementMap = objectMaterial.displacementMap; + } + + if (objectMaterial.emissiveMap) { + apiEmissiveMap = objectMaterial.emissiveMap; + } + + if (objectMaterial.environmentMap) { + apiEnvironmentMap = objectMaterial.environmentMap; + } + + if (objectMaterial.lightMap) { + apiLightMap = objectMaterial.lightMap; + } + + if (objectMaterial.metalnessMap) { + apiMetalnessMap = objectMaterial.metalnessMap; + } + + if (objectMaterial.normalMap) { + apiNormalMap = objectMaterial.normalMap; + } + + if (objectMaterial.roughnessMap) { + apiRoughnessMap = objectMaterial.roughnessMap; + } + + if (objectMaterial.specularMap) { + apiSpecularMap = objectMaterial.specularMap; + } + + return new GameLib.D3.API.Material( + objectMaterial.id, + objectMaterial.materialType, + objectMaterial.name, + objectMaterial.opacity, + objectMaterial.side, + objectMaterial.transparent, + GameLib.API.Color.FromObject(objectMaterial.specular), + objectMaterial.lightMapIntensity, + objectMaterial.aoMapIntensity, + GameLib.API.Color.FromObject(objectMaterial.color), + GameLib.API.Color.FromObject(objectMaterial.emissive), + objectMaterial.emissiveIntensity, + objectMaterial.combine, + objectMaterial.shininess, + objectMaterial.reflectivity, + objectMaterial.refractionRatio, + objectMaterial.fog, + objectMaterial.wireframe, + objectMaterial.wireframeLineWidth, + objectMaterial.wireframeLineCap, + objectMaterial.wireframeLineJoin, + objectMaterial.vertexColors, + objectMaterial.skinning, + objectMaterial.morphTargets, + objectMaterial.morphNormals, + objectMaterial.lineWidth, + objectMaterial.lineCap, + objectMaterial.lineJoin, + objectMaterial.dashSize, + objectMaterial.gapWidth, + objectMaterial.blending, + objectMaterial.blendSrc, + objectMaterial.blendDst, + objectMaterial.blendEquation, + objectMaterial.depthTest, + objectMaterial.depthFunc, + objectMaterial.depthWrite, + objectMaterial.polygonOffset, + objectMaterial.polygonOffsetFactor, + objectMaterial.polygonOffsetUnits, + objectMaterial.alphaTest, + objectMaterial.clippingPlanes, + objectMaterial.clipShadows, + objectMaterial.visible, + objectMaterial.overdraw, + objectMaterial.flatShading, + objectMaterial.bumpScale, + objectMaterial.normalScale, + objectMaterial.displacementScale, + objectMaterial.displacementBias, + objectMaterial.roughness, + objectMaterial.metalness, + objectMaterial.pointSize, + objectMaterial.pointSizeAttenuation, + objectMaterial.spriteRotation, + objectMaterial.envMapIntensity, + apiAlphaMap, + apiAoMap, + apiBumpMap, + apiDiffuseMap, + apiDisplacementMap, + apiEmissiveMap, + apiEnvironmentMap, + apiLightMap, + apiMetalnessMap, + apiNormalMap, + apiRoughnessMap, + apiSpecularMap, + objectMaterial.parentEntity + ) +}; + +/** + * Raw Mesh API object - should always correspond with the Mesh Schema + * @param id + * @param meshType + * @param name + * @param vertices GameLib.D3.Vertex[] + * @param faces GameLib.D3.Face[] + * @param materials GameLib.D3.API.Material[] + * @param parentMesh + * @param parentScene + * @param skeleton + * @param skinIndices + * @param skinWeights + * @param position GameLib.API.Vector3 + * @param quaternion GameLib.API.Quaternion + * @param rotation + * @param scale GameLib.API.Vector3 + * @param up + * @param modelMatrix GameLib.API.Matrix4 + * @param parentEntity + * @param renderOrder + * @param isBufferMesh + * @param useQuaternion (use quaternion property for rotation rather than rotation property) + * @constructor + */ +GameLib.D3.API.Mesh = function( + id, + meshType, + name, + vertices, + faces, + materials, + parentMesh, + parentScene, + skeleton, + skinIndices, + skinWeights, + position, + quaternion, + rotation, + scale, + up, + modelMatrix, + parentEntity, + renderOrder, + isBufferMesh, + useQuaternion, + visible +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(meshType)) { + meshType = GameLib.D3.Mesh.MESH_TYPE_NORMAL; + } + this.meshType = meshType; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Mesh (' + id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(vertices)) { + vertices = []; + } + this.vertices = vertices; + + if (GameLib.Utils.UndefinedOrNull(faces)) { + faces = []; + } + this.faces = faces; + + if (GameLib.Utils.UndefinedOrNull(parentMesh)) { + parentMesh = null; + } + this.parentMesh = parentMesh; + + if (GameLib.Utils.UndefinedOrNull(parentScene)) { + parentScene = null; + } + this.parentScene = parentScene; + + if (GameLib.Utils.UndefinedOrNull(skeleton)) { + skeleton = null; + } + this.skeleton = skeleton; + + if (GameLib.Utils.UndefinedOrNull(skinIndices)) { + skinIndices = []; + } + this.skinIndices = skinIndices; + + if (GameLib.Utils.UndefinedOrNull(skinWeights)) { + skinWeights = []; + } + this.skinWeights = skinWeights; + + if (GameLib.Utils.UndefinedOrNull(materials) || (materials instanceof Array && materials.length === 0)) { + materials = [new GameLib.D3.API.Material(null, GameLib.D3.Material.MATERIAL_TYPE_STANDARD, 'Material (' + this.name + ')')]; + } + this.materials = materials; + + if (GameLib.Utils.UndefinedOrNull(position)) { + position = new GameLib.API.Vector3(0,0,0); + } + this.position = position; + + if (GameLib.Utils.UndefinedOrNull(quaternion)) { + quaternion = new GameLib.API.Quaternion(); + } + this.quaternion = quaternion; + + if (GameLib.Utils.UndefinedOrNull(rotation)) { + rotation = new GameLib.API.Vector3(0,0,0); + } + this.rotation = rotation; + + if (GameLib.Utils.UndefinedOrNull(scale)) { + scale = new GameLib.API.Vector3(1,1,1); + } + this.scale = scale; + + if (GameLib.Utils.UndefinedOrNull(up)) { + up = new GameLib.API.Vector3(0,1,0); + } + this.up = up; + + if (GameLib.Utils.UndefinedOrNull(modelMatrix)) { + modelMatrix = new GameLib.API.Matrix4(); + } + this.modelMatrix = modelMatrix; + + if (GameLib.Utils.UndefinedOrNull(renderOrder)) { + renderOrder = 0; + } + this.renderOrder = renderOrder; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + + if (GameLib.Utils.UndefinedOrNull(isBufferMesh)) { + isBufferMesh = false; + } + this.isBufferMesh = isBufferMesh; + + if (GameLib.Utils.UndefinedOrNull(useQuaternion)) { + useQuaternion = true; + } + this.useQuaternion = useQuaternion; + + if (GameLib.Utils.UndefinedOrNull(visible)) { + visible = true; + } + this.visible = visible; +}; + +GameLib.D3.API.Mesh.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Mesh.prototype.constructor = GameLib.D3.API.Mesh; + +/** + * Returns an API Mesh from an Object mesh + * @param objectMesh + * @constructor + */ +GameLib.D3.API.Mesh.FromObject = function (objectMesh){ + + var apiFaces = []; + if (objectMesh.faces) { + apiFaces = objectMesh.faces.map( + function(face) { + return GameLib.D3.API.Face.FromObject(face); + } + ); + } + + var apiSkeleton = null; + if (objectMesh.skeleton) { + apiSkeleton = GameLib.D3.API.Skeleton.FromObject(objectMesh.skeleton); + } + + var apiMaterials = []; + if (objectMesh.materials) { + apiMaterials = objectMesh.materials.map( + function (objectMaterial) { + /** + * From blender we only get Ids to materials (strings) + */ + if (objectMaterial instanceof Object) { + return GameLib.D3.API.Material.FromObject(objectMaterial); + } else { + return objectMaterial + } + } + ) + } + + var apiVertices = []; + if (objectMesh.vertices) { + apiVertices = objectMesh.vertices.map( + function (objectVertex) { + return GameLib.D3.API.Vertex.FromObject(objectVertex); + } + ) + } + + var apiPosition = new GameLib.API.Vector3(); + if (objectMesh.position) { + apiPosition = GameLib.API.Vector3.FromObject(objectMesh.position); + } + + var apiRotation = new GameLib.API.Vector3(); + if (objectMesh.rotation) { + apiRotation = GameLib.API.Vector3.FromObject(objectMesh.rotation); + } + + var apiQuaternion = new GameLib.API.Quaternion(); + if (objectMesh.quaternion) { + apiQuaternion = GameLib.API.Quaternion.FromObject(objectMesh.quaternion); + } + + var apiScale = new GameLib.API.Vector3(1,1,1); + if (objectMesh.scale) { + apiScale = GameLib.API.Vector3.FromObject(objectMesh.scale); + } + + var apiUp = new GameLib.API.Vector3(0,1,0); + if (objectMesh.up) { + apiUp = GameLib.API.Vector3.FromObject(objectMesh.up); + } + + var apiModelMatrix = new GameLib.API.Matrix4(); + if (objectMesh.modelMatrix) { + apiModelMatrix = GameLib.API.Matrix4.FromObject(objectMesh.modelMatrix); + } + + return new GameLib.D3.API.Mesh( + objectMesh.id, + objectMesh.meshType, + objectMesh.name, + apiVertices, + apiFaces, + apiMaterials, + objectMesh.parentMesh, + objectMesh.parentScene, + apiSkeleton, + objectMesh.skinIndices, + objectMesh.skinWeights, + apiPosition, + apiQuaternion, + apiRotation, + apiScale, + apiUp, + apiModelMatrix, + objectMesh.parentEntity, + objectMesh.renderOrder, + objectMesh.isBufferMesh, + objectMesh.useQuaternion, + objectMesh.visible + ); +}; + +/** + * Raw ParticleEngine API object - should always correspond with the ParticleEngine Schema + * @param id + * @param name + * @param position + * @param direction + * @param enabled + * @param templateParticle + * @param particlesPerSecond + * @param frequency + * @param elapsed + * @param camera + * @param pulse + * @param parentEntity + * @constructor + */ +GameLib.D3.API.ParticleEngine = function( + id, + name, + position, + direction, + enabled, + templateParticle, + particlesPerSecond, + frequency, + elapsed, + camera, + pulse, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'ParticleEngine (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(position)) { + position = new GameLib.API.Vector3(0, 0, 0); + } + this.position = position; + + if (GameLib.Utils.UndefinedOrNull(direction)) { + direction = new GameLib.API.Vector3(0, 1, 0); + } + this.direction = direction; + + if (GameLib.Utils.UndefinedOrNull(enabled)) { + enabled = false; + } + this.enabled = enabled; + + if (GameLib.Utils.UndefinedOrNull(templateParticle)) { + templateParticle = null; + } + this.templateParticle = templateParticle; + + if (GameLib.Utils.UndefinedOrNull(particlesPerSecond)) { + particlesPerSecond = 1; + } + this.particlesPerSecond = particlesPerSecond; + + if (GameLib.Utils.UndefinedOrNull(frequency)) { + frequency = Number(1 / Number(this.particlesPerSecond)); + } + this.frequency = frequency; + + if (GameLib.Utils.UndefinedOrNull(elapsed)) { + elapsed = 0; + } + this.elapsed = elapsed; + + if (GameLib.Utils.UndefinedOrNull(camera)) { + camera = null; + } + this.camera = camera; + + if (GameLib.Utils.UndefinedOrNull(pulse)) { + pulse = false; + } + this.pulse = pulse; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.ParticleEngine.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.ParticleEngine.prototype.constructor = GameLib.D3.API.ParticleEngine; + + +/** + * Creates an API ParticleEngine from an Object ParticleEngine + * @param objectParticleEngine + * @constructor + */ +GameLib.D3.API.ParticleEngine.FromObject = function(objectParticleEngine) { + + var apiTemplateParticle = null; + if (objectParticleEngine.templateParticle) { + if (objectParticleEngine.templateParticle instanceof Object) { + apiTemplateParticle = GameLib.D3.API.Particle.FromObject(objectParticleEngine.templateParticle); + } else { + apiTemplateParticle = objectParticleEngine.templateParticle; + } + } + + var apiCamera = null; + if (objectParticleEngine.camera) { + if (objectParticleEngine.camera instanceof Object) { + apiCamera = GameLib.D3.API.Camera.FromObject(objectParticleEngine.camera); + } else { + apiCamera = objectParticleEngine.camera; + } + } + + var apiPosition = null; + if (objectParticleEngine.position) { + apiPosition = GameLib.API.Vector3.FromObject(objectParticleEngine.position); + } + + var apiDirection = null; + if (objectParticleEngine.direction) { + apiDirection = GameLib.API.Vector3.FromObject(objectParticleEngine.direction); + } + + return new GameLib.D3.API.ParticleEngine( + + objectParticleEngine.id, + objectParticleEngine.name, + apiPosition, + apiDirection, + objectParticleEngine.enabled, + apiTemplateParticle, + objectParticleEngine.particlesPerSecond, + objectParticleEngine.frequency, + objectParticleEngine.elapsed, + apiCamera, + objectParticleEngine.pulse, + objectParticleEngine.parentEntity + + ); + +}; + +/** + * Raw Particle API object - should always correspond with the Particle Schema + * @param id + * @param name + * @param lifeTime + * @param elapsed + * @param mesh + * @param opacityType + * @param opacityFactor + * @param positionOffsetType + * @param positionOffset + * @param positionOffsetFn + * @param directionType + * @param rotation + * @param scale + * @param direction + * @param directionFn + * @param speedType + * @param speed + * @param scaleFn + * @param scaleType + * @param rotationType + * @param rotationFn + * @param parentEngine + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Particle = function( + id, + name, + lifeTime, + elapsed, + mesh, + opacityType, + opacityFactor, + positionOffsetType, + positionOffset, + positionOffsetFn, + directionType, + direction, + directionFn, + speedType, + speed, + scaleType, + scale, + scaleFn, + rotationType, + rotation, + rotationFn, + parentEngine, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Particle (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(lifeTime)) { + lifeTime = 10; + } + this.lifeTime = lifeTime; + + if (GameLib.Utils.UndefinedOrNull(elapsed)) { + elapsed = 0; + } + this.elapsed = elapsed; + + if (GameLib.Utils.UndefinedOrNull(mesh)) { + mesh = null; + } + this.mesh = mesh; + + if (GameLib.Utils.UndefinedOrNull(opacityType)) { + opacityType = GameLib.D3.Particle.OPACITY_TYPE_CONSTANT; + } + this.opacityType = opacityType; + + if (GameLib.Utils.UndefinedOrNull(opacityFactor)) { + opacityFactor = 0.01; + } + this.opacityFactor = opacityFactor; + + if (GameLib.Utils.UndefinedOrNull(positionOffsetType)) { + positionOffsetType = GameLib.D3.Particle.POSITION_OFFSET_TYPE_CONSTANT; + } + this.positionOffsetType = positionOffsetType; + + if (GameLib.Utils.UndefinedOrNull(positionOffset)) { + positionOffset = new GameLib.API.Vector3(0, 0, 0); + } + this.positionOffset = positionOffset; + + if (GameLib.Utils.UndefinedOrNull(positionOffsetFn)) { + positionOffsetFn = '//@ sourceURL=positionOffsetFn.js'; + } + this.positionOffsetFn = positionOffsetFn; + + if (GameLib.Utils.UndefinedOrNull(directionType)) { + directionType = GameLib.D3.Particle.DIRECTION_TYPE_CONSTANT; + } + this.directionType = directionType; + + if (GameLib.Utils.UndefinedOrNull(direction)) { + direction = new GameLib.API.Vector3(0, 1, 0); + } + this.direction = direction; + + if (GameLib.Utils.UndefinedOrNull(directionFn)) { + directionFn = '//@ sourceURL=directionFn.js'; + } + this.directionFn = directionFn; + + if (GameLib.Utils.UndefinedOrNull(speedType)) { + speedType = GameLib.D3.Particle.SPEED_TYPE_CONSTANT; + } + this.speedType = speedType; + + if (GameLib.Utils.UndefinedOrNull(speed)) { + speed = 1; + } + this.speed = speed; + + if (GameLib.Utils.UndefinedOrNull(scaleType)) { + scaleType = GameLib.D3.Particle.SCALE_TYPE_CONSTANT; + } + this.scaleType = scaleType; + + if (GameLib.Utils.UndefinedOrNull(scale)) { + scale = new GameLib.API.Vector3(1, 1, 1); + } + this.scale = scale; + + if (GameLib.Utils.UndefinedOrNull(scaleFn)) { + scaleFn = '//@ sourceURL=scaleFn.js'; + } + this.scaleFn = scaleFn; + + if (GameLib.Utils.UndefinedOrNull(rotationType)) { + rotationType = GameLib.D3.Particle.ROTATION_TYPE_CONSTANT; + } + this.rotationType = rotationType; + + if (GameLib.Utils.UndefinedOrNull(rotation)) { + rotation = new GameLib.API.Vector3(0, 0, 0); + } + this.rotation = rotation; + + if (GameLib.Utils.UndefinedOrNull(rotationFn)) { + rotationFn = '//@ sourceURL=rotationFn.js'; + } + this.rotationFn = rotationFn; + + if (GameLib.Utils.UndefinedOrNull(parentEngine)) { + parentEngine = null; + } + this.parentEngine = parentEngine; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Particle.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Particle.prototype.constructor = GameLib.D3.API.Particle; + +/** + * Creates an API Particle from an Object Particle + * @param objectParticle + * @constructor + */ +GameLib.D3.API.Particle.FromObject = function(objectParticle) { + + var apiMesh = null; + if (objectParticle.mesh) { + if (objectParticle.mesh instanceof Object) { + apiMesh = GameLib.D3.API.Mesh.FromObject(objectParticle.mesh); + } else { + apiMesh = objectParticle.mesh; + } + } + + return new GameLib.D3.API.Particle( + objectParticle.id, + objectParticle.name, + objectParticle.lifeTime, + objectParticle.elapsed, + apiMesh, + objectParticle.opacityType, + objectParticle.opacityFactor, + objectParticle.positionOffsetType, + GameLib.API.Vector3.FromObject(objectParticle.positionOffset), + objectParticle.positionOffsetFn, + objectParticle.directionType, + GameLib.API.Vector3.FromObject(objectParticle.direction), + objectParticle.directionFn, + objectParticle.speedType, + objectParticle.speed, + objectParticle.scaleType, + GameLib.API.Vector3.FromObject(objectParticle.scale), + objectParticle.scaleFn, + objectParticle.rotationType, + GameLib.API.Vector3.FromObject(objectParticle.rotation), + objectParticle.rotationFn, + objectParticle.parentEngine, + objectParticle.parentEntity + ); + +}; + +/** + * This component renders a scene + * @param id String + * @param name String + * @param passType + * @param camera + * @param scene + * @param renderToScreen + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Pass = function ( + id, + name, + passType, + camera, + scene, + renderToScreen, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Pass (' + id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(passType)) { + passType = GameLib.D3.Pass.PASS_TYPE_RENDER; + } + this.passType = passType; + + if (GameLib.Utils.UndefinedOrNull(camera)) { + camera = null; + } + this.camera = camera; + + if (GameLib.Utils.UndefinedOrNull(scene)) { + scene = null; + } + this.scene = scene; + + if (GameLib.Utils.UndefinedOrNull(renderToScreen)) { + + if (this.passType === GameLib.D3.Pass.PASS_TYPE_RENDER) { + renderToScreen = false; + } else if (GameLib.D3.Pass.PASS_TYPE_COPY_SHADER) { + renderToScreen = true; + } else { + console.warn('Unsupported Render Pass Type : ' + this.passType); + throw new Error('Unsupported Render Pass Type : ' + this.passType); + } + + } + this.renderToScreen = renderToScreen; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Pass.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Pass.prototype.constructor = GameLib.D3.API.Pass; + +/** + * Object to GameLib.D3.API.Pass + * @param objectComponent + * @constructor + */ +GameLib.D3.API.Pass.FromObject = function(objectComponent) { + return new GameLib.D3.API.Pass( + objectComponent.id, + objectComponent.name, + objectComponent.passType, + objectComponent.camera, + objectComponent.scene, + objectComponent.renderToScreen, + objectComponent.parentEntity + ); +}; + +/** + * This component makes the parentEntity (ex. car) follow the path provided by the spline + * @param id String + * @param name String + * @param spline GameLib.D3.API.Spline + * @param mesh GameLib.D3.API.Mesh + * @param raytraceMesh GameLib.D3.API.Mesh + * @param accelleration Number + * @param maxSpeed Number + * @param baseOffset GameLib.API.Vector + * @param maxOffset GameLib.API.Vector + * @param steeringSpeed Number + * @param targetOffset GameLib.API.Vector3 + * @param currentOffset GameLib.API.Vector3 + * @param currentPathValue Number + * @param currentSpeed Number + * @param direction Number + * @param raycaster GameLib.D3.Raycaster + * @param currentPosition GameLib.API.Vector3 + * @param futurePosition GameLib.API.Vector3 + * @param up GameLib.API.Vector3 + * @param rotationMatrix GameLib.API.Matrix4 + * @param rotationVector GameLib.API.Quaternion + * @param parentEntity + * @constructor + */ +GameLib.D3.API.PathFollowing = function ( + id, + name, + spline, + mesh, + raytraceMesh, + accelleration, + maxSpeed, + baseOffset, + maxOffset, + steeringSpeed, + targetOffset, + currentOffset, + currentPathValue, + currentSpeed, + direction, + raycaster, + currentPosition, + futurePosition, + up, + rotationMatrix, + rotationVector, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = this.constructor.name; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(spline)) { + spline = null; + } + this.spline = spline; + + if (GameLib.Utils.UndefinedOrNull(mesh)) { + mesh = null; + } + this.mesh = mesh; + + if (GameLib.Utils.UndefinedOrNull(raytraceMesh)) { + raytraceMesh = null; + } + this.raytraceMesh = raytraceMesh; + + if (GameLib.Utils.UndefinedOrNull(maxSpeed)) { + maxSpeed = 0.03; + } + this.maxSpeed = maxSpeed; + + if (GameLib.Utils.UndefinedOrNull(accelleration)) { + accelleration = 0.1; + } + this.accelleration = accelleration; + + if (GameLib.Utils.UndefinedOrNull(baseOffset)) { + baseOffset = new GameLib.API.Vector3(); + } + this.baseOffset = baseOffset; + + if (GameLib.Utils.UndefinedOrNull(maxOffset)) { + maxOffset = new GameLib.API.Vector3(); + } + this.maxOffset = maxOffset; + + if (GameLib.Utils.UndefinedOrNull(steeringSpeed)) { + steeringSpeed = 1.0; + } + this.steeringSpeed = steeringSpeed; + + if (GameLib.Utils.UndefinedOrNull(targetOffset)) { + targetOffset = new GameLib.API.Vector3(); + } + this.targetOffset = targetOffset; + + if (GameLib.Utils.UndefinedOrNull(currentOffset)) { + currentOffset = new GameLib.API.Vector3(); + } + this.currentOffset = currentOffset; + + if (GameLib.Utils.UndefinedOrNull(currentPathValue)) { + currentPathValue = 0; + } + this.currentPathValue = currentPathValue; + + if (GameLib.Utils.UndefinedOrNull(currentSpeed)) { + currentSpeed = 0; + } + this.currentSpeed = currentSpeed; + + if (GameLib.Utils.UndefinedOrNull(direction)) { + direction = 1; + } + this.direction = direction; + + if (GameLib.Utils.UndefinedOrNull(raycaster)) { + raycaster = new GameLib.D3.API.Raycaster(); + } + this.raycaster = raycaster; + + if (GameLib.Utils.UndefinedOrNull(currentPosition)) { + currentPosition = new GameLib.API.Vector3(); + } + this.currentPosition = currentPosition; + + if (GameLib.Utils.UndefinedOrNull(futurePosition)) { + futurePosition = new GameLib.API.Vector3(); + } + this.futurePosition = futurePosition; + + if(GameLib.Utils.UndefinedOrNull(up)) { + up = new GameLib.API.Vector3(0, 1, 0); + } + this.up = up; + + if (GameLib.Utils.UndefinedOrNull(rotationMatrix)) { + rotationMatrix = new GameLib.API.Matrix4(); + } + this.rotationMatrix = rotationMatrix; + + if (GameLib.Utils.UndefinedOrNull(rotationVector)) { + rotationVector = new GameLib.API.Quaternion(); + } + this.rotationVector = rotationVector; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + +}; + +GameLib.D3.API.PathFollowing.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.PathFollowing.prototype.constructor = GameLib.D3.API.PathFollowing; + +/** + * Returns an API path following component from an Object path following component + * @param objectComponent + * @constructor + */ +GameLib.D3.API.PathFollowing.FromObject = function(objectComponent) { + + var apiRaycaster = null; + + if (objectComponent.raycaster) { + apiRaycaster = GameLib.D3.API.Raycaster.FromObject(objectComponent.raycaster); + } + + return new GameLib.D3.API.PathFollowing( + objectComponent.id, + objectComponent.name, + objectComponent.spline, + objectComponent.mesh, + objectComponent.raytraceMesh, + objectComponent.accelleration, + objectComponent.maxSpeed, + GameLib.API.Vector3.FromObject(objectComponent.baseOffset), + GameLib.API.Vector3.FromObject(objectComponent.maxOffset), + objectComponent.steeringSpeed, + GameLib.API.Vector3.FromObject(objectComponent.targetOffset), + GameLib.API.Vector3.FromObject(objectComponent.currentOffset), + objectComponent.currentPathValue, + objectComponent.currentSpeed, + objectComponent.direction, + apiRaycaster, + GameLib.API.Vector3.FromObject(objectComponent.currentPosition), + GameLib.API.Vector3.FromObject(objectComponent.futurePosition), + GameLib.API.Vector3.FromObject(objectComponent.up), + GameLib.API.Matrix4.FromObject(objectComponent.rotationMatrix), + GameLib.API.Quaternion.FromObject(objectComponent.rotationVector), + objectComponent.parentEntity + ); +}; + +/** + * Raw World API object - should always correspond with the World Schema + * @param id + * @param name + * @param gravity + * @param broadphase + * @param solver + * @param rigidBodies + * @param contactMaterials + * @param allowSleep + * @param parentEntity + * @constructor + */ +GameLib.D3.API.PhysicsWorld = function( + id, + name, + gravity, + broadphase, + solver, + rigidBodies, + contactMaterials, + allowSleep, + defaultContactMaterial, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Physics World (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(gravity)) { + gravity = new GameLib.API.Vector3(0, -9.81, 0); + } + this.gravity = gravity; + + if (GameLib.Utils.UndefinedOrNull(broadphase)) { + broadphase = new GameLib.D3.API.Broadphase( + null, + 'Broadphase (Physics World ' + this.id + ')' + ); + } + this.broadphase = broadphase; + + if (GameLib.Utils.UndefinedOrNull(solver)) { + solver = new GameLib.D3.API.Solver( + null, + 'Solver (Physics World ' + this.id + ')' + ) + } + this.solver = solver; + + if (GameLib.Utils.UndefinedOrNull(rigidBodies)) { + rigidBodies = []; + } + this.rigidBodies = rigidBodies; + + if (GameLib.Utils.UndefinedOrNull(contactMaterials)) { + contactMaterials = []; + } + this.contactMaterials = contactMaterials; + + if (GameLib.Utils.UndefinedOrNull(allowSleep)) { + allowSleep = true; + } + this.allowSleep = allowSleep; + + if (GameLib.Utils.UndefinedOrNull(defaultContactMaterial)) { + defaultContactMaterial = new GameLib.D3.API.FrictionContactMaterial( + null, + 'Default Contact Material (Physics World ' + this.id + ')' + ); + } + this.defaultContactMaterial = defaultContactMaterial; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.PhysicsWorld.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.PhysicsWorld.prototype.constructor = GameLib.D3.API.PhysicsWorld; + +/** + * Creates an API World from an Object World + * @param objectWorld + * @constructor + */ +GameLib.D3.API.PhysicsWorld.FromObject = function(objectWorld) { + return new GameLib.D3.API.PhysicsWorld( + objectWorld.id, + objectWorld.name, + GameLib.API.Vector3.FromObject(objectWorld.gravity), + objectWorld.broadphase, + objectWorld.solver, + objectWorld.rigidBodies, + objectWorld.contactMaterials, + objectWorld.allowSleep, + objectWorld.defaultContactMaterial, + objectWorld.parentEntity + ); +}; + + +/** + * Raw RaycastVehicle API object - should always correspond with the RaycastVehicle Schema + * @param id + * @param name + * @param chassis + * @param wheels + * @param raycastWheels + * @param parentWorld + * @param parentEntity + * @constructor + */ +GameLib.D3.API.RaycastVehicle = function( + id, + name, + chassis, + wheels, + raycastWheels, + parentWorld, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'RaycastVehicle (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(chassis)) { + chassis = null; + } + this.chassis = chassis; + + if (GameLib.Utils.UndefinedOrNull(wheels)) { + wheels = []; + } + this.wheels = wheels; + + if (GameLib.Utils.UndefinedOrNull(raycastWheels)) { + raycastWheels = []; + } + this.raycastWheels = raycastWheels; + + if (GameLib.Utils.UndefinedOrNull(parentWorld)) { + parentWorld = null; + } + this.parentWorld = parentWorld; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.RaycastVehicle.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.RaycastVehicle.prototype.constructor = GameLib.D3.API.RaycastVehicle; + +/** + * Creates an API RaycastVehicle from an Object RaycastVehicle + * @param objectRaycastVehicle + * @constructor + */ +GameLib.D3.API.RaycastVehicle.FromObject = function(objectRaycastVehicle) { + return new GameLib.D3.API.RaycastVehicle( + objectRaycastVehicle.id, + objectRaycastVehicle.name, + objectRaycastVehicle.chassis, + objectRaycastVehicle.wheels, + objectRaycastVehicle.raycastWheels, + objectRaycastVehicle.parentWorld, + objectRaycastVehicle.parentEntity + ); +}; + + +/** + * Raw RaycastWheel API object - should always correspond with the RaycastWheel Schema + * @param id + * @param name + * @param radius + * @param directionLocal + * @param suspensionStiffness + * @param suspensionRestLength + * @param frictionSlip + * @param dampingRelaxation + * @param dampingCompression + * @param maxSuspensionForce + * @param rollInfluence + * @param axleLocal + * @param chassisConnectionPointLocal + * @param maxSuspensionTravel + * @param customSlidingRotationalSpeed + * @param useCustomSlidingRotationalSpeed + * @param parentEntity + * @param parentMesh + * @constructor + */ +GameLib.D3.API.RaycastWheel = function( + id, + name, + radius, + directionLocal, + suspensionStiffness, + suspensionRestLength, + frictionSlip, + dampingRelaxation, + dampingCompression, + maxSuspensionForce, + rollInfluence, + axleLocal, + chassisConnectionPointLocal, + maxSuspensionTravel, + customSlidingRotationalSpeed, + useCustomSlidingRotationalSpeed, + parentEntity, + parentMesh +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'RaycastWheel (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(radius)) { + radius = 0.5; + } + this.radius = radius; + + if (GameLib.Utils.UndefinedOrNull(directionLocal)) { + directionLocal = new GameLib.API.Vector3(0, 0, -1); + } + this.directionLocal = directionLocal; + + if (GameLib.Utils.UndefinedOrNull(suspensionStiffness)) { + suspensionStiffness = 30; + } + this.suspensionStiffness = suspensionStiffness; + + if (GameLib.Utils.UndefinedOrNull(suspensionRestLength)) { + suspensionRestLength = 0.3; + } + this.suspensionRestLength = suspensionRestLength; + + if (GameLib.Utils.UndefinedOrNull(frictionSlip)) { + frictionSlip = 5; + } + this.frictionSlip = frictionSlip; + + if (GameLib.Utils.UndefinedOrNull(dampingRelaxation)) { + dampingRelaxation = 2.3; + } + this.dampingRelaxation = dampingRelaxation; + + if (GameLib.Utils.UndefinedOrNull(dampingCompression)) { + dampingCompression = 4.4; + } + this.dampingCompression = dampingCompression; + + if (GameLib.Utils.UndefinedOrNull(maxSuspensionForce)) { + maxSuspensionForce = 100000; + } + this.maxSuspensionForce = maxSuspensionForce; + + if (GameLib.Utils.UndefinedOrNull(rollInfluence)) { + rollInfluence = 0.01; + } + this.rollInfluence = rollInfluence; + + if (GameLib.Utils.UndefinedOrNull(axleLocal)) { + axleLocal = new GameLib.API.Vector3(0, 1, 0); + } + this.axleLocal = axleLocal; + + if (GameLib.Utils.UndefinedOrNull(chassisConnectionPointLocal)) { + chassisConnectionPointLocal = new GameLib.API.Vector3(1, 1, 0); + } + this.chassisConnectionPointLocal = chassisConnectionPointLocal; + + if (GameLib.Utils.UndefinedOrNull(maxSuspensionTravel)) { + maxSuspensionTravel = 0.3; + } + this.maxSuspensionTravel = maxSuspensionTravel; + + if (GameLib.Utils.UndefinedOrNull(customSlidingRotationalSpeed)) { + customSlidingRotationalSpeed = -30; + } + this.customSlidingRotationalSpeed = customSlidingRotationalSpeed; + + if (GameLib.Utils.UndefinedOrNull(useCustomSlidingRotationalSpeed)) { + useCustomSlidingRotationalSpeed = true; + } + this.useCustomSlidingRotationalSpeed = useCustomSlidingRotationalSpeed; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + + if (GameLib.Utils.UndefinedOrNull(parentMesh)) { + parentMesh = null; + } + this.parentMesh = parentMesh; +}; + +GameLib.D3.API.RaycastWheel.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.RaycastWheel.prototype.constructor = GameLib.D3.API.RaycastWheel; + +/** + * Creates an API RaycastWheel from an Object RaycastWheel + * @param objectRaycastWheel + * @constructor + */ +GameLib.D3.API.RaycastWheel.FromObject = function(objectRaycastWheel) { + return new GameLib.D3.API.RaycastWheel( + objectRaycastWheel.id, + objectRaycastWheel.name, + objectRaycastWheel.radius, + objectRaycastWheel.directionLocal, + objectRaycastWheel.suspensionStiffness, + objectRaycastWheel.suspensionRestLength, + objectRaycastWheel.frictionSlip, + objectRaycastWheel.dampingRelaxation, + objectRaycastWheel.dampingCompression, + objectRaycastWheel.maxSuspensionForce, + objectRaycastWheel.rollInfluence, + objectRaycastWheel.axleLocal, + objectRaycastWheel.chassisConnectionPointLocal, + objectRaycastWheel.maxSuspensionTravel, + objectRaycastWheel.customSlidingRotationalSpeed, + objectRaycastWheel.useCustomSlidingRotationalSpeed, + objectRaycastWheel.parentEntity, + objectRaycastWheel.parentMesh + ); +}; + + +/** + * Raycaster for GameLib.D3 + * @param id + * @param name + * @param position GameLib.API.Vector3 + * @param direction GameLib.API.Vector3 + * @constructor + */ +GameLib.D3.API.Raycaster = function( + id, + name, + position, + direction +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Raycaster (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(position)) { + position = new GameLib.API.Vector3(); + } + this.position = position; + + if (GameLib.Utils.UndefinedOrNull(direction)) { + direction = new GameLib.API.Vector3(0, -1, 0); + } + this.direction = direction; +}; + +GameLib.D3.API.Raycaster.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Raycaster.prototype.constructor = GameLib.D3.API.Raycaster; + +/** + * Returns an API raycaster from an Object raycaster + * @param objectRaycaster + * @constructor + */ +GameLib.D3.API.Raycaster.FromObject = function(objectRaycaster) { + return new GameLib.D3.API.Raycaster( + objectRaycaster.id, + objectRaycaster.name, + GameLib.API.Vector3.FromObject(objectRaycaster.position), + GameLib.API.Vector3.FromObject(objectRaycaster.direction) + ); +}; + +/** + * This component renders a scene + * @param id String + * @param name String + * @param width + * @param height + * @param minFilter + * @param magFilter + * @param format + * @param stencilBuffer + * @param texture + * @param parentEntity + * @constructor + */ +GameLib.D3.API.RenderTarget = function ( + id, + name, + width, + height, + stencilBuffer, + texture, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Render Target (' + id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(width)) { + width = 800; + } + this.width = width; + + if (GameLib.Utils.UndefinedOrNull(height)) { + height = 600; + } + this.height = height; + + if (GameLib.Utils.UndefinedOrNull(stencilBuffer)) { + stencilBuffer = false; + } + this.stencilBuffer = stencilBuffer; + + if (GameLib.Utils.UndefinedOrNull(texture)) { + texture = null; + } + this.texture = texture; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + +}; + +GameLib.D3.API.RenderTarget.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.RenderTarget.prototype.constructor = GameLib.D3.API.RenderTarget; + +/** + * Object to GameLib.D3.API.RenderTarget + * @param objectComponent + * @constructor + */ +GameLib.D3.API.RenderTarget.FromObject = function(objectComponent) { + return new GameLib.D3.API.RenderTarget( + objectComponent.id, + objectComponent.name, + objectComponent.width, + objectComponent.height, + objectComponent.stencilBuffer, + objectComponent.texture, + objectComponent.parentEntity + ); +}; + +/** + * This component renders a scene + * @param id String + * @param name String + * @param autoClear bool + * @param localClipping + * @param width + * @param height + * @param domElement + * @param clearColor + * @param camera + * @param scenes + * @param viewports + * @param parentEntity + * @param preserveDrawingBuffer + * @param clippingPlanes + * @param bufferScene + * @param bufferCamera + * @param renderTarget + * @param defaultScene + * @constructor + */ +GameLib.D3.API.Renderer = function ( + id, + name, + autoClear, + localClipping, + width, + height, + preserveDrawingBuffer, + domElement, + clearColor, + camera, + scenes, + viewports, + clippingPlanes, + bufferScene, + bufferCamera, + renderTarget, + defaultScene, + sortObjects, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = "Renderer (" + this.id + ")"; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(autoClear)) { + autoClear = true; + } + this.autoClear = autoClear; + + if (GameLib.Utils.UndefinedOrNull(localClipping)) { + localClipping = false; + + if (clippingPlanes && clippingPlanes.length > 0) { + localClipping = true; + } + } + this.localClipping = localClipping; + + if (GameLib.Utils.UndefinedOrNull(width)) { + width = 800; + } + this.width = width; + + if (GameLib.Utils.UndefinedOrNull(height)) { + height = 600; + } + this.height = height; + + if (GameLib.Utils.UndefinedOrNull(preserveDrawingBuffer)) { + preserveDrawingBuffer = false; + } + this.preserveDrawingBuffer = preserveDrawingBuffer; + + if (GameLib.Utils.UndefinedOrNull(domElement)) { + domElement = null; + } + this.domElement = domElement; + + if (GameLib.Utils.UndefinedOrNull(clearColor)) { + clearColor = new GameLib.API.Color(0.11, 0.11, 0.11); + } + this.clearColor = clearColor; + + if (GameLib.Utils.UndefinedOrNull(camera)) { + camera = null; + } + this.camera = camera; + + if (GameLib.Utils.UndefinedOrNull(scenes)) { + scenes = []; + } + this.scenes = scenes; + + if (GameLib.Utils.UndefinedOrNull(viewports)) { + viewports = []; + } + this.viewports = viewports; + + if (GameLib.Utils.UndefinedOrNull(clippingPlanes)) { + clippingPlanes = []; + } + this.clippingPlanes = clippingPlanes; + + if (GameLib.Utils.UndefinedOrNull(bufferScene)) { + bufferScene = null; + } + this.bufferScene = bufferScene; + + if (GameLib.Utils.UndefinedOrNull(bufferCamera)) { + bufferCamera = camera; + } + this.bufferCamera = bufferCamera; + + if (GameLib.Utils.UndefinedOrNull(renderTarget)) { + renderTarget = null; + } + this.renderTarget = renderTarget; + + if (GameLib.Utils.UndefinedOrNull(defaultScene)) { + defaultScene = null; + } + this.defaultScene = defaultScene; + + if (GameLib.Utils.UndefinedOrNull(sortObjects)) { + sortObjects = true; + } + this.sortObjects = sortObjects; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + +}; + +GameLib.D3.API.Renderer.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Renderer.prototype.constructor = GameLib.D3.API.Renderer; + +/** + * Object to GameLib.D3.API.Renderer + * @param objectComponent + * @constructor + */ +GameLib.D3.API.Renderer.FromObject = function(objectComponent) { + return new GameLib.D3.API.Renderer( + objectComponent.id, + objectComponent.name, + objectComponent.autoClear, + objectComponent.localClipping, + objectComponent.width, + objectComponent.height, + objectComponent.preserveDrawingBuffer, + objectComponent.domElement, + objectComponent.clearColor, + objectComponent.camera, + objectComponent.scenes, + objectComponent.viewports, + objectComponent.clippingPlanes, + objectComponent.bufferScene, + objectComponent.bufferCamera, + objectComponent.renderTarget, + objectComponent.defaultScene, + objectComponent.sortObjects, + objectComponent.parentEntity + ); +}; + +/** + * Raw RigidBody API object - should always correspond with the RigidBody Schema + * @param id + * @param name + * @param mass + * @param friction + * @param position + * @param quaternion + * @param velocity + * @param angularVelocity + * @param linearDamping + * @param angularDamping + * @param allowSleep + * @param sleepSpeedLimit + * @param sleepTimeLimit + * @param collisionFilterGroup + * @param collisionFilterMask + * @param fixedRotation + * @param shapes + * @param kinematic + * @param parentMesh + * @param parentWorld + * @param parentEntity + * @constructor + */ +GameLib.D3.API.RigidBody = function( + id, + name, + mass, + friction, + position, + quaternion, + velocity, + angularVelocity, + linearDamping, + angularDamping, + allowSleep, + sleepSpeedLimit, + sleepTimeLimit, + collisionFilterGroup, + collisionFilterMask, + fixedRotation, + shapes, + kinematic, + parentMesh, + parentWorld, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'RigidBody (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(mass)) { + mass = 0; + } + this.mass = mass; + + if (GameLib.Utils.UndefinedOrNull(friction)) { + friction = 5; + } + this.friction = friction; + + if (GameLib.Utils.UndefinedOrNull(position)) { + position = new GameLib.API.Vector3(0,0,0); + } + this.position = position; + + if (GameLib.Utils.UndefinedOrNull(quaternion)) { + quaternion = new GameLib.API.Quaternion(); + } + this.quaternion = quaternion; + + if (GameLib.Utils.UndefinedOrNull(velocity)) { + velocity = new GameLib.API.Vector3(); + } + this.velocity = velocity; + + if (GameLib.Utils.UndefinedOrNull(angularVelocity)) { + angularVelocity = new GameLib.API.Vector3(); + } + this.angularVelocity = angularVelocity; + + if (GameLib.Utils.UndefinedOrNull(linearDamping)) { + linearDamping = 0.01; + } + this.linearDamping = linearDamping; + + if (GameLib.Utils.UndefinedOrNull(angularDamping)) { + angularDamping = 0.01; + } + this.angularDamping = angularDamping; + + if (GameLib.Utils.UndefinedOrNull(allowSleep)) { + allowSleep = true; + } + this.allowSleep = allowSleep; + + if (GameLib.Utils.UndefinedOrNull(sleepSpeedLimit)) { + sleepSpeedLimit = 0.1; + } + this.sleepSpeedLimit = sleepSpeedLimit; + + if (GameLib.Utils.UndefinedOrNull(sleepTimeLimit)) { + sleepTimeLimit = 1.0; + } + this.sleepTimeLimit = sleepTimeLimit; + + if (GameLib.Utils.UndefinedOrNull(collisionFilterGroup)) { + collisionFilterGroup = 1; + } + this.collisionFilterGroup = collisionFilterGroup; + + if (GameLib.Utils.UndefinedOrNull(collisionFilterMask)) { + collisionFilterMask = 1; + } + this.collisionFilterMask = collisionFilterMask; + + if (GameLib.Utils.UndefinedOrNull(fixedRotation)) { + fixedRotation = false; + } + this.fixedRotation = fixedRotation; + + if (GameLib.Utils.UndefinedOrNull(shapes)) { + shapes = []; + } + this.shapes = shapes; + + if (GameLib.Utils.UndefinedOrNull(kinematic)) { + kinematic = false; + } + this.kinematic = kinematic; + + if (GameLib.Utils.UndefinedOrNull(parentMesh)) { + parentMesh = null; + } + this.parentMesh = parentMesh; + + if (GameLib.Utils.UndefinedOrNull(parentWorld)) { + parentWorld = null; + } + this.parentWorld = parentWorld; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.RigidBody.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.RigidBody.prototype.constructor = GameLib.D3.API.RigidBody; + +/** + * Creates an API RigidBody from an Object RigidBody + * @param objectRigidBody + * @constructor + */ +GameLib.D3.API.RigidBody.FromObject = function(objectRigidBody) { + return new GameLib.D3.API.RigidBody( + objectRigidBody.id, + objectRigidBody.name, + objectRigidBody.mass, + objectRigidBody.friction, + objectRigidBody.position, + objectRigidBody.quaternion, + objectRigidBody.velocity, + objectRigidBody.angularVelocity, + objectRigidBody.linearDamping, + objectRigidBody.angularDamping, + objectRigidBody.allowSleep, + objectRigidBody.sleepSpeedLimit, + objectRigidBody.sleepTimeLimit, + objectRigidBody.collisionFilterGroup, + objectRigidBody.collisionFilterMask, + objectRigidBody.fixedRotation, + objectRigidBody.shapes, + objectRigidBody.kinematic, + objectRigidBody.parentMesh, + objectRigidBody.parentWorld, + objectRigidBody.parentEntity + ); +}; + + +/** + * Raw Scene API object - should always correspond with the Scene Schema + * @param id String + * @param name String + * @param meshes [GameLib.D3.API.Mesh] + * @param lights [GameLib.D3.API.Light] + * @param textures [GameLib.D3.API.Texture] + * @param materials [GameLib.D3.API.Material] + * @param images + * @param fog + * @param renderCamera - this is a camera which takes precedence over the renderer camera at time of render + * @param showGrid + * @param showAxis + * @param gridSize + * @param gridColor + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Scene = function( + id, + name, + meshes, + lights, + textures, + materials, + images, + fog, + renderCamera, + showGrid, + showAxis, + gridSize, + gridColor, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Scene (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(meshes)) { + meshes = []; + } + this.meshes = meshes; + + if (GameLib.Utils.UndefinedOrNull(lights)) { + lights = []; + } + this.lights = lights; + + if (GameLib.Utils.UndefinedOrNull(textures)) { + textures = []; + } + this.textures = textures; + + if (GameLib.Utils.UndefinedOrNull(materials)) { + materials = []; + } + this.materials = materials; + + if (GameLib.Utils.UndefinedOrNull(images)) { + images = []; + } + this.images = images; + + if (GameLib.Utils.UndefinedOrNull(fog)) { + fog = null; + } + this.fog = fog; + + if (GameLib.Utils.UndefinedOrNull(renderCamera)) { + renderCamera = null; + } + this.renderCamera = renderCamera; + + if (GameLib.Utils.UndefinedOrNull(showGrid)) { + showGrid = true; + } + this.showGrid = showGrid; + + if (GameLib.Utils.UndefinedOrNull(showAxis)) { + showAxis = true; + } + this.showAxis = showAxis; + + if (GameLib.Utils.UndefinedOrNull(gridSize)) { + gridSize = 10; + } + this.gridSize = gridSize; + + if (GameLib.Utils.UndefinedOrNull(gridColor)) { + gridColor = new GameLib.API.Color(0.1, 0.1, 0.1); + } + this.gridColor = gridColor; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + +}; + +GameLib.D3.API.Scene.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Scene.prototype.constructor = GameLib.D3.API.Scene; + +/** + * Returns an API scene from an Object scene + * @param objectScene + * @constructor + */ +GameLib.D3.API.Scene.FromObject = function(objectScene) { + + var apiMeshes = []; + var apiLights = []; + var apiTextures = []; + var apiMaterials = []; + var apiImages = []; + + if (objectScene.meshes) { + apiMeshes = objectScene.meshes.map( + function(objectMesh) { + if (objectMesh instanceof Object){ + return GameLib.D3.API.Mesh.FromObject(objectMesh); + } else { + return objectMesh; + } + } + ) + } + + if (objectScene.lights) { + apiLights = objectScene.lights.map( + function(objectLight) { + if (objectLight instanceof Object) { + return GameLib.D3.API.Light.FromObject(objectLight); + } else { + return objectLight; + } + } + ) + } + + if (objectScene.textures) { + apiTextures = objectScene.textures.map( + function(objectTexture) { + if (objectTexture instanceof Object) { + return GameLib.D3.API.Texture.FromObject(objectTexture) + } else { + return objectTexture; + } + } + ) + } + + if (objectScene.materials) { + apiMaterials = objectScene.materials.map( + function(objectMaterial) { + if (objectMaterial instanceof Object) { + return GameLib.D3.API.Material.FromObject(objectMaterial) + } else { + return objectMaterial; + } + } + ) + } + + if (objectScene.images) { + apiImages = objectScene.images.map( + function(objectImage) { + if (objectImage instanceof Object) { + return GameLib.D3.API.Image.FromObject(objectImage) + } else { + return objectImage; + } + } + ) + } + + return new GameLib.D3.API.Scene( + objectScene.id, + objectScene.name, + apiMeshes, + apiLights, + apiTextures, + apiMaterials, + apiImages, + objectScene.fog, + objectScene.renderCamera, + objectScene.showGrid, + objectScene.showAxis, + objectScene.gridSize, + GameLib.API.Color.FromObject(objectScene.gridColor), + objectScene.parentEntity + ); + +}; + +/** + * Raw Shape API object - should always correspond with the Shape Schema + * @param id + * @param name + * @param boundingSphereRadius + * @param collisionResponse + * @param frictionMaterial + * @param parentMesh + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Shape = function( + id, + name, + boundingSphereRadius, + collisionResponse, + frictionMaterial, + parentMesh, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + + name = 'Shape (' + this.id + ')'; + + if (this instanceof GameLib.D3.Shape.ConvexHull) { + name = 'Shape Convex Hull (' + this.id + ')'; + } + + if (this instanceof GameLib.D3.Shape.ConvexHull.Cylinder) { + name = 'Shape Convex Hull Cylinder (' + this.id + ')'; + } + + if (this instanceof GameLib.D3.Shape.HeightMap) { + name = 'Shape Heightmap (' + this.id + ')'; + } + + if (this instanceof GameLib.D3.Shape.Box) { + name = 'Shape Box (' + this.id + ')'; + } + + if (this instanceof GameLib.D3.Shape.Plane) { + name = 'Shape Plane (' + this.id + ')'; + } + + if (this instanceof GameLib.D3.Shape.Sphere) { + name = 'Shape Sphere (' + this.id + ')'; + } + + if (this instanceof GameLib.D3.Shape.TriMesh) { + name = 'Shape TriMesh (' + this.id + ')'; + } + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(boundingSphereRadius)) { + boundingSphereRadius = 0; + } + this.boundingSphereRadius = boundingSphereRadius; + + if (GameLib.Utils.UndefinedOrNull(collisionResponse)) { + collisionResponse = true; + } + this.collisionResponse = collisionResponse; + + if (GameLib.Utils.UndefinedOrNull(frictionMaterial)) { + frictionMaterial = null; + } + this.frictionMaterial = frictionMaterial; + + if (GameLib.Utils.UndefinedOrNull(parentMesh)) { + parentMesh = null; + } + this.parentMesh = parentMesh; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Shape.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Shape.prototype.constructor = GameLib.D3.API.Shape; + +/** + * Creates an API Shape from an Object Shape + * @param objectShape + * @constructor + */ +GameLib.D3.API.Shape.FromObject = function(objectShape) { + return new GameLib.D3.API.Shape( + objectShape.id, + objectShape.name, + objectShape.boundingSphereRadius, + objectShape.collisionResponse, + objectShape.frictionMaterial, + objectShape.parentMesh, + objectShape.parentEntity + ); +}; + + +/** + * API Skeleton + * @param id + * @param name + * @param bones GameLib.D3.API.Bone[] + * @param boneInverses GameLib.API.Matrix4[] + * @param useVertexTexture boolean + * @param boneTextureWidth Number + * @param boneTextureHeight Number + * @param boneMatrices GameLib.API.Matrix4[] + * @param boneTexture null (not implemented) + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Skeleton = function ( + id, + name, + bones, + boneInverses, + useVertexTexture, + boneTextureWidth, + boneTextureHeight, + boneMatrices, + boneTexture, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Skeleton'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(bones)) { + bones = []; + } + this.bones = bones; + + /** + * An array of Matrix4s that represent the inverse of the matrixWorld of the individual bones. + */ + if (GameLib.Utils.UndefinedOrNull(boneInverses)) { + boneInverses = []; + } + this.boneInverses = boneInverses; + + /** + * Use a vertex texture in the shader - allows for more than 4 bones per vertex, not supported by all devices + */ + if (GameLib.Utils.UndefinedOrNull(useVertexTexture)) { + useVertexTexture = false; + } + this.useVertexTexture = useVertexTexture; + if (useVertexTexture) { + console.warn('support for vertex texture bones is not supported yet - something could break somewhere'); + } + + if (GameLib.Utils.UndefinedOrNull(boneTextureWidth)) { + boneTextureWidth = 0; + } + this.boneTextureWidth = boneTextureWidth; + + if (GameLib.Utils.UndefinedOrNull(boneTextureHeight)) { + boneTextureHeight = 0; + } + this.boneTextureHeight = boneTextureHeight; + + if (GameLib.Utils.UndefinedOrNull(boneMatrices)) { + boneMatrices = []; + } + this.boneMatrices = boneMatrices; + + if (GameLib.Utils.UndefinedOrNull(boneTexture)) { + boneTexture = null; + } + this.boneTexture = boneTexture; +}; + +GameLib.D3.API.Skeleton.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Skeleton.prototype.constructor = GameLib.D3.API.Skeleton; + +/** + * Creates an API skeleton from an Object skeleton + * @param objectSkeleton + * @constructor + */ +GameLib.D3.API.Skeleton.FromObject = function(objectSkeleton) { + return new GameLib.D3.API.Skeleton( + objectSkeleton.id, + objectSkeleton.name, + objectSkeleton.bones.map( + function (objectBone) { + return GameLib.D3.API.Bone.FromObject(objectBone); + } + ), + objectSkeleton.boneInverses.map( + function (boneInverse) { + return GameLib.D3.API.Matrix4.FromObject(boneInverse); + } + ), + objectSkeleton.useVertexTexture, + objectSkeleton.boneTextureWidth, + objectSkeleton.boneTextureHeight, + objectSkeleton.boneMatrices.map( + function (boneMatrix) { + return GameLib.D3.API.Matrix4.FromObject(boneMatrix); + } + ), + objectSkeleton.boneTexture, + objectSkeleton.parentEntity + ); +}; +/** + * Raw Solver API object - should always correspond with the Solver Schema + * @param id + * @param name + * @param solverType + * @param iterations + * @param tolerance + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Solver = function( + id, + name, + solverType, + iterations, + tolerance, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Solver (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(solverType)) { + solverType = GameLib.D3.Solver.GS_SOLVER; + } + this.solverType = solverType; + + if (GameLib.Utils.UndefinedOrNull(iterations)) { + iterations = 10; + } + this.iterations = iterations; + + if (GameLib.Utils.UndefinedOrNull(tolerance)) { + tolerance = 1e-7; + } + this.tolerance = tolerance; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Solver.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Solver.prototype.constructor = GameLib.D3.API.Solver; + +/** + * Creates an API Solver from an Object Solver + * @param objectSolver + * @constructor + */ +GameLib.D3.API.Solver.FromObject = function(objectSolver) { + return new GameLib.D3.API.Solver( + objectSolver.id, + objectSolver.name, + objectSolver.solverType, + objectSolver.iterations, + objectSolver.tolerance, + objectSolver.parentEntity + ); +}; + + +/** + * API Spline + * @param id String + * @param name String + * @param vertices GameLib.API.Vector3[] + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Spline = function( + id, + name, + vertices, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Spline (unknown)'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(vertices)) { + vertices = []; + } + this.vertices = vertices; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Spline.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Spline.prototype.constructor = GameLib.D3.API.Spline; + +/** + * Object to GameLib.D3.API.Spline + * @param objectComponent + * @constructor + */ +GameLib.D3.API.Spline.FromObject = function(objectComponent) { + return new GameLib.D3.API.Spline( + objectComponent.id, + objectComponent.name, + objectComponent.vertices.map( + function (objectVertex) { + return GameLib.API.Vector3.FromObject(objectVertex); + } + ), + objectComponent.parentEntity + ); +}; + +/** + * Raw Texture API object - should always correspond with the Texture Schema + * @param id + * @param typeId + * @param name + * @param image + * @param images + * @param wrapS + * @param wrapT + * @param repeat + * @param data + * @param format + * @param mapping + * @param magFilter + * @param minFilter + * @param textureType + * @param anisotropy + * @param offset + * @param generateMipmaps + * @param flipY + * @param mipmaps + * @param unpackAlignment + * @param premultiplyAlpha + * @param encoding + * @param canvas + * @param animated + * @param reverseAnimation + * @param forward + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Texture = function( + id, + typeId, + name, + image, + images, + wrapS, + wrapT, + repeat, + data, + format, + mapping, + magFilter, + minFilter, + textureType, + anisotropy, + offset, + generateMipmaps, + flipY, + mipmaps, + unpackAlignment, + premultiplyAlpha, + encoding, + canvas, + animated, + reverseAnimation, + forward, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(typeId)) { + typeId = GameLib.D3.Texture.TEXTURE_TYPE_NORMAL; + } + this.typeId = typeId; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Texture (' + id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(image)) { + image = null; + } + this.image = image; + + if (GameLib.Utils.UndefinedOrNull(images)) { + images = []; + } + this.images = images; + + if (GameLib.Utils.UndefinedOrNull(wrapS)) { + wrapS = GameLib.D3.Texture.TYPE_REPEAT_WRAPPING; + } + this.wrapS = wrapS; + + if (GameLib.Utils.UndefinedOrNull(wrapT)) { + wrapT = GameLib.D3.Texture.TYPE_REPEAT_WRAPPING; + } + this.wrapT = wrapT; + + if (GameLib.Utils.UndefinedOrNull(repeat)) { + repeat = new GameLib.API.Vector2(1, 1); + } + this.repeat = repeat; + + if (GameLib.Utils.UndefinedOrNull(data)) { + data = null; + } + this.data = data; + + if (GameLib.Utils.UndefinedOrNull(format)) { + format = GameLib.D3.Texture.TYPE_RGBA_FORMAT; + } + this.format = format; + + if (GameLib.Utils.UndefinedOrNull(mapping)) { + mapping = GameLib.D3.Texture.TYPE_UV_MAPPING; + } + this.mapping = mapping; + + if (GameLib.Utils.UndefinedOrNull(magFilter)) { + magFilter = GameLib.D3.Texture.TYPE_LINEAR_FILTER; + } + this.magFilter = magFilter; + + if (GameLib.Utils.UndefinedOrNull(minFilter)) { + minFilter = GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER; + } + this.minFilter = minFilter; + + if (GameLib.Utils.UndefinedOrNull(textureType)) { + textureType = GameLib.D3.Texture.TYPE_UNSIGNED_BYTE; + } + this.textureType = textureType; + + if (GameLib.Utils.UndefinedOrNull(anisotropy)) { + anisotropy = 1; + } + this.anisotropy = anisotropy; + + if (GameLib.Utils.UndefinedOrNull(offset)) { + offset = new GameLib.API.Vector2(0, 0); + } + this.offset = offset; + + if (GameLib.Utils.UndefinedOrNull(generateMipmaps)) { + generateMipmaps = true; + } + this.generateMipmaps = generateMipmaps; + + if (GameLib.Utils.UndefinedOrNull(flipY)) { + flipY = true; + } + this.flipY = flipY; + + if (GameLib.Utils.UndefinedOrNull(mipmaps)) { + mipmaps = []; + } + this.mipmaps = mipmaps; + + if (GameLib.Utils.UndefinedOrNull(unpackAlignment)) { + unpackAlignment = 4; + } + this.unpackAlignment = unpackAlignment; + + if (GameLib.Utils.UndefinedOrNull(premultiplyAlpha)) { + premultiplyAlpha = false; + } + this.premultiplyAlpha = premultiplyAlpha; + + if (GameLib.Utils.UndefinedOrNull(encoding)) { + encoding = GameLib.D3.Texture.TYPE_LINEAR_ENCODING; + } + this.encoding = encoding; + + if (GameLib.Utils.UndefinedOrNull(canvas)) { + canvas = null; + } + this.canvas = canvas; + + if (GameLib.Utils.UndefinedOrNull(animated)) { + animated = false; + } + this.animated = animated; + + if (GameLib.Utils.UndefinedOrNull(reverseAnimation)) { + reverseAnimation = false; + } + this.reverseAnimation = reverseAnimation; + + if (GameLib.Utils.UndefinedOrNull(forward)) { + forward = true; + } + this.forward = forward; + + this.needsUpdate = false; +}; + +GameLib.D3.API.Texture.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Texture.prototype.constructor = GameLib.D3.API.Texture; + +/** + * Creates an API texture from Object data + * @param objectTexture + * @constructor + */ +GameLib.D3.API.Texture.FromObject = function(objectTexture) { + return new GameLib.D3.API.Texture( + objectTexture.id, + objectTexture.typeId, + objectTexture.name, + objectTexture.image, + objectTexture.images, + objectTexture.wrapS, + objectTexture.wrapT, + GameLib.API.Vector2.FromObject(objectTexture.repeat), + objectTexture.data, + objectTexture.format, + objectTexture.mapping, + objectTexture.magFilter, + objectTexture.minFilter, + objectTexture.textureType, + objectTexture.anisotropy, + GameLib.API.Vector2.FromObject(objectTexture.offset), + objectTexture.generateMipmaps, + objectTexture.flipY, + objectTexture.mipmaps, + objectTexture.unpackAlignment, + objectTexture.premultiplyAlpha, + objectTexture.encoding, + objectTexture.canvas, + objectTexture.animated, + objectTexture.reverseAnimation, + objectTexture.forward, + objectTexture.parentEntity + ) +}; + +/** + * API Vertex + * @param position GameLib.API.Vector3 + * @param boneWeights GameLib.API.BoneWeight[] + * @constructor + */ +GameLib.D3.API.Vertex = function( + position, + boneWeights +) { + + if (GameLib.Utils.UndefinedOrNull(position)) { + position = new GameLib.API.Vector3(); + } + this.position = position; + + if (GameLib.Utils.UndefinedOrNull(boneWeights)) { + boneWeights = []; + } + this.boneWeights = boneWeights; +}; + +/** + * Creates an API vertex from an Object vertex + * @param objectVertex + * @constructor + */ +GameLib.D3.API.Vertex.FromObject = function(objectVertex) { + return new GameLib.D3.API.Vertex( + GameLib.API.Vector3.FromObject(objectVertex.position), + objectVertex.boneWeights.map( + function(boneWeight) { + return GameLib.D3.API.BoneWeight.FromObject(boneWeight); + } + ) + ); +}; + +/** + * Raw Viewport API object - should always correspond with the Viewport Schema + * @param id + * @param name + * @param width + * @param height + * @param x + * @param y + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Viewport = function( + id, + name, + width, + height, + x, + y, + parentEntity +) { + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Viewport (' + this.id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(width)) { + width = 800; + } + this.width = width; + + if (GameLib.Utils.UndefinedOrNull(height)) { + height = 600; + } + this.height = height; + + if (GameLib.Utils.UndefinedOrNull(x)) { + x = 0; + } + this.x = x; + + if (GameLib.Utils.UndefinedOrNull(y)) { + y = 0; + } + this.y = y; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Viewport.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Viewport.prototype.constructor = GameLib.D3.API.Viewport; + +/** + * Creates an API Viewport from an Object Viewport + * @param objectViewport + * @constructor + */ +GameLib.D3.API.Viewport.FromObject = function(objectViewport) { + return new GameLib.D3.API.Viewport( + objectViewport.id, + objectViewport.name, + objectViewport.width, + objectViewport.height, + objectViewport.x, + objectViewport.y, + objectViewport.parentEntity + ); +}; + + +/** + * Creates a Animation object + * @param apiAnimation GameLib.D3.API.Animation + * @constructor + */ +GameLib.D3.Animation = function( + apiAnimation +) { + + if (GameLib.Utils.UndefinedOrNull(apiAnimation)) { + apiAnimation = {}; + } + + if (apiAnimation instanceof GameLib.D3.Animation) { + return apiAnimation; + } + + GameLib.D3.API.Animation.call( + this, + apiAnimation.id, + apiAnimation.name, + apiAnimation.rotationSpeed, + apiAnimation.translationSpeed, + apiAnimation.scaleSpeed, + apiAnimation.rotationFn, + apiAnimation.translationFn, + apiAnimation.scaleFn, + apiAnimation.blocking, + apiAnimation.applyToMeshWhenDone, + apiAnimation.meshes, + apiAnimation.parentEntity + ); + + this.functionType = GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_ROTATION; + + this.editor = null; + + /** + * This indicates whether an animation is currently in process - for blocking to take effect + * @type {boolean} + */ + this.inProcess = false; + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_ANIMATION, + { + 'meshes' : [GameLib.D3.Mesh] + } + ); +}; + +GameLib.D3.Animation.prototype = Object.create(GameLib.D3.API.Animation.prototype); +GameLib.D3.Animation.prototype.constructor = GameLib.D3.Animation; + +GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_ROTATION = 1; +GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_TRANSLATION = 2; +GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_SCALE = 3; + +GameLib.D3.Animation.prototype.createInstance = function() { + + this.instance = { + rotation : null, + translation : null, + scale : null + }; + + try { + if (this.rotationFn) { + this.instance.rotation = new Function( + 'data', + this.rotationFn + ).bind(this); + } + + if (this.translationFn) { + this.instance.translation = new Function( + 'data', + this.translationFn + ).bind(this); + } + + if (this.scaleFn) { + this.instance.scale = new Function( + 'data', + this.scaleFn + ).bind(this); + } + } catch (error) { + console.error(error); + this.publish( + GameLib.Event.ANIMATION_COMPILE_FAILED, + { + component : this + } + ) + } + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Animation.prototype.updateInstance = function() { + + try { + + if (this.rotationFn) { + this.instance.rotation = new Function('data', this.rotationFn).bind(this); + this.publish( + GameLib.Event.ANIMATION_COMPILE_SUCCESS, + { + component : this, + type : GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_ROTATION + } + ) + } + + if (this.translationFn) { + this.instance.translation = new Function('data', this.translationFn).bind(this); + this.publish( + GameLib.Event.ANIMATION_COMPILE_SUCCESS, + { + component : this, + type : GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_TRANSLATION + } + ) + } + + if (this.scaleFn) { + this.instance.scale = new Function('data', this.scaleFn).bind(this); + this.publish( + GameLib.Event.ANIMATION_COMPILE_SUCCESS, + { + component : this, + type : GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_SCALE + } + ) + } + + } catch (error) { + console.error(error); + this.publish( + GameLib.Event.ANIMATION_COMPILE_FAILED, + { + component : this + } + ) + } +}; + +/** + * Converts a GameLib.D3.Animation to a new GameLib.D3.API.Animation + * @returns {GameLib.D3.API.Animation} + */ +GameLib.D3.Animation.prototype.toApiObject = function() { + + return new GameLib.D3.API.Animation( + this.id, + this.name, + this.rotationSpeed, + this.translationSpeed, + this.scaleSpeed, + this.rotationFn, + this.translationFn, + this.scaleFn, + this.blocking, + this.applyToMeshWhenDone, + this.meshes.map( + function(mesh) { + return GameLib.Utils.IdOrNull(mesh); + } + ), + GameLib.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Converts from an Object Animation to a GameLib.D3.Animation + * @param objectAnimation Object + * @returns {GameLib.D3.Animation} + * @constructor + */ +GameLib.D3.Animation.FromObject = function(objectAnimation) { + var apiAnimation = GameLib.D3.API.Animation.FromObject(objectAnimation); + return new GameLib.D3.Animation( + apiAnimation + ); +}; + +GameLib.D3.Animation.prototype.launchEditor = function(){ + + GameLib.Event.Emit( + GameLib.Event.GET_CODER_IMPLEMENTATION, + null, + function(coder) { + this.coder = coder; + this.coder.isNotCodeMirrorThrow(); + }.bind(this) + ); + + var property = null; + + if (this.functionType === GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_ROTATION) { + this.rotationFn = '//when the animation is complete, return true\nreturn true;'; + property = 'rotationFn'; + } + + if (this.functionType === GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_TRANSLATION) { + this.translationFn = '//when the animation is complete, return true\nreturn true;'; + property = 'translationFn'; + } + + if (this.functionType === GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_SCALE) { + this.scaleFn = '//when the animation is complete, return true\nreturn true;'; + property = 'scaleFn'; + } + + if (property) { + this.editor = this.coder.instance( + document.body, + { + value : this[property], + mode : 'javascript', + lineNumbers : true, + scrollbarStyle : 'overlay' + } + ); + + this.editor.on('change', function(){ + + this[property] = this.editor.getValue(); + + this.updateInstance(); + + }.bind(this)) + } else { + console.warn('invalid function type selected'); + } +}; + +GameLib.D3.Animation.prototype.closeEditor = function(){ + var dom = this.editor.getWrapperElement(); + dom.parentElement.removeChild(dom); +}; + +GameLib.D3.Animation.prototype.addMesh = function(mesh) { + + GameLib.Utils.PushUnique(this.meshes, mesh); + + GameLib.Event.Emit( + GameLib.Event.ANIMATION_MESH_ADDED, + { + animation : this, + mesh : mesh + } + ) + +}; + +GameLib.D3.Animation.prototype.removeMesh = function(mesh) { + + var index = this.meshes.indexOf(mesh); + + this.meshes.splice(index, 1); + + GameLib.Event.Emit( + GameLib.Event.ANIMATION_MESH_REMOVED, + { + animation : this, + mesh : mesh + } + ) + +}; +/** + * Creates a Audio object + * @param graphics GameLib.D3.Graphics + * @param apiAudio GameLib.D3.API.Audio + * @constructor + */ +GameLib.D3.Audio = function( + graphics, + apiAudio +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiAudio)) { + apiAudio = {}; + } + + if (apiAudio instanceof GameLib.D3.Audio) { + return apiAudio; + } + + GameLib.D3.API.Audio.call( + this, + apiAudio.id, + apiAudio.name, + apiAudio.path, + apiAudio.loop, + apiAudio.volume, + apiAudio.camera, + apiAudio.overplay, + apiAudio.parentEntity + ); + + if (this.camera instanceof GameLib.D3.API.Camera) { + this.camera = new GameLib.D3.Camera( + this.graphics, + this.camera + ) + } + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_AUDIO, + { + 'camera' : GameLib.D3.Camera + } + ); + +}; + +GameLib.D3.Audio.prototype = Object.create(GameLib.D3.API.Audio.prototype); +GameLib.D3.Audio.prototype.constructor = GameLib.D3.Audio; + +/** + * Audio create instance + */ +GameLib.D3.Audio.prototype.createInstance = function() { + + if (GameLib.Utils.UndefinedOrNull(this.camera) || + GameLib.Utils.UndefinedOrNull(this.camera.instance)) { + console.log('audio not ready to create instance'); + return; + } + + + GameLib.Event.Emit( + GameLib.Event.GET_API_URL, + null, + function(data) { + this.apiUrl = data.apiUrl; + }.bind(this) + ); + + //Create an AudioListener and add it to the camera + var listener = new THREE.AudioListener(); + + this.camera.instance.add( listener ); + + // create a global audio source + this.instance = new THREE.Audio( listener ); + + var audioLoader = new THREE.AudioLoader(); + + //Load a sound and set it as the Audio object's buffer + audioLoader.load( + this.apiUrl + this.path, + function( buffer ) { + this.instance.setBuffer( buffer ); + this.instance.setLoop( this.loop ); + this.instance.setVolume( this.volume ); + GameLib.Component.prototype.createInstance.call(this); + }.bind(this) + ); +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Audio.prototype.updateInstance = function(property) { + + if (property === 'loop') { + this.instance.setLoop(this.loop); + } + + if (property === 'volume') { + this.instance.setVolume(this.volume); + } + +}; + +/** + * Converts a GameLib.D3.Audio to a new GameLib.D3.API.Audio + * @returns {GameLib.D3.API.Audio} + */ +GameLib.D3.Audio.prototype.toApiObject = function() { + + return new GameLib.D3.API.Audio( + this.id, + this.name, + this.path, + this.loop, + this.volume, + GameLib.Utils.IdOrNull(this.camera), + this.overplay, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Converts from an Object Audio to a GameLib.D3.Audio + * @param graphics GameLib.D3.Graphics + * @param objectAudio Object + * @returns {GameLib.D3.Audio} + * @constructor + */ +GameLib.D3.Audio.FromObject = function(graphics, objectAudio) { + + var apiAudio = GameLib.D3.API.Audio.FromObject(objectAudio); + + return new GameLib.D3.Audio( + graphics, + apiAudio + ); + +}; + +/** + * BoneWeight Superset + * @constructor + * @param graphics GameLib.D3.Graphics + * @param apiBoneWeight GameLib.D3.API.BoneWeight + */ +GameLib.D3.BoneWeight = function ( + graphics, + apiBoneWeight +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiBoneWeight)) { + apiBoneWeight = {}; + } + + if (apiBoneWeight instanceof GameLib.D3.BoneWeight) { + return apiBoneWeight; + } + + GameLib.D3.API.BoneWeight.call( + this, + apiBoneWeight.boneIndex, + apiBoneWeight.weight + ); +}; + +GameLib.D3.BoneWeight.prototype = Object.create(GameLib.D3.API.BoneWeight.prototype); +GameLib.D3.BoneWeight.prototype.constructor = GameLib.D3.BoneWeight; + +/** + * Converts a GameLib.D3.BoneWeight to GameLib.D3.API.BoneWeight + * @returns {GameLib.D3.API.BoneWeight} + */ +GameLib.D3.BoneWeight.prototype.toApiObject = function() { + + var apiBoneWeight = new GameLib.D3.API.BoneWeight( + this.boneIndex, + this.weight + ); + + return apiBoneWeight; +}; + +/** + * Returns a GameLib.D3.BoneWeight from a boneWeight Object + * @param graphics GameLib.D3.Graphics + * @param objectBoneWeight Object + * @returns {GameLib.D3.BoneWeight} + * @constructor + */ +GameLib.D3.BoneWeight.FromObject = function( + graphics, + objectBoneWeight +) { + var apiBoneWeight = GameLib.D3.API.BoneWeight.FromObject(objectBoneWeight); + + var boneWeight = new GameLib.D3.BoneWeight( + graphics, + apiBoneWeight + ); + + return boneWeight; +}; +/** + * Bone Superset + * @constructor + * @param graphics GameLib.D3.Graphics + * @param apiBone GameLib.D3.API.Bone + */ +GameLib.D3.Bone = function ( + graphics, + apiBone +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiBone)) { + apiBone = {}; + } + + if (apiBone instanceof GameLib.D3.Bone) { + return apiBone; + } + + GameLib.D3.API.Bone.call( + this, + apiBone.id, + apiBone.name, + apiBone.childBoneIds, + apiBone.parentBoneIds, + apiBone.position, + apiBone.quaternion, + apiBone.scale, + apiBone.up + ); + + this.position = new GameLib.Vector3( + graphics, + this.position, + this + ); + + this.quaternion = new GameLib.Quaternion( + graphics, + this.quaternion, + this + ); + + this.scale = new GameLib.Vector3( + graphics, + this.scale, + this + ); + + this.up = new GameLib.Vector3( + graphics, + this.up, + this + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_BONE + ); +}; + +GameLib.D3.Bone.prototype = Object.create(GameLib.D3.API.Bone.prototype); +GameLib.D3.Bone.prototype.constructor = GameLib.D3.Bone; + + +/** + * Creates an instance bone + + */ +GameLib.D3.Bone.prototype.createInstance = function() { + + this.instance = new THREE.Bone(); + + this.instance.name = this.name; + + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + + this.instance.quaternion.x = this.quaternion.x; + this.instance.quaternion.y = this.quaternion.y; + this.instance.quaternion.z = this.quaternion.z; + this.instance.quaternion.w = this.quaternion.w; + + this.instance.scale.x = this.scale.x; + this.instance.scale.y = this.scale.y; + this.instance.scale.z = this.scale.z; + + this.instance.up.x = this.up.x; + this.instance.up.y = this.up.y; + this.instance.up.z = this.up.z; + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance + */ +GameLib.D3.Bone.prototype.updateInstance = function() { + this.instance.name = this.name; + + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + + this.instance.quaternion.x = this.quaternion.x; + this.instance.quaternion.y = this.quaternion.y; + this.instance.quaternion.z = this.quaternion.z; + this.instance.quaternion.w = this.quaternion.w; + + this.instance.scale.x = this.scale.x; + this.instance.scale.y = this.scale.y; + this.instance.scale.z = this.scale.z; + + this.instance.up.x = this.up.x; + this.instance.up.y = this.up.y; + this.instance.up.z = this.up.z; +}; + +/** + * Converts a GameLib.D3.Bone to GameLib.D3.API.Bone + * @returns {GameLib.D3.API.Bone} + */ +GameLib.D3.Bone.prototype.toApiObject = function() { + + var apiBone = new GameLib.D3.API.Bone( + this.id, + this.name, + this.childBoneIds, + this.parentBoneIds, + this.position.toApiObject(), + this.quaternion.toApiObject(), + this.scale.toApiObject(), + this.up.toApiObject() + ); + + return apiBone; +}; + +/** + * Returns a GameLib.D3.Bone from a bone Object + * @param graphics GameLib.D3.Graphics + * @param objectBone Object + * @returns {GameLib.D3.Bone} + * @constructor + */ +GameLib.D3.Bone.FromObject = function( + graphics, + objectBone +) { + var apiBone = GameLib.D3.API.Bone.FromObject(objectBone); + + var bone = GameLib.D3.Bone( + graphics, + apiBone + ); + + return bone; +}; +/** + * Broadphase Runtime + * @param physics GameLib.D3.Graphics + * @param apiBroadphase GameLib.D3.API.Broadphase + * @constructor + */ +GameLib.D3.Broadphase = function ( + physics, + apiBroadphase +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiBroadphase)) { + apiBroadphase = {}; + } + + if (apiBroadphase instanceof GameLib.D3.Broadphase) { + return apiBroadphase; + } + + GameLib.D3.API.Broadphase.call( + this, + apiBroadphase.id, + apiBroadphase.name, + apiBroadphase.broadphaseType, + apiBroadphase.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_BROADPHASE + ); +}; + +GameLib.D3.Broadphase.prototype = Object.create(GameLib.D3.API.Broadphase.prototype); +GameLib.D3.Broadphase.prototype.constructor = GameLib.D3.Broadphase; + +/** + * + * @returns {*} + */ +GameLib.D3.Broadphase.prototype.createInstance = function() { + + if (this.broadphaseType === GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE) { + this.instance = new CANNON.NaiveBroadphase(); + } else if (this.broadphaseType === GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID) { + this.instance = new CANNON.GridBroadphase(); + } else if (this.broadphaseType === GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP) { + this.instance = new CANNON.SAPBroadphase(); + } else { + console.warn('Unsupported broadphase type: ' + this.broadphaseType); + throw new Error('Unsupported broadphase type: ' + this.broadphaseType); + } + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * + */ +GameLib.D3.Broadphase.prototype.updateInstance = function() { + + if (this.broadphaseType === GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE) { + if (!(this.instance instanceof CANNON.NaiveBroadphase)) { + this.createInstance(); + } + } + + if (this.broadphaseType === GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID) { + if (!(this.instance instanceof CANNON.GridBroadphase)) { + this.createInstance(); + } + } + + if (this.broadphaseType === GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP) { + if (!(this.instance instanceof CANNON.SAPBroadphase)) { + this.createInstance(); + } + } +}; + +/** + * GameLib.D3.Broadphase to GameLib.D3.API.Broadphase + * @returns {GameLib.D3.API.Broadphase} + */ +GameLib.D3.Broadphase.prototype.toApiObject = function() { + + var apiBroadphase = new GameLib.D3.API.Broadphase( + this.id, + this.name, + this.broadphaseType, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiBroadphase; +}; + +/** + * GameLib.D3.Broadphase from Object Broadphase + * @param graphics + * @param objectComponent + * @returns {GameLib.D3.Broadphase} + * @constructor + */ +GameLib.D3.Broadphase.FromObject = function(graphics, objectComponent) { + + var apiBroadphase = GameLib.D3.API.Broadphase.FromObject(objectComponent); + + return new GameLib.D3.Broadphase( + graphics, + apiBroadphase + ); +}; + +/** + * Broadphase Types + * @type {number} + */ +GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE = 0x1; +GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID = 0x2; +GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP = 0x3; +/** + * Creates a Camera object + * @param graphics GameLib.D3.Graphics + * @param apiCamera GameLib.D3.API.Camera + * @constructor + */ +GameLib.D3.Camera = function( + graphics, + apiCamera +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiCamera)) { + apiCamera = {}; + } + + if (apiCamera instanceof GameLib.D3.Camera) { + return apiCamera; + } + + GameLib.D3.API.Camera.call( + this, + apiCamera.id, + apiCamera.cameraType, + apiCamera.name, + apiCamera.fov, + apiCamera.aspect, + apiCamera.near, + apiCamera.far, + apiCamera.position, + apiCamera.lookAt, + apiCamera.minX, + apiCamera.maxX, + apiCamera.minY, + apiCamera.maxY, + apiCamera.minZ, + apiCamera.maxZ, + apiCamera.offsetX, + apiCamera.offsetY, + apiCamera.quaternion, + apiCamera.parentEntity, + apiCamera.eyeSeparation, + apiCamera.focalLength + ); + + if (this.position instanceof GameLib.API.Vector3) { + this.position = new GameLib.Vector3( + graphics, + this.position, + this + ); + } else { + console.warn('position not instance of API.Vector3'); + throw new Error('position not instance of API.Vector3'); + } + + if (this.quaternion instanceof GameLib.API.Quaternion) { + this.quaternion = new GameLib.Quaternion( + graphics, + this.quaternion, + this + ); + } else { + console.warn('quaternion not instance of API.Quaternion'); + throw new Error('quaternion not instance of API.Quaternion'); + } + + if (this.lookAt instanceof GameLib.API.Vector3) { + this.lookAt = new GameLib.Vector3( + graphics, + this.lookAt, + this + ); + } else { + console.warn('lookAt not instance of API.Vector3'); + throw new Error('lookAt not instance of API.Vector3'); + } + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_CAMERA + ); + +} ; + +GameLib.D3.Camera.prototype = Object.create(GameLib.D3.API.Camera.prototype); +GameLib.D3.Camera.prototype.constructor = GameLib.D3.Camera; + +GameLib.D3.Camera.CAMERA_TYPE_PERSPECTIVE = 0x1; +GameLib.D3.Camera.CAMERA_TYPE_ORTHOGONAL = 0x2; +GameLib.D3.Camera.CAMERA_TYPE_STEREO = 0x3; + +/** + * Creates a camera instance of 'graphics' type (only THREE for now) + * @returns {THREE.Camera} + */ +GameLib.D3.Camera.prototype.createInstance = function() { + + if (this.cameraType === GameLib.D3.Camera.CAMERA_TYPE_PERSPECTIVE ) { + this.instance = new THREE.PerspectiveCamera( + this.fov, + this.aspect, + this.near, + this.far + ); + } else if (this.cameraType === GameLib.D3.Camera.CAMERA_TYPE_ORTHOGONAL) { + this.instance = new THREE.OrthographicCamera( + this.minX + this.offsetX, + this.maxX + this.offsetX, + this.maxY, + this.minY, + this.minZ, + this.maxZ + ); + } else if (this.cameraType === GameLib.D3.Camera.CAMERA_TYPE_STEREO) { + this.instance = new THREE.StereoCamera(); + } else { + throw new Error('unsupported camera type : ' + this.cameraType); + } + + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + + this.instance.quaternion.x = this.quaternion.x; + this.instance.quaternion.y = this.quaternion.y; + this.instance.quaternion.z = this.quaternion.z; + this.instance.quaternion.w = this.quaternion.w; + + this.instance.lookAt(this.lookAt.instance); + + this.instance.updateProjectionMatrix(); + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Camera.prototype.updateInstance = function(property) { + + if (GameLib.Utils.UndefinedOrNull(property)) { + console.warn('no camera property specified for : ' + this.name); + } + + if (property === 'cameraType') { + if ( + this.cameraType === GameLib.D3.Camera.CAMERA_TYPE_ORTHOGONAL && + !(this.instance instanceof THREE.OrthographicCamera) + ) { + this.createInstance(); + } + + if ( + this.cameraType === GameLib.D3.Camera.CAMERA_TYPE_PERSPECTIVE && + !(this.instance instanceof THREE.PerspectiveCamera) + ) { + this.createInstance(); + } + } + + if ( + property === 'aspect' || + property === 'minX' || + property === 'maxX' || + property === 'minZ' || + property === 'maxZ' || + property === 'offsetX' || + property === 'offsetY' || + property === 'fov' || + property === 'near' || + property === 'far' || + property === 'eyeSeparation' || + property === 'focalLength' + ) { + + if (this.cameraType === GameLib.D3.Camera.CAMERA_TYPE_ORTHOGONAL) { + + this.minX = this.aspect * this.minY; + this.maxX = this.aspect * this.maxY; + + this.instance.left = this.minX + this.offsetX; + this.instance.right = this.maxX + this.offsetX; + + this.instance.bottom = this.minY + this.offsetY; + this.instance.top = this.maxY + this.offsetY; + + this.instance.near = this.minZ; + this.instance.far = this.maxZ; + } + + if ( + this.cameraType === GameLib.D3.Camera.CAMERA_TYPE_PERSPECTIVE || + this.cameraType === GameLib.D3.Camera.CAMERA_TYPE_STEREO + ) { + this.instance.fov = this.fov; + this.instance.aspect = this.aspect; + this.instance.near = this.near; + this.instance.far = this.far; + } + + if (this.cameraType === GameLib.D3.Camera.CAMERA_TYPE_STEREO) { + this.instance.eyeSeparation = this.eyeSeparation; + this.instance.focalLength = this.focalLength; + this.instance.update(this.instance); + } + } + + if (property === 'position') { + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + } + + if (property === 'quaternion') { + this.instance.quaternion.x = this.quaternion.x; + this.instance.quaternion.y = this.quaternion.y; + this.instance.quaternion.z = this.quaternion.z; + this.instance.quaternion.w = this.quaternion.w; + } + + if (property === 'lookAt') { + this.lookAt.instance.x = this.lookAt.x; + this.lookAt.instance.y = this.lookAt.y; + this.lookAt.instance.z = this.lookAt.z; + this.instance.lookAt(this.lookAt.instance); + } + + this.instance.updateProjectionMatrix(); +}; + +/** + * Resize default + * @param width + * @param height + */ +GameLib.D3.Camera.prototype.resize = function(width, height) { + camera.aspect = width / height; + camera.updateInstance(); +}; + +/** + * Converts a GameLib.D3.Camera to a new GameLib.D3.API.Camera + * @returns {GameLib.D3.API.Camera} + */ +GameLib.D3.Camera.prototype.toApiObject = function() { + + return new GameLib.D3.API.Camera( + this.id, + this.cameraType, + this.name, + this.fov, + this.aspect, + this.near, + this.far, + this.position.toApiObject(), + this.lookAt.toApiObject(), + this.minX, + this.maxX, + this.minY, + this.maxY, + this.minZ, + this.maxZ, + this.offsetX, + this.offsetY, + this.quaternion.toApiObject(), + GameLib.Utils.IdOrNull(this.parentEntity), + this.eyeSeparation, + this.focalLength + ); + +}; + +/** + * Converts from an Object Camera to a GameLib.D3.Camera + * @param graphics GameLib.D3.Graphics + * @param objectCamera Object + * @returns {GameLib.D3.Camera} + * @constructor + */ +GameLib.D3.Camera.FromObject = function(graphics, objectCamera) { + + var apiCamera = GameLib.D3.API.Camera.FromObject(objectCamera); + + return new GameLib.D3.Camera( + graphics, + apiCamera + ); + +}; + +/** + * Canvas Superset - The apiCanvas properties get moved into the Canvas object itself, and then the instance is created + * @param graphics GameLib.D3.Graphics + * @param apiCanvas GameLib.D3.API.Canvas + * @constructor + */ +GameLib.D3.Canvas = function( + graphics, + apiCanvas +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiCanvas)) { + apiCanvas = {}; + } + + if (apiCanvas instanceof GameLib.D3.Canvas) { + return apiCanvas; + } + + GameLib.D3.API.Canvas.call( + this, + apiCanvas.id, + apiCanvas.name, + apiCanvas.width, + apiCanvas.height, + apiCanvas.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_CANVAS + ); +}; + +GameLib.D3.Canvas.prototype = Object.create(GameLib.D3.API.Canvas.prototype); +GameLib.D3.Canvas.prototype.constructor = GameLib.D3.Canvas; + +/** + * Creates a light instance + * @returns {*} + */ +GameLib.D3.Canvas.prototype.createInstance = function() { + + this.instance = document.createElement('canvas'); + + this.instance.width = this.width; + this.instance.height = this.height; + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Canvas.prototype.updateInstance = function() { + + if (GameLib.Utils.UndefinedOrNull(this.instance)) { + this.createInstance(); + } + + this.instance.width = this.width; + this.instance.height = this.height; +}; + +/** + * Converts a GameLib.D3.Canvas to a GameLib.D3.API.Canvas + * @returns {GameLib.D3.API.Canvas} + */ +GameLib.D3.Canvas.prototype.toApiObject = function() { + return new GameLib.D3.API.Canvas( + this.id, + this.name, + this.width, + this.height, + GameLib.Utils.IdOrNull(this.parentEntity) + ); +}; + +/** + * Returns a new GameLib.D3.Canvas from a GameLib.D3.API.Canvas + * @param graphics GameLib.D3.Graphics + * @param objectCanvas GameLib.D3.API.Canvas + * @returns {GameLib.D3.Canvas} + */ +GameLib.D3.Canvas.FromObject = function(graphics, objectCanvas) { + + return new GameLib.D3.Canvas( + graphics, + GameLib.D3.API.Canvas.FromObject(objectCanvas) + ); + +}; +/** + * Coder + * @param id + * @param name + * @param coderType + * @constructor + */ +GameLib.D3.Coder = function Coder( + id, + name, + coderType +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Coder (' + id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(coderType)) { + coderType = GameLib.D3.Coder.CODER_TYPE_CODE_MIRROR; + } + this.coderType = coderType; + + this.createInstance(); +}; + +/** + * GameLib.D3.Coder Types + * @type {number} + */ +GameLib.D3.Coder.CODER_TYPE_CODE_MIRROR = 0x1; + +/** + * @returns {THREE.Coder} + */ +GameLib.D3.Coder.prototype.createInstance = function() { + this.instance = CodeMirror; +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Coder.prototype.updateInstance = function() { +}; + +/** + * True if THREE physics + * @returns {boolean} + */ +GameLib.D3.Coder.prototype.isCodeMirror = function() { + return (this.coderType === GameLib.D3.Coder.CODER_TYPE_CODE_MIRROR) +}; + +/** + * Logs a warning and throws an error if not cannon + */ +GameLib.D3.Coder.prototype.isNotCodeMirrorThrow = function() { + if (this.coderType !== GameLib.D3.Coder.CODER_TYPE_CODE_MIRROR) { + console.warn('Only CodeMirror supported for this function'); + throw new Error('Only CodeMirror supported for this function'); + } +}; + +/** + * Renders a scene with a camera + * @param graphics GameLib.D3.Graphics + * @param apiComposer GameLib.D3.API.Composer + * @constructor + */ +GameLib.D3.Composer = function ( + graphics, + apiComposer +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiComposer)) { + apiComposer = {}; + } + + if (apiComposer instanceof GameLib.D3.Composer) { + return apiComposer; + } + + GameLib.D3.API.Composer.call( + this, + apiComposer.id, + apiComposer.name, + apiComposer.renderer, + apiComposer.renderTarget, + apiComposer.passes, + apiComposer.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_COMPOSER, + { + 'renderer' : GameLib.D3.Renderer, + 'renderTarget' : GameLib.D3.RenderTarget, + 'passes' : [GameLib.D3.Pass] + } + ); +}; + +GameLib.D3.Composer.prototype = Object.create(GameLib.D3.API.Composer.prototype); +GameLib.D3.Composer.prototype.constructor = GameLib.D3.Composer; + +/** + * Creates a Composer instance + * @returns {*} + */ +GameLib.D3.Composer.prototype.createInstance = function() { + + //TODO : Fix this too - make it nice (no circular references) + // var instance = null; + // + // if (update) { + // instance = this.instance; + // } + + //TODO : Fix this still (renderer and renderTarget should be objects) + // if (this.renderer && + // this.renderTarget) { + // + // if (!THREE.EffectComposer) { + // console.warn('No THREE.EffectComposer'); + // throw new Error('No THREE.EffectComposer'); + // } + // + // instance = new THREE.EffectComposer( + // this.renderer.instance, + // this.renderTarget.instance + // ); + // + // this.passes.map( + // function(pass) { + // this.instance.addPass(pass.instance); + // }.bind(this) + // ); + // } + console.log('GameLib.D3.Composer.prototype.createInstance() - fix me'); + + GameLib.Component.prototype.createInstance.call(this); + + //return instance; +}; + +/** + * Updates Composer instance + */ +GameLib.D3.Composer.prototype.updateInstance = function() { + console.log('GameLib.D3.Composer.prototype.updateInstance() - fix me'); +}; + +/** + * GameLib.D3.Composer to GameLib.D3.API.Composer + * @returns {GameLib.D3.API.Composer} + */ +GameLib.D3.Composer.prototype.toApiObject = function() { + + var apiComposer = new GameLib.D3.API.Composer( + this.id, + this.name, + GameLib.Utils.IdOrNull(this.renderer), + GameLib.Utils.IdOrNull(this.renderTarget), + this.passes.map( + function(pass) { + return GameLib.Utils.IdOrNull(pass); + } + ), + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiComposer; +}; + +/** + * + * @param graphics + * @param objectComponent + * @returns {GameLib.D3.Composer} + * @constructor + */ +GameLib.D3.Composer.FromObject = function(graphics, objectComponent) { + + var apiComposer = GameLib.D3.API.Composer.FromObject(objectComponent); + + return new GameLib.D3.Composer( + graphics, + apiComposer + ); +}; + +/** + * Controls Superset - The apiControls properties get moved into the Controls object itself, and then the instance is created + * @param graphics GameLib.D3.Graphics + * @param apiControls GameLib.D3.API.Controls + * @constructor + */ +GameLib.D3.Controls = function ( + graphics, + apiControls +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiControls)) { + apiControls = {}; + } + + if (apiControls instanceof GameLib.D3.Controls) { + return apiControls; + } + + GameLib.D3.API.Controls.call( + this, + apiControls.id, + apiControls.controlsType, + apiControls.name, + apiControls.domElement, + apiControls.parentEntity + ); + + var componentType = GameLib.Component.COMPONENT_CONTROLS; + + var linkedObjects = { + domElement : GameLib.DomElement + }; + + var delayed = false; + + if (this.controlsType === GameLib.D3.Controls.CONTROLS_TYPE_EDITOR) { + + componentType = GameLib.Component.COMPONENT_CONTROLS_EDITOR; + + linkedObjects.raycaster = GameLib.D3.Raycaster; + linkedObjects.camera = GameLib.D3.Camera; + + delayed = true; + } + + if (this.controlsType === GameLib.D3.Controls.CONTROLS_TYPE_TOUCH) { + componentType = GameLib.Component.COMPONENT_CONTROLS_TOUCH + } + + if (this.controlsType === GameLib.D3.Controls.CONTROLS_TYPE_KEYBOARD) { + componentType = GameLib.Component.COMPONENT_CONTROLS_KEYBOARD + } + + if (this.controlsType === GameLib.D3.Controls.CONTROLS_TYPE_MOUSE) { + componentType = GameLib.Component.COMPONENT_CONTROLS_MOUSE + } + + GameLib.Component.call( + this, + componentType, + linkedObjects, + delayed + ); +}; + +GameLib.D3.Controls.prototype = Object.create(GameLib.D3.API.Controls.prototype); +GameLib.D3.Controls.prototype.constructor = GameLib.D3.Controls; + +/** + * Controls Type + * @type {number} + */ +GameLib.D3.Controls.CONTROLS_TYPE_EDITOR = 0x0; +GameLib.D3.Controls.CONTROLS_TYPE_TOUCH = 0x1; +GameLib.D3.Controls.CONTROLS_TYPE_KEYBOARD = 0x2; +GameLib.D3.Controls.CONTROLS_TYPE_MOUSE = 0x3; + +/** + * Creates a mesh instance or updates it + */ +GameLib.D3.Controls.prototype.createInstance = function() { + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the mesh instance + */ +GameLib.D3.Controls.prototype.updateInstance = function() { + console.log('default controls update instance'); +}; + +/** + * Converts a GameLib.D3.Controls to a GameLib.D3.API.Controls + * @returns {GameLib.D3.API.Controls} + */ +GameLib.D3.Controls.prototype.toApiObject = function() { + + var apiControls = new GameLib.D3.API.Controls( + this.id, + this.controlsType, + this.name, + GameLib.Utils.IdOrNull(this.domElement), + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiControls; +}; + +/** + * Converts a data object to a GameLib.D3.Controls + * @param graphics GameLib.D3.Graphics + * @param objectControls {Object} + * @constructor + */ +GameLib.D3.Controls.FromObject = function(graphics, objectControls) { + + var apiControls = GameLib.D3.API.Controls.FromObject(objectControls); + + return new GameLib.D3.Controls( + graphics, + apiControls + ); + +}; + +/** + * Controls Superset - The apiControls properties get moved into the Controls object itself, and then the instance is created + * @param graphics GameLib.D3.Graphics + * @param apiControls GameLib.D3.API.Controls + * @param raycaster + * @param camera + * @constructor + */ +GameLib.D3.Controls.Editor = function ( + graphics, + apiControls, + raycaster, + camera +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(raycaster)) { + raycaster = null; + } + this.raycaster = raycaster; + + if (GameLib.Utils.UndefinedOrNull(camera)) { + camera = null; + } + this.camera = camera; + + if (this.raycaster instanceof GameLib.D3.API.Raycaster) { + this.raycaster = new GameLib.D3.Raycaster( + this.graphics, + this.raycaster + ); + } + + if (this.camera instanceof GameLib.D3.API.Camera) { + this.camera = new GameLib.D3.Camera( + this.graphics, + this.camera + ) + } + + GameLib.D3.Controls.call( + this, + this.graphics, + apiControls + ); +}; + +/** + * Inheritance + * @type {GameLib.D3.Controls} + */ +GameLib.D3.Controls.Editor.prototype = Object.create(GameLib.D3.Controls.prototype); +GameLib.D3.Controls.Editor.prototype.constructor = GameLib.D3.Controls.Editor; + +/** + * Create Instance + * @returns {THREE.EditorControls} + */ +GameLib.D3.Controls.Editor.prototype.createInstance = function() { + + if (!this.camera || !this.camera.instance) { + throw new Error('No camera at time of instance'); + } + + if (!this.domElement || !this.domElement.instance) { + throw new Error('No dom element at time of instance'); + } + + this.instance = new THREE.EditorControls( + this.camera.instance, + this.domElement.instance + ); + + GameLib.D3.Controls.prototype.createInstance.call(this); +}; + +/** + * Update Instance + */ +GameLib.D3.Controls.Editor.prototype.updateInstance = function() { + + console.warn('an update instance was called on editor controls - which, if not called from within a running system at the right time will affect the order of input event handling and cause system instability'); + + GameLib.D3.Controls.prototype.updateInstance.call(this); +}; + +/** + * Converts a GameLib.D3.Controls.Editor to a GameLib.D3.API.Mesh + * @returns {GameLib.D3.API.Controls} + */ +GameLib.D3.Controls.Editor.prototype.toApiObject = function() { + + var apiControls = GameLib.D3.Controls.prototype.toApiObject.call(this); + + apiControls.raycaster = GameLib.Utils.IdOrNull(this.raycaster); + apiControls.camera = GameLib.Utils.IdOrNull(this.camera); + + return apiControls; +}; + +/** + * Construct an Editor Controls object from data + * @param graphics + * @param objectControls + * @returns {GameLib.D3.Controls.Editor} + * @constructor + */ +GameLib.D3.Controls.Editor.FromObject = function(graphics, objectControls) { + + var apiControls = GameLib.D3.API.Controls.FromObject(objectControls); + + return new GameLib.D3.Controls.Editor( + graphics, + apiControls, + objectControls.raycaster, + objectControls.camera + ); + +}; +/** + * Keyboard Controls + * @param graphics GameLib.D3.Graphics + * @param apiControls GameLib.D3.API.Controls + * @constructor + */ +GameLib.D3.Controls.Keyboard = function ( + graphics, + apiControls +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + GameLib.D3.Controls.call( + this, + this.graphics, + apiControls + ); +}; + +/** + * Inheritance + * @type {GameLib.D3.Controls} + */ +GameLib.D3.Controls.Keyboard.prototype = Object.create(GameLib.D3.Controls.prototype); +GameLib.D3.Controls.Keyboard.prototype.constructor = GameLib.D3.Controls.Keyboard; + +/** + * Create Instance + * @returns + */ +GameLib.D3.Controls.Keyboard.prototype.createInstance = function() { + /** + * Set instance to true to indicate no dependencies to other components + */ + this.instance = true; + GameLib.D3.Controls.prototype.createInstance.call(this); +}; + +/** + * Update Instance + */ +GameLib.D3.Controls.Keyboard.prototype.updateInstance = function() { + GameLib.D3.Controls.prototype.updateInstance.call(this); +}; + +/** + * Converts a GameLib.D3.Controls.Keyboard to a GameLib.D3.API.Controls + * @returns {GameLib.D3.API.Controls} + */ +GameLib.D3.Controls.Keyboard.prototype.toApiObject = function() { + var apiControls = GameLib.D3.Controls.prototype.toApiObject.call(this); + /** + * add other properties here as this component develops... + */ + return apiControls; +}; + +/** + * Construct an Keyboard Controls object from data + * @param graphics + * @param objectControls + * @returns {GameLib.D3.Controls.Keyboard} + * @constructor + */ +GameLib.D3.Controls.Keyboard.FromObject = function(graphics, objectControls) { + + var apiControls = GameLib.D3.API.Controls.FromObject(objectControls); + + return new GameLib.D3.Controls.Keyboard( + graphics, + apiControls + ); + +}; +/** + * Mouse Controls + * @param graphics GameLib.D3.Graphics + * @param apiControls GameLib.D3.API.Controls + * @constructor + */ +GameLib.D3.Controls.Mouse = function ( + graphics, + apiControls +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + GameLib.D3.Controls.call( + this, + this.graphics, + apiControls + ); +}; + +/** + * Inheritance + * @type {GameLib.D3.Controls} + */ +GameLib.D3.Controls.Mouse.prototype = Object.create(GameLib.D3.Controls.prototype); +GameLib.D3.Controls.Mouse.prototype.constructor = GameLib.D3.Controls.Mouse; + +/** + * Create Instance + * @returns + */ +GameLib.D3.Controls.Mouse.prototype.createInstance = function() { + /** + * Set instance to true to indicate no dependencies to other components + */ + this.instance = true; + GameLib.D3.Controls.prototype.createInstance.call(this); +}; + +/** + * Update Instance + */ +GameLib.D3.Controls.Mouse.prototype.updateInstance = function() { + GameLib.D3.Controls.prototype.updateInstance.call(this); +}; + +/** + * Converts a GameLib.D3.Controls.Mouse to a GameLib.D3.API.Controls + * @returns {GameLib.D3.API.Controls} + */ +GameLib.D3.Controls.Mouse.prototype.toApiObject = function() { + var apiControls = GameLib.D3.Controls.prototype.toApiObject.call(this); + /** + * add other properties here as this component develops... + */ + return apiControls; +}; + +/** + * Construct an Mouse Controls object from data + * @param graphics + * @param objectControls + * @returns {GameLib.D3.Controls.Mouse} + * @constructor + */ +GameLib.D3.Controls.Mouse.FromObject = function(graphics, objectControls) { + + var apiControls = GameLib.D3.API.Controls.FromObject(objectControls); + + return new GameLib.D3.Controls.Mouse( + graphics, + apiControls + ); + +}; +/** + * Touch Controls + * @param graphics GameLib.D3.Graphics + * @param apiControls GameLib.D3.API.Controls + * @param sensitivity + * @constructor + */ +GameLib.D3.Controls.Touch = function ( + graphics, + apiControls, + sensitivity +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(sensitivity)) { + sensitivity = 5; + } + this.sensitivity = sensitivity; + + GameLib.D3.Controls.call( + this, + this.graphics, + apiControls + ); +}; + +/** + * Inheritance + * @type {GameLib.D3.Controls} + */ +GameLib.D3.Controls.Touch.prototype = Object.create(GameLib.D3.Controls.prototype); +GameLib.D3.Controls.Touch.prototype.constructor = GameLib.D3.Controls.Touch; + +/** + * Create Instance + * @returns + */ +GameLib.D3.Controls.Touch.prototype.createInstance = function() { + /** + * Set instance to true to indicate no dependencies to other components + */ + this.instance = true; + GameLib.D3.Controls.prototype.createInstance.call(this); +}; + +/** + * Update Instance + */ +GameLib.D3.Controls.Touch.prototype.updateInstance = function() { + GameLib.D3.Controls.prototype.updateInstance.call(this); +}; + +/** + * Converts a GameLib.D3.Controls.Touch to a GameLib.D3.API.Controls + * @returns {GameLib.D3.API.Controls} + */ +GameLib.D3.Controls.Touch.prototype.toApiObject = function() { + + var apiControls = GameLib.D3.Controls.prototype.toApiObject.call(this); + + apiControls.sensitivity = this.sensitivity; + + /** + * add other properties here as this component develops... + */ + return apiControls; +}; + +/** + * Construct an Touch Controls object from data + * @param graphics + * @param objectControls + * @returns {GameLib.D3.Controls.Touch} + * @constructor + */ +GameLib.D3.Controls.Touch.FromObject = function(graphics, objectControls) { + + var apiControls = GameLib.D3.API.Controls.FromObject(objectControls); + + return new GameLib.D3.Controls.Touch( + graphics, + apiControls, + objectControls.sensitivity + ); + +}; +/** + * Creates a CustomCode object + * @param apiCustomCode GameLib.D3.API.CustomCode + * @constructor + */ +GameLib.D3.CustomCode = function( + apiCustomCode +) { + + if (GameLib.Utils.UndefinedOrNull(apiCustomCode)) { + apiCustomCode = {}; + } + + if (apiCustomCode instanceof GameLib.D3.CustomCode) { + return apiCustomCode; + } + + GameLib.D3.API.CustomCode.call( + this, + apiCustomCode.id, + apiCustomCode.name, + apiCustomCode.eventId, + apiCustomCode.code, + apiCustomCode.parentEntity + ); + + this.editor = null; + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_CUSTOM_CODE + ); +}; + +GameLib.D3.CustomCode.prototype = Object.create(GameLib.D3.API.CustomCode.prototype); +GameLib.D3.CustomCode.prototype.constructor = GameLib.D3.CustomCode; + +GameLib.D3.CustomCode.prototype.createInstance = function() { + + try { + this.instance = new Function('data', this.code).bind(this); + } catch (error) { + /** + * Set the instance to true here to indicate that even though the compilation failed, the instance will be fine and + * this component loaded fine. + */ + this.instance = new Function('data', "console.log('compilation failed for : " + this.name + "');").bind(this); + } + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.CustomCode.prototype.updateInstance = function() { + + try { + this.instance = new Function('data', this.code).bind(this); + this.publish( + GameLib.Event.COMPILE_SUCCESS, + { + component : this + } + ) + } catch (error) { + this.instance = new Function('data', "console.log('compilation update failed for : " + this.name + "');").bind(this); + this.publish( + GameLib.Event.COMPILE_FAILED, + { + component : this + } + ) + } + +}; + +/** + * Converts a GameLib.D3.CustomCode to a new GameLib.D3.API.CustomCode + * @returns {GameLib.D3.API.CustomCode} + */ +GameLib.D3.CustomCode.prototype.toApiObject = function() { + + return new GameLib.D3.API.CustomCode( + this.id, + this.name, + this.eventId, + this.code, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Converts from an Object CustomCode to a GameLib.D3.CustomCode + * @param objectCustomCode Object + * @returns {GameLib.D3.CustomCode} + * @constructor + */ +GameLib.D3.CustomCode.FromObject = function(objectCustomCode) { + var apiCustomCode = GameLib.D3.API.CustomCode.FromObject(objectCustomCode); + return new GameLib.D3.CustomCode( + apiCustomCode + ); +}; + +GameLib.D3.CustomCode.prototype.launchEditor = function(){ + + GameLib.Event.Emit( + GameLib.Event.GET_CODER_IMPLEMENTATION, + null, + function(coder) { + this.coder = coder; + this.coder.isNotCodeMirrorThrow(); + }.bind(this) + ); + + this.editor = this.coder.instance( + document.body, + { + value : this.code, + mode : 'javascript', + lineNumbers : true, + scrollbarStyle : 'overlay', + indentWithTabs: true, + indentUnit : 4 + } + ); + + this.editor.on('change', function(){ + + this.code = this.editor.getValue(); + + this.updateInstance(); + + }.bind(this)) +}; + +GameLib.D3.CustomCode.prototype.closeEditor = function(){ + var dom = this.editor.getWrapperElement(); + dom.parentElement.removeChild(dom); +}; +/** + * Face + * @constructor + * @param implementation + * @param apiFace + */ +GameLib.D3.Face = function Face( + implementation, + apiFace +) { + + this.implementation = implementation; + if (implementation instanceof GameLib.D3.Graphics) { + this.implementation.isNotThreeThrow(); + } else if (implementation instanceof GameLib.D3.Physics) { + this.implementation.isNotCannonThrow(); + } else { + throw new Error('Unhandled implementation : ' + implementation); + } + + if (GameLib.Utils.UndefinedOrNull(apiFace)) { + apiFace = {}; + } + + if (apiFace instanceof GameLib.D3.Face) { + return apiFace; + } + + GameLib.D3.API.Face.call( + this, + apiFace.id, + apiFace.name, + apiFace.v0index, + apiFace.v1index, + apiFace.v2index, + apiFace.materialIndex, + apiFace.uvs, + apiFace.color, + apiFace.vertexColors, + apiFace.vertexNormals, + apiFace.normal + ); + + if (this.implementation instanceof GameLib.D3.Graphics) { + /** + * physics faces have no color... a little sad right? + */ + this.color = new GameLib.Color( + this.implementation, + this.color, + this + ); + + this.vertexColors = this.vertexColors.map(function(vertexColor){ + if (vertexColor instanceof GameLib.Color) { + return vertexColor; + } + + if (vertexColor instanceof GameLib.API.Color) { + return new GameLib.Color( + this.implementation, + vertexColor, + this + ) + } + + console.warn('unknown vertex color type', vertexColor); + }.bind(this)); + + } + + this.vertexNormals = this.vertexNormals.map(function(vertexNormal){ + if (vertexNormal instanceof GameLib.Vector3) { + return vertexNormal; + } + + if (vertexNormal instanceof GameLib.API.Vector3) { + return new GameLib.Vector3( + this.implementation, + vertexNormal, + this + ) + } + + console.warn('unknown vertex normal type', vertexNormal); + }.bind(this)); + + this.uvs = this.uvs.reduce( + + function(result, uvArray, index) { + + result[index] = uvArray.reduce( + function(uvResult, uv) { + + if (uv instanceof GameLib.API.Vector2) { + uvResult.push( + new GameLib.Vector2( + this.implementation, + uv, + this + ) + ); + } else { + console.warn('unknown uv type'); + } + + return uvResult; + }.bind(this), + [] + ); + + return result; + + + }.bind(this), + [] + ); + + this.normal = new GameLib.Vector3( + this.implementation, + this.normal, + this + ); + +}; + +GameLib.D3.Face.prototype = Object.create(GameLib.D3.API.Face.prototype); +GameLib.D3.Face.prototype.constructor = GameLib.D3.Face; + +GameLib.D3.Face.prototype.createInstance = function() { + +}; + +GameLib.D3.Face.prototype.updateInstance = function() { + +}; + +GameLib.D3.Face.prototype.toApiObject = function() { + + return new GameLib.D3.API.Face( + this.id, + this.name, + this.v0index, + this.v1index, + this.v2index, + this.materialIndex, + this.uvs.reduce( + function(result, uvArray, index) { + + result[index] = uvArray.reduce( + function(uvResult, uv) { + + if (uv instanceof GameLib.Vector2) { + uvResult.push(uv.toApiObject()); + } else { + console.warn('unknown uv type - cannot commit to API'); + } + + return uvResult; + }.bind(this), + [] + ); + + return result; + + }.bind(this), + [] + ), + this.color.toApiObject(), + this.vertexColors.map(function(vertexColor){ + return vertexColor.toApiObject(); + }), + this.vertexNormals.map(function(vertexNormal){ + return vertexNormal.toApiObject(); + }), + this.normal.toApiObject() + ); +}; + +/** + * @param implementation + * @param objectFace + * @returns {GameLib.D3.Face} + * @constructor + */ +GameLib.D3.Face.FromObject = function(implementation, objectFace) { + return new GameLib.D3.Face( + implementation, + GameLib.D3.API.Face.FromObject(objectFace) + ); +}; + + +/** + * Fog Superset - The apiFog properties get moved into the Fog object itself, and then the instance is + * created + * @param graphics + * @param apiFog GameLib.D3.API.Fog + * @constructor + */ +GameLib.D3.Fog = function ( + graphics, + apiFog +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiFog)) { + apiFog = {}; + } + + if (apiFog instanceof GameLib.D3.Fog) { + return apiFog; + } + + GameLib.D3.API.Fog.call( + this, + apiFog.id, + apiFog.name, + apiFog.exponential, + apiFog.color, + apiFog.near, + apiFog.far, + apiFog.density, + apiFog.parentEntity + ); + + this.color = new GameLib.Color( + this.graphics, + this.color, + this + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_FOG + ); +}; + +GameLib.D3.Fog.prototype = Object.create(GameLib.D3.API.Fog.prototype); +GameLib.D3.Fog.prototype.constructor = GameLib.D3.Fog; + +/** + * Creates an instance scene + * @returns {THREE.Fog} + */ +GameLib.D3.Fog.prototype.createInstance = function() { + + if (this.exponential) { + + this.instance = new THREE.FogExp2( + this.color.instance, + this.density + ); + + } else { + + this.instance = new THREE.Fog( + this.color.instance, + this.near, + this.far + ); + + } + + this.instance.name = this.name; + + GameLib.Component.prototype.createInstance.call(this); + +}; + +GameLib.D3.Fog.prototype.updateInstance = function(property) { + + if (property === 'exponential') { + if ( + this.exponential && + !(this.instance instanceof THREE.FogExp2) + ) { + this.createInstance(); + return; + } + + if ( + !this.exponential && + !(this.instance instanceof THREE.Fog) + ) { + this.createInstance(); + return; + } + } + + if (property === 'color') { + this.color.instance.setRGB( + this.color.r, + this.color.g, + this.color.b + ); + this.instance.color = this.color.instance; + } + + if (property === 'near' || property === 'far') { + if (this.instance instanceof THREE.Fog) { + this.instance.near = this.near; + this.instance.far = this.far; + } + } + + if (property === 'density') { + if (this.instance instanceof THREE.FogExp2) { + this.instance.density = this.density; + } + } + +}; + +/** + * Converts a GameLib.D3.Fog to a GameLib.D3.API.Fog + * @returns {GameLib.D3.API.Fog} + */ +GameLib.D3.Fog.prototype.toApiObject = function() { + + return new GameLib.D3.API.Fog( + this.id, + this.name, + this.exponential, + this.color.toApiObject(), + this.near, + this.far, + this.density, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Converts a scene Object to a GameLib.D3.Fog object + * @param graphics GameLib.D3.Graphics + * @param objectFog Object + * @returns {GameLib.D3.Fog} + * @constructor + */ +GameLib.D3.Fog.FromObject = function( + graphics, + objectFog +) { + var apiFog = GameLib.D3.API.Fog.FromObject(objectFog); + + return new GameLib.D3.Fog( + graphics, + apiFog + ); +}; + +/** + * Font Superset - The apiFont properties get moved into the Font object itself, and then the instance is created + * @param graphics GameLib.D3.Graphics + * @param apiFont GameLib.D3.API.Font + * @constructor + */ +GameLib.D3.Font = function( + graphics, + apiFont +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiFont)) { + apiFont = {}; + } + + if (apiFont instanceof GameLib.D3.Font) { + return apiFont; + } + + GameLib.D3.API.Font.call( + this, + apiFont.id, + apiFont.name, + apiFont.url, + apiFont.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_FONT + ); +}; + +GameLib.D3.Font.prototype = Object.create(GameLib.D3.API.Font.prototype); +GameLib.D3.Font.prototype.constructor = GameLib.D3.Font; + +/** + * Creates a light instance + * @returns {*} + */ +GameLib.D3.Font.prototype.createInstance = function() { + + GameLib.Event.Emit( + GameLib.Event.LOAD_FONT, + { + font : this + } + ); + + this.instance = null; + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Font.prototype.updateInstance = function() { + + GameLib.Event.Emit( + GameLib.Event.LOAD_FONT, + { + font : this + } + ); +}; + +/** + * Converts a GameLib.D3.Font to a GameLib.D3.API.Font + * @returns {GameLib.D3.API.Font} + */ +GameLib.D3.Font.prototype.toApiObject = function() { + return new GameLib.D3.API.Font( + this.id, + this.name, + this.url, + GameLib.Utils.IdOrNull(this.parentEntity) + ); +}; + +/** + * Returns a new GameLib.D3.Font from a GameLib.D3.API.Font + * @param graphics GameLib.D3.Graphics + * @param objectFont GameLib.D3.API.Font + * @returns {GameLib.D3.Font} + */ +GameLib.D3.Font.FromObject = function(graphics, objectFont) { + + return new GameLib.D3.Font( + graphics, + GameLib.D3.API.Font.FromObject(objectFont) + ); + +}; +/** + * FrictionContactMaterial Runtime + * @param physics GameLib.D3.Graphics + * @param apiFrictionContactMaterial GameLib.D3.API.FrictionContactMaterial + * @constructor + */ +GameLib.D3.FrictionContactMaterial = function ( + physics, + apiFrictionContactMaterial +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiFrictionContactMaterial)) { + apiFrictionContactMaterial = {}; + } + + if (apiFrictionContactMaterial instanceof GameLib.D3.FrictionContactMaterial) { + return apiFrictionContactMaterial; + } + + GameLib.D3.API.FrictionContactMaterial.call( + this, + apiFrictionContactMaterial.id, + apiFrictionContactMaterial.name, + apiFrictionContactMaterial.materials, + apiFrictionContactMaterial.friction, + apiFrictionContactMaterial.restitution, + apiFrictionContactMaterial.contactEquationStiffness, + apiFrictionContactMaterial.contactEquationRelaxation, + apiFrictionContactMaterial.frictionEquationStiffness, + apiFrictionContactMaterial.frictionEquationRelaxation, + apiFrictionContactMaterial.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_FRICTION_CONTACT_MATERIAL, + { + materials : [GameLib.D3.FrictionMaterial] + } + ); +}; + +GameLib.D3.FrictionContactMaterial.prototype = Object.create(GameLib.D3.API.FrictionContactMaterial.prototype); +GameLib.D3.FrictionContactMaterial.prototype.constructor = GameLib.D3.FrictionContactMaterial; + +/** + * + * @returns {*} + */ +GameLib.D3.FrictionContactMaterial.prototype.createInstance = function() { + + this.instance = new CANNON.ContactMaterial( + null, + null, + { + friction: this.friction, + restitution: this.restitution, + contactEquationStiffness: this.contactEquationStiffness + } + ); + + this.instance.materials = this.materials.map( + function(material){ + return material.instance; + } + ); + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * + */ +GameLib.D3.FrictionContactMaterial.prototype.updateInstance = function() { + + this.instance.materials = this.materials.map( + function(material) { + return material.instance; + } + ); + + this.instance.friction = this.friction; + this.instance.restitution = this.restitution; + this.instance.contactEquationStiffness = this.contactEquationStiffness; + this.instance.contactEquationRelaxation = this.contactEquationRelaxation; + this.instance.frictionEquationStiffness = this.frictionEquationStiffness; + this.instance.frictionEquationRelaxation = this.frictionEquationRelaxation; + +}; + +/** + * GameLib.D3.FrictionContactMaterial to GameLib.D3.API.FrictionContactMaterial + * @returns {GameLib.D3.API.FrictionContactMaterial} + */ +GameLib.D3.FrictionContactMaterial.prototype.toApiObject = function() { + + var apiFrictionContactMaterial = new GameLib.D3.API.FrictionContactMaterial( + this.id, + this.name, + this.materials.map( + function(material) { + return GameLib.Utils.IdOrNull(material); + } + ), + this.friction, + this.restitution, + this.contactEquationStiffness, + this.contactEquationRelaxation, + this.frictionEquationStiffness, + this.frictionEquationRelaxation, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + return apiFrictionContactMaterial; +}; + +/** + * GameLib.D3.FrictionContactMaterial from Object FrictionContactMaterial + * @param physics + * @param objectComponent + * @returns {GameLib.D3.FrictionContactMaterial} + * @constructor + */ +GameLib.D3.FrictionContactMaterial.FromObject = function(physics, objectComponent) { + + var apiFrictionContactMaterial = GameLib.D3.API.FrictionContactMaterial.FromObject(objectComponent); + + return new GameLib.D3.FrictionContactMaterial( + physics, + apiFrictionContactMaterial + ); +}; + +/** + * FrictionMaterial Runtime + * @param physics GameLib.D3.Graphics + * @param apiFrictionMaterial GameLib.D3.API.FrictionMaterial + * @constructor + */ +GameLib.D3.FrictionMaterial = function ( + physics, + apiFrictionMaterial +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiFrictionMaterial)) { + apiFrictionMaterial = {}; + } + + if (apiFrictionMaterial instanceof GameLib.D3.FrictionMaterial) { + return apiFrictionMaterial; + } + + GameLib.D3.API.FrictionMaterial.call( + this, + apiFrictionMaterial.id, + apiFrictionMaterial.name, + apiFrictionMaterial.friction, + apiFrictionMaterial.restitution, + apiFrictionMaterial.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_FRICTION_MATERIAL + ); +}; + +GameLib.D3.FrictionMaterial.prototype = Object.create(GameLib.D3.API.FrictionMaterial.prototype); +GameLib.D3.FrictionMaterial.prototype.constructor = GameLib.D3.FrictionMaterial; + +/** + * create instance + */ +GameLib.D3.FrictionMaterial.prototype.createInstance = function() { + + this.instance = new CANNON.Material( + this.name + ); + + this.instance.friction = this.friction; + this.instance.restitution = this.restitution; + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * + */ +GameLib.D3.FrictionMaterial.prototype.updateInstance = function() { + this.instance.friction = this.friction; + this.instance.restitution = this.restitution; + this.instance.name = this.name; +}; + +/** + * GameLib.D3.FrictionMaterial to GameLib.D3.API.FrictionMaterial + * @returns {GameLib.D3.API.FrictionMaterial} + */ +GameLib.D3.FrictionMaterial.prototype.toApiObject = function() { + + var apiFrictionMaterial = new GameLib.D3.API.FrictionMaterial( + this.id, + this.name, + this.friction, + this.restitution, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiFrictionMaterial; +}; + +/** + * GameLib.D3.FrictionMaterial from Object FrictionMaterial + * @param physics + * @param objectComponent + * @returns {GameLib.D3.FrictionMaterial} + * @constructor + */ +GameLib.D3.FrictionMaterial.FromObject = function(physics, objectComponent) { + + var apiFrictionMaterial = GameLib.D3.API.FrictionMaterial.FromObject(objectComponent); + + return new GameLib.D3.FrictionMaterial( + physics, + apiFrictionMaterial + ); +}; + +/** + * Graphics + * @param id + * @param name + * @param graphicsType + * @constructor + */ +GameLib.D3.Graphics = function Graphics( + id, + name, + graphicsType +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Graphics (' + id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(graphicsType)) { + graphicsType = GameLib.D3.Graphics.GRAPHICS_TYPE_THREE; + } + this.graphicsType = graphicsType; + + this.createInstance(); +}; + +/** + * GameLib.D3.Graphics Types + * @type {number} + */ +GameLib.D3.Graphics.GRAPHICS_TYPE_THREE = 0x1; + +/** + * @returns {THREE.Graphics} + */ +GameLib.D3.Graphics.prototype.createInstance = function() { + this.instance = THREE; +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Graphics.prototype.updateInstance = function() { +}; + +/** + * True if THREE physics + * @returns {boolean} + */ +GameLib.D3.Graphics.prototype.isThree = function() { + return (this.graphicsType === GameLib.D3.Graphics.GRAPHICS_TYPE_THREE) +}; + +/** + * Logs a warning and throws an error if not cannon + */ +GameLib.D3.Graphics.prototype.isNotThreeThrow = function() { + if (this.graphicsType !== GameLib.D3.Graphics.GRAPHICS_TYPE_THREE) { + console.warn('Only THREE supported for this function'); + throw new Error('Only THREE supported for this function'); + } +}; + +/** + * Helpers for displaying outlines or making 'invisible' scene objects visible + * @param graphics GameLib.D3.Graphics + * @param id + * @param name + * @param object + * @param helperType + * @param parentEntity + * @constructor + */ +GameLib.D3.Helper = function( + graphics, + id, + name, + object, + helperType, + parentEntity +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Helper (' + id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(object)) { + console.warn('Cannot create a helper for an Object which does not exist'); + throw new Error('Cannot create a helper for an Object which does not exist'); + } + this.object = object; + + if (GameLib.Utils.UndefinedOrNull(helperType)) { + + helperType = GameLib.D3.Helper.HELPER_TYPE_NONE; + + if ( + object instanceof GameLib.D3.Mesh && + object.meshType !== GameLib.D3.Mesh.MESH_TYPE_CURVE + ) { + helperType = GameLib.D3.Helper.HELPER_TYPE_EDGES; + } + + if (object instanceof GameLib.D3.Light) { + if (object.lightType === GameLib.D3.Light.LIGHT_TYPE_DIRECTIONAL) { + helperType = GameLib.D3.Helper.HELPER_TYPE_DIRECTIONAL_LIGHT; + } + + if (object.lightType === GameLib.D3.Light.LIGHT_TYPE_POINT) { + helperType = GameLib.D3.Helper.HELPER_TYPE_POINT_LIGHT; + } + + if (object.lightType === GameLib.D3.Light.LIGHT_TYPE_SPOT) { + helperType = GameLib.D3.Helper.HELPER_TYPE_SPOT_LIGHT; + } + } + + if (object instanceof GameLib.D3.Skeleton) { + helperType = GameLib.D3.Helper.HELPER_TYPE_SKELETON; + } + } + this.helperType = helperType; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + + this.createInstance(); + /** + * A helper as a component - does this make sense at all? + */ + // GameLib.Component.call( + // this, + // GameLib.Component.COMPONENT_HELPER + // ); +}; + +GameLib.D3.Helper.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.Helper.prototype.constructor = GameLib.D3.Helper; + +/** + * Helper types + * @type {string} + */ +GameLib.D3.Helper.HELPER_TYPE_NONE = 0x0; +GameLib.D3.Helper.HELPER_TYPE_EDGES = 0x1; +GameLib.D3.Helper.HELPER_TYPE_DIRECTIONAL_LIGHT = 0x2; +GameLib.D3.Helper.HELPER_TYPE_SPOT_LIGHT = 0x3; +GameLib.D3.Helper.HELPER_TYPE_POINT_LIGHT = 0x4; +GameLib.D3.Helper.HELPER_TYPE_WIREFRAME = 0x5; +GameLib.D3.Helper.HELPER_TYPE_SKELETON = 0x6; + +/** + * Creates a helper instance + */ +GameLib.D3.Helper.prototype.createInstance = function() { + + if (this.helperType === GameLib.D3.Helper.HELPER_TYPE_EDGES) { + this.instance = new THREE.LineSegments( + new THREE.EdgesGeometry( + this.object.instance.geometry + ), + new THREE.LineBasicMaterial( + { + color:0x00ff00, + linewidth:2 + } + ) + ) + } + + if (this.helperType === GameLib.D3.Helper.HELPER_TYPE_DIRECTIONAL_LIGHT) { + this.instance = new THREE.DirectionalLightHelper(this.object.instance); + } + + if (this.helperType === GameLib.D3.Helper.HELPER_TYPE_POINT_LIGHT) { + this.instance = new THREE.PointLightHelper(this.object.instance, 1); + } + + if (this.helperType === GameLib.D3.Helper.HELPER_TYPE_SPOT_LIGHT) { + this.instance = new THREE.SpotLightHelper(this.object.instance); + } + + if (this.helperType === GameLib.D3.Helper.HELPER_TYPE_WIREFRAME) { + this.instance = new THREE.WireframeGeometry(this.object.instance, 0x00FF00); + } + + if (this.helperType === GameLib.D3.Helper.HELPER_TYPE_SKELETON) { + this.instance = new THREE.SkeletonHelper(this.object.instance); + } + +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Helper.prototype.updateInstance = function() { + this.instance.position.copy(this.object.instance.position); + + if (this.object.instance.parentMesh && this.object.instance.parentMesh.instance) { + this.instance.position.add(this.object.instance.parentMesh.instance.position); + } + + this.instance.scale.copy(this.object.instance.scale); + this.instance.quaternion.copy(this.object.instance.quaternion); +}; + +/** + * Image + * @constructor + * @param graphics + * @param apiImage + */ +GameLib.D3.Image = function( + graphics, + apiImage +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiImage)) { + apiImage = {}; + } + + if (apiImage instanceof GameLib.D3.Image) { + return apiImage; + } + + GameLib.D3.API.Image.call( + this, + apiImage.id, + apiImage.name, + apiImage.fileName, + apiImage.extension, + apiImage.path, + apiImage.contentType, + apiImage.size, + apiImage.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_IMAGE, + null, + true + ); + + GameLib.Event.Emit( + GameLib.Event.LOAD_IMAGE, + { + image : this + } + ); +}; + +GameLib.D3.Image.prototype = Object.create(GameLib.D3.API.Image.prototype); +GameLib.D3.Image.prototype.constructor = GameLib.D3.Image; + +/** + * Creates an image instance + * @returns {*} + */ +GameLib.D3.Image.prototype.createInstance = function() { + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Image.prototype.updateInstance = function() { + this.createInstance(); +}; + +/** + * + * @returns {GameLib.D3.API.Image} + */ +GameLib.D3.Image.prototype.toApiObject = function() { + + var apiImage = new GameLib.D3.API.Image( + this.id, + this.name, + this.fileName, + this.extension, + this.path, + this.contentType, + this.size, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiImage; +}; + +/** + * @param graphics + * @param objectImage + * @returns {GameLib.D3.Image} + * @constructor + */ +GameLib.D3.Image.FromObject = function(graphics, objectImage) { + return new GameLib.D3.Image( + graphics, + GameLib.D3.API.Image.FromObject(objectImage) + ); +}; + +/** + * Light Superset - The apiLight properties get moved into the Light object itself, and then the instance is created + * @param graphics GameLib.D3.Graphics + * @param apiLight GameLib.D3.API.Light + * @constructor + */ +GameLib.D3.Light = function( + graphics, + apiLight +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiLight)) { + apiLight = {}; + } + + if (apiLight instanceof GameLib.D3.Light) { + return apiLight; + } + + GameLib.D3.API.Light.call( + this, + apiLight.id, + apiLight.lightType, + apiLight.name, + apiLight.color, + apiLight.intensity, + apiLight.position, + apiLight.targetPosition, + apiLight.quaternion, + apiLight.rotation, + apiLight.scale, + apiLight.distance, + apiLight.decay, + apiLight.power, + apiLight.angle, + apiLight.penumbra, + apiLight.parentScene, + apiLight.parentEntity + ); + + this.color = new GameLib.Color( + graphics, + this.color, + this + ); + + this.position = new GameLib.Vector3( + graphics, + this.position, + this + ); + + this.targetPosition = new GameLib.Vector3( + graphics, + this.targetPosition, + this + ); + + this.scale = new GameLib.Vector3( + graphics, + this.scale, + this + ); + + this.quaternion = new GameLib.Quaternion( + graphics, + this.quaternion, + this + ); + + this.rotation = new GameLib.Vector3( + graphics, + this.rotation, + this + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_LIGHT, + { + 'parentScene' : GameLib.D3.Scene + } + ); +}; + +GameLib.D3.Light.prototype = Object.create(GameLib.D3.API.Light.prototype); +GameLib.D3.Light.prototype.constructor = GameLib.D3.Light; + +/** + * Light Types + * @type {number} + */ +GameLib.D3.Light.LIGHT_TYPE_AMBIENT = 0x1; +GameLib.D3.Light.LIGHT_TYPE_DIRECTIONAL = 0x2; +GameLib.D3.Light.LIGHT_TYPE_POINT = 0x3; +GameLib.D3.Light.LIGHT_TYPE_SPOT = 0x4; + +/** + * Creates a light instance + * @returns {*} + */ +GameLib.D3.Light.prototype.createInstance = function() { + + if ( + this.lightType === GameLib.D3.Light.LIGHT_TYPE_AMBIENT || + this.lightType === 'AmbientLight' + ) { + this.instance = new THREE.AmbientLight( + this.color.instance, + this.intensity + ); + } else if ( + this.lightType === GameLib.D3.Light.LIGHT_TYPE_DIRECTIONAL || + this.lightType === 'DirectionalLight' + ) { + this.instance = new THREE.DirectionalLight( + this.color.instance, + this.intensity + ); + } else if ( + this.lightType === GameLib.D3.Light.LIGHT_TYPE_POINT || + this.lightType === 'PointLight' + ) { + this.instance = new THREE.PointLight( + this.color.instance, + this.intensity + ); + this.instance.distance = this.distance; + this.instance.decay = this.decay; + } else if ( + this.lightType === GameLib.D3.Light.LIGHT_TYPE_SPOT || + this.lightType === 'SpotLight' + ) { + this.instance = new THREE.SpotLight( + this.color.instance, + this.intensity + ); + this.instance.distance = this.distance; + this.instance.angle = this.angle; + this.instance.penumbra = this.penumbra; + this.instance.decay = this.decay; + } else { + console.warn('unsupported light type: ' + this.lightType); + return; + } + + this.instance.name = this.name; + + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + + this.instance.scale.x = this.scale.x; + this.instance.scale.y = this.scale.y; + this.instance.scale.z = this.scale.z; + + if (this.instance.target) { + this.instance.target.position.x = this.targetPosition.x; + this.instance.target.position.y = this.targetPosition.y; + this.instance.target.position.z = this.targetPosition.z; + } + + this.instance.quaternion.x = this.quaternion.x; + this.instance.quaternion.y = this.quaternion.y; + this.instance.quaternion.z = this.quaternion.z; + this.instance.quaternion.w = this.quaternion.w; + + this.instance.intensity = this.intensity; + + this.instance.color.set(this.color.toHex()); + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Light.prototype.updateInstance = function(property) { + + if (GameLib.Utils.UndefinedOrNull(property)) { + console.warn('no property for light: ' + this.name); + } + + if (property === 'lightType') { + this.parentScene.instance.remove(this.instance); + this.createInstance(); + this.parentScene.instance.add(this.instance); + } + + if (property === 'name') { + this.instance.name = this.name; + } + + if (property === 'position') { + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + } + + if (property === 'scale') { + this.instance.scale.x = this.scale.x; + this.instance.scale.y = this.scale.y; + this.instance.scale.z = this.scale.z; + } + + if (property === 'target') { + if (this.instance.target) { + this.instance.target.position.x = this.targetPosition.x; + this.instance.target.position.y = this.targetPosition.y; + this.instance.target.position.z = this.targetPosition.z; + } + } + + if (property === 'quaternion') { + this.instance.quaternion.x = this.quaternion.x; + this.instance.quaternion.y = this.quaternion.y; + this.instance.quaternion.z = this.quaternion.z; + this.instance.quaternion.w = this.quaternion.w; + } + + if (property === 'intensity') { + this.instance.intensity = this.intensity; + } + + if (property === 'color') { + this.instance.color.set(this.color.toHex()); + } +}; + +/** + * Converts a GameLib.D3.Light to a GameLib.D3.API.Light + * @returns {GameLib.D3.API.Light} + */ +GameLib.D3.Light.prototype.toApiObject = function() { + return new GameLib.D3.API.Light( + this.id, + this.lightType, + this.name, + this.color.toApiObject(), + this.intensity, + this.position.toApiObject(), + this.targetPosition.toApiObject(), + this.quaternion.toApiObject(), + this.rotation.toApiObject(), + this.scale.toApiObject(), + this.distance, + this.decay, + this.power, + this.angle, + this.penumbra, + GameLib.Utils.IdOrNull(this.parentScene), + GameLib.Utils.IdOrNull(this.parentEntity) + ); +}; + +/** + * Returns a new GameLib.D3.Light from a GameLib.D3.API.Light + * @param graphics GameLib.D3.Graphics + * @param objectLight GameLib.D3.API.Light + * @returns {GameLib.D3.Light} + */ +GameLib.D3.Light.FromObject = function(graphics, objectLight) { + + return new GameLib.D3.Light( + graphics, + GameLib.D3.API.Light.FromObject(objectLight) + ); + +}; +/** + * Entities with LookAt component looks to targetPosition (default up is 0,1,0) + * @param graphics GameLib.D3.Graphics + * @param apiLookAt GameLib.D3.API.LookAt + * @constructor + */ +GameLib.D3.LookAt = function ( + graphics, + apiLookAt +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiLookAt)) { + apiLookAt = {}; + } + + if (apiLookAt instanceof GameLib.D3.LookAt) { + return apiLookAt; + } + + GameLib.D3.API.LookAt.call( + this, + apiLookAt.id, + apiLookAt.name, + apiLookAt.currentComponent, + apiLookAt.targetComponent, + apiLookAt.targetPositionOffset, + apiLookAt.rotationSpeed, + apiLookAt.parentEntity + ); + + this.targetPositionOffset = new GameLib.Vector3( + this.graphics, + this.targetPositionOffset, + this + ); + + this.lookAtMatrix = new GameLib.Matrix4( + this.graphics, + this.lookAtMatrix, + this + ); + + this.up = new GameLib.Vector3( + this.graphics, + this.up, + this + ); + + this.currentRotation = new GameLib.Quaternion( + this.graphics, + this.currentRotation, + this + ); + + this.targetPosition = new GameLib.Vector3( + this.graphics, + this.targetPosition, + this + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_LOOK_AT, + { + 'currentComponent' : GameLib.Component, + 'targetComponent' : GameLib.Component + } + ); +}; + +GameLib.D3.LookAt.prototype = Object.create(GameLib.D3.API.LookAt.prototype); +GameLib.D3.LookAt.prototype.constructor = GameLib.D3.LookAt; + +GameLib.D3.LookAt.prototype.createInstance = function() { + this.instance = true; + GameLib.Component.prototype.createInstance.call(this); +}; + +GameLib.D3.LookAt.prototype.updateInstance = function() { +}; + +/** + * to API object + * @returns {GameLib.D3.API.LookAt} + */ +GameLib.D3.LookAt.prototype.toApiObject = function() { + + var apiLookAt = new GameLib.D3.API.LookAt( + this.id, + this.name, + GameLib.Utils.IdOrNull(this.currentComponent), + GameLib.Utils.IdOrNull(this.targetComponent), + this.targetPositionOffset.toApiObject(), + this.rotationSpeed, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiLookAt; +}; + +GameLib.D3.LookAt.FromObject = function(graphics, objectComponent) { + + var apiLookAt = GameLib.D3.API.LookAt.FromObject(objectComponent); + + return new GameLib.D3.LookAt( + graphics, + apiLookAt + ); +}; + +/** + * Looks at using time + * @param deltaTime + */ +GameLib.D3.LookAt.prototype.update = function(deltaTime) { + + if (this.currentComponent && this.targetComponent) { + + this.targetPosition.x = this.targetComponent.position.x + this.targetPositionOffset.x; + this.targetPosition.y = this.targetComponent.position.y + this.targetPositionOffset.y; + this.targetPosition.z = this.targetComponent.position.z + this.targetPositionOffset.z; + + this.targetPosition.updateInstance(); + + // this.lookAtMatrix.lookAt( + // this.currentComponent.position, + // this.targetPosition, + // this.up + // ); + // + // this.currentRotation = new GameLib.Quaternion(this.graphics, this, new GameLib.API.Quaternion()); + // + // this.currentRotation.setFromRotationMatrix(this.lookAtMatrix); + + // var t = deltaTime * this.rotationSpeed; + // t = t * t * t * (t * (6.0 * t - 15.0) + 10.0); + + // this.currentRotation.slerp(this.currentRotation, t); + + // this.currentRotation.normalize(); + // + // this.currentComponent.quaternion.x = this.currentRotation.x; + // this.currentComponent.quaternion.y = this.currentRotation.y; + // this.currentComponent.quaternion.z = this.currentRotation.z; + // this.currentComponent.quaternion.w = this.currentRotation.w; + // + this.currentComponent.lookAt.x = this.targetPosition.x; + this.currentComponent.lookAt.y = this.targetPosition.y; + this.currentComponent.lookAt.z = this.targetPosition.z; + + this.currentComponent.lookAt.updateInstance(); + } + +}; +/** + * Material Superset - The apiMaterial properties get moved into the Material object itself, and then the instance is + * created + * @param graphics GameLib.D3.Graphics + * @param apiMaterial GameLib.D3.API.Material + * @constructor + * @returns {GameLib.D3.Material | GameLib.D3.API.Material} + */ +GameLib.D3.Material = function( + graphics, + apiMaterial +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiMaterial)) { + apiMaterial = {}; + } + + if (apiMaterial instanceof GameLib.D3.Material) { + return apiMaterial; + } + + GameLib.D3.API.Material.call( + this, + apiMaterial.id, + apiMaterial.materialType, + apiMaterial.name, + apiMaterial.opacity, + apiMaterial.side, + apiMaterial.transparent, + apiMaterial.specular, + apiMaterial.lightMapIntensity, + apiMaterial.aoMapIntensity, + apiMaterial.color, + apiMaterial.emissive, + apiMaterial.emissiveIntensity, + apiMaterial.combine, + apiMaterial.shininess, + apiMaterial.reflectivity, + apiMaterial.refractionRatio, + apiMaterial.fog, + apiMaterial.wireframe, + apiMaterial.wireframeLineWidth, + apiMaterial.wireframeLineCap, + apiMaterial.wireframeLineJoin, + apiMaterial.vertexColors, + apiMaterial.skinning, + apiMaterial.morphTargets, + apiMaterial.morphNormals, + apiMaterial.lineWidth, + apiMaterial.lineCap, + apiMaterial.lineJoin, + apiMaterial.dashSize, + apiMaterial.gapWidth, + apiMaterial.blending, + apiMaterial.blendSrc, + apiMaterial.blendDst, + apiMaterial.blendEquation, + apiMaterial.depthTest, + apiMaterial.depthFunc, + apiMaterial.depthWrite, + apiMaterial.polygonOffset, + apiMaterial.polygonOffsetFactor, + apiMaterial.polygonOffsetUnits, + apiMaterial.alphaTest, + apiMaterial.clippingPlanes, + apiMaterial.clipShadows, + apiMaterial.visible, + apiMaterial.overdraw, + apiMaterial.flatShading, + apiMaterial.bumpScale, + apiMaterial.normalScale, + apiMaterial.displacementScale, + apiMaterial.displacementBias, + apiMaterial.roughness, + apiMaterial.metalness, + apiMaterial.pointSize, + apiMaterial.pointSizeAttenuation, + apiMaterial.spriteRotation, + apiMaterial.envMapIntensity, + apiMaterial.alphaMap, + apiMaterial.aoMap, + apiMaterial.bumpMap, + apiMaterial.diffuseMap, + apiMaterial.displacementMap, + apiMaterial.emissiveMap, + apiMaterial.environmentMap, + apiMaterial.lightMap, + apiMaterial.metalnessMap, + apiMaterial.normalMap, + apiMaterial.roughnessMap, + apiMaterial.specularMap, + apiMaterial.parentEntity + ); + + this.specular = new GameLib.Color( + graphics, + this.specular, + this + ); + + this.color = new GameLib.Color( + graphics, + this.color, + this + ); + + this.emissive = new GameLib.Color( + graphics, + this.emissive, + this + ); + + if (this.alphaMap) { + if (this.alphaMap instanceof GameLib.D3.API.Texture) { + this.alphaMap = new GameLib.D3.Texture( + this.graphics, + this.alphaMap + ); + } + } + + if (this.aoMap) { + if (this.aoMap instanceof GameLib.D3.API.Texture) { + this.aoMap = new GameLib.D3.Texture( + this.graphics, + this.aoMap + ); + } + } + + if (this.bumpMap) { + if (this.bumpMap instanceof GameLib.D3.API.Texture) { + this.bumpMap = new GameLib.D3.Texture( + this.graphics, + this.bumpMap + ); + } + } + + if (this.diffuseMap) { + if (this.diffuseMap instanceof GameLib.D3.API.Texture) { + this.diffuseMap = new GameLib.D3.Texture( + this.graphics, + this.diffuseMap + ); + } + } + + if (this.displacementMap) { + if (this.displacementMap instanceof GameLib.D3.API.Texture) { + this.displacementMap = new GameLib.D3.Texture( + this.graphics, + this.displacementMap + ); + } + } + + if (this.emissiveMap) { + if (this.emissiveMap instanceof GameLib.D3.API.Texture) { + this.emissiveMap = new GameLib.D3.Texture( + this.graphics, + this.emissiveMap + ); + } + } + + if (this.environmentMap) { + if (this.environmentMap instanceof GameLib.D3.API.Texture) { + this.environmentMap = new GameLib.D3.Texture( + this.graphics, + this.environmentMap + ); + } + } + + if (this.lightMap) { + if (this.lightMap instanceof GameLib.D3.API.Texture) { + this.lightMap = new GameLib.D3.Texture( + this.graphics, + this.lightMap + ); + } + } + + if (this.metalnessMap) { + if (this.metalnessMap instanceof GameLib.D3.API.Texture) { + this.metalnessMap = new GameLib.D3.Texture( + this.graphics, + this.metalnessMap + ); + } + } + + if (this.normalMap) { + if (this.normalMap instanceof GameLib.D3.API.Texture) { + this.normalMap = new GameLib.D3.Texture( + this.graphics, + this.normalMap + ); + } + } + + if (this.roughnessMap) { + if (this.roughnessMap instanceof GameLib.D3.API.Texture) { + this.roughnessMap = new GameLib.D3.Texture( + this.graphics, + this.roughnessMap + ); + } + } + + if (this.specularMap) { + if (this.specularMap instanceof GameLib.D3.API.Texture) { + this.specularMap = new GameLib.D3.Texture( + this.graphics, + this.specularMap + ); + } + } + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_MATERIAL, + { + 'alphaMap' : GameLib.D3.Texture, + 'aoMap' : GameLib.D3.Texture, + 'bumpMap' : GameLib.D3.Texture, + 'diffuseMap' : GameLib.D3.Texture, + 'displacementMap' : GameLib.D3.Texture, + 'emissiveMap' : GameLib.D3.Texture, + 'environmentMap' : GameLib.D3.Texture, + 'lightMap' : GameLib.D3.Texture, + 'metalnessMap' : GameLib.D3.Texture, + 'normalMap' : GameLib.D3.Texture, + 'roughnessMap' : GameLib.D3.Texture, + 'specularMap' : GameLib.D3.Texture + } + ); +}; + +GameLib.D3.Material.prototype = Object.create(GameLib.D3.API.Material.prototype); +GameLib.D3.Material.prototype.constructor = GameLib.D3.Material; + +/** + * Combine Method + * @type {number} + */ +GameLib.D3.Material.TYPE_MULTIPLY_OPERATION = 0; +GameLib.D3.Material.TYPE_MIX_OPERATION = 1; +GameLib.D3.Material.TYPE_ADD_OPERATION = 2; + +/** + * Vertex Color Mode + * @type {number} + */ +GameLib.D3.Material.TYPE_NO_COLORS = 0; +GameLib.D3.Material.TYPE_FACE_COLORS = 1; +GameLib.D3.Material.TYPE_VERTEX_COLORS = 2; + +/** + * Blending Mode + * @type {number} + */ +GameLib.D3.Material.TYPE_NO_BLENDING = 0; +GameLib.D3.Material.TYPE_NORMAL_BLENDING = 1; +GameLib.D3.Material.TYPE_ADDITIVE_BLENDING = 2; +GameLib.D3.Material.TYPE_SUBTRACTIVE_BLENDING = 3; +GameLib.D3.Material.TYPE_MULTIPLY_BLENDING = 4; +GameLib.D3.Material.TYPE_CUSTOM_BLENDING = 5; + +/** + * Blend Source and Destination + * @type {number} + */ +GameLib.D3.Material.TYPE_ZERO_FACTOR = 200; +GameLib.D3.Material.TYPE_ONE_FACTOR = 201; +GameLib.D3.Material.TYPE_SRC_COLOR_FACTOR = 202; +GameLib.D3.Material.TYPE_ONE_MINUS_SRC_COLOR_FACTOR = 203; +GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR = 204; +GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR = 205; +GameLib.D3.Material.TYPE_DST_ALPHA_FACTOR = 206; +GameLib.D3.Material.TYPE_ONE_MINUS_DST_ALPHA_FACTOR = 207; +GameLib.D3.Material.TYPE_DST_COLOR_FACTOR = 208; +GameLib.D3.Material.TYPE_ONE_MINUS_DST_COLOR_FACTOR = 209; +GameLib.D3.Material.TYPE_SRC_ALPHA_SATURATE_FACTOR = 210; + +/** + * Blend Operation + * @type {number} + */ +GameLib.D3.Material.TYPE_ADD_EQUATION = 100; +GameLib.D3.Material.TYPE_SUBTRACT_EQUATION = 101; +GameLib.D3.Material.TYPE_REVERSE_SUBTRACT_EQUATION = 102; +GameLib.D3.Material.TYPE_MIN_EQUATION = 103; +GameLib.D3.Material.TYPE_MAX_EQUATION = 104; + +/** + * Depth Function + * @type {number} + */ +GameLib.D3.Material.TYPE_NEVER_DEPTH = 0; +GameLib.D3.Material.TYPE_ALWAYS_DEPTH = 1; +GameLib.D3.Material.TYPE_LESS_DEPTH = 2; +GameLib.D3.Material.TYPE_LESS_EQUAL_DEPTH = 3; +GameLib.D3.Material.TYPE_EQUAL_DEPTH = 4; +GameLib.D3.Material.TYPE_GREATER_EQUAL_DEPTH = 5; +GameLib.D3.Material.TYPE_GREATER_DEPTH = 6; +GameLib.D3.Material.TYPE_NOT_EQUAL_DEPTH = 7; + +/** + * Culling Mode + * @type {number} + */ +GameLib.D3.Material.TYPE_FRONT_SIDE = 0; +GameLib.D3.Material.TYPE_BACK_SIDE = 1; +GameLib.D3.Material.TYPE_DOUBLE_SIDE = 2; + +/** + * Shading Type + * @type {number} + */ +GameLib.D3.Material.TYPE_FLAT_SHADING = 1; +GameLib.D3.Material.TYPE_SMOOTH_SHADING = 2; + +/** + * Material Type + * @type {string} + */ +GameLib.D3.Material.MATERIAL_TYPE_LINE_BASIC = 0x1; +GameLib.D3.Material.MATERIAL_TYPE_LINE_DASHED = 0x2; +GameLib.D3.Material.MATERIAL_TYPE_BASIC = 0x3; +GameLib.D3.Material.MATERIAL_TYPE_DEPTH = 0x4; +GameLib.D3.Material.MATERIAL_TYPE_LAMBERT = 0x5; +GameLib.D3.Material.MATERIAL_TYPE_NORMAL = 0x6; +GameLib.D3.Material.MATERIAL_TYPE_PHONG = 0x7; +GameLib.D3.Material.MATERIAL_TYPE_STANDARD = 0x8; +GameLib.D3.Material.MATERIAL_TYPE_POINTS = 0x9; +GameLib.D3.Material.MATERIAL_TYPE_SPRITE = 0xa; + +GameLib.D3.Material.LINE_CAP_BUTT = 0x1;//'butt'; +GameLib.D3.Material.LINE_CAP_ROUND = 0x2;//'round'; +GameLib.D3.Material.LINE_CAP_SQUARE = 0x3;//'square'; + +GameLib.D3.Material.LINE_JOIN_ROUND = 0x1;//'round'; +GameLib.D3.Material.LINE_JOIN_BEVEL = 0x2;//'bevel'; +GameLib.D3.Material.LINE_JOIN_MITER = 0x3;//'miter'; + +GameLib.D3.Material.prototype.createStandardMaterialInstance = function() { + return new THREE.MeshStandardMaterial({ + name: this.name, + opacity: this.opacity, + transparent: this.transparent, + blending: this.blending, + blendSrc: this.blendSrc, + blendDst: this.blendDst, + blendEquation: this.blendEquation, + depthTest: this.depthTest, + depthFunc: this.depthFunc, + depthWrite: this.depthWrite, + polygonOffset: this.polygonOffset, + polygonOffsetFactor: this.polygonOffsetFactor, + polygonOffsetUnits: this.polygonOffsetUnits, + alphaTest: this.alphaTest, + clippingPlanes: this.clippingPlanes, + clipShadows: this.clipShadows, + overdraw: this.overdraw, + visible: this.visible, + side: this.side, + color: this.color.instance, + roughness: this.roughness, + metalness: this.metalness, + lightMapIntensity: this.lightMapIntensity, + aoMapIntensity: this.aoMapIntensity, + emissive: this.emissive.instance, + emissiveIntensity: this.emissiveIntensity, + bumpScale: this.bumpScale, + normalScale: this.normalScale, + displacementScale: this.displacementScale, + refractionRatio: this.refractionRatio, + fog: this.fog, + flatShading: this.flatShading, + wireframe: this.wireframe, + wireframeLinewidth: this.wireframeLineWidth, + wireframeLinecap: this.wireframeLineCap, + wireframeLinejoin: this.wireframeLineJoin, + vertexColors: GameLib.D3.Material.TYPE_VERTEX_COLORS, + skinning: this.skinning, + morphTargets: this.morphTargets, + morphNormals: this.morphNormals + }); +}; + +GameLib.D3.Material.prototype.createPointsMaterialInstance = function() { + return new THREE.PointsMaterial({ + name: this.name, + opacity: this.opacity, + transparent: this.transparent, + // blending: this.blending, + // blendSrc: this.blendSrc, + // blendDst: this.blendDst, + // blendEquation: this.blendEquation, + depthTest: this.depthTest, + depthFunc: this.depthFunc, + depthWrite: this.depthWrite, + // polygonOffset: this.polygonOffset, + // polygonOffsetFactor: this.polygonOffsetFactor, + // polygonOffsetUnits: this.polygonOffsetUnits, + // alphaTest: this.alphaTest, + // clippingPlanes: this.clippingPlanes, + // clipShadows: this.clipShadows, + // overdraw: this.overdraw, + visible: this.visible, + side: this.side, + color: this.color.instance, + size: this.pointSize, + sizeAttenuation: this.pointSizeAttenuation + // vertexColors: GameLib.D3.Material.TYPE_VERTEX_COLORS, + // fog: this.fog + }); +}; + +GameLib.D3.Material.prototype.createLineBasicMaterialInstance = function() { + + var linecap = 'round'; + + if (this.lineCap === GameLib.D3.Material.LINE_CAP_BUTT) { + linecap = 'butt'; + } + + if (this.lineCap === GameLib.D3.Material.LINE_CAP_SQUARE) { + linecap = 'square'; + } + + var linejoin = 'round'; + + if (this.lineJoin === GameLib.D3.Material.LINE_JOIN_BEVEL) { + linejoin = 'bevel'; + } + + if (this.lineJoin === GameLib.D3.Material.LINE_JOIN_MITER) { + linejoin = 'miter'; + } + + return new THREE.LineBasicMaterial({ + name: this.name, + opacity: this.opacity, + transparent: this.transparent, + // blending: this.blending, + // blendSrc: this.blendSrc, + // blendDst: this.blendDst, + // blendEquation: this.blendEquation, + depthTest: this.depthTest, + depthFunc: this.depthFunc, + depthWrite: this.depthWrite, + // polygonOffset: this.polygonOffset, + // polygonOffsetFactor: this.polygonOffsetFactor, + // polygonOffsetUnits: this.polygonOffsetUnits, + // alphaTest: this.alphaTest, + // clippingPlanes: this.clippingPlanes, + // clipShadows: this.clipShadows, + // overdraw: this.overdraw, + visible: this.visible, + side: this.side, + color: this.color.instance, + linewidth: this.lineWidth, + linecap: linecap, + linejoin: linejoin + // vertexColors: GameLib.D3.Material.TYPE_VERTEX_COLORS, + // fog: this.fog + }); +}; + +GameLib.D3.Material.prototype.createPhongMaterialInstance = function() { + return new THREE.MeshPhongMaterial({ + name: this.name, + opacity: this.opacity, + transparent: this.transparent, + blending: this.blending, + blendSrc: this.blendSrc, + blendDst: this.blendDst, + blendEquation: this.blendEquation, + depthTest: this.depthTest, + depthFunc: this.depthFunc, + depthWrite: this.depthWrite, + polygonOffset: this.polygonOffset, + polygonOffsetFactor: this.polygonOffsetFactor, + polygonOffsetUnits: this.polygonOffsetUnits, + alphaTest: this.alphaTest, + clippingPlanes: this.clippingPlanes, + clipShadows: this.clipShadows, + overdraw: this.overdraw, + visible: this.visible, + side: this.side, + color: this.color.instance, + specular: this.specular.instance, + shininess: this.shininess, + lightMapIntensity: this.lightMapIntensity, + aoMapIntensity: this.aoMapIntensity, + emissive: this.emissive.instance, + emissiveIntensity: this.emissiveIntensity, + bumpScale: this.bumpScale, + normalScale: this.normalScale, + displacementScale: this.displacementScale, + combine: this.combine, + refractionRatio: this.refractionRatio, + fog: this.fog, + flatShading: this.flatShading, + wireframe: this.wireframe, + wireframeLinewidth: this.wireframeLineWidth, + wireframeLinecap: this.wireframeLineCap, + wireframeLinejoin: this.wireframeLineJoin, + vertexColors: GameLib.D3.Material.TYPE_VERTEX_COLORS, + skinning: this.skinning, + morphTargets: this.morphTargets, + morphNormals: this.morphNormals + }); +}; + +GameLib.D3.Material.prototype.createMeshBasicMaterialInstance = function() { + return new THREE.MeshBasicMaterial({ + name: this.name, + opacity: this.opacity, + transparent: this.transparent, + blending: this.blending, + blendSrc: this.blendSrc, + blendDst: this.blendDst, + blendEquation: this.blendEquation, + depthTest: this.depthTest, + depthFunc: this.depthFunc, + depthWrite: this.depthWrite, + polygonOffset: this.polygonOffset, + polygonOffsetFactor: this.polygonOffsetFactor, + polygonOffsetUnits: this.polygonOffsetUnits, + alphaTest: this.alphaTest, + clippingPlanes: this.clippingPlanes, + clipShadows: this.clipShadows, + overdraw: this.overdraw, + visible: this.visible, + side: this.side, + color: this.color.instance, + vertexColors: GameLib.D3.Material.TYPE_VERTEX_COLORS, + fog: this.fog + }); +}; + +GameLib.D3.Material.prototype.checkTexture = function(runtimeMap, instanceMap) { + + var textureChanged = false; + + if (this[runtimeMap] && this[runtimeMap].instance) { + if (this.instance[instanceMap] !== this[runtimeMap].instance) { + this.instance[instanceMap] = this[runtimeMap].instance; + textureChanged = true; + } + } else { + if (this.instance[instanceMap] !== null) { + this.instance[instanceMap] = null; + textureChanged = true; + } + } + + return textureChanged; +}; + +/** + * updates textures + */ +GameLib.D3.Material.prototype.updateTextures = function() { + + var textureChanged = false; + + if (this.checkTexture('alphaMap', 'alphaMap')) { + textureChanged = true; + } + + if (this.checkTexture('aoMap', 'aoMap')) { + textureChanged = true; + } + + if (this.checkTexture('bumpMap', 'bumpMap')) { + textureChanged = true; + } + + if (this.checkTexture('diffuseMap', 'map')) { + textureChanged = true; + } + + if (this.checkTexture('displacementMap', 'displacementMap')) { + textureChanged = true; + } + + if (this.checkTexture('emissiveMap', 'emissiveMap')) { + textureChanged = true; + } + + if (this.checkTexture('environmentMap', 'envMap')) { + textureChanged = true; + } + + if (this.checkTexture('lightMap', 'lightMap')) { + textureChanged = true; + } + + if (this.checkTexture('metalnessMap', 'metalnessMap')) { + textureChanged = true; + } + + if (this.checkTexture('normalMap', 'normalMap')) { + textureChanged = true; + } + + if (this.checkTexture('roughnessMap', 'roughnessMap')) { + textureChanged = true; + } + + if (this.checkTexture('specularMap', 'specularMap')) { + textureChanged = true; + } + + if (textureChanged) { + this.publish( + GameLib.Event.MATERIAL_TEXTURES_UPDATED, + { + material : this + } + ); + } + + return textureChanged; +}; + + +GameLib.D3.Material.prototype.updateStandardMaterialInstance = function(property) { + this.instance.name = this.name; + this.instance.opacity = this.opacity; + this.instance.transparent = this.transparent; + this.instance.blending = this.blending; + this.instance.blendSrc = this.blendSrc; + this.instance.blendDst = this.blendDst; + this.instance.blendEquation = this.blendEquation; + this.instance.depthTest = this.depthTest; + this.instance.depthFunc = this.depthFunc; + this.instance.depthWrite = this.depthWrite; + this.instance.polygonOffset = this.polygonOffset; + this.instance.polygonOffsetFactor = this.polygonOffsetFactor; + this.instance.polygonOffsetUnits = this.polygonOffsetUnits; + this.instance.alphaTest = this.alphaTest; + this.instance.clippingPlanes = this.clippingPlanes; + this.instance.clipShadows = this.clipShadows; + this.instance.overdraw = this.overdraw; + this.instance.visible = this.visible; + this.instance.side = this.side; + this.instance.color = this.color.instance; + this.instance.envMapIntensity = this.envMapIntensity; //standard material doesnt have specular color + this.instance.roughness = this.roughness; + this.instance.metalness = this.metalness; + this.instance.lightMapIntensity = this.lightMapIntensity; + this.instance.aoMapIntensity = this.aoMapIntensity; + this.instance.emissive = this.emissive.instance; + this.instance.emissiveIntensity = this.emissiveIntensity; + this.instance.bumpScale = this.bumpScale; + this.instance.normalScale = this.normalScale; + this.instance.displacementScale = this.displacementScale; + this.instance.refractionRatio = this.refractionRatio; + this.instance.fog = this.fog; + this.instance.flatShading = this.flatShading; + this.instance.wireframe = this.wireframe; + this.instance.wireframeLinewidth = this.wireframeLineWidth; + this.instance.wireframeLinecap = this.wireframeLineCap; + this.instance.wireframeLinejoin = this.wireframeLineJoin; + this.instance.vertexColors = GameLib.D3.Material.TYPE_VERTEX_COLORS; + this.instance.skinning = this.skinning; + this.instance.morphTargets = this.morphTargets; + this.instance.morphNormals = this.morphNormals; +}; + +GameLib.D3.Material.prototype.updatePointsMaterialInstance = function(property) { + this.instance.name = this.name; + this.instance.opacity = this.opacity; + this.instance.transparent = this.transparent; + // this.instance.blending = this.blending; + // this.instance.blendSrc = this.blendSrc; + // this.instance.blendDst = this.blendDst; + // this.instance.blendEquation = this.blendEquation; + // this.instance.depthTest = this.depthTest; + this.instance.depthFunc = this.depthFunc; + this.instance.depthWrite = this.depthWrite; + // this.instance.polygonOffset = this.polygonOffset; + // this.instance.polygonOffsetFactor = this.polygonOffsetFactor; + // this.instance.polygonOffsetUnits = this.polygonOffsetUnits; + // this.instance.alphaTest = this.alphaTest; + // this.instance.clippingPlanes = this.clippingPlanes; + // this.instance.clipShadows = this.clipShadows; + // this.instance.overdraw = this.overdraw; + this.instance.visible = this.visible; + this.instance.side = this.side; + this.instance.color = this.color.instance; + this.instance.size = this.pointSize; + this.instance.sizeAttenuation = this.pointSizeAttenuation; + //this.instance.vertexColors = GameLib.D3.Material.TYPE_VERTEX_COLORS; + //this.instance.fog = this.fog; +}; + +GameLib.D3.Material.prototype.updateLineBasicMaterialInstance = function(property) { + + var linecap = 'round'; + + if (this.lineCap === GameLib.D3.Material.LINE_CAP_BUTT) { + linecap = 'butt'; + } + + if (this.lineCap === GameLib.D3.Material.LINE_CAP_SQUARE) { + linecap = 'square'; + } + + var linejoin = 'round'; + + if (this.lineJoin === GameLib.D3.Material.LINE_JOIN_BEVEL) { + linejoin = 'bevel'; + } + + if (this.lineJoin === GameLib.D3.Material.LINE_JOIN_MITER) { + linejoin = 'miter'; + } + + this.instance.name = this.name; + this.instance.opacity = this.opacity; + this.instance.transparent = this.transparent; + // this.instance.blending = this.blending; + // this.instance.blendSrc = this.blendSrc; + // this.instance.blendDst = this.blendDst; + // this.instance.blendEquation = this.blendEquation; + // this.instance.depthTest = this.depthTest; + this.instance.depthFunc = this.depthFunc; + this.instance.depthWrite = this.depthWrite; + // this.instance.polygonOffset = this.polygonOffset; + // this.instance.polygonOffsetFactor = this.polygonOffsetFactor; + // this.instance.polygonOffsetUnits = this.polygonOffsetUnits; + // this.instance.alphaTest = this.alphaTest; + // this.instance.clippingPlanes = this.clippingPlanes; + // this.instance.clipShadows = this.clipShadows; + // this.instance.overdraw = this.overdraw; + this.instance.visible = this.visible; + this.instance.side = this.side; + this.instance.color = this.color.instance; + + this.instance.linewidth = this.lineWidth; + this.instance.linecap = linecap; + this.instance.linejoin = linejoin; + + //this.instance.vertexColors = GameLib.D3.Material.TYPE_VERTEX_COLORS; + //this.instance.fog = this.fog; +}; + + +GameLib.D3.Material.prototype.updatePhongMaterialInstance = function(property) { + this.instance.name = this.name; + this.instance.opacity = this.opacity; + this.instance.transparent = this.transparent; + this.instance.blending = this.blending; + this.instance.blendSrc = this.blendSrc; + this.instance.blendDst = this.blendDst; + this.instance.blendEquation = this.blendEquation; + this.instance.depthTest = this.depthTest; + this.instance.depthFunc = this.depthFunc; + this.instance.depthWrite = this.depthWrite; + this.instance.polygonOffset = this.polygonOffset; + this.instance.polygonOffsetFactor = this.polygonOffsetFactor; + this.instance.polygonOffsetUnits = this.polygonOffsetUnits; + this.instance.alphaTest = this.alphaTest; + this.instance.clippingPlanes = this.clippingPlanes; + this.instance.clipShadows = this.clipShadows; + this.instance.overdraw = this.overdraw; + this.instance.visible = this.visible; + this.instance.side = this.side; + this.instance.color = this.color.instance; + this.instance.specular = this.specular.instance; + this.instance.shininess = this.shininess; + this.instance.lightMapIntensity = this.lightMapIntensity; + this.instance.aoMapIntensity = this.aoMapIntensity; + this.instance.emissive = this.emissive.instance; + this.instance.emissiveIntensity = this.emissiveIntensity; + this.instance.envMapIntensity = this.envMapIntensity; + this.instance.bumpScale = this.bumpScale; + this.instance.normalScale = this.normalScale; + this.instance.displacementScale = this.displacementScale; + this.instance.combine = this.combine; + this.instance.refractionRatio = this.refractionRatio; + this.instance.fog = this.fog; + this.instance.flatShading = this.flatShading; + this.instance.wireframe = this.wireframe; + this.instance.wireframeLinewidth = this.wireframeLineWidth; + this.instance.wireframeLinecap = this.wireframeLineCap; + this.instance.wireframeLinejoin = this.wireframeLineJoin; + this.instance.vertexColors = GameLib.D3.Material.TYPE_VERTEX_COLORS; + this.instance.skinning = this.skinning; + this.instance.morphTargets = this.morphTargets; + this.instance.morphNormals = this.morphNormals; +}; + +GameLib.D3.Material.prototype.updateMeshBasicMaterialInstance = function(property) { + this.instance.name = this.name; + this.instance.opacity = this.opacity; + this.instance.transparent = this.transparent; + this.instance.blending = this.blending; + this.instance.blendSrc = this.blendSrc; + this.instance.blendDst = this.blendDst; + this.instance.blendEquation = this.blendEquation; + this.instance.depthTest = this.depthTest; + this.instance.depthFunc = this.depthFunc; + this.instance.depthWrite = this.depthWrite; + this.instance.polygonOffset = this.polygonOffset; + this.instance.polygonOffsetFactor = this.polygonOffsetFactor; + this.instance.polygonOffsetUnits = this.polygonOffsetUnits; + this.instance.alphaTest = this.alphaTest; + this.instance.clippingPlanes = this.clippingPlanes; + this.instance.clipShadows = this.clipShadows; + this.instance.overdraw = this.overdraw; + this.instance.visible = this.visible; + this.instance.side = this.side; + this.instance.color = this.color.instance; + this.instance.vertexColors = GameLib.D3.Material.TYPE_VERTEX_COLORS; + this.instance.fog = this.fog; +}; + +/** + * Material instance + * @returns {*} + */ +GameLib.D3.Material.prototype.createInstance = function() { + + if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_STANDARD) { + + this.instance = this.createStandardMaterialInstance(); + + } else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_POINTS) { + + this.instance = this.createPointsMaterialInstance(); + + } else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_PHONG) { + + this.instance = this.createPhongMaterialInstance(); + + } else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_BASIC) { + + this.instance = this.createMeshBasicMaterialInstance(); + + } else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_LINE_BASIC) { + + this.instance = this.createLineBasicMaterialInstance(); + + } else { + console.warn("material type is not implemented yet: " + this.materialType); + } + + this.instance.needsUpdate = true; + + this.updateTextures(); + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Material.prototype.updateInstance = function(property) { + + if (!this.instance) { + console.warn('Attempt to update a non-existent instance'); + return; + } + + if (property === 'materialType') { + + this.createInstance(); + + this.publish( + GameLib.Event.MATERIAL_TYPE_CHANGED, + { + material: this + } + ); + + return; + } + + if ( + property === 'alphaMap' || + property === 'aoMap' || + property === 'bumpMap' || + property === 'diffuseMap' || + property === 'displacementMap' || + property === 'emissiveMap' || + property === 'environmentMap' || + property === 'lightMap' || + property === 'metalnessMap' || + property === 'normalMap' || + property === 'roughnessMap' || + property === 'specularMap' + ) { + this.updateTextures(); + } + + if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_STANDARD) { + this.updateStandardMaterialInstance(property); + } else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_POINTS) { + this.updatePointsMaterialInstance(property); + } else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_PHONG) { + this.updatePhongMaterialInstance(property); + } else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_BASIC) { + this.updateMeshBasicMaterialInstance(property); + } else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_LINE_BASIC) { + this.updateLineBasicMaterialInstance(property); + } else { + console.warn('not yet implemented (material type = ' + this.materialType + ')'); + } + + this.instance.needsUpdate = true; +}; + +/** + * Converts a GameLib.D3.Material to a GameLib.D3.API.Material + * @returns {GameLib.D3.API.Material} + */ +GameLib.D3.Material.prototype.toApiObject = function(save) { + + if (GameLib.Utils.UndefinedOrNull(save)) { + save = false; + } + + var apiAlphaMap = null; + if (this.alphaMap) { + if (save) { + this.alphaMap.save(); + } + apiAlphaMap = this.alphaMap.id; + } + + var apiAoMap = null; + if (this.aoMap) { + if (save) { + this.aoMap.save(); + } + apiAoMap = this.aoMap.id; + } + + var apiBumpMap = null; + if (this.bumpMap) { + if (save) { + this.bumpMap.save(); + } + apiBumpMap = this.bumpMap.id; + } + + var apiDiffuseMap = null; + if (this.diffuseMap) { + if (save) { + this.diffuseMap.save(); + } + apiDiffuseMap = this.diffuseMap.id; + } + + var apiDisplacementMap = null; + if (this.displacementMap) { + if (save) { + this.displacementMap.save(); + } + apiDisplacementMap = this.displacementMap.id; + } + + var apiEmissiveMap = null; + if (this.emissiveMap) { + if (save) { + this.emissiveMap.save(); + } + apiEmissiveMap = this.emissiveMap.id; + } + + var apiEnvironmentMap = null; + if (this.environmentMap) { + if (save) { + this.environmentMap.save(); + } + apiEnvironmentMap = this.environmentMap.id; + } + + var apiLightMap = null; + if (this.lightMap) { + if (save) { + this.lightMap.save(); + } + apiLightMap = this.lightMap.id; + } + + var apiMetalnessMap = null; + if (this.metalnessMap) { + if (save) { + this.metalnessMap.save(); + } + apiMetalnessMap = this.metalnessMap.id; + } + + var apiNormalMap = null; + if (this.normalMap) { + this.normalMap.save(); + apiNormalMap = this.normalMap.id; + } + + var apiRoughnessMap = null; + if (this.roughnessMap) { + if (save) { + this.roughnessMap.save(); + } + apiRoughnessMap = this.roughnessMap.id; + } + + var apiSpecularMap = null; + if (this.specularMap) { + if (save) { + this.specularMap.save(); + } + apiSpecularMap = this.specularMap.id; + } + + var apiMaterial = new GameLib.D3.API.Material( + this.id, + this.materialType, + this.name, + this.opacity, + this.side, + this.transparent, + this.specular.toApiObject(), + this.lightMapIntensity, + this.aoMapIntensity, + this.color.toApiObject(), + this.emissive.toApiObject(), + this.emissiveIntensity, + this.combine, + this.shininess, + this.reflectivity, + this.refractionRatio, + this.fog, + this.wireframe, + this.wireframeLineWidth, + this.wireframeLineCap, + this.wireframeLineJoin, + this.vertexColors, + this.skinning, + this.morphTargets, + this.morphNormals, + this.lineWidth, + this.lineCap, + this.lineJoin, + this.dashSize, + this.gapWidth, + this.blending, + this.blendSrc, + this.blendDst, + this.blendEquation, + this.depthTest, + this.depthFunc, + this.depthWrite, + this.polygonOffset, + this.polygonOffsetFactor, + this.polygonOffsetUnits, + this.alphaTest, + this.clippingPlanes, + this.clipShadows, + this.visible, + this.overdraw, + this.flatShading, + this.bumpScale, + this.normalScale, + this.displacementScale, + this.displacementBias, + this.roughness, + this.metalness, + this.pointSize, + this.pointSizeAttenuation, + this.spriteRotation, + this.envMapIntensity, + apiAlphaMap, + apiAoMap, + apiBumpMap, + apiDiffuseMap, + apiDisplacementMap, + apiEmissiveMap, + apiEnvironmentMap, + apiLightMap, + apiMetalnessMap, + apiNormalMap, + apiRoughnessMap, + apiSpecularMap, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiMaterial; +}; + +GameLib.D3.Material.prototype.getTextures = function() { + + var textures = []; + + if (this.alphaMap) { + textures.push(this.alphaMap); + } + + if (this.aoMap) { + textures.push(this.aoMap); + } + + if (this.bumpMap) { + textures.push(this.bumpMap); + } + + if (this.diffuseMap) { + textures.push(this.diffuseMap); + } + + if (this.displacementMap) { + textures.push(this.displacementMap); + } + + if (this.emissiveMap) { + textures.push(this.emissiveMap); + } + + if (this.environmentMap) { + textures.push(this.environmentMap); + } + + if (this.lightMap) { + textures.push(this.lightMap); + } + + if (this.metalnessMap) { + textures.push(this.metalnessMap); + } + + if (this.normalMap) { + textures.push(this.normalMap); + } + + if (this.roughnessMap) { + textures.push(this.roughnessMap); + } + + if (this.specularMap) { + textures.push(this.specularMap); + } + + return textures; +}; + +/** + * Creates a GameLib.D3.Material from a material Object + * @param graphics GameLib.D3.Graphics + * @param objectMaterial Object + * @constructor + */ +GameLib.D3.Material.FromObject = function(graphics, objectMaterial) { + + var gameLibMaterial = new GameLib.D3.Material( + graphics, + GameLib.D3.API.Material.FromObject(objectMaterial) + ); + + return gameLibMaterial; +}; + +/** + * Mesh Superset - The apiMesh properties get moved into the Mesh object itself, and then the instance is created + * @param graphics GameLib.D3.Graphics + * @param apiMesh GameLib.D3.API.Mesh + * @constructor + */ +GameLib.D3.Mesh = function ( + graphics, + apiMesh +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiMesh)) { + apiMesh = {}; + } + + if (apiMesh instanceof GameLib.D3.Mesh) { + return apiMesh; + } + + GameLib.D3.API.Mesh.call( + this, + apiMesh.id, + apiMesh.meshType, + apiMesh.name, + apiMesh.vertices, + apiMesh.faces, + apiMesh.materials, + apiMesh.parentMesh, + apiMesh.parentScene, + apiMesh.skeleton, + apiMesh.skinIndices, + apiMesh.skinWeights, + apiMesh.position, + apiMesh.quaternion, + apiMesh.rotation, + apiMesh.scale, + apiMesh.up, + apiMesh.modelMatrix, + apiMesh.parentEntity, + apiMesh.renderOrder, + apiMesh.isBufferMesh, + apiMesh.useQuaternion, + apiMesh.visible + ); + + this.faces = this.faces.map( + function(face) { + if (face instanceof GameLib.D3.API.Face) { + return new GameLib.D3.Face( + this.graphics, + face + ) + } else { + return face; + } + }.bind(this) + ); + + this.materials = this.materials.map( + function(material) { + if (material instanceof GameLib.D3.API.Material) { + return new GameLib.D3.Material( + this.graphics, + material + ) + } else { + return material; + } + }.bind(this) + ); + + if (this.skeleton) { + this.skeleton = new GameLib.D3.Skeleton( + this.graphics, + this.skeleton + ); + } + + this.vertices = this.vertices.map( + function (apiVertex) { + return new GameLib.D3.Vertex( + this.graphics, + apiVertex + ); + }.bind(this) + ); + + this.position = new GameLib.Vector3( + this.graphics, + this.position, + this + ); + + this.quaternion = new GameLib.Quaternion( + this.graphics, + this.quaternion, + this + ); + + this.rotation = new GameLib.Vector3( + this.graphics, + this.rotation, + this + ); + + this.scale = new GameLib.Vector3( + this.graphics, + this.scale, + this + ); + + this.up = new GameLib.Vector3( + this.graphics, + this.up, + this + ); + + this.modelMatrix = new GameLib.Matrix4( + this.graphics, + this.modelMatrix, + this + ); + + this.dimensions = new GameLib.Vector3( + this.graphics, + new GameLib.API.Vector3(), + this + ); + + var linkedObjects = { + 'parentMesh' : GameLib.D3.Mesh, + 'parentScene' : GameLib.D3.Scene, + 'materials' : [GameLib.D3.Material], + 'skeleton' : GameLib.D3.Skeleton + }; + + var componentType = GameLib.Component.COMPONENT_MESH; + + if (this.meshType === GameLib.D3.Mesh.MESH_TYPE_PLANE) { + componentType = GameLib.Component.COMPONENT_MESH_PLANE + } + + if (this.meshType === GameLib.D3.Mesh.MESH_TYPE_BOX) { + componentType = GameLib.Component.COMPONENT_MESH_BOX + } + + if (this.meshType === GameLib.D3.Mesh.MESH_TYPE_CYLINDER) { + componentType = GameLib.Component.COMPONENT_MESH_CYLINDER + } + + if (this.meshType === GameLib.D3.Mesh.MESH_TYPE_SPHERE) { + componentType = GameLib.Component.COMPONENT_MESH_SPHERE + } + + if (this.meshType === GameLib.D3.Mesh.MESH_TYPE_LINE) { + componentType = GameLib.Component.COMPONENT_MESH_LINE + } + + if (this.meshType === GameLib.D3.Mesh.MESH_TYPE_TEXT) { + componentType = GameLib.Component.COMPONENT_MESH_TEXT; + linkedObjects.font = GameLib.D3.Font; + } + + /** + * Runtime meshes have helpers too + * @type {null} + */ + this.helper = null; + + this.updateRotationFromAxisAngle = true; + + GameLib.Component.call( + this, + componentType, + linkedObjects + ); +}; + +GameLib.D3.Mesh.prototype = Object.create(GameLib.D3.API.Mesh.prototype); +GameLib.D3.Mesh.prototype.constructor = GameLib.D3.Mesh; + +/** + * Mesh Type + * @type {number} + */ +GameLib.D3.Mesh.MESH_TYPE_NORMAL = 0x0; +GameLib.D3.Mesh.MESH_TYPE_SKINNED = 0x1; +GameLib.D3.Mesh.MESH_TYPE_CURVE = 0x2; +GameLib.D3.Mesh.MESH_TYPE_SPHERE = 0x3; +GameLib.D3.Mesh.MESH_TYPE_PLANE = 0x4; +GameLib.D3.Mesh.MESH_TYPE_BOX = 0x5; +GameLib.D3.Mesh.MESH_TYPE_CYLINDER = 0x6; +GameLib.D3.Mesh.MESH_TYPE_TEXT = 0x7; +GameLib.D3.Mesh.MESH_TYPE_LINE = 0x8; + +GameLib.D3.Mesh.prototype.lookAt = function(vector) { + + this.instance.lookAt( + new THREE.Vector3( + vector.x, + vector.y, + vector.z + ) + ); + + this.rotation.x = this.instance.rotation.x; + this.rotation.y = this.instance.rotation.y; + this.rotation.z = this.instance.rotation.z; + + this.quaternion.x = this.instance.quaternion.x; + this.quaternion.y = this.instance.quaternion.y; + this.quaternion.z = this.instance.quaternion.z; + this.quaternion.w = this.instance.quaternion.w; + +}; + + +GameLib.D3.Mesh.prototype.createInstanceGeometry = function(instanceGeometry) { + + if (instanceGeometry instanceof THREE.Geometry) { + + this.computeBoundingBox(instanceGeometry); + + if (this.isBufferMesh) { + return new THREE.BufferGeometry().fromGeometry(instanceGeometry); + } + } + + /** + * Setup face indexes - first we sort according to the material index, because later we will create + * groups for each vertice group + */ + this.faces.sort(function(a, b){ + + if (a.materialIndex < b.materialIndex) { + return -1; + } + + if (a.materialIndex > b.materialIndex) { + return 1; + } + + return 0; + }); + + /** + * Setup mesh vertices positions + * @type {Float32Array} + */ + var vertices = new Float32Array( + + this.faces.reduce( + function(result, face){ + result.push(this.vertices[face.v0index].position.x); + result.push(this.vertices[face.v0index].position.y); + result.push(this.vertices[face.v0index].position.z); + result.push(this.vertices[face.v1index].position.x); + result.push(this.vertices[face.v1index].position.y); + result.push(this.vertices[face.v1index].position.z); + result.push(this.vertices[face.v2index].position.x); + result.push(this.vertices[face.v2index].position.y); + result.push(this.vertices[face.v2index].position.z); + return result; + }.bind(this), + [] + ) + + ); + + var geometry = null; + + + if (this.isBufferMesh) { + + geometry = new THREE.BufferGeometry(); + + geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3)); + + /** + * Setyp mesh vertices colors + */ + var colors = Float32Array.from( + this.faces.reduce( + function(result, face){ + result.push(1,1,1,1,1,1,1,1,1); + // result.push(face.color.r); + // result.push(face.color.g); + // result.push(face.color.b); + // result.push(face.color.r); + // result.push(face.color.g); + // result.push(face.color.b); + // result.push(face.color.r); + // result.push(face.color.g); + // result.push(face.color.b); + return result; + }.bind(this), + [] + ) + ); + geometry.addAttribute('color', new THREE.BufferAttribute(colors, 3, true)); + + /** + * Setup face UVs + */ + var uvs = Float32Array.from( + this.faces.reduce( + function(result, face) { + + face.uvs[0].map( + function(uv) { + result.push(uv.x); + result.push(uv.y); + } + ); + + return result; + }, + [] + ) + ); + geometry.addAttribute('uv', new THREE.BufferAttribute(uvs, 2)); + + /** + * Setup material groups - this means creating a new group for each material index change + * We know faces are sorted according to material index + */ + var groupIndexCounts = this.faces.reduce( + function(result, face) { + + var currentGroup = result.pop(); + + if (currentGroup.index !== face.materialIndex) { + /** + * We have a new group + */ + result.push(currentGroup); + result.push({ + index: face.materialIndex, + count: 3 + }) + } else { + currentGroup.count += 3; + result.push(currentGroup); + } + + return result; + }, + [ + { + index : 0, + count : 0 + } + ] + ); + + groupIndexCounts.reduce( + function(start, group) { + geometry.addGroup(start, group.count, group.index); + return start + group.count; + }, + 0 + ); + + + } else { + + geometry = new THREE.Geometry(); + + var standardUvs = []; + + /** + * Face data + * @type {Array} + */ + geometry.faces = this.faces.map( + function (face) { + + if (face.uvs[0].length > 0) { + standardUvs.push( + face.uvs[0].map( + function(uv) { + return new THREE.Vector2( + uv.x, + uv.y + ) + } + ) + ); + } + + var faceInstance = new THREE.Face3( + face.v0index, + face.v1index, + face.v2index + ); + + if (face.normal) { + faceInstance.normal = new THREE.Vector3( + face.normal.x, + face.normal.y, + face.normal.z + ); + } + + if (face.color) { + faceInstance.color = new THREE.Color( + face.color.r, + face.color.g, + face.color.b + ) + } + + faceInstance.materialIndex = face.materialIndex; + + return faceInstance; + } + ); + + /** + * Vertex data + * @type {Array} + */ + geometry.vertices = this.vertices.map( + function (vertex) { + return new THREE.Vector3( + vertex.position.x, + vertex.position.y, + vertex.position.z + ) + } + ); + geometry.verticesNeedUpdate = true; + + + /** + * UV data - but only if it exists + */ + if (standardUvs.length > 0) { + geometry.faceVertexUvs = [standardUvs]; + } + + /** + * Re-compute normals - we don't do this for buffer geometry because it assigns to every vertex normal the face + * normal - essentially disabling 'smooth shading' + */ + geometry.computeFaceNormals(); + // geometry.computeBoundingBox(); + geometry.computeVertexNormals(); + + // geometry.verticesNeedUpdate = true; + // geometry.elementsNeedUpdate = true; + // geometry.morphTargetsNeedUpdate = true; + // geometry.uvsNeedUpdate = true; + // geometry.normalsNeedUpdate = true; + // geometry.colorsNeedUpdate = true; + // geometry.tangentsNeedUpdate = true; + } + + /** + * Apply skin indices + */ + // this.applyBones(geometry); + + this.computeBoundingBox(geometry); + + return geometry; +}; + + +/** + * Creates a mesh instance or updates it + */ +GameLib.D3.Mesh.prototype.createInstance = function() { + + var geometry = this.createInstanceGeometry(); + + if (this.skeleton) { + + if (this.materials.length === 1) { + this.instance = new THREE.SkinnedMesh( + geometry, + this.materials[0].instance + ) + } else { + this.instance = new THREE.SkinnedMesh( + geometry, + this.materials.map( + function(material) { + return material.instance; + } + ) + ) + } + + this.instance.add(this.skeleton.rootBoneInstance); + this.instance.bind(this.skeleton.instance); + + } else { + if (this.materials.length === 1) { + this.instance = new THREE.Mesh( + geometry, + this.materials[0].instance + ) + } else { + this.instance = new THREE.Mesh( + geometry, + this.materials.map( + function(material) { + return material.instance; + } + ) + ) + } + } + + this.instance.name = this.name; + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.add(this.instance, this); + } + + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + + if (this.useQuaternion) { + this.instance.quaternion.x = this.quaternion.x; + this.instance.quaternion.y = this.quaternion.y; + this.instance.quaternion.z = this.quaternion.z; + this.instance.quaternion.w = this.quaternion.w; + this.instance.quaternion.setFromAxisAngle( + new THREE.Vector3( + this.quaternion.axis.x, + this.quaternion.axis.y, + this.quaternion.axis.z + ), + this.quaternion.angle + ); + } else { + this.instance.rotation.x = this.rotation.x; + this.instance.rotation.y = this.rotation.y; + this.instance.rotation.z = this.rotation.z; + } + + this.instance.scale.x = this.scale.x; + this.instance.scale.y = this.scale.y; + this.instance.scale.z = this.scale.z; + + this.instance.up.x = this.up.x; + this.instance.up.y = this.up.y; + this.instance.up.z = this.up.z; + + this.instance.renderOrder = this.renderOrder; + + this.instance.visible = this.visible; + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the mesh instance + */ +GameLib.D3.Mesh.prototype.updateInstance = function(property) { + + if (( this.isBufferMesh && !(this.instance.geometry instanceof THREE.BufferGeometry)) || + ( !this.isBufferMesh && (this.instance.geometry instanceof THREE.BufferGeometry))) + { + /** + * The buffer geometry needs updating + */ + this.instance.geometry = this.createInstanceGeometry(this.instance.geometry); + } + + if (this.useQuaternion) { + if (this.updateRotationFromAxisAngle) { + this.updateInstanceRotationFromAxisAngle(); + } else { + this.instance.quaternion.x = this.quaternion.x; + this.instance.quaternion.y = this.quaternion.y; + this.instance.quaternion.z = this.quaternion.z; + this.instance.quaternion.w = this.quaternion.w; + } + } else { + this.instance.rotation.x = this.rotation.x; + this.instance.rotation.y = this.rotation.y; + this.instance.rotation.z = this.rotation.z; + } + + if (this.parentMesh && this.parentMesh.instance) { + if (this.instance.parent !== this.parentMesh.instance) { + this.instance.parent = this.parentMesh.instance; + } + } + + this.instance.scale.x = this.scale.x; + this.instance.scale.y = this.scale.y; + this.instance.scale.z = this.scale.z; + + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + + this.instance.up.x = this.up.x; + this.instance.up.y = this.up.y; + this.instance.up.z = this.up.z; + + this.instance.name = this.name; + + if (this.materials.length === 1 && this.materials[0].instance) { + this.instance.material = this.materials[0].instance; + } + + this.instance.renderOrder = this.renderOrder; + + if (this.helper) { + this.removeHelper(); + this.createHelper(); + } + + if (property === 'visible') { + this.instance.visible = this.visible; + } +}; + +/** + * Apply geometry data to our game-lib object from the geometry instance (reverse of applyVertexData) + * @param geometryInstance + */ +GameLib.D3.Mesh.prototype.updateVerticesFromGeometryInstance = function(geometryInstance) { + + /** + * Setup vertices + */ + this.vertices = []; + + this.faces = []; + + if (geometryInstance instanceof THREE.BufferGeometry) { + + var vertices = geometryInstance.getAttribute('position').array; + + var uvs = geometryInstance.getAttribute('uv').array; + + geometryInstance.groups.map(function(group){ + + var materialIndex = group.materialIndex; + + var start = group.start; + + var count = group.count; + + var faceIndexes = []; + + var indexedUvs = []; + + for (var i = start; i < count; i ++) { + + var vertex = new GameLib.D3.Vertex( + this.graphics, + new GameLib.D3.API.Vertex( + new GameLib.Vector3( + this.graphics, + new GameLib.API.Vector3( + vertices[i*3], + vertices[i*3 + 1], + vertices[i*3 + 2] + ) + ) + ) + ); + + var uv = new GameLib.Vector2( + this.graphics, + new GameLib.API.Vector2( + uvs[i*2], + uvs[i*2 + 1] + ) + ); + + indexedUvs.push(uv); + + var vertexIndex = this.vertices.reduce( + function(result, indexedVertex, currentIndex){ + if (indexedVertex.position.equals(vertex.position)) { + result = currentIndex; + } + return result; + }, + -1 + ); + + var faceIndex = vertexIndex; + + if (vertexIndex === -1) { + this.vertices.push(vertex); + faceIndex = this.vertices.length - 1; + } + + faceIndexes.push(faceIndex); + + if (faceIndexes.length === 3) { + + this.faces.push( + new GameLib.D3.Face( + this.graphics, + new GameLib.D3.API.Face( + null, + null, + faceIndexes[0], + faceIndexes[1], + faceIndexes[2], + materialIndex, + [[indexedUvs[0], indexedUvs[1], indexedUvs[2]]] + ) + ) + ); + + indexedUvs = []; + faceIndexes = []; + } + } + + }.bind(this)); + + + + console.log('todo : update vertices from buffer geometry'); + } else { + + var processed = 0; + + geometryInstance.faces.map(function(face, faceIndex){ + + processed++; + + if (processed % 100 === 0) { + console.log('processed ' + processed + ' faces'); + } + + this.faces.push( + new GameLib.D3.Face( + this.graphics, + new GameLib.D3.API.Face( + null, + null, + face.a, + face.b, + face.c, + face.materialIndex, + [[ + new GameLib.API.Vector2( + geometryInstance.faceVertexUvs[0][faceIndex][0].x, + geometryInstance.faceVertexUvs[0][faceIndex][0].y + ), + new GameLib.API.Vector2( + geometryInstance.faceVertexUvs[0][faceIndex][1].x, + geometryInstance.faceVertexUvs[0][faceIndex][1].y + ), + new GameLib.API.Vector2( + geometryInstance.faceVertexUvs[0][faceIndex][2].x, + geometryInstance.faceVertexUvs[0][faceIndex][2].y + ) + ]], + new GameLib.Color( + this.graphics, + new GameLib.API.Color( + face.color.r, + face.color.g, + face.color.b + ) + ), + face.vertexColors.map(function(vertexColor){ + return new GameLib.Color( + this.graphics, + new GameLib.API.Color( + vertexColor.r, + vertexColor.g, + vertexColor.b + ) + ) + }.bind(this)), + face.vertexNormals.map(function(vertexNormal){ + return new GameLib.Vector3( + this.graphics, + new GameLib.API.Vector3( + vertexNormal.x, + vertexNormal.y, + vertexNormal.z + ) + ) + }.bind(this)), + new GameLib.Vector3( + this.graphics, + new GameLib.API.Vector3( + face.normal.x, + face.normal.y, + face.normal.z + ) + ) + ) + ) + ) + }.bind(this)); + + processed = 0; + + geometryInstance.vertices.map(function(vertex){ + + processed++; + + if (processed % 100 === 0) { + console.log('processed ' + processed + ' vertices'); + } + + this.vertices.push( + new GameLib.D3.Vertex( + this.graphics, + new GameLib.D3.API.Vertex( + new GameLib.Vector3( + this.graphics, + new GameLib.API.Vector3( + vertex.x, + vertex.y, + vertex.z + ) + ) + ) + ) + ) + }.bind(this)); + } + +}; + + +GameLib.D3.Mesh.prototype.applyBones = function(geometry) { + + /** + * Setup Bone Indexes + */ + this.skinIndices.map( + function(skinIndex) { + geometry.skinIndices.push( + new THREE.Vector4( + skinIndex.x, + skinIndex.y, + skinIndex.z, + skinIndex.w + ) + ); + } + ); + + /** + * Setup Bone Weights + */ + this.skinWeights.map( + function(skinWeight) { + geometry.skinWeights.push( + new THREE.Vector4( + skinWeight.x, + skinWeight.y, + skinWeight.z, + skinWeight.w + ) + ); + } + ); + +}; + +/** + * Adds a child instance to this instance + * @param childInstance + * @param child + */ +GameLib.D3.Mesh.prototype.addChild = function(childInstance, child) { + + if (!this.instance) { + throw new Error('mesh instance not loaded yet : ' + this.name); + } + + if (GameLib.Utils.UndefinedOrNull(childInstance)) { + throw new Error('no child mesh instance'); + } + + if (GameLib.Utils.UndefinedOrNull(child)) { + throw new Error('no child mesh'); + } + + this.instance.add(childInstance); + + childInstance.parent = this.instance; + + child.parentMesh = this; +}; + +/** + * Sets a parent for this mesh + * @param parentMesh + */ +GameLib.D3.Mesh.prototype.setParentMesh = function(parentMesh) { + + /** + * Are we removing this child from the parent? + */ + if (GameLib.Utils.UndefinedOrNull(parentMesh)) { + + if (this.instance && this.instance.parent && this.parentScene.instance) { + + /** + * Update the parent matrix world + */ + this.instance.parent.updateMatrixWorld(); + + /** + * Copy the child world position into a temporary vector + * @type {THREE.Vector3} + */ + var vector = new THREE.Vector3(); + vector.setFromMatrixPosition(this.instance.matrixWorld); + + /** + * Detach child from parent within this scene + */ + THREE.SceneUtils.detach( + this.instance, + this.instance.parent, + this.parentScene.instance + ); + + /** + * We remember from now on that we have no parent mesh + * @type {null} + */ + this.parentMesh = null; + + /** + * We store the world position back to the child + */ + this.position.x = vector.x; + this.position.y = vector.y; + this.position.z = vector.z; + + /** + * Update the instance position + */ + this.updateInstancePosition(); + + /** + * Don't touch this instance parent - since it is now probably a scene object + */ + + /** + * TODO: do we apply rotation somehow? + */ + + } else { + throw new Error('Not enough information to detach') + } + + } else { + + if (!this.instance) { + throw new Error('No valid instance at time of adding to parent for mesh ' + this.name); + } + + if (!(parentMesh instanceof GameLib.D3.Mesh)) { + throw new Error('Not a valid parent mesh'); + } + + this.parentMesh = parentMesh; + + /** + * Add this as a child to the parent + */ + this.parentMesh.addChild(this.instance, this); + } + +}; + + +// GameLib.D3.Mesh.prototype.getBoundingBox = function() { +// +// this.instance.geometry.computeBoundingBox(); +// +// return new GameLib.Vector3( +// this.graphics, +// new GameLib.API.Vector3( +// this.instance.geometry.boundingBox.max.x - this.instance.geometry.boundingBox.min.x, +// this.instance.geometry.boundingBox.max.y - this.instance.geometry.boundingBox.min.y, +// this.instance.geometry.boundingBox.max.z - this.instance.geometry.boundingBox.min.z +// ) +// ); +// +// }; + +/** + * Converts a GameLib.D3.Mesh to a GameLib.D3.API.Mesh + * @returns {GameLib.D3.API.Mesh} + */ +GameLib.D3.Mesh.prototype.toApiObject = function() { + + var apiSkeleton = null; + if (this.skeleton) { + apiSkeleton = this.skeleton.id; + } + + var apiMaterials = null; + if (this.materials) { + apiMaterials = this.materials.map( + function(material) { + return material.id; + } + ) + } + + var apiFaces = this.faces.map( + function(face){ + return face.toApiObject(); + } + ); + + var apiMesh = new GameLib.D3.API.Mesh( + this.id, + this.meshType, + this.name, + this.vertices.map( + function (vertex) { + return vertex.toApiObject(); + } + ), + apiFaces, + apiMaterials, + GameLib.Utils.IdOrNull(this.parentMesh), + GameLib.Utils.IdOrNull(this.parentScene), + apiSkeleton, + this.skinIndices, + this.skinWeights, + this.position.toApiObject(), + this.quaternion.toApiObject(), + this.rotation.toApiObject(), + this.scale.toApiObject(), + this.up.toApiObject(), + this.modelMatrix.toApiObject(), + GameLib.Utils.IdOrNull(this.parentEntity), + this.renderOrder, + this.isBufferMesh, + this.useQuaternion, + this.visible + ); + + return apiMesh; +}; + +/** + * Converts a standard object mesh to a GameLib.D3.Mesh + * @param graphics GameLib.D3.Graphics + * @param objectMesh {Object} + * @constructor + */ +GameLib.D3.Mesh.FromObject = function(graphics, objectMesh) { + + var apiMesh = GameLib.D3.API.Mesh.FromObject(objectMesh); + + return new GameLib.D3.Mesh( + graphics, + apiMesh + ); + +}; + +/** + * Centers the mesh around origin + */ +GameLib.D3.Mesh.prototype.centerAroundOrigin = function() { + + var position = this.instance.geometry.center(); + + this.instance.position.set(0,0,0); + + this.instance.updateMatrix(); + + for (var v = 0; v < this.instance.geometry.vertices.length; v++) { + this.vertices[v].position.x = this.instance.geometry.vertices[v].x; + this.vertices[v].position.y = this.instance.geometry.vertices[v].y; + this.vertices[v].position.z = this.instance.geometry.vertices[v].z; + } + + this.position.x = -position.x; + this.position.y = -position.y; + this.position.z = -position.z; + + this.updateInstancePosition(); + + return position; +}; + +GameLib.D3.Mesh.prototype.applyAxisAngleToPosition = function(axis, angle) { + + if (GameLib.Utils.UndefinedOrNull(axis)) { + axis = this.quaternion.axis; + } + + if (GameLib.Utils.UndefinedOrNull(angle)) { + angle = this.quaternion.angle; + } + + this.position.applyAxisAngle(axis, angle); + this.updateInstancePosition(); +}; + +GameLib.D3.Mesh.prototype.applyAxisAngleToUvs = function(axis, angle) { + + if (GameLib.Utils.UndefinedOrNull(axis)) { + axis = this.quaternion.axis; + } + + if (GameLib.Utils.UndefinedOrNull(angle)) { + angle = this.quaternion.angle; + } + + // this.instance.geometry.faceVertexUvs[0].map( + // function(uvs) { + // uvs.map(function(uv) { + // + // var x = uv.x; + // + // uv.x = uv.y; + // uv.y = x; + // + // //var v = new THREE.Vector3(uv.x, uv.y, 0); + // //v.applyAxisAngle(axis, angle); + // //uv.x = v.x; + // //uv.y = v.u; + // }); + // } + // ); + + this.instance.geometry.uvsNeedUpdate = true; + // + // this.faces.map( + // function(face) { + // face.uvs.map(function(uvs){ + // uvs.map( + // function(uv) { + // var v = new GameLib.Vector3(this.graphics, new GameLib.API.Vector3(uv.x, uv.y, 0)); + // v.applyAxisAngle(axis, angle); + // uv.x = v.x; + // uv.y = v.y; + // } + // ) + // }); + // } + // ) +}; + +GameLib.D3.Mesh.prototype.translate = function(vector3) { + + this.position.x += vector3.x; + this.position.y += vector3.y; + this.position.z += vector3.z; + + this.updateInstancePosition(); +}; + +GameLib.D3.Mesh.prototype.getDistanceFromCenter = function() { + var position = this.instance.geometry.center(); + return new GameLib.Vector3( + this.graphics, + new GameLib.API.Vector3( + position.x, + position.y, + position.z + ) + ) +}; + +/** + * Applies position, rotation and scale to the object vertice data, resets scale, rotation and sets position to origin. + */ +GameLib.D3.Mesh.prototype.applyPositionRotationScale = function() { + + this.instance.updateMatrix(); + + this.instance.geometry.applyMatrix(this.instance.matrix); + + /** + * Reset position + * @type {number} + */ + this.position.x = 0; + this.position.y = 0; + this.position.z = 0; + this.updateInstancePosition(); + + /** + * Reset scale + * @type {number} + */ + this.scale.x = 1; + this.scale.y = 1; + this.scale.z = 1; + this.instance.scale.set(1,1,1); + + /** + * Reset rotation + * @type {number} + */ + this.quaternion.x = 0; + this.quaternion.y = 0; + this.quaternion.z = 0; + this.quaternion.w = 1; + this.quaternion.axis.x = 0; + this.quaternion.axis.y = 0; + this.quaternion.axis.z = 0; + this.quaternion.angle = 0; + + this.rotation.x = 0; + this.rotation.y = 0; + this.rotation.z = 0; + + this.updateInstanceRotation(); + + /** + * Update our instance matrix + */ + this.instance.updateMatrix(); + + /** + * Let this reflect back to our vertices + */ + this.updateVerticesFromGeometryInstance(this.instance.geometry); +}; + +GameLib.D3.Mesh.prototype.updateInstanceRotationFromAxisAngle = function(axis, angle) { + + if (GameLib.Utils.UndefinedOrNull(axis)) { + axis = this.quaternion.axis; + } + + if (GameLib.Utils.UndefinedOrNull(angle)) { + angle = this.quaternion.angle; + } + + this.quaternion.axis.instance.x = axis.x; + this.quaternion.axis.instance.y = axis.y; + this.quaternion.axis.instance.z = axis.z; + this.quaternion.instance.setFromAxisAngle(this.quaternion.axis.instance, angle); + this.instance.quaternion.copy(this.quaternion.instance); + this.quaternion.x = this.quaternion.instance.x; + this.quaternion.y = this.quaternion.instance.y; + this.quaternion.z = this.quaternion.instance.z; + this.quaternion.w = this.quaternion.instance.w; +}; + +GameLib.D3.Mesh.prototype.updateInstanceRotation = function() { + + if (this.useQuaternion) { + + this.updateInstanceRotationFromAxisAngle(); + + } else { + + this.rotation.instance.set( + this.rotation.x, + this.rotation.y, + this.rotation.z + ); + + this.instance.rotation.set( + this.rotation.x, + this.rotation.y, + this.rotation.z + ); + } + + if (this.helper) { + this.helper.updateInstance(); + } +}; + +GameLib.D3.Mesh.prototype.updateInstancePosition = function() { + + this.position.instance.set( + this.position.x, + this.position.y, + this.position.z + ); + + this.instance.position.copy(this.position.instance); + + if (this.helper) { + this.removeHelper(); + this.createHelper(); + } +}; + +GameLib.D3.Mesh.prototype.updateInstanceScale = function() { + + this.scale.instance.set( + this.scale.x, + this.scale.y, + this.scale.z + ); + + this.instance.scale.copy(this.scale.instance); + + if (this.helper) { + this.removeHelper(); + this.createHelper(); + } +}; + + + +/** + * Gets all children components of this Mesh (all linked objects only - no object references i.e. string ids) + * @returns {Array} + */ +GameLib.D3.Mesh.prototype.getChildrenComponents = function() { + + var components = []; + + this.materials.map( + function (material) { + + if (material instanceof GameLib.D3.Material) { + GameLib.Utils.PushUnique(components, material); + + for (var property in material.linkedObjects) { + if ( + material.linkedObjects.hasOwnProperty(property) && + material.hasOwnProperty(property) && + material[property] && + typeof material[property] !== 'string' && + property !== 'parentEntity' + ) { + GameLib.Utils.PushUnique(components, material[property]); + for (var tProperty in material[property].linkedObjects) { + if ( + material[property].linkedObjects.hasOwnProperty(tProperty) && + material[property].hasOwnProperty(tProperty) && + material[property][tProperty] && + typeof material[property][tProperty] !== 'string' && + tProperty !== 'parentEntity' + ) { + + if (material[property][tProperty] instanceof Array) { + material[property][tProperty].map( + function(object) { + GameLib.Utils.PushUnique(components, object); + } + ) + } else { + GameLib.Utils.PushUnique(components, material[property][tProperty]); + } + } + } + } + } + } + + }.bind(this) + ); + + /** + * Push RigidBodies + */ + var rigidBodies = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.RigidBody); + rigidBodies.map( + function(rigidBody) { + + if (rigidBody.parentMesh === this) { + GameLib.Utils.PushUnique(components, rigidBody); + } + + }.bind(this) + ); + + /** + * Push Shapes + */ + var shapes = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Shape); + shapes.map( + function(shape) { + + if (shape.parentMesh === this) { + GameLib.Utils.PushUnique(components, shape); + } + + }.bind(this) + ); + + return components; +}; + +/** + * Convenience function for creating a helper for this Mesh - should be called from Systems only + */ +GameLib.D3.Mesh.prototype.createHelper = function() { + + if (GameLib.Utils.UndefinedOrNull(this.parentScene) || + GameLib.Utils.UndefinedOrNull(this.parentScene.instance)) { + console.warn('this mesh has no parent scene - cannot create helper'); + return; + } + + if (this.helper) { + this.removeHelper(); + } + + this.helper = new GameLib.D3.Helper( + this.graphics, + null, + this.name + ' Helper', + this, + GameLib.D3.Helper.HELPER_TYPE_EDGES + ); + + this.helper.updateInstance(); + + /** + * Backup the polygonOffset value, then set it to 'true' - helps for clear nice outlines + */ + this.polygonOffset = this.instance.material.polygonOffset; + + this.instance.material.polygonOffset = true; + + this.parentScene.instance.add(this.helper.instance); + +}; + +GameLib.D3.Mesh.prototype.addMaterial = function(material) { + if (this.materials.length === 1) { + this.instance.material = material.instance; + } else { + this.instance.material = this.materials.map( + function(material) { + return material.instance; + } + ); + } +}; + +/** + * Convenience function for removing a helper for this Mesh - should be called from Systems only + */ +GameLib.D3.Mesh.prototype.removeHelper = function() { + + if (GameLib.Utils.UndefinedOrNull(this.parentScene) || + GameLib.Utils.UndefinedOrNull(this.parentScene.instance)) { + console.warn('this mesh has no parent scene - cannot remove helper'); + return; + } + + if (this.helper && this.helper.instance) { + this.parentScene.instance.remove(this.helper.instance); + delete this.helper.instance; + } + + this.instance.material.polygonOffset = this.polygonOffset; + + this.helper = null; +}; + +GameLib.D3.Mesh.prototype.computeBoundingBox = function(geometry) { + + if (GameLib.Utils.UndefinedOrNull(geometry)) { + + if (this.instance && this.instance.geometry) { + geometry = this.instance.geometry; + } else { + console.log('no instance geometry to compute bounding box'); + } + } + + geometry.computeBoundingBox(); + this.dimensions.x = geometry.boundingBox.getSize().x; + this.dimensions.y = geometry.boundingBox.getSize().y; + this.dimensions.z = geometry.boundingBox.getSize().z; +}; + +/** + * Mesh Superset - The apiMesh properties get moved into the Mesh object itself, and then the instance is created + * @param graphics GameLib.D3.Graphics + * @param apiMesh GameLib.D3.API.Mesh + * @param width + * @param height + * @param depth + * @constructor + */ +GameLib.D3.Mesh.Box = function ( + graphics, + apiMesh, + width, + height, + depth +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiMesh)) { + apiMesh = {}; + } + + if (apiMesh instanceof GameLib.D3.Mesh.Box) { + return apiMesh; + } + + apiMesh.meshType = GameLib.D3.Mesh.MESH_TYPE_BOX; + + if (GameLib.Utils.UndefinedOrNull(width)) { + width = 1; + } + this.width = width; + + if (GameLib.Utils.UndefinedOrNull(height)) { + height = 1; + } + this.height = height; + + if (GameLib.Utils.UndefinedOrNull(depth)) { + depth = 1; + } + this.depth = depth; + + GameLib.D3.Mesh.call( + this, + this.graphics, + apiMesh + ); +}; + +GameLib.D3.Mesh.Box.prototype = Object.create(GameLib.D3.Mesh.prototype); +GameLib.D3.Mesh.Box.prototype.constructor = GameLib.D3.Mesh.Box; + +GameLib.D3.Mesh.Box.prototype.createInstance = function() { + + var geometry = null; + + if (this.vertices.length === 0) { + geometry = new THREE.BoxGeometry( + this.width, + this.height, + this.depth + ); + + this.updateVerticesFromGeometryInstance(geometry); + } + + GameLib.D3.Mesh.prototype.createInstance.call(this); + + this.instance.userData.width = this.width; + this.instance.userData.height = this.height; + this.instance.userData.depth = this.depth; +}; + +GameLib.D3.Mesh.Box.prototype.updateInstance = function(property) { + + if ( + this.instance.userData.width !== this.width || + this.instance.userData.height !== this.height || + this.instance.userData.depth !== this.depth + ) { + this.instance.userData.width = this.width; + this.instance.userData.height = this.height; + this.instance.userData.depth = this.depth; + + var geometry = new THREE.BoxGeometry( + this.width, + this.height, + this.depth + ); + + this.updateVerticesFromGeometryInstance(geometry); + + geometry = this.createInstanceGeometry(); + + this.instance.geometry = geometry; + } + + GameLib.D3.Mesh.prototype.updateInstance.call(this, property); + +}; + +/** + * Converts a GameLib.D3.Mesh to a GameLib.D3.API.Mesh + * @returns {GameLib.D3.API.Mesh} + */ +GameLib.D3.Mesh.Box.prototype.toApiObject = function() { + + var apiMesh = GameLib.D3.Mesh.prototype.toApiObject.call(this); + + apiMesh.width = this.width; + apiMesh.height = this.height; + apiMesh.depth = this.depth; + + return apiMesh; +}; + +/** + * Converts a standard object mesh to a GameLib.D3.Mesh + * @param graphics GameLib.D3.Graphics + * @param objectMesh {Object} + * @constructor + */ +GameLib.D3.Mesh.Box.FromObject = function(graphics, objectMesh) { + + var apiMesh = GameLib.D3.API.Mesh.FromObject(objectMesh); + + return new GameLib.D3.Mesh.Box( + graphics, + apiMesh, + objectMesh.width, + objectMesh.height, + objectMesh.depth + ); + +}; + +/** + * Mesh Superset - The apiMesh properties get moved into the Mesh object itself, and then the instance is created + * @param graphics GameLib.D3.Graphics + * @param apiMesh GameLib.D3.API.Mesh + * @constructor + */ +GameLib.D3.Mesh.Curve = function ( + graphics, + apiMesh +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + GameLib.D3.Mesh.call( + this, + this.graphics, + apiMesh + ); +}; + +GameLib.D3.Mesh.Curve.prototype = Object.create(GameLib.D3.Mesh.prototype); +GameLib.D3.Mesh.Curve.prototype.constructor = GameLib.D3.Mesh.Curve; + + +GameLib.D3.Mesh.Curve.prototype.createInstance = function() { + + var geometry = new THREE.Geometry(); + + /** + * Setup vertices + */ + this.applyVertexDataToInstance(geometry); + + var instance = new THREE.Points(geometry); + + this.createInstanceDefaults(instance); + + return instance; +}; +/** + * Mesh Superset - The apiMesh properties get moved into the Mesh object itself, and then the instance is created + * @param graphics GameLib.D3.Graphics + * @param apiMesh GameLib.D3.API.Mesh + * @param radiusTop + * @param radiusBottom + * @param height + * @param radiusSegments + * @param heightSegments + * @param openEnded + * @param thetaStart + * @param thetaLength + * @constructor + */ +GameLib.D3.Mesh.Cylinder = function ( + graphics, + apiMesh, + radiusTop, + radiusBottom, + height, + radiusSegments, + heightSegments, + openEnded, + thetaStart, + thetaLength +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + + if (GameLib.Utils.UndefinedOrNull(apiMesh)) { + apiMesh = {}; + } + + if (apiMesh instanceof GameLib.D3.Mesh.Box) { + return apiMesh; + } + + apiMesh.meshType = GameLib.D3.Mesh.MESH_TYPE_CYLINDER; + + if (GameLib.Utils.UndefinedOrNull(radiusTop)) { + radiusTop = 1; + } + this.radiusTop = radiusTop; + + if (GameLib.Utils.UndefinedOrNull(radiusBottom)) { + radiusBottom = 1; + } + this.radiusBottom = radiusBottom; + + if (GameLib.Utils.UndefinedOrNull(height)) { + height = 5; + } + this.height = height; + + if (GameLib.Utils.UndefinedOrNull(radiusSegments)) { + radiusSegments = 10; + } + this.radiusSegments = radiusSegments; + + if (GameLib.Utils.UndefinedOrNull(heightSegments)) { + heightSegments = 10; + } + this.heightSegments = heightSegments; + + if (GameLib.Utils.UndefinedOrNull(openEnded)) { + openEnded = false; + } + this.openEnded = openEnded; + + if (GameLib.Utils.UndefinedOrNull(thetaStart)) { + thetaStart = 0; + } + this.thetaStart = thetaStart; + + if (GameLib.Utils.UndefinedOrNull(thetaLength)) { + thetaLength = Math.PI * 2; + } + this.thetaLength = thetaLength; + + GameLib.D3.Mesh.call( + this, + this.graphics, + apiMesh + ); +}; + +GameLib.D3.Mesh.Cylinder.prototype = Object.create(GameLib.D3.Mesh.prototype); +GameLib.D3.Mesh.Cylinder.prototype.constructor = GameLib.D3.Mesh.Cylinder; + +GameLib.D3.Mesh.Cylinder.prototype.createInstance = function() { + + var geometry = null; + + if (this.vertices.length === 0) { + geometry = new THREE.CylinderGeometry( + this.radiusTop, + this.radiusBottom, + this.height, + this.radiusSegments, + this.heightSegments, + this.openEnded, + this.thetaStart, + this.thetaLength + ); + this.updateVerticesFromGeometryInstance(geometry); + } + + GameLib.D3.Mesh.prototype.createInstance.call(this); + + this.instance.userData.radiusTop = this.radiusTop; + this.instance.userData.radiusBottom = this.radiusBottom; + this.instance.userData.height = this.height; + this.instance.userData.radiusSegments = this.radiusSegments; + this.instance.userData.heightSegments = this.heightSegments; + this.instance.userData.openEnded = this.openEnded; + this.instance.userData.thetaStart = this.thetaStart; + this.instance.userData.thetaLength = this.thetaLength; +}; + +GameLib.D3.Mesh.Cylinder.prototype.updateInstance = function(property) { + + if ( + this.instance.userData.radiusTop !== this.radiusTop || + this.instance.userData.radiusBottom !== this.radiusBottom || + this.instance.userData.height !== this.height || + this.instance.userData.radiusSegments !== this.radiusSegments || + this.instance.userData.heightSegments !== this.heightSegments || + this.instance.userData.openEnded !== this.openEnded || + this.instance.userData.thetaStart !== this.thetaStart || + this.instance.userData.thetaLength !== this.thetaLength + ) { + this.instance.userData.radiusTop = this.radiusTop; + this.instance.userData.radiusBottom = this.radiusBottom; + this.instance.userData.height = this.height; + this.instance.userData.radiusSegments = this.radiusSegments; + this.instance.userData.heightSegments = this.heightSegments; + this.instance.userData.openEnded = this.openEnded; + this.instance.userData.thetaStart = this.thetaStart; + this.instance.userData.thetaLength = this.thetaLength; + + var geometry = new THREE.CylinderGeometry( + this.radiusTop, + this.radiusBottom, + this.height, + this.radiusSegments, + this.heightSegments, + this.openEnded, + this.thetaStart, + this.thetaLength + ); + this.updateVerticesFromGeometryInstance(geometry); + + geometry = this.createInstanceGeometry(); + + this.instance.geometry = geometry; + } + + GameLib.D3.Mesh.prototype.updateInstance.call(this, property); + +}; + +/** + * Converts a GameLib.D3.Mesh to a GameLib.D3.API.Mesh + * @returns {GameLib.D3.API.Mesh} + */ +GameLib.D3.Mesh.Cylinder.prototype.toApiObject = function() { + + var apiMesh = GameLib.D3.Mesh.prototype.toApiObject.call(this); + + apiMesh.radiusTop = this.radiusTop; + apiMesh.radiusBottom = this.radiusBottom; + apiMesh.height = this.height; + apiMesh.radiusSegments = this.radiusSegments; + apiMesh.heightSegments = this.heightSegments; + apiMesh.openEnded = this.openEnded; + apiMesh.thetaStart = this.thetaStart; + apiMesh.thetaLength = this.thetaLength; + + return apiMesh; +}; + +/** + * Converts a standard object mesh to a GameLib.D3.Mesh + * @param graphics GameLib.D3.Graphics + * @param objectMesh {Object} + * @constructor + */ +GameLib.D3.Mesh.Cylinder.FromObject = function(graphics, objectMesh) { + + var apiMesh = GameLib.D3.API.Mesh.FromObject(objectMesh); + + return new GameLib.D3.Mesh.Cylinder( + graphics, + apiMesh, + objectMesh.radiusTop, + objectMesh.radiusBottom, + objectMesh.height, + objectMesh.radiusSegments, + objectMesh.heightSegments, + objectMesh.openEnded, + objectMesh.thetaStart, + objectMesh.thetaLength + ); + +}; + +/** + * Mesh Superset - The apiMesh properties get moved into the Mesh object itself, and then the instance is created + * @param graphics GameLib.D3.Graphics + * @param apiMesh GameLib.D3.API.Mesh + * @param lineWidth + * @constructor + */ +GameLib.D3.Mesh.Line = function ( + graphics, + apiMesh, + lineWidth +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiMesh)) { + apiMesh = {}; + } + + if (apiMesh instanceof GameLib.D3.Mesh.Line) { + return apiMesh; + } + + apiMesh.meshType = GameLib.D3.Mesh.MESH_TYPE_LINE; + + if (GameLib.Utils.UndefinedOrNull(lineWidth)) { + lineWidth = 1; + } + this.lineWidth = lineWidth; + + GameLib.D3.Mesh.call( + this, + this.graphics, + apiMesh + ); +}; + +GameLib.D3.Mesh.Line.prototype = Object.create(GameLib.D3.Mesh.prototype); +GameLib.D3.Mesh.Line.prototype.constructor = GameLib.D3.Mesh.Line; + +GameLib.D3.Mesh.Line.prototype.createInstance = function() { + + var geometry = new THREE.Geometry(); + + geometry.vertices.push( + this.vertices.map( + function(vertex){ + return vertex.instance; + } + ) + ); + + this.instance = new THREE.Line(geometry); + + GameLib.D3.Mesh.prototype.createInstance.call(this); + + this.instance.userData.lineWidth = this.lineWidth; +}; + +GameLib.D3.Mesh.Line.prototype.updateInstance = function(property) { + + this.instance.linewidth = this.lineWidth; + + GameLib.D3.Mesh.prototype.updateInstance.call(this, property); + +}; + +/** + * Converts a GameLib.D3.Mesh to a GameLib.D3.API.Mesh + * @returns {GameLib.D3.API.Mesh} + */ +GameLib.D3.Mesh.Line.prototype.toApiObject = function() { + + var apiMesh = GameLib.D3.Mesh.prototype.toApiObject.call(this); + + apiMesh.lineWidth = this.lineWidth; + + return apiMesh; +}; + +/** + * Converts a standard object mesh to a GameLib.D3.Mesh + * @param graphics GameLib.D3.Graphics + * @param objectMesh {Object} + * @constructor + */ +GameLib.D3.Mesh.Line.FromObject = function(graphics, objectMesh) { + + var apiMesh = GameLib.D3.API.Mesh.FromObject(objectMesh); + + return new GameLib.D3.Mesh.Line( + graphics, + apiMesh, + objectMesh.lineWidth + ); + +}; + +/** + * Mesh Superset - The apiMesh properties get moved into the Mesh object itself, and then the instance is created + * @param graphics GameLib.D3.Graphics + * @param apiMesh GameLib.D3.API.Mesh + * @param width + * @param height + * @param widthSegments + * @param heightSegments + * @param heightMapScale + * @param isHeightMap + * @param isClippingPlane + * @param distanceFromOrigin + * @constructor + */ +GameLib.D3.Mesh.Plane = function ( + graphics, + apiMesh, + width, + height, + widthSegments, + heightSegments, + heightMapScale, + isHeightMap, + isClippingPlane, + distanceFromOrigin +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiMesh)) { + apiMesh = {}; + } + + if (apiMesh instanceof GameLib.D3.Mesh.Box) { + return apiMesh; + } + + apiMesh.meshType = GameLib.D3.Mesh.MESH_TYPE_PLANE; + + if (GameLib.Utils.UndefinedOrNull(width)) { + width = 1; + } + this.width = width; + + if (GameLib.Utils.UndefinedOrNull(height)) { + height = 1; + } + this.height = height; + + if (GameLib.Utils.UndefinedOrNull(widthSegments)) { + widthSegments = 1; + } + this.widthSegments = widthSegments; + + if (GameLib.Utils.UndefinedOrNull(heightSegments)) { + heightSegments = 1 + } + this.heightSegments = heightSegments; + + if (GameLib.Utils.UndefinedOrNull(heightMapScale)) { + heightMapScale = 1; + } + this.heightMapScale = heightMapScale; + + if (GameLib.Utils.UndefinedOrNull(isHeightMap)) { + isHeightMap = false; + } + this.isHeightMap = isHeightMap; + + if (GameLib.Utils.UndefinedOrNull(isClippingPlane)) { + isClippingPlane = false; + } + this.isClippingPlane = isClippingPlane; + + if (GameLib.Utils.UndefinedOrNull(distanceFromOrigin)) { + distanceFromOrigin = 0; + } + this.distanceFromOrigin = distanceFromOrigin; + + GameLib.D3.Mesh.call( + this, + this.graphics, + apiMesh + ); +}; + +GameLib.D3.Mesh.Plane.prototype = Object.create(GameLib.D3.Mesh.prototype); +GameLib.D3.Mesh.Plane.prototype.constructor = GameLib.D3.Mesh.Plane; + + +GameLib.D3.Mesh.Plane.prototype.createInstance = function() { + + var geometry = null; + + /** + * If this geometry is not coming from the database, apply the vertex data from the instance to our runtime object + */ + if (this.vertices.length === 0) { + + geometry = new THREE.PlaneGeometry( + this.width, + this.height, + this.widthSegments, + this.heightSegments + ); + + this.updateVerticesFromGeometryInstance(geometry); + + /** + * If this is a heightmap - first generate the z-coordinates + */ + if (this.isHeightMap) { + this.generateHeightMapFromBumpMap(); + } + } + + /** + * Now construct the mesh instance + */ + GameLib.D3.Mesh.prototype.createInstance.call(this); + + /** + * Apply some plane specific data to the instance + */ + this.instance.userData.width = this.width; + this.instance.userData.height = this.height; + this.instance.userData.widthSegments = this.widthSegments; + this.instance.userData.heightSegments = this.heightSegments; + this.instance.userData.heightMapScale = this.heightMapScale; + this.instance.userData.isHeightMap = this.isHeightMap; + this.instance.userData.isClippingPlane = this.isClippingPlane; + this.instance.userData.distanceFromOrigin = this.distanceFromOrigin; + + if (this.isClippingPlane) { + this.instance.clipping = new THREE.Plane( + geometry.faces[0].normal, + this.distanceFromOrigin + ); + } +}; + +/** + * + */ +GameLib.D3.Mesh.Plane.prototype.updateInstance = function(property) { + + var geometry = null; + + if ( + this.instance.userData.width !== this.width || + this.instance.userData.height !== this.height || + this.instance.userData.widthSegments !== this.widthSegments || + this.instance.userData.heightSegments !== this.heightSegments || + this.instance.userData.isHeightMap !== this.isHeightMap || + this.instance.userData.heightMapScale !== this.heightMapScale || + this.instance.userData.isClippingPlane !== this.isClippingPlane || + this.instance.userData.distanceFromOrigin !== this.distanceFromOrigin + ) { + this.instance.userData.width = this.width; + this.instance.userData.height = this.height; + this.instance.userData.widthSegments = this.widthSegments; + this.instance.userData.heightSegments = this.heightSegments; + this.instance.userData.isHeightMap = this.isHeightMap; + this.instance.userData.heightMapScale = this.heightMapScale; + this.instance.userData.isClippingPlane = this.isClippingPlane; + this.instance.userData.distanceFromOrigin = this.distanceFromOrigin; + + geometry = new THREE.PlaneGeometry( + this.width, + this.height, + this.widthSegments, + this.heightSegments + ); + + this.updateVerticesFromGeometryInstance(geometry); + + if (this.isHeightMap) { + this.generateHeightMapFromBumpMap(); + } + + geometry = this.createInstanceGeometry(); + + this.instance.geometry = geometry; + + if (this.isClippingPlane) { + this.instance.clipping = new THREE.Plane( + geometry.faces[0].normal, + this.distanceFromOrigin + ) + } + } + + GameLib.D3.Mesh.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a GameLib.D3.Mesh to a GameLib.D3.API.Mesh + * @returns {GameLib.D3.API.Mesh} + */ +GameLib.D3.Mesh.Plane.prototype.toApiObject = function() { + + var apiMesh = GameLib.D3.Mesh.prototype.toApiObject.call(this); + + apiMesh.width = this.width; + apiMesh.height = this.height; + apiMesh.widthSegments = this.widthSegments; + apiMesh.heightSegments = this.heightSegments; + apiMesh.heightMapScale = this.heightMapScale; + apiMesh.isHeightMap = this.isHeightMap; + apiMesh.isClippingPlane = this.isClippingPlane; + apiMesh.distanceFromOrigin = this.distanceFromOrigin; + + return apiMesh; +}; + +/** + * TODO fix all this weird loading shit + * Converts a standard object mesh to a GameLib.D3.Mesh + * @param graphics GameLib.D3.Graphics + * @param objectMesh {Object} + * @constructor + */ +GameLib.D3.Mesh.Plane.FromObject = function(graphics, objectMesh) { + + var apiMesh = GameLib.D3.API.Mesh.FromObject(objectMesh); + + return new GameLib.D3.Mesh.Plane( + graphics, + apiMesh, + objectMesh.width, + objectMesh.height, + objectMesh.widthSegments, + objectMesh.heightSegments, + objectMesh.heightMapScale, + objectMesh.isHeightMap, + objectMesh.isClippingPlane, + objectMesh.distanceFromOrigin + ); + +}; + +GameLib.D3.Mesh.Plane.prototype.getHeightData = function() { + + var i; + + var img = this.materials.reduce( + function(result, material) { + if ( + material.bumpMap && + material.bumpMap.image && + material.bumpMap.image.instance + ) { + result = material.bumpMap.image.instance; + } + + return result; + }, + null + ); + + if (!img) { + throw new Error('bumpmap image not found'); + } + + var canvas = document.createElement( 'canvas' ); + canvas.width = this.widthSegments + 1;//img.width; + canvas.height = this.heightSegments + 1;//img.height; + var context = canvas.getContext( '2d' ); + + var size = (this.widthSegments + 1) * (this.heightSegments + 1); + var data = new Float32Array( size ); + + context.drawImage(img,0,0, canvas.width, canvas.height); + + for (i = 0; i < size; i ++ ) { + data[i] = 0 + } + + var imgd = context.getImageData(0, 0, (this.widthSegments + 1), (this.heightSegments + 1)); + var pix = imgd.data; + + var j=0; + for (i = 0; i particle.userData.lifeTime) { + // particle.parent.remove(particle); + // } else { + // result.push(particle); + // } + // + // return result; + // }, + // [] + // ); +}; + +GameLib.D3.ParticleEngine.prototype.createNewParticle = function(camera) { + // + // var particle = this.templateParticle.clone(camera); + // + // this.particles.push(particle); + +}; + +/** + * Converts a GameLib.D3.ParticleEngine to a new GameLib.D3.API.ParticleEngine + * @returns {GameLib.D3.API.ParticleEngine} + */ +GameLib.D3.ParticleEngine.prototype.toApiObject = function() { + + return new GameLib.D3.API.ParticleEngine( + this.id, + this.name, + this.position.toApiObject(), + this.direction.toApiObject(), + this.enabled, + GameLib.Utils.IdOrNull(this.templateParticle), + this.particlesPerSecond, + this.frequency, + this.elapsed, + GameLib.Utils.IdOrNull(this.camera), + this.pulse, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Converts from an Object ParticleEngine to a GameLib.D3.ParticleEngine + * @param graphics GameLib.D3.Graphics + * @param objectParticleEngine Object + * @returns {GameLib.D3.ParticleEngine} + * @constructor + */ +GameLib.D3.ParticleEngine.FromObject = function(graphics, objectParticleEngine) { + + var apiParticleEngine = GameLib.D3.API.ParticleEngine.FromObject(objectParticleEngine); + + return new GameLib.D3.ParticleEngine( + graphics, + apiParticleEngine + ); + +}; + +/** + * Creates a Particle object + * @param graphics GameLib.D3.Graphics + * @param apiParticle GameLib.D3.API.Particle + * @constructor + */ +GameLib.D3.Particle = function( + graphics, + apiParticle +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiParticle)) { + apiParticle = {}; + } + + if (apiParticle instanceof GameLib.D3.Particle) { + return apiParticle; + } + + GameLib.D3.API.Particle.call( + this, + apiParticle.id, + apiParticle.name, + apiParticle.lifeTime, + apiParticle.elapsed, + apiParticle.mesh, + apiParticle.opacityType, + apiParticle.opacityFactor, + apiParticle.positionOffsetType, + apiParticle.positionOffset, + apiParticle.positionOffsetFn, + apiParticle.directionType, + apiParticle.direction, + apiParticle.directionFn, + apiParticle.speedType, + apiParticle.speed, + apiParticle.scaleType, + apiParticle.scale, + apiParticle.scaleFn, + apiParticle.rotationType, + apiParticle.rotation, + apiParticle.rotationFn, + apiParticle.parentEngine, + apiParticle.parentEntity + ); + + if (this.mesh instanceof GameLib.D3.API.Mesh) { + this.mesh = new GameLib.D3.Mesh( + graphics, + this.mesh + ) + } + + if (this.positionOffset instanceof GameLib.API.Vector3) { + this.positionOffset = new GameLib.Vector3( + graphics, + this.positionOffset, + this + ); + } else { + console.warn('positionOffset not instance of API.Vector3'); + throw new Error('positionOffset not instance of API.Vector3'); + } + + if (this.direction instanceof GameLib.API.Vector3) { + this.direction = new GameLib.Vector3( + graphics, + this.direction, + this + ); + } else { + console.warn('direction not instance of API.Vector3'); + throw new Error('direction not instance of API.Vector3'); + } + + if (this.scale instanceof GameLib.API.Vector3) { + this.scale = new GameLib.Vector3( + graphics, + this.scale, + this + ); + } else { + console.warn('scale not instance of API.Vector3'); + throw new Error('scale not instance of API.Vector3'); + } + + if (this.rotation instanceof GameLib.API.Vector3) { + this.rotation = new GameLib.Vector3( + graphics, + this.rotation, + this + ); + } else { + console.warn('rotation not instance of API.Vector3'); + throw new Error('rotation not instance of API.Vector3'); + } + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_PARTICLE, + { + mesh : GameLib.D3.Mesh, + parentEngine : GameLib.D3.ParticleEngine + } + ); + +}; + +GameLib.D3.Particle.prototype = Object.create(GameLib.D3.API.Particle.prototype); +GameLib.D3.Particle.prototype.constructor = GameLib.D3.Particle; + +GameLib.D3.Particle.OPACITY_TYPE_CONSTANT = 0x1; +GameLib.D3.Particle.OPACITY_TYPE_DECREASE_LINEAR = 0x2; +GameLib.D3.Particle.OPACITY_TYPE_INCREASE_LINEAR = 0x3; + +GameLib.D3.Particle.POSITION_OFFSET_TYPE_CONSTANT = 0x1; +GameLib.D3.Particle.POSITION_OFFSET_TYPE_RANDOM = 0x2; +GameLib.D3.Particle.POSITION_OFFSET_TYPE_FUNCTION = 0x3; + +GameLib.D3.Particle.DIRECTION_TYPE_CONSTANT = 0x1; +GameLib.D3.Particle.DIRECTION_TYPE_RANDOM = 0x2; +GameLib.D3.Particle.DIRECTION_TYPE_RANDOM_NORMALIZED = 0x3; +GameLib.D3.Particle.DIRECTION_TYPE_FUNCTION = 0x4; + +GameLib.D3.Particle.SCALE_TYPE_CONSTANT = 0x1; +GameLib.D3.Particle.SCALE_TYPE_LINEAR = 0x2; +GameLib.D3.Particle.SCALE_TYPE_EXPONENTIAL = 0x3; +GameLib.D3.Particle.SCALE_TYPE_RANDOM = 0x4; +GameLib.D3.Particle.SCALE_TYPE_RANDOM_X_EQUALS_Y = 0x6; +GameLib.D3.Particle.SCALE_TYPE_FUNCTION = 0x7; + +GameLib.D3.Particle.SPEED_TYPE_CONSTANT = 0x1; +GameLib.D3.Particle.SPEED_TYPE_LINEAR = 0x2; +GameLib.D3.Particle.SPEED_TYPE_EXPONENTIAL = 0x3; +GameLib.D3.Particle.SPEED_TYPE_LOGARITHMIC = 0x4; +GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_LOG = 0x5; +GameLib.D3.Particle.SPEED_TYPE_EXP = 0x6; +GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_EXP = 0x7; + +GameLib.D3.Particle.ROTATION_TYPE_CONSTANT = 0x1; +GameLib.D3.Particle.ROTATION_TYPE_RANDOM = 0x2; +GameLib.D3.Particle.ROTATION_TYPE_FUNCTION = 0x3; + +/** + * Particle create instance + */ +GameLib.D3.Particle.prototype.createInstance = function() { + + if (!this.mesh) { + console.warn('no mesh to clone from - failed dependency check?'); + return + } + + this.instance = this.mesh.instance; + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Particle.prototype.updateInstance = function(property) { + + if (property === 'positionOffset') { + this.positionOffset.instance.x = this.positionOffset.x; + this.positionOffset.instance.y = this.positionOffset.y; + this.positionOffset.instance.z = this.positionOffset.z; + } + + if (property === 'direction') { + this.direction.instance.x = this.direction.x; + this.direction.instance.y = this.direction.y; + this.direction.instance.z = this.direction.z; + } + + if (property === 'scale') { + this.scale.instance.x = this.scale.x; + this.scale.instance.y = this.scale.y; + this.scale.instance.z = this.scale.z; + } + + if (property === 'rotation') { + this.rotation.instance.x = this.rotation.x; + this.rotation.instance.y = this.rotation.y; + this.rotation.instance.z = this.rotation.z; + } + +}; + + +/** + * Clones a particle - this only clones 3rd party instances, so we have less overhead of creating these types of objects + */ +GameLib.D3.Particle.prototype.cloneInstance = function() { + + this.updateInstance('positionOffset'); + this.updateInstance('direction'); + this.updateInstance('scale'); + this.updateInstance('rotation'); + + var clone = GameLib.Component.prototype.cloneInstance.call(this); + + clone.position = this.parentEngine.position.instance.clone(); + + clone.material = this.mesh.materials[0].instance.clone(); + + clone.visible = true; + + if (this.positionOffsetType === GameLib.D3.Particle.POSITION_OFFSET_TYPE_CONSTANT) { + clone.position.add(this.positionOffset.instance); + } + + var addX = 1; + var addY = 1; + var addZ = 1; + + if (this.positionOffsetType === GameLib.D3.Particle.POSITION_OFFSET_TYPE_RANDOM) { + + addX = GameLib.Utils.GetRandomIntInclusive(1,2); + addY = GameLib.Utils.GetRandomIntInclusive(1,2); + addZ = GameLib.Utils.GetRandomIntInclusive(1,2); + + if (addX === 1) { + clone.position.x += Math.random() * this.positionOffset.x; + } else { + clone.position.x -= Math.random() * this.positionOffset.x; + } + + if (addY === 1) { + clone.position.y -= Math.random() * this.positionOffset.y; + } else { + clone.position.y += Math.random() * this.positionOffset.y; + } + + if (addZ === 1) { + clone.position.z -= Math.random() * this.positionOffset.z; + } else { + clone.position.z += Math.random() * this.positionOffset.z; + } + } + + clone.userData.direction = this.direction.clone(); + + if (this.directionType === GameLib.D3.Particle.DIRECTION_TYPE_CONSTANT) { + + /** + * Nothing to do + */ + + } else if ( + this.directionType === GameLib.D3.Particle.DIRECTION_TYPE_RANDOM || + this.directionType === GameLib.D3.Particle.DIRECTION_TYPE_RANDOM_NORMALIZED + ) { + + addX = GameLib.Utils.GetRandomIntInclusive(1,2); + addY = GameLib.Utils.GetRandomIntInclusive(1,2); + addZ = GameLib.Utils.GetRandomIntInclusive(1,2); + + clone.userData.direction.x = 0; + clone.userData.direction.y = 0; + clone.userData.direction.z = 0; + + if (addX === 1) { + clone.userData.direction.x += Math.random() * this.direction.x; + } else { + clone.userData.direction.x -= Math.random() * this.direction.x; + } + + if (addY === 1) { + clone.userData.direction.y -= Math.random() * this.direction.y; + } else { + clone.userData.direction.y += Math.random() * this.direction.y; + } + + if (addZ === 1) { + clone.userData.direction.z -= Math.random() * this.direction.z; + } else { + clone.userData.direction.z += Math.random() * this.direction.z; + } + + if (this.directionType === GameLib.D3.Particle.DIRECTION_TYPE_RANDOM_NORMALIZED) { + clone.userData.direction.normalize(); + } + + } else { + throw new Error('not yet implemented') + } + + + if (this.scaleType === GameLib.D3.Particle.SCALE_TYPE_CONSTANT) { + clone.scale.x += this.scale.x; + clone.scale.y += this.scale.y; + clone.scale.z += this.scale.z; + } + + if (this.scaleType === GameLib.D3.Particle.SCALE_TYPE_RANDOM) { + + add = GameLib.Utils.GetRandomIntInclusive(1,2); + + if (add === 1) { + clone.scale.x += Math.random() * this.scale.x; + clone.scale.y += Math.random() * this.scale.y; + clone.scale.z += Math.random() * this.scale.z; + } else { + clone.scale.x -= Math.random() * this.scale.x; + clone.scale.y -= Math.random() * this.scale.y; + clone.scale.z -= Math.random() * this.scale.z; + } + } + + if (this.scaleType === GameLib.D3.Particle.SCALE_TYPE_RANDOM_X_EQUALS_Y) { + + add = GameLib.Utils.GetRandomIntInclusive(1,2); + + var factor = Math.random() * this.scale.x; + + if (add === 1) { + clone.scale.x += factor; + clone.scale.y += factor; + clone.scale.z += Math.random() * this.scale.z; + } else { + clone.scale.x -= factor; + clone.scale.y -= factor; + clone.scale.z -= Math.random() * this.scale.z; + } + } + + + clone.userData.scale = this.scale.clone(); + clone.userData.lifeTime = this.lifeTime; + clone.userData.speedType = this.speedType; + clone.userData.speed = this.speed; + clone.userData.scene = this.mesh.parentScene.instance; + + clone.userData.elapsed = 0; + + clone.userData.scene.add(clone); + + return clone; +}; + +/** + * Converts a GameLib.D3.Particle to a new GameLib.D3.API.Particle + * @returns {GameLib.D3.API.Particle} + */ +GameLib.D3.Particle.prototype.toApiObject = function() { + + return new GameLib.D3.API.Particle( + this.id, + this.name, + this.lifeTime, + this.elapsed, + GameLib.Utils.IdOrNull(this.mesh), + this.opacityType, + this.opacityFactor, + this.positionOffsetType, + this.positionOffset.toApiObject(), + this.positionOffsetFn, + this.directionType, + this.direction.toApiObject(), + this.directionFn, + this.speedType, + this.speed, + this.scaleType, + this.scale.toApiObject(), + this.scaleFn, + this.rotationType, + this.rotation.toApiObject(), + this.rotationFn, + GameLib.Utils.IdOrNull(this.parentEngine), + GameLib.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Converts from an Object Particle to a GameLib.D3.Particle + * @param graphics GameLib.D3.Graphics + * @param objectParticle Object + * @returns {GameLib.D3.Particle} + * @constructor + */ +GameLib.D3.Particle.FromObject = function(graphics, objectParticle) { + + var apiParticle = GameLib.D3.API.Particle.FromObject(objectParticle); + + return new GameLib.D3.Particle( + graphics, + apiParticle + ); + +}; + +/** + * Renders a scene with a camera + * @param graphics GameLib.D3.Graphics + * @param apiPass GameLib.D3.API.Pass + * @constructor + */ +GameLib.D3.Pass = function ( + graphics, + apiPass +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiPass)) { + apiPass = {}; + } + + if (apiPass instanceof GameLib.D3.Pass) { + return apiPass; + } + + GameLib.D3.API.Pass.call( + this, + apiPass.id, + apiPass.name, + apiPass.passType, + apiPass.camera, + apiPass.scene, + apiPass.renderToScreen, + apiPass.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_PASS, + { + 'camera' : GameLib.D3.Camera, + 'scene' : GameLib.D3.Scene + } + ); +}; + +GameLib.D3.Pass.prototype = Object.create(GameLib.D3.API.Pass.prototype); +GameLib.D3.Pass.prototype.constructor = GameLib.D3.Pass; + +GameLib.D3.Pass.PASS_TYPE_RENDER = 0x1; +GameLib.D3.Pass.PASS_TYPE_COPY_SHADER = 0x2; + +/** + * Create Pass instance + * @returns {*} + */ +GameLib.D3.Pass.prototype.createInstance = function() { + + if (this.passType === GameLib.D3.Pass.PASS_TYPE_RENDER) { + + if (GameLib.Utils.UndefinedOrNull(this.scene)) { + throw new Error('no scene object'); + } + + if (GameLib.Utils.UndefinedOrNull(this.camera)) { + throw new Error('no camera object'); + } + + if (GameLib.Utils.UndefinedOrNull(THREE.RenderPass)) { + throw new Error('no render pass library') + } + + this.instance = new THREE.RenderPass( + this.scene.instance, + this.camera.instance + ); + + } else if (this.passType === GameLib.D3.Pass.PASS_TYPE_COPY_SHADER) { + + if (GameLib.Utils.UndefinedOrNull(THREE.CopyShader)) { + throw new Error('no copyshader library') + } + + this.instance = THREE.CopyShader; + + } else { + console.warn('Render pass not supported yet: ' + this.passType); + throw new Error('Render pass not supported yet: ' + this.passType); + } + + this.instance.renderToScreen = this.renderToScreen; + + GameLib.Component.prototype.createInstance.call(this); + +}; + +/** + * Update Pass instance + */ +GameLib.D3.Pass.prototype.updateInstance = function() { + + if ( + this.passType === GameLib.D3.Pass.PASS_TYPE_RENDER && !(this.instance instanceof THREE.RenderPass)){ + this.createInstance(); + } + + if ( + this.passType === GameLib.D3.Pass.PASS_TYPE_COPY_SHADER && !(this.instance instanceof THREE.CopyShader)){ + this.createInstance(); + } + + this.instance.renderToScreen = this.renderToScreen; + +}; + +/** + * GameLib.D3.Pass to GameLib.D3.API.Pass + * @returns {GameLib.D3.API.Pass} + */ +GameLib.D3.Pass.prototype.toApiObject = function() { + + var apiPass = new GameLib.D3.API.Pass( + this.id, + this.name, + this.passType, + GameLib.Utils.IdOrNull(this.camera), + GameLib.Utils.IdOrNull(this.scene), + this.renderToScreen, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiPass; +}; + +/** + * GameLib.D3.Pass from Object + * @param graphics + * @param objectComponent + * @returns {GameLib.D3.Pass} + * @constructor + */ +GameLib.D3.Pass.FromObject = function(graphics, objectComponent) { + + var apiPass = GameLib.D3.API.Pass.FromObject(objectComponent); + + return new GameLib.D3.Pass( + graphics, + apiPass + ); +}; + +/** + * This component makes the parentEntity (ex. car) follow the path provided by the spline + * @param graphics GameLib.D3.Graphics + * @param apiPathFollowing GameLib.D3.API.PathFollowing + * @constructor + */ +GameLib.D3.PathFollowing = function ( + graphics, + apiPathFollowing +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiPathFollowing)) { + apiPathFollowing = {}; + } + + if (apiPathFollowing instanceof GameLib.D3.PathFollowing) { + return apiPathFollowing; + } + + GameLib.D3.API.PathFollowing.call( + this, + apiPathFollowing.id, + apiPathFollowing.name, + apiPathFollowing.spline, + apiPathFollowing.mesh, + apiPathFollowing.raytraceMesh, + apiPathFollowing.accelleration, + apiPathFollowing.maxSpeed, + apiPathFollowing.baseOffset, + apiPathFollowing.maxOffset, + apiPathFollowing.steeringSpeed, + apiPathFollowing.targetOffset, + apiPathFollowing.currentOffset, + apiPathFollowing.currentPathValue, + apiPathFollowing.currentSpeed, + apiPathFollowing.direction, + apiPathFollowing.raycaster, + apiPathFollowing.currentPosition, + apiPathFollowing.futurePosition, + apiPathFollowing.up, + apiPathFollowing.rotationMatrix, + apiPathFollowing.rotationVector, + apiPathFollowing.parentEntity + ); + + this.baseOffset = new GameLib.Vector3( + this.graphics, + this.baseOffset, + this + ); + + this.maxOffset = new GameLib.Vector3( + this.graphics, + this.maxOffset, + this + ); + + this.targetOffset = new GameLib.Vector3( + this.graphics, + this.targetOffset, + this + ); + + this.currentOffset = new GameLib.Vector3( + this.graphics, + this.currentOffset, + this + ); + + this.raycaster = new GameLib.D3.Raycaster( + this.graphics, + this.raycaster + ); + + this.currentPosition = new GameLib.Vector3( + this.graphics, + this.currentPosition, + this + ); + + this.futurePosition = new GameLib.Vector3( + this.graphics, + this.futurePosition, + this + ); + + this.up = new GameLib.Vector3( + this.graphics, + this.up, + this + ); + + this.rotationMatrix = new GameLib.Matrix4( + this.graphics, + this.rotationMatrix, + this + ); + + this.rotationVector = new GameLib.Quaternion( + this.graphics, + this.rotationVector, + this + ); + + this.mx = new GameLib.Utils.MovingAverage(10); + this.my = new GameLib.Utils.MovingAverage(10); + this.mz = new GameLib.Utils.MovingAverage(10); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_PATH_FOLLOWING, + { + 'spline': GameLib.D3.Spline, + 'mesh' : GameLib.D3.Mesh, + 'raytraceMesh' : GameLib.D3.Mesh + } + ); +}; + +GameLib.D3.PathFollowing.prototype = Object.create(GameLib.D3.API.PathFollowing.prototype); +GameLib.D3.PathFollowing.prototype.constructor = GameLib.D3.PathFollowing; + +GameLib.D3.PathFollowing.prototype.createInstance = function() { + + console.log('GameLib.D3.PathFollowing.prototype.createInstance()'); + + GameLib.Component.prototype.createInstance.call(this); + +}; + +GameLib.D3.PathFollowing.prototype.toApiObject = function() { + + var apiPathFollowing = new GameLib.D3.API.PathFollowing( + this.id, + this.name, + GameLib.Utils.IdOrNull(this.spline), + GameLib.Utils.IdOrNull(this.mesh), + GameLib.Utils.IdOrNull(this.raytraceMesh), + this.accelleration, + this.maxSpeed, + this.baseOffset.toApiObject(), + this.maxOffset.toApiObject(), + this.steeringSpeed, + this.targetOffset.toApiObject(), + this.currentOffset.toApiObject(), + this.currentPathValue, + this.currentSpeed, + this.direction, + this.raycaster.toApiObject(), + this.currentPosition.toApiObject(), + this.futurePosition.toApiObject(), + this.up.toApiObject(), + this.rotationMatrix.toApiObject(), + this.rotationVector.toApiObject(), + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiPathFollowing; +}; + +/** + * Object path following to GameLib.D3.PathFollowing + * @param graphics + * @param objectComponent + * @returns {GameLib.D3.PathFollowing} + * @constructor + */ +GameLib.D3.PathFollowing.FromObject = function(graphics, objectComponent) { + + var apiPathFollowing = GameLib.D3.API.PathFollowing.FromObject(objectComponent); + + return new GameLib.D3.PathFollowing( + graphics, + apiPathFollowing + ); +}; + +/** + * Updates the component + * @param deltaTime + */ +GameLib.D3.PathFollowing.prototype.update = function(deltaTime) { + + if (this.spline && this.mesh && this.raytraceMesh) { + + this.currentSpeed += this.accelleration * deltaTime * this.direction; + if(this.currentSpeed > this.maxSpeed) { + this.currentSpeed = this.maxSpeed; + } + this.grain = (this.currentSpeed / 100.0); + + var currentPosition = this.spline.getPointAt(this.currentPathValue); + + this.currentPosition.x = currentPosition.x; + this.currentPosition.y = currentPosition.y; + this.currentPosition.z = currentPosition.z; + + this.currentPathValue += this.grain; + + if (this.currentPathValue >= 1) { + this.currentPathValue = this.currentPathValue - 1; + } + + if (this.currentPathValue < 0) { + this.currentPathValue = 0.0; + } + + var futurePosition = this.spline.getPointAt(this.currentPathValue); + + this.futurePosition.x = futurePosition.x; + this.futurePosition.y = futurePosition.y; + this.futurePosition.z = futurePosition.z; + + this.raycaster.setPosition( + this.currentPosition + ); + + this.raycaster.setDirection( + { + x : -this.up.x, + y : -this.up.y, + z : -this.up.z + } + ); + + var normal = this.raycaster.getFaceNormal(this.raytraceMesh); + + if (normal) { + this.up.x = this.mx(normal.x); + this.up.y = this.my(normal.y); + this.up.z = this.mz(normal.z); + } + + this.rotationMatrix.lookAt( + this.currentPosition, + this.futurePosition, + this.up + ); + + this.rotationVector.setFromRotationMatrix(this.rotationMatrix); + + this.mesh.position.x = this.futurePosition.x; + this.mesh.position.y = this.futurePosition.y; + this.mesh.position.z = this.futurePosition.z; + + /** + * Update Rotation + */ + this.mesh.quaternion.x = this.rotationVector.x; + this.mesh.quaternion.y = this.rotationVector.y; + this.mesh.quaternion.z = this.rotationVector.z; + this.mesh.quaternion.w = this.rotationVector.w; + } +}; +/** + * World SuperSet - contains the custom world instance + * @constructor + * @param physics + * @param apiWorld + */ +GameLib.D3.PhysicsWorld = function( + physics, + apiWorld +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiWorld)) { + apiWorld = {}; + } + + if (apiWorld instanceof GameLib.D3.PhysicsWorld) { + return apiWorld; + } + + GameLib.D3.API.PhysicsWorld.call( + this, + apiWorld.id, + apiWorld.name, + apiWorld.gravity, + apiWorld.broadphase, + apiWorld.solver, + apiWorld.rigidBodies, + apiWorld.contactMaterials, + apiWorld.allowSleep, + apiWorld.defaultContactMaterial, + apiWorld.parentEntity + ); + + if (this.gravity instanceof GameLib.API.Vector3) { + this.gravity = new GameLib.Vector3( + this.physics, + this.gravity, + this + ); + } + + if (this.broadphase instanceof GameLib.D3.API.Broadphase) { + this.broadphase = new GameLib.D3.Broadphase( + this.physics, + this.broadphase + ); + } + + if (this.solver instanceof GameLib.D3.API.Solver) { + this.solver = new GameLib.D3.Solver( + this.physics, + this.solver + ); + } + + this.rigidBodies = this.rigidBodies.map( + function(rigidBody) { + if (rigidBody instanceof GameLib.D3.API.RigidBody) { + return new GameLib.D3.RigidBody( + this.physics, + rigidBody + ); + } + return rigidBody; + }.bind(this) + ); + + this.contactMaterials = this.contactMaterials.map( + function(contactMaterial) { + if (contactMaterial instanceof GameLib.D3.API.FrictionContactMaterial) { + return new GameLib.D3.FrictionContactMaterial( + this.physics, + contactMaterial + ); + } + return contactMaterial; + }.bind(this) + ); + + if (this.defaultContactMaterial instanceof GameLib.D3.API.FrictionContactMaterial) { + this.defaultContactMaterial = new GameLib.D3.FrictionContactMaterial( + this.physics, + this.defaultContactMaterial + ) + } + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_PHYSICS_WORLD, + { + 'broadphase' : GameLib.D3.Broadphase, + 'solver' : GameLib.D3.Solver, + 'rigidBodies' : [GameLib.D3.RigidBody], + 'contactMaterials' : [GameLib.D3.FrictionContactMaterial], + 'defaultContactMaterial' : GameLib.D3.FrictionContactMaterial + } + ); +}; + +GameLib.D3.PhysicsWorld.prototype = Object.create(GameLib.D3.API.PhysicsWorld.prototype); +GameLib.D3.PhysicsWorld.prototype.constructor = GameLib.D3.PhysicsWorld; + +/** + * private + * @returns {GameLib.D3.PhysicsWorld|GameLib.D3.Physics.World|*} + */ +GameLib.D3.PhysicsWorld.prototype.createInstance = function() { + + if (GameLib.Utils.UndefinedOrNull(this.broadphase)) { + throw new Error('no broadphase'); + } + + if (GameLib.Utils.UndefinedOrNull(this.broadphase.instance)) { + throw new Error('no broadphase instance'); + } + + if (GameLib.Utils.UndefinedOrNull(this.solver)) { + throw new Error('no solver'); + } + + if (GameLib.Utils.UndefinedOrNull(this.solver.instance)) { + throw new Error('no solver instance'); + } + + this.instance = new CANNON.World(); + this.instance.broadphase = this.broadphase.instance; + this.instance.solver = this.solver.instance; + this.instance.gravity = this.gravity.instance; + this.instance.allowSleep = this.allowSleep; + + this.contactMaterials.map( + function (contactMaterial) { + + if (GameLib.Utils.UndefinedOrNull(contactMaterial)) { + throw new Error('no contact material'); + } + + if (GameLib.Utils.UndefinedOrNull(contactMaterial.instance)) { + throw new Error('no contact material instance'); + } + + this.instance.addContactMaterial(contactMaterial.instance); + + }.bind(this) + ); + + this.rigidBodies.map( + function (rigidBody) { + + if (GameLib.Utils.UndefinedOrNull(rigidBody)) { + throw new Error('no rigidbody'); + } + + if (GameLib.Utils.UndefinedOrNull(rigidBody.instance)) { + throw new Error('no rigidbody instance'); + } + + rigidBody.parentWorld = this; + + this.instance.add(rigidBody.instance); + + }.bind(this) + ); + + this.instance.defaultContactMaterial.friction = this.defaultContactMaterial.friction; + this.instance.defaultContactMaterial.restitution = this.defaultContactMaterial.restitution; + this.instance.defaultContactMaterial.contactEquationStiffness = this.defaultContactMaterial.contactEquationStiffness; + this.instance.defaultContactMaterial.contactEquationRelaxation = this.defaultContactMaterial.contactEquationRelaxation; + this.instance.defaultContactMaterial.frictionEquationStiffness = this.defaultContactMaterial.frictionEquationStiffness; + this.instance.defaultContactMaterial.frictionEquationRelaxation = this.defaultContactMaterial.frictionEquationRelaxation; + + GameLib.Component.prototype.createInstance.call(this); +}; + +GameLib.D3.PhysicsWorld.prototype.addRigidBody = function(rigidBody) { + + if (rigidBody && rigidBody.instance) { + + /** + * Add the rigid body to the instance world + */ + this.instance.add(rigidBody.instance); + + /** + * Remember to set the parentWorld for this rigidBody + * @type {GameLib.D3.PhysicsWorld} + */ + rigidBody.parentWorld = this; + + /** + * Ensure this rigidBody is in our rigidBodies array, just not too many times.. + */ + GameLib.Utils.PushUnique(this.rigidBodies, rigidBody); + + } else { + console.warn('Attempt to add rigidBody ' + rigidBody.name + ' without an instance'); + } +}; + +/** + * + * @param rigidBody + */ +GameLib.D3.PhysicsWorld.prototype.removeRigidBody = function(rigidBody) { + + if (!rigidBody instanceof GameLib.D3.RigidBody) { + console.warn('not a rigid body'); + return; + } + + /** + * Remove the instance + */ + if (rigidBody.instance) { + + this.instance.remove(rigidBody.instance); + + } else { + console.warn('Attempt to remove rigidBody ' + rigidBody.name + ' without an instance'); + } + + /** + * Remember to set the parentWorld for this rigidBody + * @type {GameLib.D3.PhysicsWorld} + */ + rigidBody.parentWorld = null; + + /** + * Remove from this rigidBodies array + */ + var index = this.rigidBodies.indexOf(rigidBody); + + if (index !== -1) { + this.rigidBodies.splice(index, 1); + } else { + console.warn('could not remove a rigidbody from an array where it should have existed'); + } + +}; + + +/** + * + */ +GameLib.D3.PhysicsWorld.prototype.updateInstance = function() { + + if (!this.instance) { + console.log('no world instance'); + return; + } + + this.instance.broadphase = this.broadphase.instance; + this.instance.solver = this.solver.instance; + this.instance.gravity = this.gravity.instance; + this.instance.allowSleep = this.allowSleep; + + this.instance.defaultContactMaterial.friction = this.defaultContactMaterial.friction; + this.instance.defaultContactMaterial.restitution = this.defaultContactMaterial.restitution; + this.instance.defaultContactMaterial.contactEquationStiffness = this.defaultContactMaterial.contactEquationStiffness; + this.instance.defaultContactMaterial.contactEquationRelaxation = this.defaultContactMaterial.contactEquationRelaxation; + this.instance.defaultContactMaterial.frictionEquationStiffness = this.defaultContactMaterial.frictionEquationStiffness; + this.instance.defaultContactMaterial.frictionEquationRelaxation = this.defaultContactMaterial.frictionEquationRelaxation; + +}; + +/** + * GameLib.D3.PhysicsWorld to GameLib.D3.API.PhysicsWorld + * @returns {GameLib.D3.API.PhysicsWorld} + */ +GameLib.D3.PhysicsWorld.prototype.toApiObject = function() { + + var apiWorld = new GameLib.D3.API.PhysicsWorld( + this.id, + this.name, + this.gravity.toApiObject(), + GameLib.Utils.IdOrNull(this.broadphase), + GameLib.Utils.IdOrNull(this.solver), + this.rigidBodies.map(function(body){ + return GameLib.Utils.IdOrNull(body); + }), + this.contactMaterials.map(function(contactMaterial){ + return GameLib.Utils.IdOrNull(contactMaterial); + }), + this.allowSleep, + GameLib.Utils.IdOrNull(this.defaultContactMaterial), + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiWorld; +}; + +/** + * GameLib.D3.PhysicsWorld from Object World + * @param graphics + * @param objectComponent + * @returns {GameLib.D3.PhysicsWorld} + * @constructor + */ +GameLib.D3.PhysicsWorld.FromObject = function(graphics, objectComponent) { + var apiWorld = GameLib.D3.API.PhysicsWorld.FromObject(objectComponent); + return new GameLib.D3.PhysicsWorld( + graphics, + apiWorld + ); +}; + +// +// GameLib.D3.PhysicsWorld.prototype.step = function( +// fixedStep, +// dtStep +// ) { +// +// }; +// +// GameLib.D3.PhysicsWorld.prototype.generateWireframeViewTriangleMesh = function( +// graphics, +// triangleMeshShape, +// normalLength, +// scale, +// opacity, +// wireframeColor +// ) { +// graphics.isNotThreeThrow(); +// this.engine.isNotCannonThrow(); +// +// if(typeof normalLength == 'undefined') { +// normalLength = 10; +// } +// +// if(typeof scale == 'undefined') { +// scale = new graphics.instance.Vector3(1, 1, 1); +// } +// +// if(typeof opacity == 'undefined') { +// opacity = 0.5; +// } +// +// if(typeof wireframeColor == 'undefined') { +// wireframeColor = 0xfefefe; +// } +// +// var graphicsGeometry = new graphics.instance.Geometry(); +// +// var wireframeMesh = new graphics.instance.Mesh( +// graphicsGeometry, +// new graphics.instance.MeshBasicMaterial({ +// color: wireframeColor, +// wireframe: true, +// opacity: opacity +// }) +// ); +// +// for(var v = 0, l = triangleMeshShape.instance.vertices.length / 3; v < l; ++v) { +// graphicsGeometry.vertices.push( +// new graphics.instance.Vector3( +// triangleMeshShape.instance.vertices[v * 3], +// triangleMeshShape.instance.vertices[v * 3 + 1], +// triangleMeshShape.instance.vertices[v * 3 + 2] +// ) +// ); +// } +// +// for(var i = 0, l = triangleMeshShape.instance.indices.length / 3; i < l; ++i) { +// var i0 = triangleMeshShape.instance.indices[i * 3]; +// var i1 = triangleMeshShape.instance.indices[i * 3 + 1]; +// var i2 = triangleMeshShape.instance.indices[i * 3 + 2]; +// +// graphicsGeometry.faces.push( +// new graphics.instance.Face3( +// i0, +// i1, +// i2 +// ) +// ); +// +// // Center point on the current triangle +// +// var centroid = new graphics.instance.Vector3() +// .add(graphicsGeometry.vertices[i0]) +// .add(graphicsGeometry.vertices[i1]) +// .add(graphicsGeometry.vertices[i2]) +// .divideScalar(3); +// +// // Get the normal from the mesh shape itself +// var normal = new this.engine.instance.Vec3(); +// triangleMeshShape.instance.getNormal(i , normal); +// +// var arrow = new graphics.instance.ArrowHelper( +// new graphics.instance.Vector3( +// normal.x, +// normal.y, +// normal.z +// ), +// centroid, +// normalLength, +// new graphics.instance.Color( +// normal.x, +// normal.y, +// normal.z +// ) +// ); +// wireframeMesh.add( arrow ); +// } +// +// wireframeMesh.scale.x = scale.x; +// wireframeMesh.scale.y = scale.y; +// wireframeMesh.scale.z = scale.z; +// +// return wireframeMesh; +// }; +// +// /** +// * @param convexPolyMeshShape GameLib.D3.Shape +// * @param normalLength Number +// * @param scale GameLib.API.Vector3 +// * @param opacity Number +// * @param wireframeColor HexCode +// * @param graphics THREE +// * @returns {THREE.Mesh|this.meshes} +// * @constructor +// */ +// GameLib.D3.PhysicsWorld.prototype.generateWireframeViewConvexPolyMesh = function( +// graphics, +// convexPolyMeshShape, +// normalLength, +// scale, +// opacity, +// wireframeColor +// ) { +// graphics.isNotThreeThrow(); +// this.engine.isNotCannonThrow(); +// +// if(typeof normalLength == 'undefined') { +// normalLength = 10; +// } +// +// if(typeof scale == 'undefined') { +// scale = new graphics.instance.Vector3(1, 1, 1); +// } +// +// if(typeof opacity == 'undefined') { +// opacity = 0.5; +// } +// +// if(typeof wireframeColor == 'undefined') { +// wireframeColor = 0xfefefe; +// } +// +// +// var graphicsGeometry = new graphics.instance.Geometry(); +// var wireframeMesh = new graphics.instance.Mesh( +// graphicsGeometry, +// new graphics.instance.MeshBasicMaterial({ +// color: wireframeColor, +// wireframe: true, +// opacity: opacity +// }) +// ); +// +// for(var i = 0, l = convexPolyMeshShape.instance.vertices.length; i < l; i++) { +// var vertex = convexPolyMeshShape.instance.vertices[i]; +// graphicsGeometry.vertices.push(new graphics.instance.Vector3(vertex.x, vertex.y, vertex.z)); +// } +// +// for(var i = 0, l = convexPolyMeshShape.instance.faces.length; i < l; i++) { +// var face = convexPolyMeshShape.instance.faces[i]; +// +// var i0 = face[0]; +// var i1 = face[1]; +// var i2 = face[2]; +// +// graphicsGeometry.faces.push(new graphics.instance.Face3(i0, i1, i2)); +// +// // Center point on the current triangle +// var centroid = new graphics.instance.Vector3() +// .add(graphicsGeometry.vertices[i0]) +// .add(graphicsGeometry.vertices[i1]) +// .add(graphicsGeometry.vertices[i2]) +// .divideScalar(3); +// +// var normalVec3 = convexPolyMeshShape.instance.faceNormals[i]; +// var normal = new graphics.instance.Vector3( +// normalVec3.x, +// normalVec3.y, +// normalVec3.z +// ); +// +// var arrow = new graphics.instance.ArrowHelper( +// normal, +// centroid, +// normalLength, +// new graphics.instance.Color( +// normal.x, +// normal.y, +// normal.z +// ) +// ); +// +// wireframeMesh.add( arrow ); +// } +// +// wireframeMesh.scale.x = scale.x; +// wireframeMesh.scale.y = scale.y; +// wireframeMesh.scale.z = scale.z; +// +// return wireframeMesh; +// }; +// +// /** +// * @param graphics GameLib.D3.Graphics +// * @param graphicsMesh THREE.Mesh +// * @param mass Number +// * @param friction Number +// * @param createCollisionSubMeshes Boolean +// * @param facesPerSubsection Number +// * @param subsectionsToMerge Number +// * @returns {Object} +// * @constructor +// */ +// GameLib.D3.PhysicsWorld.prototype.generateTriangleMeshShapeDivided = function( +// graphics, +// graphicsMesh, +// mass, +// friction, +// createCollisionSubMeshes, +// facesPerSubsection, +// subsectionsToMerge +// ) { +// graphics.isNotThreeThrow(); +// this.engine.isNotCannonThrow(); +// +// if(mass == null || typeof mass == 'undefined') { +// mass = 0; +// } +// +// if(friction == null || typeof friction == 'undefined') { +// friction = 10; +// } +// +// if(createCollisionSubMeshes == null || typeof createCollisionSubMeshes == 'undefined') { +// createCollisionSubMeshes = false; +// } +// +// var processedFaces = 0; +// var facesPerSubSection = facesPerSubsection || 0; +// var subMeshesToMerge = subsectionsToMerge || 0; +// var totalAmtFaces = graphicsMesh.geometry.faces.length; +// var facesToProcess = createCollisionSubMeshes ? (subMeshesToMerge * facesPerSubSection) : totalAmtFaces; +// +// var pairs = []; // output +// +// var vertices = []; +// var indicies = []; +// +// for(var i = 0; i <= totalAmtFaces; i++) { +// if(processedFaces == facesToProcess || i == totalAmtFaces) { +// +// var body = null; +// +// var meshShape = new this.engine.instance.Trimesh(vertices, indicies); +// +// meshShape.setScale(new this.engine.instance.Vec3( +// graphicsMesh.scale.x, +// graphicsMesh.scale.y, +// graphicsMesh.scale.z +// )); +// +// meshShape.updateAABB(); +// meshShape.updateNormals(); +// meshShape.updateEdges(); +// meshShape.updateBoundingSphereRadius(); +// meshShape.updateTree(); +// +// body = new this.engine.instance.Body({ +// mass: mass, +// friction: friction +// }); +// body.addShape(meshShape); +// +// pairs.push({ +// threeObject : createCollisionSubMeshes ? null : graphicsMesh, +// physicsObject : body +// }); +// +// vertices = []; +// indicies = []; +// processedFaces = 0; +// +// if(i == totalAmtFaces) { +// return pairs; +// } +// } +// +// var face = graphicsMesh.geometry.faces[i]; +// indicies.push(indicies.length); +// indicies.push(indicies.length); +// indicies.push(indicies.length); +// +// var v0 = graphicsMesh.geometry.vertices[face.a]; +// var v1 = graphicsMesh.geometry.vertices[face.b]; +// var v2 = graphicsMesh.geometry.vertices[face.c]; +// +// vertices.push(v0.x, v0.y, v0.z); +// vertices.push(v1.x, v1.y, v1.z); +// vertices.push(v2.x, v2.y, v2.z); +// +// processedFaces++; +// } +// }; +// +// GameLib.D3.PhysicsWorld.prototype.generateConvexPolyShape = function( +// graphics, +// mesh +// ) { +// var processedFaces = 0; +// var facesPerSubSection = 2; // *2 -> SUBDIVISION MESH +// var subMeshesToMerge = 4; // *2 -> SUBDIVISION MESH +// var facesToProcess = subMeshesToMerge * facesPerSubSection; +// +// var vertices = []; +// var indicies = []; +// +// for(var i = 0; i <= mesh.geometry.faces.length; i++) { +// if(processedFaces == facesToProcess || i == mesh.geometry.faces.length) { +// +// // try and create convex poly........... +// var convexIndices = []; +// for(var index = 0; index < indicies.length / 3; index++) { +// convexIndices.push([ indicies[index * 3], indicies[index * 3 + 1], indicies[index * 3 + 2] ]); +// } +// +// var convexVertices = []; +// for(var vert = 0; vert < vertices.length / 3; vert++) { +// convexVertices[vert] = new CANNON.Vec3(vertices[vert * 3] * mesh.scale.x, vertices[vert * 3 + 1] * mesh.scale.y, vertices[vert * 3 + 2] * mesh.scale.z); +// } +// +// var meshShape = new GameLib.D3.Shape(this.engine, GameLib.D3.Shape.SHAPE_TYPE_CONVEX_HULL, {x:1,y:1,z:1},convexVertices, convexIndices); +// +// var body = new GameLib.D3.RigidBody(this.engine, 0, 1); +// body.addShape(meshShape); +// +// this.addRigidBody(body); +// +// vertices = []; +// indicies = []; +// processedFaces = 0; +// +// console.log("SPLIT MESH TO CONVEX POLY"); +// +// if(i == mesh.geometry.faces.length) { +// break; +// } +// } +// +// var face = mesh.geometry.faces[i]; +// indicies.push(indicies.length); +// indicies.push(indicies.length); +// indicies.push(indicies.length); +// +// var v0 = mesh.geometry.vertices[face.a]; +// var v1 = mesh.geometry.vertices[face.b]; +// var v2 = mesh.geometry.vertices[face.c]; +// +// vertices.push(v0.x, v0.y, v0.z); +// vertices.push(v1.x, v1.y, v1.z); +// vertices.push(v2.x, v2.y, v2.z); +// +// processedFaces++; +// } +// +// }; +// +// /** +// * @param graphics GameLib.D3.Graphics +// * @param graphicsMesh THREE.Mesh +// * @returns {GameLib.D3.Shape} +// * @constructor +// */ +// GameLib.D3.PhysicsWorld.prototype.generateTriangleMeshShape = function( +// graphics, +// graphicsMesh +// ) { +// +// // - - - - - - - - - - - - - - - - - - - - - - - - - +// // Note: I did not test this yet with the API data. +// // - - - - - - - - - - - - - - - - - - - - - - - - - +// +// var scaledVertices = []; +// for(var i = 0, l = graphicsMesh.geometry.vertices.length; i < l; i++) { +// +// var vertex = graphicsMesh.geometry.vertices[i]; +// +// scaledVertices.push(new this.engine.instance.Vec3( +// vertex.x * graphicsMesh.scale.x, +// vertex.y * graphicsMesh.scale.y, +// vertex.z * graphicsMesh.scale.z +// )); +// } +// +// var triangleFaces = []; +// for(var f = 0, fl = graphicsMesh.geometry.faces.length; f < fl; f++) { +// var i0 = graphicsMesh.geometry.faces[f].a; +// var i1 = graphicsMesh.geometry.faces[f].b; +// var i2 = graphicsMesh.geometry.faces[f].c; +// +// triangleFaces.push([ +// i0, i1, i2 +// ]); +// } +// +// // - - - - - - - - - - - - - - - - - - - +// // Create collision mesh +// // - - - - - - - - - - - - - - - - - - - +// +// var reindexedFaces = {}; +// var vertices = []; +// var faces = []; +// +// var processedFaces = 0; +// var totalFacesToProcess = triangleFaces.length; +// var flLastIndex = 0; +// +// for(var f = 0; f < totalFacesToProcess; f++) { +// +// var i0 = triangleFaces[f][0]; +// var i1 = triangleFaces[f][1]; +// var i2 = triangleFaces[f][2]; +// +// if(typeof reindexedFaces[i0] === 'undefined') { +// vertices.push(scaledVertices[i0].x, scaledVertices[i0].y, scaledVertices[i0].z); +// reindexedFaces[i0] = flLastIndex; +// flLastIndex++; +// } +// +// if(typeof reindexedFaces[i1] === 'undefined') { +// vertices.push(scaledVertices[i1].x, scaledVertices[i1].y, scaledVertices[i1].z); +// reindexedFaces[i1] = flLastIndex; +// flLastIndex++; +// } +// +// if(typeof reindexedFaces[i2] === 'undefined') { +// vertices.push(scaledVertices[i2].x, scaledVertices[i2].y, scaledVertices[i2].z); +// reindexedFaces[i2] = flLastIndex; +// flLastIndex++; +// } +// +// faces.push(reindexedFaces[i0], reindexedFaces[i1], reindexedFaces[i2]); +// +// processedFaces++; +// } +// +// return new GameLib.D3.Shape(this.engine, GameLib.D3.Shape.SHAPE_TYPE_TRIMESH, {x : 1, y : 1, z : 1}, vertices, faces); +// }; +// +// /** +// * @param triangleMeshBody GameLib.D3.RigidBody +// * @param rayscale Number +// * @param maxTriangleDistance Number +// * @param createCompoundShape Boolean +// * @param graphics GameLib.D3.Graphics +// * @param triangleMeshShapes GameLib.D3.Shape[] +// * @param createDebugView Boolean +// * @returns {GameLib.D3.RigidBody} +// * @constructor +// */ +// GameLib.D3.PhysicsWorld.prototype.fixupTriangleMeshShape = function( +// triangleMeshBody, +// triangleMeshShapes, +// rayscale, +// maxTriangleDistance, +// createCompoundShape, +// graphics, +// createDebugView +// ) { +// this.engine.isNotCannonThrow(); +// +// graphics.isNotThreeThrow(); +// +// if(rayscale == null || typeof rayscale == 'undefined' || rayscale == 0) { +// rayscale = 10; +// } +// +// if(maxTriangleDistance == null || typeof maxTriangleDistance == 'undefined') { +// maxTriangleDistance = 13; +// } +// +// var world = this.instance; +// +// var raycastResult = new this.engine.instance.RaycastResult(); +// +// var brokenFaceIndicators = []; +// +// var totalFaces = 0; +// var totalBrokenFaces = 0; +// var totalFixedFaces = 0; +// var fixedTriangleMeshObjects = []; +// +// for(var i in triangleMeshShapes) { +// var trimesh = triangleMeshShapes[i].instance; +// +// var brokenFaces = []; +// totalFaces += (trimesh.indices.length / 3); +// +// for(var face = 0; face < trimesh.indices.length / 3; face++) { +// +// var i0 = trimesh.indices[face * 3]; +// var i1 = trimesh.indices[face * 3 + 1]; +// var i2 = trimesh.indices[face * 3 + 2]; +// +// var triangleCenterPoint = new graphics.instance.Vector3() +// .add(new graphics.instance.Vector3( +// trimesh.vertices[i0 * 3], +// trimesh.vertices[i0 * 3 + 1], +// trimesh.vertices[i0 * 3 + 2]) +// ) +// .add(new graphics.instance.Vector3( +// trimesh.vertices[i1 * 3], +// trimesh.vertices[i1 * 3 + 1], +// trimesh.vertices[i1 * 3 + 2]) +// ) +// .add(new graphics.instance.Vector3( +// trimesh.vertices[i2 * 3], +// trimesh.vertices[i2 * 3 + 1], +// trimesh.vertices[i2 * 3 + 2]) +// ) +// .divideScalar(3); +// +// var triangleNormal = new this.engine.instance.Vec3(); +// trimesh.getNormal(face , triangleNormal); +// +// var from = new this.engine.instance.Vec3( +// triangleCenterPoint.x + triangleNormal.x, +// triangleCenterPoint.y + triangleNormal.y, +// triangleCenterPoint.z + triangleNormal.z +// ); +// +// var to = new this.engine.instance.Vec3( +// from.x - triangleNormal.x * rayscale, +// from.y - triangleNormal.y * rayscale, +// from.z - triangleNormal.z * rayscale +// ); +// +// world.raycastClosest(from, to, {}, raycastResult); +// +// // visualize results +// if(createDebugView){ +// var graphicsGeometry = new graphics.instance.Geometry(); +// var wireframeMesh = new graphics.instance.Mesh( +// graphicsGeometry, +// new graphics.instance.MeshBasicMaterial({ +// color: 0xff0000, +// wireframe: true, +// opacity: 1 +// }) +// ); +// +// var arrow = new graphics.instance.ArrowHelper( +// new graphics.instance.Vector3( +// triangleNormal.x, +// triangleNormal.y, +// triangleNormal.z +// ).normalize(), +// +// new graphics.instance.Vector3( +// from.x, +// from.y, +// from.z +// ), +// +// rayscale / 2, +// raycastResult.hasHit ? new graphics.instance.Color(0, 1, 0) +// : new graphics.instance.Color(1, 0, 0) +// ); +// +// wireframeMesh.add( arrow ); +// brokenFaceIndicators.push(wireframeMesh); +// } +// +// if(!raycastResult.hasHit) { +// brokenFaces.push({ +// faceIndex : face, +// +// vertices : [ +// new this.engine.instance.Vec3( +// trimesh.vertices[i0 * 3], +// trimesh.vertices[i0 * 3 + 1], +// trimesh.vertices[i0 * 3 + 2] +// ), +// +// new this.engine.instance.Vec3( +// trimesh.vertices[i1 * 3], +// trimesh.vertices[i1 * 3 + 1], +// trimesh.vertices[i1 * 3 + 2] +// ), +// +// new this.engine.instance.Vec3( +// trimesh.vertices[i2 * 3], +// trimesh.vertices[i2 * 3 + 1], +// trimesh.vertices[i2 * 3 + 2] +// ) +// ], +// +// center : triangleCenterPoint, +// +// parent : trimesh +// }); +// } +// } +// +// // fix up broken faces +// +// var bFaceIndexed = {}; +// for(var b = 0; b < brokenFaces.length; b++) { +// var brokenFace = brokenFaces[b]; +// +// if(brokenFace.marked) { +// continue; +// } +// +// bFaceIndexed[b] = { +// indices : [], +// vertices : [] +// }; +// +// var indicesAmount = bFaceIndexed[b].indices.length; +// +// // add the current broken face itself to the array +// bFaceIndexed[b].indices.push( +// indicesAmount, +// indicesAmount + 1, +// indicesAmount + 2 +// ); +// +// bFaceIndexed[b].vertices.push( +// brokenFace.vertices[0].x, +// brokenFace.vertices[0].y, +// brokenFace.vertices[0].z +// ); +// +// bFaceIndexed[b].vertices.push( +// brokenFace.vertices[1].x, +// brokenFace.vertices[1].y, +// brokenFace.vertices[1].z +// ); +// +// bFaceIndexed[b].vertices.push( +// brokenFace.vertices[2].x, +// brokenFace.vertices[2].y, +// brokenFace.vertices[2].z +// ); +// +// for(var bb = 0; bb < brokenFaces.length; bb++) { +// +// if(bb == b) { +// continue; +// } +// +// var otherBrokenFace = brokenFaces[bb]; +// +// if(otherBrokenFace.marked) { +// continue; +// } +// +// if(brokenFace.center.distanceTo(otherBrokenFace.center) <= maxTriangleDistance) { +// var indicesAmount = bFaceIndexed[b].indices.length; +// +// bFaceIndexed[b].indices.push( +// indicesAmount, +// indicesAmount + 1, +// indicesAmount + 2 +// ); +// +// bFaceIndexed[b].vertices.push( +// otherBrokenFace.vertices[0].x, +// otherBrokenFace.vertices[0].y, +// otherBrokenFace.vertices[0].z +// ); +// +// bFaceIndexed[b].vertices.push( +// otherBrokenFace.vertices[1].x, +// otherBrokenFace.vertices[1].y, +// otherBrokenFace.vertices[1].z +// ); +// +// bFaceIndexed[b].vertices.push( +// otherBrokenFace.vertices[2].x, +// otherBrokenFace.vertices[2].y, +// otherBrokenFace.vertices[2].z +// ); +// +// otherBrokenFace.marked = true; +// } +// } +// } +// +// +// // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// // Decide if we want to create new rigiwyd bodies, or create a compound mesh +// // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// +// for(var e in bFaceIndexed) { +// var element = bFaceIndexed[e]; +// +// var shape = new GameLib.D3.Shape(this.engine, GameLib.D3.Shape.SHAPE_TYPE_TRIMESH, { x : 1, y : 1, z : 1 }, element.vertices, element.indices); +// +// if(createCompoundShape) { +// triangleMeshBody.addShape(shape); +// } else { +// +// var body = new GameLib.D3.RigidBody(this.engine, 0, 12); +// +// //TODO: this is just a hack. +// body.instance.collisionFilterGroup = 1 | 2; // puts this body in two groups. +// +// body.addShape(shape); +// this.addRigidBody(body); +// } +// +// fixedTriangleMeshObjects.push(shape); +// totalFixedFaces += element.indices.length / 3; +// } +// +// // TODO: remove duplicate indices +// /*trimesh.updateNormals(); +// trimesh.updateEdges(); +// trimesh.updateTree(); +// trimesh.updateAABB(); +// trimesh.updateBoundingSphereRadius();*/ +// +// // map faceIndex to flat face index (faceIndex * 3) +0, 1, 2 -> triangle indices +// console.log("i = " + i, brokenFaces); +// totalBrokenFaces += brokenFaces.length; +// } +// +// console.log("total faces", totalFaces); +// console.log("total broken faces", totalBrokenFaces); +// console.log("broken faces in percent", (totalBrokenFaces / totalFaces) * 100); +// console.log("total fixed faces", totalFixedFaces); +// console.log("fixed triangle mesh shapes", fixedTriangleMeshObjects.length); +// +// return { +// brokenFaceIndicators : brokenFaceIndicators, +// fixedTriangleMeshShapes : fixedTriangleMeshObjects +// }; +// }; +/** + * Physics + * @param id + * @param name + * @param physicsType + * @constructor + */ +GameLib.D3.Physics = function Physics( + id, + name, + physicsType +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Physics (' + id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(physicsType)) { + physicsType = GameLib.D3.Physics.PHYSICS_TYPE_CANNON; + } + this.physicsType = physicsType; + + this.createInstance(); +}; + +/** + * GameLib.D3.Physics Types + * @type {number} + */ +GameLib.D3.Physics.PHYSICS_TYPE_CANNON = 0x1; + +/** + * @returns {THREE.Physics} + */ +GameLib.D3.Physics.prototype.createInstance = function() { + this.instance = CANNON; +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Physics.prototype.updateInstance = function() { +}; + +/** + * Logs a warning and throws an error if not cannon + */ +GameLib.D3.Physics.prototype.isNotCannonThrow = function() { + if (this.physicsType !== GameLib.D3.Physics.PHYSICS_TYPE_CANNON) { + console.warn('Only CANNON supported for this function'); + throw new Error('Only CANNON supported for this function'); + } +}; + +/** + * Contains a Poly vertex data structure + * @param localIndex + * @param mvertIndex + * @param uv GameLib.API.Vector2 + * @param materialIndex + * @param edgeIndex + * @constructor + */ +GameLib.D3.PolyVertex = function( + localIndex, + mvertIndex, + uv, + materialIndex, + edgeIndex +) { + this.localIndex = localIndex; + this.mvertIndex = mvertIndex; + this.uv = uv; + this.materialIndex = materialIndex; + this.edgeIndex = edgeIndex; +}; + +/** + * Clone a PolyVertex + * @returns {GameLib.D3.PolyVertex} + */ +GameLib.D3.PolyVertex.prototype.clone = function() { + return new GameLib.D3.PolyVertex( + this.localIndex, + this.mvertIndex, + this.uv.copy(), + this.materialIndex, + this.edgeIndex + ) +}; +/** + * RaycastVehicle Runtime + * @param physics GameLib.D3.Graphics + * @param apiRaycastVehicle GameLib.D3.API.RaycastVehicle + * @constructor + */ +GameLib.D3.RaycastVehicle = function ( + physics, + apiRaycastVehicle +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiRaycastVehicle)) { + apiRaycastVehicle = {}; + } + + if (apiRaycastVehicle instanceof GameLib.D3.RaycastVehicle) { + return apiRaycastVehicle; + } + + GameLib.D3.API.RaycastVehicle.call( + this, + apiRaycastVehicle.id, + apiRaycastVehicle.name, + apiRaycastVehicle.chassis, + apiRaycastVehicle.wheels, + apiRaycastVehicle.raycastWheels, + apiRaycastVehicle.parentWorld, + apiRaycastVehicle.parentEntity + ); + + if (this.chassis instanceof GameLib.D3.API.RaycastVehicle) { + this.chassis = new GameLib.D3.RaycastVehicle( + this.physics, + this.chassis + ) + } + + this.wheels = this.wheels.map(function(wheel){ + if (wheel instanceof GameLib.D3.API.RigidBody) { + return new GameLib.D3.RigidBody( + this.physics, + wheel + ) + } else { + return wheel; + } + }.bind(this)); + + this.raycastWheels = this.raycastWheels.map(function(raycastWheel){ + if (raycastWheel instanceof GameLib.D3.API.RaycastWheel) { + return new GameLib.D3.RaycastWheel( + this.physics, + raycastWheel + ) + } else { + return raycastWheel; + } + }.bind(this)); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_RAYCAST_VEHICLE, + { + 'chassis' : GameLib.D3.RigidBody, + 'wheels' : [GameLib.D3.RigidBody], + 'raycastWheels' : [GameLib.D3.RaycastWheel], + 'parentWorld' : GameLib.D3.PhysicsWorld + } + ); +}; + +GameLib.D3.RaycastVehicle.prototype = Object.create(GameLib.D3.API.RaycastVehicle.prototype); +GameLib.D3.RaycastVehicle.prototype.constructor = GameLib.D3.RaycastVehicle; + +/** + * + * @returns {*} + */ +GameLib.D3.RaycastVehicle.prototype.createInstance = function() { + + /** + * At this point - even though this component exists - the chassis could maybe not been have assigned, failed to + * register as a dependency, and therefore is not present at the time of createInstance() - we will need to call + * delayedInstance somehow... + * @type {GameLib.D3.RaycastVehicle|GameLib.D3.API.RaycastVehicle|*} + */ + + if (GameLib.Utils.UndefinedOrNull(this.chassis)) { + throw new Error('no chassis'); + } + + if (GameLib.Utils.UndefinedOrNull(this.chassis.instance)) { + throw new Error('no chassis instance'); + } + + if (GameLib.Utils.UndefinedOrNull(this.parentWorld)) { + throw new Error('no parent world'); + } + + if (GameLib.Utils.UndefinedOrNull(this.parentWorld.instance)) { + throw new Error('no parent world instance'); + } + + this.instance = new CANNON.RaycastVehicle({ + chassisBody: this.chassis.instance + }); + + this.raycastWheels.map( + function(wheel){ + + if (GameLib.Utils.UndefinedOrNull(wheel)) { + throw new Error('no wheel'); + } + + if (GameLib.Utils.UndefinedOrNull(wheel.instance)) { + throw new Error('no wheel instance'); + } + + this.instance.addWheel(wheel.instance); + + }.bind(this) + ); + + this.instance.addToWorld(this.parentWorld.instance); + + GameLib.Component.prototype.createInstance.call(this); + +}; + +GameLib.D3.RaycastVehicle.prototype.updateInstance = function() { + // this.instance.chassisBody = this.chassis.instance; + //TODO: add / remove wheels? + console.log('TODO: update raycast vehicle instance'); +}; + +/** + * GameLib.D3.RaycastVehicle to GameLib.D3.API.RaycastVehicle + * @returns {GameLib.D3.API.RaycastVehicle} + */ +GameLib.D3.RaycastVehicle.prototype.toApiObject = function() { + + var apiRaycastVehicle = new GameLib.D3.API.RaycastVehicle( + this.id, + this.name, + GameLib.Utils.IdOrNull(this.chassis), + this.wheels.map(function(wheel){ + return GameLib.Utils.IdOrNull(wheel); + }), + this.raycastWheels.map(function(raycastWheel){ + return GameLib.Utils.IdOrNull(raycastWheel); + }), + GameLib.Utils.IdOrNull(this.parentWorld), + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiRaycastVehicle; +}; + +/** + * GameLib.D3.RaycastVehicle from Object RaycastVehicle + * @param physics + * @param objectComponent + * @returns {GameLib.D3.RaycastVehicle} + * @constructor + */ +GameLib.D3.RaycastVehicle.FromObject = function(physics, objectComponent) { + + var apiRaycastVehicle = GameLib.D3.API.RaycastVehicle.FromObject(objectComponent); + + return new GameLib.D3.RaycastVehicle( + physics, + apiRaycastVehicle + ); +}; + +/** + * RaycastWheel Runtime + * @param physics GameLib.D3.Graphics + * @param apiRaycastWheel GameLib.D3.API.RaycastWheel + * @constructor + */ +GameLib.D3.RaycastWheel = function ( + physics, + apiRaycastWheel +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiRaycastWheel)) { + apiRaycastWheel = {}; + } + + if (apiRaycastWheel instanceof GameLib.D3.RaycastWheel) { + return apiRaycastWheel; + } + + GameLib.D3.API.RaycastWheel.call( + this, + apiRaycastWheel.id, + apiRaycastWheel.name, + apiRaycastWheel.radius, + apiRaycastWheel.directionLocal, + apiRaycastWheel.suspensionStiffness, + apiRaycastWheel.suspensionRestLength, + apiRaycastWheel.frictionSlip, + apiRaycastWheel.dampingRelaxation, + apiRaycastWheel.dampingCompression, + apiRaycastWheel.maxSuspensionForce, + apiRaycastWheel.rollInfluence, + apiRaycastWheel.axleLocal, + apiRaycastWheel.chassisConnectionPointLocal, + apiRaycastWheel.maxSuspensionTravel, + apiRaycastWheel.customSlidingRotationalSpeed, + apiRaycastWheel.useCustomSlidingRotationalSpeed, + apiRaycastWheel.parentEntity, + apiRaycastWheel.parentMesh + ); + + this.directionLocal = new GameLib.Vector3( + this.physics, + this.directionLocal, + this + ); + + this.axleLocal = new GameLib.Vector3( + this.physics, + this.axleLocal, + this + ); + + this.chassisConnectionPointLocal = new GameLib.Vector3( + this.physics, + this.chassisConnectionPointLocal, + this + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_RAYCAST_WHEEL, + { + 'parentMesh' : GameLib.D3.Mesh + } + ); +}; + +GameLib.D3.RaycastWheel.prototype = Object.create(GameLib.D3.API.RaycastWheel.prototype); +GameLib.D3.RaycastWheel.prototype.constructor = GameLib.D3.RaycastWheel; + +/** + * + * @returns {*} + */ +GameLib.D3.RaycastWheel.prototype.createInstance = function() { + + this.instance = { + radius: this.radius, + directionLocal: this.directionLocal.instance, + suspensionStiffness: this.suspensionStiffness, + suspensionRestLength: this.suspensionRestLength, + frictionSlip: this.frictionSlip, + dampingRelaxation: this.dampingRelaxation, + dampingCompression: this.dampingCompression, + maxSuspensionForce: this.maxSuspensionForce, + rollInfluence: this.rollInfluence, + axleLocal: this.axleLocal.instance, + chassisConnectionPointLocal: this.chassisConnectionPointLocal.instance, + maxSuspensionTravel: this.maxSuspensionTravel, + customSlidingRotationalSpeed: this.customSlidingRotationalSpeed, + useCustomSlidingRotationalSpeed: this.useCustomSlidingRotationalSpeed + }; + + GameLib.Component.prototype.createInstance.call(this); +}; + +GameLib.D3.RaycastWheel.prototype.updateInstance = function() { + this.instance.radius = this.radius; + this.instance.directionLocal = this.directionLocal.instance; + this.instance.suspensionStiffness = this.suspensionStiffness; + this.instance.suspensionRestLength = this.suspensionRestLength; + this.instance.frictionSlip = this.frictionSlip; + this.instance.dampingRelaxation = this.dampingRelaxation; + this.instance.dampingCompression = this.dampingCompression; + this.instance.maxSuspensionForce = this.maxSuspensionForce; + this.instance.rollInfluence = this.rollInfluence; + this.instance.axleLocal = this.axleLocal.instance; + this.instance.chassisConnectionPointLocal = this.chassisConnectionPointLocal.instance; + this.instance.maxSuspensionTravel = this.maxSuspensionTravel; + this.instance.customSlidingRotationalSpeed = this.customSlidingRotationalSpeed; + this.instance.useCustomSlidingRotationalSpeed = this.useCustomSlidingRotationalSpeed; +}; + +/** + * GameLib.D3.RaycastWheel to GameLib.D3.API.RaycastWheel + * @returns {GameLib.D3.API.RaycastWheel} + */ +GameLib.D3.RaycastWheel.prototype.toApiObject = function() { + + var apiRaycastWheel = new GameLib.D3.API.RaycastWheel( + this.id, + this.name, + this.radius, + this.directionLocal.toApiObject(), + this.suspensionStiffness, + this.suspensionRestLength, + this.frictionSlip, + this.dampingRelaxation, + this.dampingCompression, + this.maxSuspensionForce, + this.rollInfluence, + this.axleLocal.toApiObject(), + this.chassisConnectionPointLocal.toApiObject(), + this.maxSuspensionTravel, + this.customSlidingRotationalSpeed, + this.useCustomSlidingRotationalSpeed, + GameLib.Utils.IdOrNull(this.parentEntity), + GameLib.Utils.IdOrNull(this.parentMesh) + ); + + return apiRaycastWheel; +}; + +/** + * GameLib.D3.RaycastWheel from Object RaycastWheel + * @param physics + * @param objectComponent + * @returns {GameLib.D3.RaycastWheel} + * @constructor + */ +GameLib.D3.RaycastWheel.FromObject = function(physics, objectComponent) { + + var apiRaycastWheel = GameLib.D3.API.RaycastWheel.FromObject(objectComponent); + + return new GameLib.D3.RaycastWheel( + physics, + apiRaycastWheel + ); +}; + +GameLib.D3.RaycastWheel.prototype.setChassisLocalConnectionPoint = function() { + + if (!this.parentMesh) { + console.log('you need to set the parent mesh first'); + } + + this.chassisConnectionPointLocal.x = this.parentMesh.position.x; + this.chassisConnectionPointLocal.y = this.parentMesh.position.y; + this.chassisConnectionPointLocal.z = this.parentMesh.position.z; + +}; +/** + * Raycaster for GameLib.D3 + * @param graphics GameLib.D3.Graphics + * @param apiRaycaster + * @constructor + */ +GameLib.D3.Raycaster = function( + graphics, + apiRaycaster +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiRaycaster)) { + apiRaycaster = {}; + } + + if (apiRaycaster instanceof GameLib.D3.Raycaster) { + return apiRaycaster; + } + + GameLib.D3.API.Raycaster.call( + this, + apiRaycaster.id, + apiRaycaster.name, + apiRaycaster.position, + apiRaycaster.direction + ); + + this.position = new GameLib.Vector3( + this.graphics, + this.position, + this + ); + + this.direction = new GameLib.Vector3( + this.graphics, + this.direction, + this + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_RAYCASTER + ); +}; + +GameLib.D3.Raycaster.prototype = Object.create(GameLib.D3.API.Raycaster.prototype); +GameLib.D3.Raycaster.prototype.constructor = GameLib.D3.Raycaster; + +/** + * Creates or updates a raycaster instance + */ +GameLib.D3.Raycaster.prototype.createInstance = function() { + this.instance = new THREE.Raycaster(); + this.instance.set( + this.position.instance, + this.direction.instance + ); + + GameLib.Component.prototype.createInstance.call(this); +}; + +GameLib.D3.Raycaster.prototype.updateInstance = function() { + + this.position.instance.x = this.position.x; + this.position.instance.y = this.position.y; + this.position.instance.z = this.position.z; + + this.direction.instance.x = this.direction.x; + this.direction.instance.y = this.direction.y; + this.direction.instance.z = this.direction.z; + + this.instance.set( + this.position.instance, + this.direction.instance + ); +}; + +GameLib.D3.Raycaster.prototype.toApiObject = function() { + return new GameLib.D3.API.Raycaster( + this.id, + this.name, + this.position.toApiObject(), + this.direction.toApiObject() + ) +}; + +GameLib.D3.Raycaster.FromObject = function(graphics, objectRaycaster) { + + var apiRaycaster = GameLib.D3.API.Raycaster.FromObject(objectRaycaster); + + var raycaster = new GameLib.D3.Raycaster( + graphics, + apiRaycaster + ); + + return raycaster; +}; + +/** + * Sets the direction and position of this raycaster + * @param position GameLib.Vector3 + * @param direction GameLib.Vector3 + */ +GameLib.D3.Raycaster.prototype.set = function( + position, + direction +) { + this.position.x = position.x; + this.position.y = position.y; + this.position.z = position.z; + + this.direction.x = direction.x; + this.direction.y = direction.y; + this.direction.z = direction.z; + + this.position.updateInstance(); + this.direction.updateInstance(); +}; + +/** + * Sets the direction of this raycaster + * @param direction GameLib.Vector3 + */ +GameLib.D3.Raycaster.prototype.setDirection = function( + direction +) { + this.direction.x = direction.x; + this.direction.y = direction.y; + this.direction.z = direction.z; + + this.direction.updateInstance(); +}; + +/** + * Sets the position of this raycaster + * @param position GameLib.Vector3 + */ +GameLib.D3.Raycaster.prototype.setPosition = function( + position +) { + this.position.x = position.x; + this.position.y = position.y; + this.position.z = position.z; + + this.position.updateInstance(); +}; + +/** + * Sets the ray position and direction from the mouse coordinates (in proper x and y (-1 to 1)) + * @param mouse + * @param camera + */ +GameLib.D3.Raycaster.prototype.setFromCamera = function( + mouse, + camera +) { + this.instance.setFromCamera( + mouse, + camera.instance + ); + + this.position.x = this.instance.ray.origin.x; + this.position.y = this.instance.ray.origin.y; + this.position.z = this.instance.ray.origin.z; + + this.direction.x = this.instance.ray.direction.x; + this.direction.y = this.instance.ray.direction.y; + this.direction.z = this.instance.ray.direction.z; +}; + +/** + * Gets all interesected GameLib.D3.Mesh objects + * @param meshes [GameLib.D3.Mesh] + */ +GameLib.D3.Raycaster.prototype.getIntersectedObjects = function(meshes) { + + return meshes.reduce( + function (result, mesh) { + + var intersects = this.instance.intersectObject(mesh.instance); + + if (intersects.length > 0) { + result.push( + { + mesh: mesh, + distance : intersects[0].distance + } + ); + } + + return result; + }.bind(this), + [] + ); + + // var intersects = this.instance.intersectObjects(meshInstances); + // + // return intersects.reduce( + // + // function (result, intersect) { + // + // meshes.map( + // function(mesh){ + // if (mesh.instance === intersect.object){ + // result.push( + // { + // mesh : mesh, + // distance : intersect.distance + // } + // ); + // } + // } + // ); + // + // return result; + // }, + // [] + // ); + +}; + + +/** + * Returns the face normal (if any) of an intersection between current ray position, direction and a provided mesh + * @param mesh GameLib.D3.Mesh + * @returns {null | GameLib.Vector3} + */ +GameLib.D3.Raycaster.prototype.getFaceNormal = function(mesh) { + + var normal = null; + + var intersect = this.instance.intersectObject( + mesh.instance + ); + + if (intersect && intersect.length > 0) { + + normal = new GameLib.Vector3( + this.graphics, + new GameLib.API.Vector3( + intersect[0].face.normal.x, + intersect[0].face.normal.y, + intersect[0].face.normal.z + ), + this + ); + } + + return normal; +}; + +/** + * Returns the face normal (if any) of an intersection between current ray position, direction and a provided mesh + * @param mesh GameLib.D3.Mesh + * @returns {null | GameLib.Vector3} + */ +GameLib.D3.Raycaster.prototype.getIntersectPoint = function(mesh) { + + var point = null; + + var intersect = this.instance.intersectObject( + mesh.instance + ); + + if (intersect && intersect.length > 0) { + point = new GameLib.Vector3( + this.graphics, + new GameLib.API.Vector3( + intersect[0].point.x, + intersect[0].point.y, + intersect[0].point.z + ), + this + ); + } + + return point; +}; +/** + * Renders a scene with a camera + * @param graphics GameLib.D3.Graphics + * @param apiRenderTarget GameLib.D3.API.RenderTarget + * @constructor + */ +GameLib.D3.RenderTarget = function ( + graphics, + apiRenderTarget +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiRenderTarget)) { + apiRenderTarget = {}; + } + + if (apiRenderTarget instanceof GameLib.D3.RenderTarget) { + return apiRenderTarget; + } + + GameLib.D3.API.RenderTarget.call( + this, + apiRenderTarget.id, + apiRenderTarget.name, + apiRenderTarget.width, + apiRenderTarget.height, + apiRenderTarget.stencilBuffer, + apiRenderTarget.texture + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_RENDER_TARGET, + { + 'texture' : GameLib.D3.Texture + } + ); +}; + +GameLib.D3.RenderTarget.prototype = Object.create(GameLib.D3.API.RenderTarget.prototype); +GameLib.D3.RenderTarget.prototype.constructor = GameLib.D3.RenderTarget; + +/** + * Creates a Render Target instance + * @returns {*} + */ +GameLib.D3.RenderTarget.prototype.createInstance = function() { + + if (GameLib.Utils.UndefinedOrNull(this.texture)) { + throw new Error('no texture'); + } + + if (GameLib.Utils.UndefinedOrNull(this.texture.instance)) { + throw new Error('no texture instance'); + } + + this.instance = new THREE.WebGLRenderTarget( + this.width, + this.height, + { + stencilBuffer : this.stencilBuffer + } + ); + + this.instance.texture = this.texture.instance; + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * updates instance + */ +GameLib.D3.RenderTarget.prototype.updateInstance = function() { + + if (this.instance) { + this.instance.setSize(this.width, this.height); + this.instance.stencilBuffer = this.stencilBuffer; + if (this.texture && this.texture.instance) { + this.instance.texture = this.texture.instance; + this.instance.texture.needsUpdate = true; + } else { + this.instance.texture = null; + } + } else { + try { + this.createInstance(); + } catch (error) { + console.error(error); + } + } +}; + +/** + * Render Target to API Render Target + * @returns {GameLib.D3.API.RenderTarget} + */ +GameLib.D3.RenderTarget.prototype.toApiObject = function() { + + var apiRenderTarget = new GameLib.D3.API.RenderTarget( + this.id, + this.name, + this.width, + this.height, + this.stencilBuffer, + GameLib.Utils.IdOrNull(this.texture), + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiRenderTarget; +}; + +/** + * + * @param graphics + * @param objectComponent + * @returns {GameLib.D3.RenderTarget} + * @constructor + */ +GameLib.D3.RenderTarget.FromObject = function(graphics, objectComponent) { + + var apiRenderTarget = GameLib.D3.API.RenderTarget.FromObject(objectComponent); + + return new GameLib.D3.RenderTarget( + graphics, + apiRenderTarget + ); +}; + +/** + * Renders a scene with a camera + * @param graphics GameLib.D3.Graphics + * @param apiRenderer GameLib.D3.API.Renderer + * @constructor + */ +GameLib.D3.Renderer = function ( + graphics, + apiRenderer +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiRenderer)) { + apiRenderer = {}; + } + + if (apiRenderer instanceof GameLib.D3.Renderer) { + return apiRenderer; + } + + GameLib.D3.API.Renderer.call( + this, + apiRenderer.id, + apiRenderer.name, + apiRenderer.autoClear, + apiRenderer.localClipping, + apiRenderer.width, + apiRenderer.height, + apiRenderer.preserveDrawingBuffer, + apiRenderer.domElement, + apiRenderer.clearColor, + apiRenderer.camera, + apiRenderer.scenes, + apiRenderer.viewports, + apiRenderer.clippingPlanes, + apiRenderer.bufferScene, + apiRenderer.bufferCamera, + apiRenderer.renderTarget, + apiRenderer.defaultScene, + apiRenderer.sortObjects, + apiRenderer.parentEntity + ); + + this.clearColor = new GameLib.Color( + this.graphics, + this.clearColor, + this + ); + + if (this.domElement instanceof GameLib.API.DomElement) { + this.domElement = new GameLib.DomElement( + this.domElement + ); + } + + if (this.camera instanceof GameLib.D3.API.Camera) { + this.camera = new GameLib.D3.Camera( + this.graphics, + this.camera + ) + } + + this.scenes = this.scenes.map(function(scene){ + if (scene instanceof GameLib.D3.API.Scene) { + return new GameLib.D3.Scene( + this.graphics, + scene + ); + } else { + return scene; + } + }.bind(this)); + + this.viewports = this.viewports.map(function(viewport){ + if (viewport instanceof GameLib.D3.API.Viewport) { + return new GameLib.D3.Viewport( + this.graphics, + viewport + ); + } else { + return viewport; + } + }.bind(this)); + + this.clippingPlanes = this.clippingPlanes.map(function(clippingPlane){ + if (clippingPlane instanceof GameLib.D3.API.Mesh) { + return new GameLib.D3.Mesh.Plane( + this.graphics, + clippingPlane, + clippingPlane.width, + clippingPlane.height, + clippingPlane.widthSegments, + clippingPlane.heightSegments, + clippingPlane.heightMapScale, + clippingPlane.isHeightMap, + clippingPlane.isClippingPlane, + clippingPlane.distanceFromOrigin + ); + } else { + return clippingPlane; + } + }.bind(this)); + + if (this.bufferScene instanceof GameLib.D3.API.Scene) { + this.bufferScene = new GameLib.D3.Scene( + this.graphics, + this.bufferScene + ) + } + + if (this.bufferCamera instanceof GameLib.D3.API.Camera) { + this.bufferCamera = new GameLib.D3.Camera( + this.graphics, + this.bufferCamera + ) + } + + if (this.renderTarget instanceof GameLib.D3.API.RenderTarget) { + this.renderTarget = new GameLib.D3.RenderTarget( + this.graphics, + this.renderTarget + ) + } + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_RENDERER, + { + 'domElement' : GameLib.DomElement, + 'camera' : GameLib.D3.Camera, + 'scenes' : [GameLib.D3.Scene], + 'viewports' : [GameLib.D3.Viewport], + 'clippingPlanes': [GameLib.D3.Mesh.Plane], + 'bufferScene' : GameLib.D3.Scene, + 'bufferCamera' : GameLib.D3.Camera, + 'renderTarget' : GameLib.D3.RenderTarget, + 'defaultScene' : GameLib.D3.Scene + } + ); + +}; + +GameLib.D3.Renderer.prototype = Object.create(GameLib.D3.API.Renderer.prototype); +GameLib.D3.Renderer.prototype.constructor = GameLib.D3.Renderer; + +/** + * Create Renderer Instance + * @returns {*} + */ +GameLib.D3.Renderer.prototype.createInstance = function() { + + if (GameLib.Utils.UndefinedOrNull(this.domElement)) { + throw new Error('no dom element'); + } + + if (GameLib.Utils.UndefinedOrNull(this.domElement.instance)) { + throw new Error('no dom element instance'); + } + + this.instance = new THREE.WebGLRenderer( + { + canvas : this.domElement.instance + } + ); + + if (this.clippingPlanes.length > 0) { + this.instance.clippingPlanes = this.clippingPlanes.map( + function(clippingPlane) { + + if (!clippingPlane.isClippingPlane || !clippingPlane.instance || !clippingPlane.instance.clipping) { + throw new Error('is not a clipping plane or no clipping plane instance'); + } + + return clippingPlane.instance.clipping; + } + ) + } + + this.instance.localClippingEnabled = this.localClipping; + + this.instance.setSize( + this.width, + this.height + ); + + this.instance.setClearColor( + new THREE.Color( + this.clearColor.r, + this.clearColor.g, + this.clearColor.b + ), + 1 - this.clearColor.a + ); + + this.instance.domElement.width = this.width; + this.instance.domElement.height = this.height; + + this.instance.autoClear = this.autoClear; + this.instance.preserveDrawingBuffer = this.preserveDrawingBuffer; + + this.instance.sortObjects = this.sortObjects; + + GameLib.Component.prototype.createInstance.call(this); + +}; + +/** + * + */ +GameLib.D3.Renderer.prototype.updateInstance = function(property) { + + if (!this.instance) { + try { + this.createInstance(); + } catch (error) { + console.error(error.message); + } + return; + } + + if (!property) { + console.error('no property for renderer'); + } + + if (property === 'localClipping') { + this.instance.localClippingEnabled = this.localClipping; + } + + if (property === 'width' || 'height') { + this.instance.setSize( + this.width, + this.height + ); + + this.instance.domElement.width = this.width; + this.instance.domElement.height = this.height; + } + + + if (property === 'clearColor') { + this.instance.setClearColor( + new THREE.Color( + this.clearColor.r, + this.clearColor.g, + this.clearColor.b + ), + 1 - this.clearColor.a + ); + } + + + if (property === 'autoClear') { + this.instance.autoClear = this.autoClear; + } + + if (property === 'preserveDrawingBuffer') { + this.instance.preserveDrawingBuffer = this.preserveDrawingBuffer; + } + + if (this.clippingPlanes.length > 0) { + this.instance.clippingPlanes = this.clippingPlanes.map( + function(clippingPlane) { + + if (!clippingPlane.isClippingPlane || !clippingPlane.instance || !clippingPlane.instance.clipping) { + throw new Error('is not a clipping plane or no clipping plane instance'); + } + + return clippingPlane.instance.clipping; + } + ) + } else { + this.instance.clippingPlanes = []; + } + + if (property === 'sortObjects') { + this.instance.sortObjects = this.sortObjects; + } +}; + +/** + * + * @returns {GameLib.D3.API.Renderer} + */ +GameLib.D3.Renderer.prototype.toApiObject = function() { + + var apiRenderer = new GameLib.D3.API.Renderer( + this.id, + this.name, + this.autoClear, + this.localClipping, + this.width, + this.height, + this.preserveDrawingBuffer, + GameLib.Utils.IdOrNull(this.domElement), + this.clearColor.toApiObject(), + GameLib.Utils.IdOrNull(this.camera), + this.scenes.map(function(scene){ + return GameLib.Utils.IdOrNull(scene); + }), + this.viewports.map(function(viewport){ + return GameLib.Utils.IdOrNull(viewport); + }), + this.clippingPlanes.map( + function(clippingPlane) { + return GameLib.Utils.IdOrNull(clippingPlane); + } + ), + GameLib.Utils.IdOrNull(this.bufferScene), + GameLib.Utils.IdOrNull(this.bufferCamera), + GameLib.Utils.IdOrNull(this.renderTarget), + GameLib.Utils.IdOrNull(this.defaultScene), + this.sortObjects, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiRenderer; +}; + +/** + * + * @param graphics + * @param objectComponent + * @returns {GameLib.D3.Renderer} + * @constructor + */ +GameLib.D3.Renderer.FromObject = function(graphics, objectComponent) { + + var apiRenderer = GameLib.D3.API.Renderer.FromObject(objectComponent); + + return new GameLib.D3.Renderer( + graphics, + apiRenderer + ); +}; + +/** + * Convenience render function + */ +GameLib.D3.Renderer.prototype.render = function(delta, scenes) { + + if (!this.instance) { + return; + } + + if (GameLib.Utils.UndefinedOrNull(scenes)) { + scenes = this.scenes; + } + + if (this.viewports.length > 1) { + this.instance.autoClear = false; + } + + if (scenes.length > 1) { + this.instance.autoClear = false; + } + + this.instance.clear(); + + if ( + this.bufferScene && + this.bufferScene.instance && + this.bufferCamera && + this.bufferCamera.instance && + this.renderTarget && + this.renderTarget.instance + ) { + /** + * We have a buffer that should render to an offscreen render target + */ + this.instance.render( + this.bufferScene.instance, + this.bufferCamera.instance, + this.renderTarget.instance + ); + } + + this.viewports.map( + + function(viewport) { + + this.instance.setViewport( + viewport.x * this.width, + viewport.y * this.height, + viewport.width * this.width, + viewport.height * this.height + ); + + scenes.map(function(scene) { + + if (!scene.instance) { + return; + } + + if (!this.camera.instance && !(scene.renderCamera || scene.renderCamera.instance)) { + return; + } + + /** + * A scene's renderCamera instance overrides the default renderer camera + */ + if (scene.renderCamera && scene.renderCamera.instance) { + this.instance.render( + scene.instance, + scene.renderCamera.instance + ) + } else { + this.instance.render( + scene.instance, + this.camera.instance + ) + } + + }.bind(this)); + + }.bind(this) + ); + +}; + +GameLib.D3.Renderer.prototype.setSize = function(width, height) { + this.width = width; + this.height = height; + + if (this.instance) { + this.instance.setSize( + this.width, + this.height + ); + } else { + console.log('renderer not ready to set size'); + } + +}; + + +/** + * RigidBody Runtime + * @param physics GameLib.D3.Graphics + * @param apiRigidBody GameLib.D3.API.RigidBody + * @constructor + */ +GameLib.D3.RigidBody = function ( + physics, + apiRigidBody +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiRigidBody)) { + apiRigidBody = {}; + } + + if (apiRigidBody instanceof GameLib.D3.RigidBody) { + return apiRigidBody; + } + + GameLib.D3.API.RigidBody.call( + this, + apiRigidBody.id, + apiRigidBody.name, + apiRigidBody.mass, + apiRigidBody.friction, + apiRigidBody.position, + apiRigidBody.quaternion, + apiRigidBody.velocity, + apiRigidBody.angularVelocity, + apiRigidBody.linearDamping, + apiRigidBody.angularDamping, + apiRigidBody.allowSleep, + apiRigidBody.sleepSpeedLimit, + apiRigidBody.sleepTimeLimit, + apiRigidBody.collisionFilterGroup, + apiRigidBody.collisionFilterMask, + apiRigidBody.fixedRotation, + apiRigidBody.shapes, + apiRigidBody.kinematic, + apiRigidBody.parentMesh, + apiRigidBody.parentWorld, + apiRigidBody.parentEntity + ); + + this.position = new GameLib.Vector3( + this.physics, + this.position, + this + ); + + this.quaternion = new GameLib.Quaternion( + this.physics, + this.quaternion, + this + ); + + this.velocity = new GameLib.Vector3( + this.physics, + this.velocity, + this + ); + + this.angularVelocity = new GameLib.Vector3( + this.physics, + this.angularVelocity, + this + ); + + this.force = new GameLib.Vector3( + this.physics + ); + + this.forcePoint = new GameLib.Vector3( + this.physics + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_RIGID_BODY, + { + 'shapes' : [GameLib.D3.Shape], + 'parentMesh' : GameLib.D3.Mesh, + 'parentWorld' : GameLib.D3.PhysicsWorld + } + ); +}; + +GameLib.D3.RigidBody.prototype = Object.create(GameLib.D3.API.RigidBody.prototype); +GameLib.D3.RigidBody.prototype.constructor = GameLib.D3.RigidBody; + +/** + * + * @returns {*} + */ +GameLib.D3.RigidBody.prototype.createInstance = function() { + + this.instance = new CANNON.Body( + { + mass : this.mass, + friction : this.friction, + position : this.position.instance, + quaternion : this.quaternion.instance, + velocity : this.velocity.instance, + angularVelocity : this.angularVelocity.instance, + linearDamping : this.linearDamping, + angularDamping : this.angularDamping, + allowSleep : this.allowSleep, + sleepSpeedLimit : this.sleepSpeedLimit, + sleepTimeLimit : this.sleepTimeLimit, + collisionFilterGroup : this.collisionFilterGroup, + collisionFilterMask : this.collisionFilterMask, + fixedRotation : this.fixedRotation, + kinematic : this.kinematic + } + ); + + this.instance.addEventListener( + "sleepy", + function() { + console.log(this.name + " is feeling sleepy..."); + }.bind(this) + ); + + this.instance.addEventListener( + "sleep", + function() { + console.log(this.name + " fell asleep!"); + }.bind(this) + ); + + this.instance.addEventListener( + "wakeup", + function() { + console.log(this.name + " woke up!"); + }.bind(this) + ); + + this.shapes.map( + function(shape) { + + if (GameLib.Utils.UndefinedOrNull(shape)) { + throw new Error('no shape'); + } + + if (GameLib.Utils.UndefinedOrNull(shape.instance)) { + throw new Error('no shape instance'); + } + + this.instance.addShape(shape.instance) + + }.bind(this) + ); + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * + */ +GameLib.D3.RigidBody.prototype.updateInstance = function() { + + this.instance.mass = this.mass; + this.instance.friction = this.friction; + + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + + this.quaternion.axis.instance.x = this.quaternion.axis.x; + this.quaternion.axis.instance.y = this.quaternion.axis.y; + this.quaternion.axis.instance.z = this.quaternion.axis.z; + + this.instance.quaternion.setFromAxisAngle( + this.quaternion.axis.instance, + this.quaternion.angle + ); + + this.quaternion.x = this.instance.quaternion.x; + this.quaternion.y = this.instance.quaternion.y; + this.quaternion.z = this.instance.quaternion.z; + this.quaternion.w = this.instance.quaternion.w; + + this.parentMesh.position.setFrom(this.position); + this.parentMesh.quaternion.setFrom(this.quaternion); + this.parentMesh.updateInstance(); + + this.instance.velocity.x = this.velocity.x; + this.instance.velocity.y = this.velocity.y; + this.instance.velocity.z = this.velocity.z; + + this.instance.angularVelocity.x = this.angularVelocity.x; + this.instance.angularVelocity.y = this.angularVelocity.y; + this.instance.angularVelocity.z = this.angularVelocity.z; + + this.instance.linearDamping = this.linearDamping; + this.instance.angularDamping = this.angularDamping; + this.instance.allowSleep = this.allowSleep; + this.instance.sleepSpeedLimit = this.sleepSpeedLimit; + this.instance.sleepTimeLimit = this.sleepTimeLimit; + this.instance.collisionFilterGroup = this.collisionFilterGroup; + this.instance.collisionFilterMask = this.collisionFilterMask; + this.instance.fixedRotation = this.fixedRotation; + this.instance.kinematic = this.kinematic; +}; + +GameLib.D3.RigidBody.prototype.setFromParentMesh = function() { + + if (!this.parentMesh || !this.parentMesh.instance) { + console.log('no parent mesh or instance'); + } + + this.instance.position.x = this.parentMesh.position.x; + this.instance.position.y = this.parentMesh.position.y; + this.instance.position.z = this.parentMesh.position.z; + + this.instance.quaternion.x = this.parentMesh.quaternion.x; + this.instance.quaternion.y = this.parentMesh.quaternion.y; + this.instance.quaternion.z = this.parentMesh.quaternion.z; + this.instance.quaternion.w = this.parentMesh.quaternion.w; + + // this.updateInstance(); + +}; + +/** + * GameLib.D3.RigidBody to GameLib.D3.API.RigidBody + * @returns {GameLib.D3.API.RigidBody} + */ +GameLib.D3.RigidBody.prototype.toApiObject = function() { + + var apiRigidBody = new GameLib.D3.API.RigidBody( + this.id, + this.name, + this.mass, + this.friction, + this.position.toApiObject(), + this.quaternion.toApiObject(), + this.velocity.toApiObject(), + this.angularVelocity.toApiObject(), + this.linearDamping, + this.angularDamping, + this.allowSleep, + this.sleepSpeedLimit, + this.sleepTimeLimit, + this.collisionFilterGroup, + this.collisionFilterMask, + this.fixedRotation, + this.shapes.map(function(shape){return GameLib.Utils.IdOrNull(shape)}), + this.kinematic, + GameLib.Utils.IdOrNull(this.parentMesh), + GameLib.Utils.IdOrNull(this.parentWorld), + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiRigidBody; +}; + +/** + * GameLib.D3.RigidBody from Object RigidBody + * @param physics + * @param objectComponent + * @returns {GameLib.D3.RigidBody} + * @constructor + */ +GameLib.D3.RigidBody.FromObject = function(physics, objectComponent) { + + var apiRigidBody = GameLib.D3.API.RigidBody.FromObject(objectComponent); + + return new GameLib.D3.RigidBody( + physics, + apiRigidBody + ); +}; + +GameLib.D3.RigidBody.prototype.applyForce = function() { + this.instance.applyForce( + this.force.instance, + this.forcePoint.instance + ) +}; + + +GameLib.D3.RigidBody.prototype.applyLocalForce = function() { + this.instance.applyLocalForce( + this.force.instance, + this.forcePoint.instance + ) +}; + +/** + * Scene Superset - The apiScene properties get moved into the Scene object itself, and then the instance is + * created + * @param graphics + * @param apiScene GameLib.D3.API.Scene + * @constructor + */ +GameLib.D3.Scene = function ( + graphics, + apiScene +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiScene)) { + apiScene = {}; + } + + if (apiScene instanceof GameLib.D3.Scene) { + return apiScene; + } + + GameLib.D3.API.Scene.call( + this, + apiScene.id, + apiScene.name, + apiScene.meshes, + apiScene.lights, + apiScene.textures, + apiScene.materials, + apiScene.images, + apiScene.fog, + apiScene.renderCamera, + apiScene.showGrid, + apiScene.showAxis, + apiScene.gridSize, + apiScene.gridColor, + apiScene.parentEntity + ); + + this.meshes = this.meshes.map( + function(apiMesh) { + + if (apiMesh instanceof GameLib.D3.API.Mesh) { + + apiMesh.parentScene = this; + + return new GameLib.D3.Mesh( + this.graphics, + apiMesh + ); + + } else { + return apiMesh; + } + + }.bind(this) + ); + + this.lights = this.lights.map( + function(apiLight) { + + if (apiLight instanceof GameLib.D3.API.Light) { + + return new GameLib.D3.Light( + this.graphics, + apiLight + ); + + } else { + return apiLight; + } + + }.bind(this) + ); + + this.textures = this.textures.map( + function(apiTexture) { + + if (apiTexture instanceof GameLib.D3.API.Texture) { + + var texture = new GameLib.D3.Texture( + this.graphics, + apiTexture + ); + + return texture; + } else { + return apiTexture; + } + + }.bind(this) + ); + + this.materials = this.materials.map( + function(apiMaterial) { + + if (apiMaterial instanceof GameLib.D3.API.Material) { + + var material = new GameLib.D3.Material( + this.graphics, + apiMaterial + ); + + return material; + + } else { + return apiMaterial; + } + + }.bind(this) + ); + + this.images = this.images.map( + function(apiImage) { + + if (apiImage instanceof GameLib.D3.API.Image) { + + var image = new GameLib.D3.Image( + this.graphics, + apiImage + ); + + return image; + } else { + return apiImage; + } + + }.bind(this) + ); + + if (this.fog instanceof GameLib.D3.API.Fog) { + this.fog = new GameLib.D3.Fog( + this.graphics, + this.fog + ) + } + + if (this.renderCamera instanceof GameLib.D3.API.Camera) { + this.renderCamera = new GameLib.D3.Camera( + this.graphics, + this.renderCamera + ) + } + + if (this.gridColor instanceof GameLib.API.Color) { + this.gridColor = new GameLib.Color( + this.graphics, + this.gridColor, + this + ) + } + + /** + * Runtime scenes have helpers (just used to store which helper belongs to which scene) + * @type {Array} + */ + this.helpers = []; + + this.clones = []; + + this.grid = []; + + this.axis = []; + + this.storeClones = false; + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_SCENE, + { + 'meshes' : [GameLib.D3.Mesh], + 'lights' : [GameLib.D3.Light], + 'textures' : [GameLib.D3.Texture], + 'materials' : [GameLib.D3.Material], + 'images' : [GameLib.D3.Image], + 'fog' : GameLib.D3.Fog, + 'renderCamera' : GameLib.D3.Camera + } + ); +}; + +GameLib.D3.Scene.prototype = Object.create(GameLib.D3.API.Scene.prototype); +GameLib.D3.Scene.prototype.constructor = GameLib.D3.Scene; + +/** + * Creates an instance scene + * @returns {THREE.Scene} + */ +GameLib.D3.Scene.prototype.createInstance = function() { + + this.instance = new THREE.Scene(); + + this.instance.name = this.name; + + if (this.fog && this.fog.instance) { + this.instance.fog = this.fog.instance; + } + + this.meshes.map( + function(mesh) { + + if (GameLib.Utils.UndefinedOrNull(mesh)) { + throw new Error('no mesh'); + } + + if (GameLib.Utils.UndefinedOrNull(mesh.instance)) { + throw new Error('no mesh instance'); + } + + this.instance.add(mesh.instance); + + mesh.parentScene = this; + + }.bind(this) + ); + + this.lights.map( + function(light) { + + + if (GameLib.Utils.UndefinedOrNull(light)) { + throw new Error('no light'); + } + + if (GameLib.Utils.UndefinedOrNull(light.instance)) { + throw new Error('no light instance'); + } + + this.instance.add(light.instance); + + light.parentScene = this; + + }.bind(this) + ); + + if (this.showGrid) { + this.drawGrid(); + } + + if (this.showAxis) { + this.drawAxis(); + } + + GameLib.Component.prototype.createInstance.call(this); + +}; + +GameLib.D3.Scene.prototype.updateInstance = function(property) { + + if (property === 'name') { + this.instance.name = this.name; + return; + } + + if (this.fog && this.fog.instance !== this.instance.fog) { + this.instance.fog = this.fog.instance; + } + + /** + * Add missing meshes + */ + this.meshes.map( + function(mesh) { + if (this.instance.children.indexOf(mesh.instance === -1)) { + this.instance.add(mesh.instance); + } + }.bind(this) + ); + + /** + * Add missing lights + */ + this.lights.map( + function(light) { + if (this.instance.children.indexOf(light.instance) === -1) { + this.instance.add(light.instance); + } + }.bind(this) + ); + + /** + * Remove extra meshes and lights + */ + this.instance.children.map( + function(instanceObject) { + + var instanceMeshes = this.meshes.map( + function(mesh) { + return mesh.instance; + } + ); + + var instanceLights = this.lights.map( + function(light) { + return light.instance; + } + ); + + if ( + ( + instanceObject instanceof THREE.Mesh || + instanceObject instanceof THREE.Light + ) && + ( + instanceLights.indexOf(instanceObject) === -1 && + instanceMeshes.indexOf(instanceObject) === -1 + ) + ) { + this.instance.remove(instanceObject); + } + + }.bind(this) + ); + + if ( + property === 'showGrid' || + property === 'gridSize' || + property === 'gridColor' + ) { + if (this.showGrid) { + this.drawGrid(); + } else { + this.removeGrid(); + } + } + + if (property === 'showAxis') { + if (this.showAxis) { + this.drawAxis(); + } else { + this.removeAxis(); + } + + } +}; + +/** + * Converts a GameLib.D3.Scene to a GameLib.D3.API.Scene + * @returns {GameLib.D3.API.Scene} + */ +GameLib.D3.Scene.prototype.toApiObject = function() { + + var apiMeshes = this.meshes.reduce( + function(result, mesh) { + + /** + * Do not store any cloned meshes + */ + if ((this.clones.indexOf(mesh) === -1) || this.storeClones) { + result.push(GameLib.Utils.IdOrNull(mesh)); + } + + return result; + }.bind(this), + [] + ); + + var apiLights = this.lights.reduce( + function(result, light) { + + /** + * Do not store any cloned lights + */ + if (this.clones.indexOf(light) === -1 || this.storeClones) { + result.push(GameLib.Utils.IdOrNull(light)); + } + + return result; + + }.bind(this), + [] + ); + + var apiTextures = this.textures.map( + function(texture) { + return GameLib.Utils.IdOrNull(texture); + } + ); + + var apiMaterials = this.materials.map( + function(material) { + return GameLib.Utils.IdOrNull(material); + } + ); + + var apiImages = this.images.map( + function(image) { + return GameLib.Utils.IdOrNull(image); + } + ); + + return new GameLib.D3.API.Scene( + this.id, + this.name, + apiMeshes, + apiLights, + apiTextures, + apiMaterials, + apiImages, + GameLib.Utils.IdOrNull(this.fog), + GameLib.Utils.IdOrNull(this.renderCamera), + this.showGrid, + this.showAxis, + this.gridSize, + this.gridColor.toApiObject(), + GameLib.Utils.IdOrNull(this.parentEntity) + ); +}; + +/** + * Converts a scene Object to a GameLib.D3.Scene object + * @param graphics GameLib.D3.Graphics + * @param objectScene Object + * @returns {GameLib.D3.Scene} + * @constructor + */ +GameLib.D3.Scene.FromObject = function( + graphics, + objectScene +) { + var apiScene = GameLib.D3.API.Scene.FromObject(objectScene); + + return new GameLib.D3.Scene( + graphics, + apiScene + ); +}; + + +/** + * Adds a mesh to the scene + * @param object GameLib.D3.Mesh + */ +GameLib.D3.Scene.prototype.addObject = function(object) { + + if (object instanceof GameLib.D3.Mesh) { + if (this.meshes.indexOf(object) === -1) { + this.meshes.push(object); + } + } else if (object instanceof GameLib.D3.API.Mesh) { + object = new GameLib.D3.Mesh( + this.graphics, + object + ); + this.meshes.push(object); + } + + if (object instanceof GameLib.D3.Light) { + if (this.lights.indexOf(object) === -1) { + this.lights.push(object); + } + } else if (object instanceof GameLib.D3.API.Light) { + object = new GameLib.D3.Light( + this.graphics, + object + ); + this.lights.push(object); + } + + object.parentScene = this; + + if ( + this.instance && + object.instance + ) { + if (this.instance.children.indexOf(object.instance) === -1) { + this.instance.add(object.instance); + } + } + +}; + +GameLib.D3.Scene.prototype.addClone = function(component) { + + if (component instanceof GameLib.D3.Mesh || + component instanceof GameLib.D3.Light + ) { + if (this.instance && component.instance) { + this.instance.add(component.instance); + } + + GameLib.Utils.PushUnique(this.clones, component); + + component.parentScene = this; + } +}; + +/** + * + * @param object + */ +GameLib.D3.Scene.prototype.removeObject = function(object) { + + var index = -1; + + if (object instanceof GameLib.D3.Mesh) { + + index = this.meshes.indexOf(object); + if (index !== -1) { + this.meshes.splice(index, 1); + } + + index = this.clones.indexOf(object); + if (index !== -1) { + this.clones.splice(index, 1); + } + + } else if (object instanceof GameLib.D3.Light) { + + index = this.lights.indexOf(object); + if (index !== -1) { + this.lights.splice(index, 1); + } + + index = this.clones.indexOf(object); + if (index !== -1) { + this.clones.splice(index, 1); + } + + } else { + console.warn('Cannot remove this object - what is this ?' + object.toString()); + return; + } + + if (this.instance.children.indexOf(object.instance) !== -1) { + this.instance.remove(object.instance); + } else { + console.warn('no scene instance'); + } + + if (object.parentScene === this) { + object.parentScene = null; + } + + // this.buildIdToObject(); +}; + +GameLib.D3.Scene.prototype.drawGrid = function() { + + this.removeGrid(); + + var lineMaterial = new THREE.LineBasicMaterial({ + color: this.gridColor.toHex(), + linewidth: 1 + }); + + for (var y = -this.gridSize; y <= this.gridSize; y += 1) { + + var Xgeometry = new THREE.Geometry(); + Xgeometry.vertices.push( + new THREE.Vector3( y, 0, this.gridSize * -1 ), + new THREE.Vector3( y, 0, this.gridSize ) + ); + + var lineX = new THREE.Line(Xgeometry, lineMaterial); + + this.instance.add(lineX); + + this.grid.push(lineX); + + var Ygeometry = new THREE.Geometry(); + Ygeometry.vertices.push( + new THREE.Vector3( this.gridSize * -1 , 0, y ), + new THREE.Vector3( this.gridSize, 0, y ) + ); + + var lineY = new THREE.Line(Ygeometry, lineMaterial); + + this.instance.add(lineY); + + this.grid.push(lineY); + } +}; + +GameLib.D3.Scene.prototype.removeGrid = function() { + this.grid.map( + function(object) { + this.instance.remove(object); + }.bind(this) + ); +}; + +GameLib.D3.Scene.prototype.drawAxis = function() { + + this.removeAxis(); + + var Xmaterial = new THREE.LineBasicMaterial({ + color: 0xff0000, + linewidth: 2 + }); + + var Xgeometry = new THREE.Geometry(); + Xgeometry.vertices.push( + new THREE.Vector3( 0, 0, 0 ), + new THREE.Vector3( 100, 0, 0 ) + ); + + var lineX = new THREE.Line(Xgeometry, Xmaterial); + + this.instance.add(lineX); + + this.axis.push(lineX); + + var Ymaterial = new THREE.LineBasicMaterial({ + color: 0x00ff00, + linewidth: 2 + }); + + var Ygeometry = new THREE.Geometry(); + Ygeometry.vertices.push( + new THREE.Vector3( 0, 0, 0 ), + new THREE.Vector3( 0, 100, 0 ) + ); + + var lineY = new THREE.Line(Ygeometry, Ymaterial); + + this.instance.add(lineY); + + this.axis.push(lineY); + + var Zmaterial = new THREE.LineBasicMaterial({ + color: 0x0000ff, + linewidth: 2 + }); + + var Zgeometry = new THREE.Geometry(); + Zgeometry.vertices.push( + new THREE.Vector3( 0, 0, 0 ), + new THREE.Vector3( 0, 0, 100 ) + ); + + var lineZ = new THREE.Line(Zgeometry, Zmaterial); + + this.instance.add(lineZ); + + this.axis.push(lineZ); +}; + +GameLib.D3.Scene.prototype.removeAxis = function() { + this.axis.map( + function(object) { + this.instance.remove(object); + }.bind(this) + ); +}; + +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics GameLib.D3.Physics + * @param apiShape GameLib.D3.API.Shape + * @constructor + */ +GameLib.D3.Shape = function ( + physics, + apiShape +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiShape)) { + apiShape = {}; + } + + if (apiShape instanceof GameLib.D3.Shape) { + return apiShape; + } + + GameLib.D3.API.Shape.call( + this, + apiShape.id, + apiShape.name, + apiShape.boundingSphereRadius, + apiShape.collisionResponse, + apiShape.frictionMaterial, + apiShape.parentMesh, + apiShape.parentEntity + ); + + var componentType = GameLib.Component.COMPONENT_SHAPE; + + var linkedObjects = { + frictionMaterial : GameLib.D3.FrictionMaterial, + parentMesh : GameLib.D3.Mesh + }; + + if (this instanceof GameLib.D3.Shape.Box) { + componentType = GameLib.Component.COMPONENT_SHAPE_BOX; + } + + if (this instanceof GameLib.D3.Shape.ConvexHull) { + componentType = GameLib.Component.COMPONENT_SHAPE_CONVEX_HULL; + } + + if (this instanceof GameLib.D3.Shape.ConvexHull.Cylinder) { + componentType = GameLib.Component.COMPONENT_SHAPE_CONVEX_HULL_CYLINDER; + } + + if (this instanceof GameLib.D3.Shape.Sphere) { + componentType = GameLib.Component.COMPONENT_SHAPE_SPHERE; + } + + if (this instanceof GameLib.D3.Shape.TriMesh) { + componentType = GameLib.Component.COMPONENT_SHAPE_TRI_MESH; + } + + if (this instanceof GameLib.D3.Shape.Plane) { + componentType = GameLib.Component.COMPONENT_SHAPE_PLANE; + } + + if (this instanceof GameLib.D3.Shape.HeightMap) { + componentType = GameLib.Component.COMPONENT_SHAPE_HEIGHT_MAP; + } + + GameLib.Component.call( + this, + componentType, + linkedObjects + ); +}; + +GameLib.D3.Shape.prototype = Object.create(GameLib.D3.API.Shape.prototype); +GameLib.D3.Shape.prototype.constructor = GameLib.D3.Shape; + +/** + * Creates a shape instance or updates it + */ +GameLib.D3.Shape.prototype.createInstance = function() { + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the mesh instance + */ +GameLib.D3.Shape.prototype.updateInstance = function() { + throw new Error('Do not instantiate this class directly - use a child class instead'); +}; + +/** + * Converts a GameLib.D3.Shape to a GameLib.D3.API.Shape + * @returns {GameLib.D3.API.Shape} + */ +GameLib.D3.Shape.prototype.toApiObject = function() { + + var apiShape = new GameLib.D3.API.Shape( + this.id, + this.name, + this.boundingSphereRadius, + this.collisionResponse, + GameLib.Utils.IdOrNull(this.frictionMaterial), + GameLib.Utils.IdOrNull(this.parentMesh), + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiShape; +}; + +/** + * Converts a standard object mesh to a GameLib.D3.Shape + * @param physics GameLib.D3.Physics + * @param objectShape {Object} + * @constructor + */ +GameLib.D3.Shape.FromObject = function(physics, objectShape) { + throw ('not implemented'); +}; + +GameLib.D3.Shape.prototype.stopVisualize = function() { + GameLib.Event.Emit( + GameLib.Event.STOP_VISUALIZE, + { + mesh : this.mesh + } + ) +}; + +GameLib.D3.Shape.prototype.visualize = function() { + GameLib.Event.Emit( + GameLib.Event.VISUALIZE, + { + shape : this + } + ) +}; +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape GameLib.D3.API.Shape + * @param halfExtents + * @constructor + */ +GameLib.D3.Shape.Box = function ( + physics, + apiShape, + halfExtents +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(halfExtents)) { + halfExtents = new GameLib.Vector3( + physics, + new GameLib.API.Vector3( + 1,1,1 + ) + ); + } else if (halfExtents instanceof GameLib.API.Vector3) { + halfExtents = new GameLib.Vector3( + this.physics, + halfExtents, + this + ) + } + this.halfExtents = halfExtents; + + GameLib.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +GameLib.D3.Shape.Box.prototype = Object.create(GameLib.D3.Shape.prototype); +GameLib.D3.Shape.Box.prototype.constructor = GameLib.D3.Shape.Box; + +/** + * + * @returns {GameLib.D3.Shape.Box|*|SEA3D.Box} + */ +GameLib.D3.Shape.Box.prototype.createInstance = function() { + + if (GameLib.Utils.UndefinedOrNull(this.halfExtents)) { + throw new Error('no halfExtents'); + } + + if (GameLib.Utils.UndefinedOrNull(this.halfExtents.instance)) { + throw new Error('no halfExtents instance'); + } + + this.instance = new CANNON.Box( + this.halfExtents.instance + ); + + GameLib.D3.Shape.prototype.createInstance.call(this); + +}; + +GameLib.D3.Shape.Box.prototype.updateInstance = function() { + this.instance.halfExtents.x = this.halfExtents.x; + this.instance.halfExtents.y = this.halfExtents.y; + this.instance.halfExtents.z = this.halfExtents.z; + this.instance.updateBoundingSphereRadius(); + this.instance.updateConvexPolyhedronRepresentation(); +}; + +GameLib.D3.Shape.Box.prototype.toApiObject = function() { + + var apiShape = GameLib.D3.Shape.prototype.toApiObject.call(this); + + apiShape.halfExtents = this.halfExtents.toApiObject(); + + return apiShape; +}; + +GameLib.D3.Shape.Box.prototype.setFromMesh = function() { + + if (this.parentMesh === null) { + console.log('select a mesh first'); + return; + } + + var box = this.parentMesh.getBoundingBox(); + + this.halfExtents.x = box.x / 2; + this.halfExtents.y = box.y / 2; + this.halfExtents.z = box.z / 2; + + this.halfExtents.updateInstance(); +}; + +GameLib.D3.Shape.Box.FromObject = function(physics, objectShape) { + + var apiShape = GameLib.D3.API.Shape.FromObject(objectShape); + + apiShape.halfExtents = GameLib.API.Vector3.FromObject(objectShape.halfExtents); + + return new GameLib.D3.Shape.Box( + physics, + apiShape, + apiShape.halfExtents + ); + +}; +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape GameLib.D3.API.Shape + * @param faces + * @param uniqueAxes + * @param uniqueEdges + * @param vertices + * @constructor + */ +GameLib.D3.Shape.ConvexHull = function ( + physics, + apiShape, + vertices, + faces, + uniqueAxes, + uniqueEdges +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiShape)) { + apiShape = {}; + } + + if (apiShape instanceof GameLib.D3.Shape.ConvexHull) { + return apiShape; + } + + if (GameLib.Utils.UndefinedOrNull(vertices)) { + vertices = []; + } + this.vertices = vertices; + + if (GameLib.Utils.UndefinedOrNull(faces)) { + faces = []; + } + this.faces = faces; + + if (GameLib.Utils.UndefinedOrNull(uniqueAxes)) { + uniqueAxes = []; + } + this.uniqueAxes = uniqueAxes; + + if (GameLib.Utils.UndefinedOrNull(uniqueEdges)) { + uniqueEdges = []; + } + this.uniqueEdges = uniqueEdges; + + this.vertices = this.vertices.map(function(vertex){ + if (vertex instanceof GameLib.D3.API.Vertex){ + return new GameLib.D3.Vertex( + this.physics, + vertex + ) + } + return vertex; + }.bind(this)); + + this.faces = this.faces.map(function(face){ + if (face instanceof GameLib.D3.API.Face){ + return new GameLib.D3.Face( + this.physics, + face + ) + } + return face; + }.bind(this)); + + this.uniqueAxes = this.uniqueAxes.map(function(axis){ + if (axis instanceof GameLib.API.Vector3) { + return new GameLib.Vector3( + this.physics, + axis, + this + ) + } + return axis; + }.bind(this)); + + this.uniqueEdges = this.uniqueEdges.map(function(edge){ + if (edge instanceof GameLib.API.Vector3) { + return new GameLib.Vector3( + this.physics, + edge, + this + ) + } + return edge; + }.bind(this)); + + GameLib.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +GameLib.D3.Shape.ConvexHull.prototype = Object.create(GameLib.D3.Shape.prototype); +GameLib.D3.Shape.ConvexHull.prototype.constructor = GameLib.D3.Shape.ConvexHull; + +/** + * Create instance + * @returns {GameLib.D3.Shape.ConvexHull} + */ +GameLib.D3.Shape.ConvexHull.prototype.createInstance = function() { + + var faceNormals = []; + + this.instance = new CANNON.ConvexPolyhedron( + this.vertices.map( + function(vertex) { + + if (GameLib.Utils.UndefinedOrNull(vertex)) { + throw new Error('no vertex'); + } + + if (GameLib.Utils.UndefinedOrNull(vertex.position)) { + throw new Error('no vertex position'); + } + + if (GameLib.Utils.UndefinedOrNull(vertex.position.instance)) { + throw new Error('no vertex position instance'); + } + + return vertex.position.instance; + } + ), + this.faces.map( + function(face) { + + if (GameLib.Utils.UndefinedOrNull(face)) { + throw new Error('no face'); + } + + if (GameLib.Utils.UndefinedOrNull(face.normal)) { + throw new Error('no face normal'); + } + + if (GameLib.Utils.UndefinedOrNull(face.normal.instance)) { + throw new Error('no face normal instance'); + } + + if (GameLib.Utils.UndefinedOrNull(face.v0index)) { + throw new Error('no face v0index'); + } + + if (GameLib.Utils.UndefinedOrNull(face.v1index)) { + throw new Error('no face v1index'); + } + + if (GameLib.Utils.UndefinedOrNull(face.v2index)) { + throw new Error('no face v2index'); + } + + faceNormals.push(face.normal.instance); + + return [face.v0index, face.v1index, face.v2index]; + } + ) + ); + + this.instance.faceNormals = faceNormals; + + GameLib.D3.Shape.prototype.createInstance.call(this); +}; + +/** + * Update instance + */ +GameLib.D3.Shape.ConvexHull.prototype.updateInstance = function() { + console.log('todo: update convex hull instance'); + // this.instance.vertices = this.vertices; + // this.instance.indices = this.indices; + // this.instance.updateAABB(); + // this.instance.updateBoundingSphereRadius(); + // this.instance.updateEdges(); + // this.instance.updateNormals(); + // this.instance.updateTree(); +}; + +GameLib.D3.Shape.ConvexHull.prototype.loadFromInstance = function() { + console.log('todo: eventually load the faces and vertices from the instance faces and vertices and normals'); + console.log('todo: this way we can nicely visualize them with our gamelib classes :)'); +}; + +GameLib.D3.Shape.ConvexHull.prototype.toApiObject = function() { + + var apiShape = GameLib.D3.Shape.prototype.toApiObject.call(this); + + apiShape.vertices = this.vertices.map( + function(vertex) { + if (vertex instanceof GameLib.D3.Vertex) { + return vertex.toApiObject(); + } + return vertex; + } + ); + + apiShape.faces = this.faces.map( + function(face) { + if (face instanceof GameLib.D3.Face){ + return face.toApiObject(); + } + return face; + } + ); + + apiShape.uniqueAxes = this.uniqueAxes.map( + function(axis){ + if (axis instanceof GameLib.Vector3) { + return axis.toApiObject(); + } + return axis; + } + ); + + apiShape.uniqueEdges = this.uniqueEdges.map( + function(edge) { + if (edge instanceof GameLib.Vector3) { + return edge.toApiObject(); + } + return edge; + } + ); + + return apiShape; +}; + +GameLib.D3.Shape.ConvexHull.prototype.setFromMesh = function() { + console.log('todo: set convex hull from mesh'); + this.updateInstance(); +}; + +GameLib.D3.Shape.ConvexHull.InheritableProperties = function(physics, objectShape) { + var vertices = objectShape.vertices.map( + function(objectVertex) { + return GameLib.D3.Vertex.FromObject(physics, objectVertex); + } + ); + + var faces = objectShape.faces.map( + function(objectFace) { + return GameLib.D3.Face.FromObject(physics, objectFace); + } + ); + + var uniqueAxes = objectShape.uniqueAxes.map( + function(axis) { + return GameLib.API.Vector3.FromObject(axis); + } + ); + + var uniqueEdges = objectShape.uniqueEdges.map( + function(edge) { + return GameLib.API.Vector3.FromObject(edge); + } + ); + + return { + vertices : vertices, + faces : faces, + uniqueAxes : uniqueAxes, + uniqueEdges : uniqueEdges + }; +}; + +GameLib.D3.Shape.ConvexHull.FromObject = function(physics, objectShape) { + + var apiShape = GameLib.D3.API.Shape.FromObject(objectShape); + + var inheritableProperties = GameLib.D3.Shape.ConvexHull.InheritableProperties(physics, objectShape); + + return new GameLib.D3.Shape.ConvexHull.call( + this, + physics, + apiShape, + inheritableProperties.vertices, + inheritableProperties.faces, + inheritableProperties.uniqueAxes, + inheritableProperties.uniqueEdges + ); +}; +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape GameLib.D3.API.Shape + * @param radiusTop + * @param radiusBottom + * @param height + * @param numSegments + * @constructor + */ +GameLib.D3.Shape.ConvexHull.Cylinder = function ( + physics, + apiShape, + radiusTop, + radiusBottom, + height, + numSegments +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(radiusTop)) { + radiusTop = 1; + } + this.radiusTop = radiusTop; + + if (GameLib.Utils.UndefinedOrNull(radiusBottom)) { + radiusBottom = 1; + } + this.radiusBottom = radiusBottom; + + if (GameLib.Utils.UndefinedOrNull(height)) { + height = radiusBottom / 2; + } + this.height = height; + + if (GameLib.Utils.UndefinedOrNull(numSegments)) { + numSegments = 20; + } + this.numSegments = numSegments; + + GameLib.D3.Shape.ConvexHull.call( + this, + this.physics, + apiShape + ); +}; + +GameLib.D3.Shape.ConvexHull.Cylinder.prototype = Object.create(GameLib.D3.Shape.ConvexHull.prototype); +GameLib.D3.Shape.ConvexHull.Cylinder.prototype.constructor = GameLib.D3.Shape.ConvexHull.Cylinder; + +/** + * + * @returns {GameLib.D3.Shape.Cylinder|*|SEA3D.Cylinder} + */ +GameLib.D3.Shape.ConvexHull.Cylinder.prototype.createInstance = function() { + + this.instance = new CANNON.Cylinder( + this.radiusTop, + this.radiusBottom, + this.height, + this.numSegments + ); + + GameLib.D3.Shape.prototype.createInstance.call(this); +}; + +GameLib.D3.Shape.ConvexHull.Cylinder.prototype.updateInstance = function() { + + console.log('todo : update cylinder instance'); + // this.instance.radius = this.radius; + // this.instance.updateAABB(); + // this.instance.updateBoundingCylinderRadius(); + // this.instance.updateEdges(); + // this.instance.updateNormals(); + // this.instance.updateTree(); +}; + +GameLib.D3.Shape.ConvexHull.Cylinder.prototype.setFromMesh = function() { + this.radiusTop = this.parentMesh.dimensions.x / 2; + this.radiusBottom = this.parentMesh.dimensions.x / 2; + this.height = this.parentMesh.dimensions.z; +}; + +GameLib.D3.Shape.ConvexHull.Cylinder.prototype.toApiObject = function() { + + var apiShape = GameLib.D3.Shape.ConvexHull.prototype.toApiObject.call(this); + + apiShape.radiusTop = this.radiusTop; + apiShape.radiusBottom = this.radiusBottom; + apiShape.height = this.height; + apiShape.numSegments = this.numSegments; + + return apiShape; +}; + + +GameLib.D3.Shape.ConvexHull.Cylinder.FromObject = function(physics, objectShape) { + + /** + * Just a reminder that below line is wrong and commented out - we need to call the constructors eventually with + * the right 'this' parameter and args. + * + * var apiShape = GameLib.D3.Shape.ConvexHull.FromObject(physics, objectShape); + * + * Instead, do this: + */ + var apiShape = GameLib.D3.API.Shape.FromObject(objectShape); + + var inheritableProperties = GameLib.D3.Shape.ConvexHull.InheritableProperties(physics, objectShape); + + for (var property in inheritableProperties) { + if (inheritableProperties.hasOwnProperty(property)) { + apiShape[property] = inheritableProperties[property]; + } + } + + return new GameLib.D3.Shape.ConvexHull.Cylinder( + physics, + apiShape, + objectShape.radiusTop, + objectShape.radiusBottom, + objectShape.height, + objectShape.numSegments + ); + +}; +/** + * + * @param physics + * @param apiShape + * @param heightData + * @param minValue + * @param maxValue + * @param elementSize + * @constructor + */ +GameLib.D3.Shape.HeightMap = function ( + physics, + apiShape, + heightData, + minValue, + maxValue, + elementSize +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(heightData)) { + heightData = [[10, 10, 10], [10, 10, 10], [10, 10, 10]]; + } + this.heightData = heightData; + + if (GameLib.Utils.UndefinedOrNull(minValue)) { + minValue = 0; + } + this.minValue = minValue; + + if (GameLib.Utils.UndefinedOrNull(maxValue)) { + maxValue = 10; + } + this.maxValue = maxValue; + + if (GameLib.Utils.UndefinedOrNull(elementSize)) { + elementSize = 1; + } + this.elementSize = elementSize; + + GameLib.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +GameLib.D3.Shape.HeightMap.prototype = Object.create(GameLib.D3.Shape.prototype); +GameLib.D3.Shape.HeightMap.prototype.constructor = GameLib.D3.Shape.HeightMap; + +/** + * Create instance + * @returns {GameLib.D3.Shape.HeightMap} + */ +GameLib.D3.Shape.HeightMap.prototype.createInstance = function() { + + //TODO: initialize properly and throw when errors + + this.instance = new CANNON.Heightfield( + this.heightData, + { + elemSize : this.elementSize + } + ); + + GameLib.D3.Shape.prototype.createInstance.call(this); +}; + +/** + * Update instance + */ +GameLib.D3.Shape.HeightMap.prototype.updateInstance = function() { + this.instance.data = this.heightData; + // this.instance.minValue = this.minValue; + // this.instance.maxValue = this.maxValue; + this.instance.elemSize = this.elemSize; + this.instance.update(); + // this.instance.updateBoundingSphereRadius(); + // this.instance.updateMaxValue(); + // this.instance.updateMinValue(); +}; + + +GameLib.D3.Shape.HeightMap.prototype.toApiObject = function() { + var apiShape = GameLib.D3.Shape.prototype.toApiObject.call(this); + apiShape.heightData = this.heightData; + apiShape.minValue = this.minValue; + apiShape.maxValue = this.maxValue; + apiShape.elemSize = this.elemSize; + return apiShape; +}; + +GameLib.D3.Shape.HeightMap.prototype.setFromMesh = function() { + + if (this.parentMesh === null) { + console.log('select a mesh first'); + return; + } + + if (!this.parentMesh.isHeightMap) { + console.log('not a heightmap mesh'); + return; + } + + var dim1Array = Array.prototype.slice.call(this.parentMesh.getHeightData()); + + // var w = this.parentMesh.widthSegments + 1; + // + // var h = 0; + + // var offset = 0; + + this.heightData = []; + + for (var x = 0; x <= this.parentMesh.widthSegments; x++) { + + this.heightData[x] = []; + + for (var y = 0; y <= this.parentMesh.heightSegments; y++) { + + this.heightData[x][y] = dim1Array[((x * (this.parentMesh.widthSegments + 1)) + y)]; + + } + + } + + + + // this.heightData = dim1Array.reduce( + // function(result, value) { + // + // result[h].push(value); + // + // w--; + // + // if (w === 0) { + // w = this.parentMesh.widthSegments; + // + // if (h < this.parentMesh.heightSegments) { + // h++; + // } + // } + // + // return result; + // }.bind(this), + // result + // ); + + this.updateInstance(); +}; + +GameLib.D3.Shape.HeightMap.FromObject = function(physics, objectShape) { + + var apiShape = GameLib.D3.API.Shape.FromObject(objectShape); + + return new GameLib.D3.Shape.HeightMap( + physics, + apiShape, + objectShape.heightData, + objectShape.minValue, + objectShape.maxValue, + objectShape.elemSize + ); +}; +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape GameLib.D3.API.Shape + * @constructor + */ +GameLib.D3.Shape.Plane = function ( + physics, + apiShape +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + GameLib.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +GameLib.D3.Shape.Plane.prototype = Object.create(GameLib.D3.Shape.prototype); +GameLib.D3.Shape.Plane.prototype.constructor = GameLib.D3.Shape.Plane; + +/** + * + * @returns {GameLib.D3.Shape.Plane|*|SEA3D.Plane} + */ +GameLib.D3.Shape.Plane.prototype.createInstance = function() { + /** + * A plane is just a plane at z = 0, to rotate it put it inside a rigid body and rotate the body + */ + this.instance = new CANNON.Plane(); + GameLib.D3.Shape.prototype.createInstance.call(this); +}; + +GameLib.D3.Shape.Plane.prototype.updateInstance = function() { +}; + +GameLib.D3.Shape.Plane.FromObject = function(physics, objectShape) { + + var apiShape = GameLib.D3.API.Shape.FromObject(objectShape); + + return new GameLib.D3.Shape.Plane( + physics, + apiShape + ); +}; +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape GameLib.D3.API.Shape + * @param radius + * @constructor + */ +GameLib.D3.Shape.Sphere = function ( + physics, + apiShape, + radius +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(radius)) { + radius = 1; + } + this.radius = radius; + + GameLib.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +GameLib.D3.Shape.Sphere.prototype = Object.create(GameLib.D3.Shape.prototype); +GameLib.D3.Shape.Sphere.prototype.constructor = GameLib.D3.Shape.Sphere; + +/** + * + * @returns {GameLib.D3.Shape.Sphere|*|SEA3D.Sphere} + */ +GameLib.D3.Shape.Sphere.prototype.createInstance = function() { + + this.instance = new CANNON.Sphere( + this.radius + ); + + GameLib.D3.Shape.prototype.createInstance.call(this); +}; + +GameLib.D3.Shape.Sphere.prototype.updateInstance = function() { + this.instance.radius = this.radius; + this.instance.updateBoundingSphereRadius(); +}; + + +GameLib.D3.Shape.Sphere.prototype.toApiObject = function() { + var apiShape = GameLib.D3.Shape.prototype.toApiObject.call(this); + apiShape.radius = this.radius; + return apiShape; +}; + +GameLib.D3.Shape.Sphere.FromObject = function(physics, objectShape) { + + var apiShape = GameLib.D3.API.Shape.FromObject(objectShape); + + return new GameLib.D3.Shape.Sphere( + physics, + apiShape, + objectShape.radius + ); +}; +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape GameLib.D3.API.Shape + * @param vertices + * @param indices + * @constructor + */ +GameLib.D3.Shape.TriMesh = function ( + physics, + apiShape, + vertices, + indices +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(vertices)) { + vertices = []; + } + this.vertices = vertices; + + if (GameLib.Utils.UndefinedOrNull(indices)) { + indices = []; + } + this.indices = indices; + + GameLib.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +GameLib.D3.Shape.TriMesh.prototype = Object.create(GameLib.D3.Shape.prototype); +GameLib.D3.Shape.TriMesh.prototype.constructor = GameLib.D3.Shape.TriMesh; + +/** + * Create instance + * @returns {GameLib.D3.Shape.TriMesh} + */ +GameLib.D3.Shape.TriMesh.prototype.createInstance = function() { + + this.instance = new CANNON.TriMesh( + this.vertices, + this.indices + ); + + GameLib.D3.Shape.prototype.createInstance.call(this); + +}; + +/** + * Update instance + */ +GameLib.D3.Shape.TriMesh.prototype.updateInstance = function() { + this.instance.vertices = this.vertices; + this.instance.indices = this.indices; + this.instance.updateAABB(); + this.instance.updateBoundingSphereRadius(); + this.instance.updateEdges(); + this.instance.updateNormals(); + this.instance.updateTree(); +}; +/** + * Skeleton Superset + * @constructor + * @param graphics GameLib.D3.Graphics + * @param apiSkeleton GameLib.D3.API.Skeleton + */ +GameLib.D3.Skeleton = function Skeleton( + graphics, + apiSkeleton +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiSkeleton)) { + apiSkeleton = {}; + } + + if (apiSkeleton instanceof GameLib.D3.Skeleton) { + return apiSkeleton; + } + + GameLib.D3.API.Skeleton.call( + this, + apiSkeleton.id, + apiSkeleton.name, + apiSkeleton.bones, + apiSkeleton.boneInverses, + apiSkeleton.useVertexTexture, + apiSkeleton.boneTextureWidth, + apiSkeleton.boneTextureHeight, + apiSkeleton.boneMatrices, + apiSkeleton.boneTexture, + apiSkeleton.parentEntity + ); + + this.bones = this.bones.map( + function(apiBone) { + + if (apiBone instanceof GameLib.D3.API.Bone) { + return new GameLib.D3.Bone( + this.graphics, + apiBone + ) + } else { + console.warn('apiBone not an instance of API.Bone'); + throw new Error('apiBone not an instance of API.Bone'); + } + + }.bind(this) + ); + + this.boneInverses = this.boneInverses.map( + function(boneInverse) { + + if (boneInverse instanceof GameLib.API.Matrix4) { + return new GameLib.Matrix4( + this.graphics, + boneInverse, + this + ); + } else { + console.warn('boneInverse not an instance of API.Matrix4'); + throw new Error('boneInverse not an instance of API.Matrix4'); + } + + }.bind(this) + ); + + + this.boneMatrices = this.boneMatrices.map( + function(boneMatrices) { + if (boneMatrices instanceof GameLib.API.Matrix4) { + return new GameLib.Matrix4( + this.graphics, + boneMatrices, + this + ); + } else { + console.warn('boneMatrices not an instance of API.Matrix4'); + throw new Error('boneMatrices not an instance of API.Matrix4'); + } + + }.bind(this) + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_SKELETON, + { + 'bones' : [GameLib.D3.Bone] + } + ); +}; + +GameLib.D3.Skeleton.prototype = Object.create(GameLib.D3.API.Skeleton.prototype); +GameLib.D3.Skeleton.prototype.constructor = GameLib.D3.Skeleton; + + +/** + * Creates an instance skeleton + * @param update boolean + */ +GameLib.D3.Skeleton.prototype.createInstance = function(update) { + + var boneInstances = this.bones.map ( + function (bone) { + + if (GameLib.Utils.UndefinedOrNull(bone)) { + throw new Error('no bone'); + } + + if (GameLib.Utils.UndefinedOrNull(bone.instance)) { + throw new Error('no bone instance'); + } + + return bone.instance; + } + ); + + var parentBoneInstance = this.bones.reduce( + + function (result, bone) { + + if (result) { + return result; + } + + if (bone.parentBoneIds.length === 0) { + return bone.instance; + } + + return null; + }, + null + ); + + if (GameLib.Utils.UndefinedOrNull(parentBoneInstance)) { + throw new Error('could not find parent bone instance'); + } + + this.instance = new THREE.Skeleton(boneInstances); + + this.rootBoneInstance = parentBoneInstance; + + this.instance.useVertexTexture = this.useVertexTexture; + + this.boneIdToBone = {}; + + this.bones.map( + function (bone) { + this.boneIdToBone[bone.id] = bone; + }.bind(this) + ); + + /** + * TODO: check if this code does what its supposed to + */ + this.bones.map( + function (__parentBoneInstance) { + return function(bone) { + bone.childBoneIds.map( + function (childBoneId) { + __parentBoneInstance.add(this.boneIdToBone[childBoneId].instance); + }.bind(this) + ); + }; + }(parentBoneInstance).bind(this) + ); + + this.instance.update(); + + this.instance.calculateInverses(); + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance + */ +GameLib.D3.Skeleton.prototype.updateInstance = function() { + +}; + +/** + * Converts a GameLib.D3.Skeleton to GameLib.D3.API.Skeleton + * @returns {GameLib.D3.API.Skeleton} + */ +GameLib.D3.Skeleton.prototype.toApiObject = function() { + + var apiSkeleton = new GameLib.D3.API.Skeleton( + this.id, + this.name, + this.bones.map( + function (bone) { + return bone.toApiObject(); + } + ), + this.boneInverses.map( + function (boneInverse) { + return boneInverse.toApiObject(); + } + ), + this.useVertexTexture, + this.boneTextureWidth, + this.boneTextureHeight, + this.boneMatrices.map( + function (boneMatrix) { + return boneMatrix.toApiObject(); + } + ), + this.boneTexture, + this.parentEntity + ); + + return apiSkeleton; +}; + +/** + * Returns a GameLib.D3.Skeleton from a skeleton Object + * @param graphics GameLib.D3.Graphics + * @param objectSkeleton Object + * @returns {GameLib.D3.Skeleton} + * @constructor + */ +GameLib.D3.Skeleton.FromObject = function( + graphics, + objectSkeleton +) { + + if (!objectSkeleton) { + return null; + } + + var apiSkeleton = GameLib.D3.API.Skeleton.FromObject(objectSkeleton); + + var skeleton = new GameLib.D3.Skeleton( + graphics, + apiSkeleton + ); + + return skeleton; +}; +/** + * Solver Runtime + * @param physics GameLib.D3.Graphics + * @param apiSolver GameLib.D3.API.Solver + * @constructor + */ +GameLib.D3.Solver = function ( + physics, + apiSolver +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiSolver)) { + apiSolver = {}; + } + + if (apiSolver instanceof GameLib.D3.Solver) { + return apiSolver; + } + + GameLib.D3.API.Solver.call( + this, + apiSolver.id, + apiSolver.name, + apiSolver.solverType, + apiSolver.iterations, + apiSolver.tolerance, + apiSolver.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_SOLVER + ); +}; + +GameLib.D3.Solver.prototype = Object.create(GameLib.D3.API.Solver.prototype); +GameLib.D3.Solver.prototype.constructor = GameLib.D3.Solver; + +/** + * + * @returns {*} + */ +GameLib.D3.Solver.prototype.createInstance = function() { + + if (this.solverType === GameLib.D3.Solver.GS_SOLVER) { + this.instance = new CANNON.GSSolver(); + } else if (this.solverType === GameLib.D3.Solver.SPLIT_SOLVER) { + this.instance = new CANNON.SplitSolver(); + } else { + throw new Error('unsupported solver type: ' + this.solverType); + } + + this.instance.tolerance = this.tolerance; + this.instance.iterations = this.iterations; + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * + */ +GameLib.D3.Solver.prototype.updateInstance = function() { + + if (this.solverType === GameLib.D3.Solver.GS_SOLVER) { + if (!(this.instance instanceof CANNON.GSSolver)) { + this.instance = new CANNON.GSSolver(); + } + } + + if (this.solverType === GameLib.D3.Solver.SPLIT_SOLVER) { + if (!(this.instance instanceof CANNON.SplitSolver)) { + this.instance = new CANNON.SplitSolver(); + } + } + + this.instance.iterations = this.iterations; + this.instance.tolerance = this.tolerance; +}; + +/** + * GameLib.D3.Solver to GameLib.D3.API.Solver + * @returns {GameLib.D3.API.Solver} + */ +GameLib.D3.Solver.prototype.toApiObject = function() { + + var apiSolver = new GameLib.D3.API.Solver( + this.id, + this.name, + this.solverType, + this.iterations, + this.tolerance, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiSolver; +}; + +/** + * GameLib.D3.Solver from Object Solver + * @param graphics + * @param objectComponent + * @returns {GameLib.D3.Solver} + * @constructor + */ +GameLib.D3.Solver.FromObject = function(graphics, objectComponent) { + + var apiSolver = GameLib.D3.API.Solver.FromObject(objectComponent); + + return new GameLib.D3.Solver( + graphics, + apiSolver + ); +}; + +/** + * Solver Types + * @type {number} + */ +GameLib.D3.Solver.GS_SOLVER = 0x1; +GameLib.D3.Solver.SPLIT_SOLVER = 0x2; + +/** + * Spline constructor + * @param graphics GameLib.D3.Graphics + * @param apiSpline GameLib.D3.API.Spline + * @constructor + */ +GameLib.D3.Spline = function ( + graphics, + apiSpline +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiSpline)) { + apiSpline = {}; + } + + if (apiSpline instanceof GameLib.D3.Spline) { + return apiSpline; + } + + GameLib.D3.API.Spline.call( + this, + apiSpline.id, + apiSpline.name, + apiSpline.vertices, + apiSpline.parentEntity + ); + + this.vertices = this.vertices.map( + function (vertex) { + return new GameLib.Vector3( + graphics, + vertex, + this + ) + } + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_SPLINE + ); +}; + +GameLib.D3.Spline.prototype = Object.create(GameLib.D3.API.Spline.prototype); +GameLib.D3.Spline.prototype.constructor = GameLib.D3.Spline; + +/** + * Creates an instance spline + */ +GameLib.D3.Spline.prototype.createInstance = function() { + + var vertices = this.vertices.map( + function (vertex) { + + if (GameLib.Utils.UndefinedOrNull(vertex)) { + throw new Error('no vertex') + } + + if (GameLib.Utils.UndefinedOrNull(vertex.instance)) { + throw new Error('no vertex instance') + } + + return vertex.instance; + } + ); + + this.instance = THREE.CatmullRomCurve3(vertices); + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance + */ +GameLib.D3.Spline.prototype.updateInstance = function() { + + var vertices = this.vertices.map( + function (vertex) { + + if (GameLib.Utils.UndefinedOrNull(vertex)) { + throw new Error('no vertex') + } + + if (GameLib.Utils.UndefinedOrNull(vertex.instance)) { + throw new Error('no vertex instance') + } + + return vertex.instance; + } + ); + + this.instance = new THREE.CatmullRomCurve3(vertices); +}; + +/** + * Converts a GameLib.D3.Spline to GameLib.D3.API.Spline + * @returns {GameLib.D3.API.Spline} + */ +GameLib.D3.Spline.prototype.toApiObject = function() { + + return new GameLib.D3.API.Spline( + this.id, + this.name, + this.vertices.map( + function (vertex) { + return vertex.toApiObject() + } + ), + GameLib.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Returns a GameLib.D3.Spline from a spline Object + * @param graphics GameLib.D3.Graphics + * @param objectComponent Object + * @returns {GameLib.D3.Spline} + * @constructor + */ +GameLib.D3.Spline.FromObject = function( + graphics, + objectComponent +) { + var apiSpline = GameLib.D3.API.Spline.FromObject(objectComponent); + + return new GameLib.D3.Spline( + graphics, + apiSpline + ); +}; + +/** + * Gets the current point from the spline at the proper value + * @param proper Number (fraction between 0 and 1 indicating position on spline) + * @returns {*} + */ +GameLib.D3.Spline.prototype.getPointAt = function(proper) { + var point = this.instance.getPointAt(proper); + return new GameLib.Vector3( + this.graphics, + new GameLib.API.Vector3(point.x, point.y, point.z), + this, + 0.1 + ); +}; + +/** + * Stats component for displaying some render statistics (framerate, memory consumption, etc) + * @param stats + * @param id + * @param name + * @param domElement + * @param parentEntity + * @constructor + */ +GameLib.D3.Stats = function( + stats, + id, + name, + domElement, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(stats)) { + throw new Error('Need Stats object') + } + this.stats = stats; + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Stats (' + id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(domElement)) { + console.warn('Need a DOM element for stats'); + throw new Error('Need a DOM element for stats'); + } + this.domElement = domElement; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_STATS, + { + 'domElement': GameLib.DomElement + } + ); +}; + +GameLib.D3.Stats.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.Stats.prototype.constructor = GameLib.D3.Stats; + +GameLib.D3.Stats.prototype.resize = function() { + console.log('override stats resize per implementation'); +}; + +/** + * Creates a helper instance + */ +GameLib.D3.Stats.prototype.createInstance = function() { + this.instance = this.stats(); + + this.resize(); + + this.domElement.instance.parentElement.appendChild(this.instance.dom); + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Stats.prototype.updateInstance = function() { + this.instance = new this.stats(); +}; + +GameLib.D3.Stats.prototype.start = function() { + this.instance.begin(); +}; + +GameLib.D3.Stats.prototype.end = function() { + this.instance.end(); +}; + +/** + * Texture Superset - The apiTexture properties get moved into the Texture object itself, and then the instance is + * created + * @param apiTexture + * @param graphics GameLib.D3.Graphics + * @constructor + */ +GameLib.D3.Texture = function( + graphics, + apiTexture +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiTexture)) { + apiTexture = {}; + } + + if (apiTexture instanceof GameLib.D3.Texture) { + return apiTexture; + } + + GameLib.D3.API.Texture.call( + this, + apiTexture.id, + apiTexture.typeId, + apiTexture.name, + apiTexture.image, + apiTexture.images, + apiTexture.wrapS, + apiTexture.wrapT, + apiTexture.repeat, + apiTexture.data, + apiTexture.format, + apiTexture.mapping, + apiTexture.magFilter, + apiTexture.minFilter, + apiTexture.textureType, + apiTexture.anisotropy, + apiTexture.offset, + apiTexture.generateMipmaps, + apiTexture.flipY, + apiTexture.mipmaps, + apiTexture.unpackAlignment, + apiTexture.premultiplyAlpha, + apiTexture.encoding, + apiTexture.canvas, + apiTexture.animated, + apiTexture.reverseAnimation, + apiTexture.forward, + apiTexture.parentEntity + ); + + this.offset = new GameLib.Vector2( + this.graphics, + this.offset, + this + ); + + this.repeat = new GameLib.Vector2( + this.graphics, + this.repeat, + this + ); + + if (this.image instanceof GameLib.D3.API.Image) { + this.image = new GameLib.D3.Image( + this.graphics, + this.image + ); + } + + this.images = this.images.map( + function(image) { + if (image instanceof GameLib.D3.API.Image) { + return new GameLib.D3.Image( + this.graphics, + image + ); + } else { + return image; + } + }.bind(this) + ); + + if (this.canvas instanceof GameLib.D3.API.Canvas) { + this.canvas = new GameLib.D3.Canvas( + this.graphics, + this.canvas + ); + } + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_TEXTURE, + { + 'image' : GameLib.D3.Image, + 'images' : [GameLib.D3.Image], + 'canvas' : GameLib.D3.Canvas + } + ); +}; + +GameLib.D3.Texture.prototype = Object.create(GameLib.D3.API.Texture.prototype); +GameLib.D3.Texture.prototype.constructor = GameLib.D3.Texture; + +/** + * Texture Formats + * @type {number} + */ +GameLib.D3.Texture.TYPE_ALPHA_FORMAT = 1019; +GameLib.D3.Texture.TYPE_RGB_FORMAT = 1020; +GameLib.D3.Texture.TYPE_RGBA_FORMAT = 1021; +GameLib.D3.Texture.TYPE_LUMINANCE_FORMAT = 1022; +GameLib.D3.Texture.TYPE_LUMINANCE_ALPHA_FORMAT = 1023; +GameLib.D3.Texture.TYPE_DEPTH_FORMAT = 1026; + +/** + * Mapping modes + * @type {number} + */ +GameLib.D3.Texture.TYPE_UV_MAPPING = 300; +GameLib.D3.Texture.TYPE_CUBE_REFLECTION_MAPPING = 301; +GameLib.D3.Texture.TYPE_CUBE_REFRACTION_MAPPING = 302; +GameLib.D3.Texture.TYPE_EQUI_RECTANGULAR_REFLECTION_MAPPING = 303; +GameLib.D3.Texture.TYPE_EQUI_RECTANGULAR_REFRACTION_MAPPING = 304; +GameLib.D3.Texture.TYPE_SPHERICAL_REFLECTION_MAPPING = 305; +GameLib.D3.Texture.TYPE_CUBE_UV_REFLECTION_MAPPING = 306; +GameLib.D3.Texture.TYPE_CUBE_UV_REFRACTION_MAPPING = 307; + +/** + * Wrapping Modes + * @type {number} + */ +GameLib.D3.Texture.TYPE_REPEAT_WRAPPING = 1000; +GameLib.D3.Texture.TYPE_CLAMP_TO_EDGE_WRAPPING = 1001; +GameLib.D3.Texture.TYPE_MIRRORED_REPEAT_WRAPPING = 1002; + +/** + * Mipmap Filters + * @type {number} + */ +GameLib.D3.Texture.TYPE_NEAREST_FILTER = 1003; +GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_NEAREST_FILTER = 1004; +GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_LINEAR_FILTER = 1005; +GameLib.D3.Texture.TYPE_LINEAR_FILTER = 1006; +GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_NEAREST_FILTER = 1007; +GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER = 1008; + +/** + * Texture Data Types + * @type {number} + */ +GameLib.D3.Texture.TYPE_UNSIGNED_BYTE = 1009; +GameLib.D3.Texture.TYPE_BYTE = 1010; +GameLib.D3.Texture.TYPE_SHORT = 1011; +GameLib.D3.Texture.TYPE_UNSIGNED_SHORT = 1012; +GameLib.D3.Texture.TYPE_INT = 1013; +GameLib.D3.Texture.TYPE_UNSIGNED_INT = 1014; +GameLib.D3.Texture.TYPE_FLOAT = 1015; +GameLib.D3.Texture.TYPE_HALF_FLOAT = 1025; + +/** + * Encoding Modes + * @type {number} + */ +GameLib.D3.Texture.TYPE_LINEAR_ENCODING = 3000; // NO ENCODING AT ALL. +GameLib.D3.Texture.TYPE_SRGB_ENCODING = 3001; +GameLib.D3.Texture.TYPE_GAMMA_ENCODING = 3007; // USES GAMMA_FACTOR, FOR BACKWARDS COMPATIBILITY WITH WEBGLRENDERER.GAMMAINPUT/GAMMAOUTPUT +GameLib.D3.Texture.TYPE_RGBE_ENCODING = 3002; // AKA RADIANCE. +GameLib.D3.Texture.TYPE_LOG_LUV_ENCODING = 3003; +GameLib.D3.Texture.TYPE_RGBM7_ENCODING = 3004; +GameLib.D3.Texture.TYPE_RGBM16_ENCODING = 3005; +GameLib.D3.Texture.TYPE_RGBD_ENCODING = 3006; // MAXRANGE IS 256. + +GameLib.D3.Texture.TEXTURE_TYPE_NORMAL = 0x1; +GameLib.D3.Texture.TEXTURE_TYPE_CUBE = 0x2; +GameLib.D3.Texture.TEXTURE_TYPE_CANVAS = 0x3; + +/** + * Creates an instance of our texture object + * @returns {*} + */ +GameLib.D3.Texture.prototype.createInstance = function() { + + if (this.typeId === GameLib.D3.Texture.TEXTURE_TYPE_CUBE) { + + if (this.images.length !== 6) { + throw new Error('not enough images for cube texture'); + } + + var imageInstances = this.images.map( + function(image) { + + if (GameLib.Utils.UndefinedOrNull(image)) { + throw new Error('no image'); + } + + if (GameLib.Utils.UndefinedOrNull(image.instance)) { + throw new Error('no image instance'); + } + + return image.instance + } + ); + + this.instance = new THREE.CubeTexture(imageInstances); + + } else if (this.typeId === GameLib.D3.Texture.TEXTURE_TYPE_NORMAL) { + + if ( + GameLib.Utils.UndefinedOrNull(this.image) || + GameLib.Utils.UndefinedOrNull(this.image.instance) + ) { + + this.instance = new THREE.Texture(); + + } else { + + //if (GameLib.Utils.UndefinedOrNull(this.image.instance)) { + // throw new Error('no image instance'); + //} + + this.instance = new THREE.Texture( + this.image.instance + ); + + } + + } else if (this.typeId === GameLib.D3.Texture.TEXTURE_TYPE_CANVAS) { + + if (GameLib.Utils.UndefinedOrNull(this.canvas)) { + + this.instance = new THREE.Texture(); + + } else { + + if (GameLib.Utils.UndefinedOrNull(this.canvas.instance)) { + throw new Error('no canvas instance'); + } + + this.instance = new THREE.Texture( + this.canvas.instance + ); + + } + + } + + /** + * Some settings we copy from the instance + */ + this.mapping = this.instance.mapping; + this.encoding = this.instance.encoding; + this.format = this.instance.format; + + /** + * Others we apply to the instance + */ + this.instance.name = this.name; + this.instance.flipY = this.flipY; + this.instance.offset.x = this.offset.x; + this.instance.offset.y = this.offset.y; + this.instance.repeat.x = this.repeat.x; + this.instance.repeat.y = this.repeat.y; + this.instance.wrapS = this.wrapS; + this.instance.wrapT = this.wrapT; + + this.instance.needsUpdate = true; + + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +GameLib.D3.Texture.prototype.updateInstance = function(property) { + + if (GameLib.Utils.UndefinedOrNull(this.instance)) { + try { + this.createInstance(); + return; + } catch (error) { + console.error(error); + } + } + + if (GameLib.Utils.UndefinedOrNull(property)) { + throw new Error('need to specify a property'); + } + + if (property === 'image') { + + if (this.typeId === GameLib.D3.Texture.TEXTURE_TYPE_NORMAL) { + + if ( + GameLib.Utils.UndefinedOrNull(this.image) && + this.instance.image + ) { + try { + this.createInstance(); + } catch (error) { + console.error(error); + } + } + + if (this.image && this.image.instance && this.instance.image !== this.image.instance) { + try { + this.createInstance(); + } catch (error) { + console.error(error); + } + } + + } else if (this.typeId === GameLib.D3.Texture.TEXTURE_TYPE_CANVAS) { + + if ( + GameLib.Utils.UndefinedOrNull(this.canvas) && + this.instance.canvas + ) { + try { + this.createInstance(); + } catch (error) { + console.error(error); + } + } + + if (this.canvas && this.canvas.instance && this.instance.image !== this.canvas.instance) { + try { + this.createInstance(); + } catch (error) { + console.error(error); + } + } + + } else if (this.typeId === GameLib.D3.Texture.TEXTURE_TYPE_CUBE) { + + console.log('todo : cube images change check here'); + + } + + this.publish( + GameLib.Event.IMAGE_CHANGED, + { + texture : this + } + ); + + this.instance.needsUpdate = true; + } + + if (property === 'name') { + this.instance.name = this.name; + } + + if (property === 'flipY') { + this.instance.flipY = this.flipY; + } + + if (property === 'encoding') { + this.instance.encoding = this.encoding; + } + + if (property === 'offset') { + this.instance.offset.x = this.offset.x; + this.instance.offset.y = this.offset.y; + } + + if (property === 'repeat') { + this.instance.repeat.x = this.repeat.x; + this.instance.repeat.y = this.repeat.y; + } + + if (property === 'mapping') { + this.instance.mapping = this.mapping; + } + + if (property === 'format') { + this.instance.format = this.format; + } + + if (property === 'wrapS') { + this.instance.wrapS = this.wrapS; + } + + if (property === 'wrapT') { + this.instance.wrapT = this.wrapT; + } + + if (property === 'animated') { + GameLib.Event.Emit( + GameLib.Event.TEXTURE_ANIMATED_CHANGE, + { + texture : this + } + ) + } +}; + +/** + * Converts a GameLib.D3.Texture to a GameLib.D3.API.Texture + * @returns {GameLib.D3.API.Texture} + */ +GameLib.D3.Texture.prototype.toApiObject = function() { + + var apiTexture = new GameLib.D3.API.Texture( + this.id, + this.typeId, + this.name, + GameLib.Utils.IdOrNull(this.image), + this.images.map( + function(image) { + return GameLib.Utils.IdOrNull(image) + } + ), + this.wrapS, + this.wrapT, + this.repeat.toApiObject(), + this.data, + this.format, + this.mapping, + this.magFilter, + this.minFilter, + this.textureType, + this.anisotropy, + this.offset.toApiObject(), + this.generateMipmaps, + this.flipY, + this.mipmaps, + this.unpackAlignment, + this.premultiplyAlpha, + this.encoding, + GameLib.Utils.IdOrNull(this.canvas), + this.animated, + this.reverseAnimation, + this.forward, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiTexture; + +}; + +/** + * Converts from an Object texture to a GameLib.D3.Texture + * @param graphics GameLib.D3.Graphics + * @param objectTexture Object + * @constructor + */ +GameLib.D3.Texture.FromObject = function( + graphics, + objectTexture +) { + var apiTexture = GameLib.D3.API.Texture.FromObject(objectTexture); + + return new GameLib.D3.Texture( + graphics, + apiTexture + ); +}; + +/** + * TriangleEdge + * @param triangle + * @param edge + * @constructor + */ +GameLib.D3.TriangleEdge = function( + triangle, + edge +) { + this.triangle = triangle; + this.edge = edge; +}; +/** + * Runtime Vertex + * @constructor + * @param implementation + * @param apiVertex + */ +GameLib.D3.Vertex = function Vertex( + implementation, + apiVertex +) { + this.implementation = implementation; + if (implementation instanceof GameLib.D3.Graphics) { + this.implementation.isNotThreeThrow(); + } else if (implementation instanceof GameLib.D3.Physics) { + this.implementation.isNotCannonThrow(); + } else { + throw new Error('Unhandled implementation : ' + implementation); + } + + if (GameLib.Utils.UndefinedOrNull(apiVertex)) { + apiVertex = {}; + } + + if (apiVertex instanceof GameLib.D3.Vertex) { + return apiVertex; + } + + GameLib.D3.API.Vertex.call( + this, + apiVertex.position, + apiVertex.boneWeights + ); + + this.position = new GameLib.Vector3( + this.implementation, + this.position, + null + ); + + if (implementation instanceof GameLib.D3.Graphics) { + this.boneWeights = this.boneWeights.map( + function(apiBoneWeight) { + return new GameLib.D3.BoneWeight( + this.implementation, + apiBoneWeight + ) + }.bind(this) + ) + } +}; + +GameLib.D3.Vertex.prototype = Object.create(GameLib.D3.API.Vertex.prototype); +GameLib.D3.Vertex.prototype.constructor = GameLib.D3.Vertex; + +/** + * Converts a GameLib.D3.Vertex to GameLib.D3.API.Vertex + * @returns {GameLib.D3.API.Vertex} + */ +GameLib.D3.Vertex.prototype.toApiObject = function() { + + return new GameLib.D3.API.Vertex( + this.position.toApiObject(), + this.boneWeights.map(function(boneWeight){ + return boneWeight.toApiObject(); + }) + ); + +}; + +/** + * Returns a GameLib.D3.Vertex from a vertex Object + * @param implementation (graphics or physics object) + * @param objectVertex Object + * @returns {GameLib.D3.Vertex} + * @constructor + */ +GameLib.D3.Vertex.FromObject = function( + implementation, + objectVertex +) { + var apiVertex = GameLib.D3.API.Vertex.FromObject(objectVertex); + + return new GameLib.D3.Vertex( + implementation, + apiVertex + ); +}; + +/** + * Viewport Runtime + * @param graphics GameLib.D3.Graphics + * @param apiViewport GameLib.D3.API.Viewport + * @constructor + */ +GameLib.D3.Viewport = function ( + graphics, + apiViewport +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiViewport)) { + apiViewport = {}; + } + + if (apiViewport instanceof GameLib.D3.Viewport) { + return apiViewport; + } + + GameLib.D3.API.Viewport.call( + this, + apiViewport.id, + apiViewport.name, + apiViewport.width, + apiViewport.height, + apiViewport.x, + apiViewport.y, + apiViewport.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_VIEWPORT + ); +}; + +GameLib.D3.Viewport.prototype = Object.create(GameLib.D3.API.Viewport.prototype); +GameLib.D3.Viewport.prototype.constructor = GameLib.D3.Viewport; + +/** + * + * @returns {boolean} + */ +GameLib.D3.Viewport.prototype.createInstance = function() { + this.instance = true; + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * + */ +GameLib.D3.Viewport.prototype.updateInstance = function() { +}; + +/** + * GameLib.D3.Viewport to GameLib.D3.API.Viewport + * @returns {GameLib.D3.API.Viewport} + */ +GameLib.D3.Viewport.prototype.toApiObject = function() { + + var apiViewport = new GameLib.D3.API.Viewport( + this.id, + this.name, + this.width, + this.height, + this.x, + this.y, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiViewport; +}; + +/** + * GameLib.D3.Viewport from Object Viewport + * @param graphics + * @param objectComponent + * @returns {GameLib.D3.Viewport} + * @constructor + */ +GameLib.D3.Viewport.FromObject = function(graphics, objectComponent) { + + var apiViewport = GameLib.D3.API.Viewport.FromObject(objectComponent); + + return new GameLib.D3.Viewport( + graphics, + apiViewport + ); +}; +/** + * Runtime domElement for updating instance objects + * @param apiDomElement GameLib.API.DomElement + * @constructor + */ +GameLib.DomElement = function (apiDomElement) { + + if (GameLib.Utils.UndefinedOrNull(apiDomElement)) { + apiDomElement = {}; + } + + if (apiDomElement instanceof GameLib.DomElement) { + return apiDomElement; + } + + GameLib.API.DomElement.call( + this, + apiDomElement.id, + apiDomElement.name, + apiDomElement.domElementId, + apiDomElement.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_DOM_ELEMENT + ); +}; + +GameLib.DomElement.prototype = Object.create(GameLib.API.DomElement.prototype); +GameLib.DomElement.prototype.constructor = GameLib.DomElement; + +/** + * Creates an instance domElement + * @returns {*} + */ +GameLib.DomElement.prototype.createInstance = function() { + this.instance = document.getElementById(this.domElementId); + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates instance domElement + */ +GameLib.DomElement.prototype.updateInstance = function() { + this.instance = document.getElementById(this.domElementId); +}; + +/** + * Converts runtime DomElement to API DomElement + * @returns {GameLib.API.DomElement} + */ +GameLib.DomElement.prototype.toApiObject = function() { + return new GameLib.API.DomElement( + this.id, + this.name, + this.domElementId, + GameLib.Utils.IdOrNull(this.parentEntity) + ); +}; + +/** + * Appends domInstance to DOM instance + * @param domInstance + */ +GameLib.DomElement.prototype.append = function(domInstance) { + this.instance.appendChild(domInstance); +}; + +/** + * Clears DOM instance + */ +GameLib.DomElement.prototype.clear = function() { + this.instance.innerHTML = ''; +}; + +GameLib.DomElement.FromObject = function(objectDom) { + + var apiDomElement = GameLib.API.DomElement.FromObject(objectDom); + + var domElement = new GameLib.DomElement( + apiDomElement + ); + + return domElement; +}; +/** + * Runtime Dom + * @constructor + * @param document DOM Document + * @param window DOM Window + */ +GameLib.Dom = function( + document, + window +) { + this.document = document; + this.window = window; +}; + +/** + * GameLib.EntityManager + * @constructor + */ +GameLib.EntityManager = function(apiEntityManager) { + + if (GameLib.Utils.UndefinedOrNull(apiEntityManager)) { + apiEntityManager = {}; + } + + if (apiEntityManager instanceof GameLib.EntityManager) { + return apiEntityManager; + } + + GameLib.API.EntityManager.call( + this, + apiEntityManager.id, + apiEntityManager.name, + apiEntityManager.entities, + apiEntityManager.defaultEntity, + apiEntityManager.defaultRenderer + ); + + /** + * The 'register' array is a register of each component currently loaded - when the linking + * system starts it also loads all the current components from the entity manager + * @type {Array} + */ + this.register = []; + + GameLib.Event.Subscribe( + GameLib.Event.COMPONENT_REGISTER, + this.registerComponent.bind(this) + ); + + GameLib.Event.Subscribe( + GameLib.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_ENTITY_MANAGER, + { + 'entities' : [GameLib.Entity], + 'defaultEntity' : GameLib.Entity, + 'defaultRenderer' : GameLib.D3.Renderer + } + ); +}; + +GameLib.EntityManager.prototype = Object.create(GameLib.API.EntityManager.prototype); +GameLib.EntityManager.prototype.constructor = GameLib.EntityManager; + +GameLib.EntityManager.prototype.createInstance = function() { + this.instance = GameLib.EntityManager.Instance; + GameLib.Component.prototype.createInstance.call(this); +}; + +GameLib.EntityManager.prototype.registerComponent = function(data) { + + var length = this.register.length; + + GameLib.Utils.PushUnique(this.register, data.component); + + if (length !== this.register.length) { + GameLib.Event.Emit( + GameLib.Event.REGISTER_UPDATE, + { + register : this.register + } + ); + } +}; + +GameLib.EntityManager.prototype.removeComponent = function(data) { + + var index = this.register.indexOf(data.component); + + if (index !== -1) { + + this.register.splice(index, 1); + + GameLib.Event.Emit( + GameLib.Event.REGISTER_UPDATE, + { + register : this.register + } + ); + } + +}; + +/** + * Creates an GameLib.Entity and adds it to entities array + * @returns {*} + */ +GameLib.EntityManager.prototype.createEntity = function(name) { + + var apiEntity = new GameLib.API.Entity( + null, + name, + null, + null, + this + ); + + var entity = new GameLib.Entity( + apiEntity + ); + + this.entities.push(entity); + + this.defaultEntity = entity; + + GameLib.Event.Emit( + GameLib.Event.NEW_ENTITY, + { + entity : entity + } + ); + + return entity; +}; + +/** + * Returns an entity by ID or null + * @param id + * @returns {*} + */ +GameLib.EntityManager.prototype.findEntityById = function(id) { + + return this.entities.reduce( + function(result, entity){ + + if (entity.id === id) { + result = entity; + } + + return result; + }, + null + ); +}; + +GameLib.EntityManager.prototype.findComponentById = function(id) { + return this.register.reduce( + function(result, component){ + if (component.id === id){ + result = component; + } + return result; + }, + null + ); +}; + +GameLib.EntityManager.prototype.findHelperByObject = function(object) { + return this.register.reduce( + function(result, component) { + if (component instanceof GameLib.D3.Helper) { + if (component.object === object) { + result = component; + } + } + return result; + }, + null + ); +}; + +GameLib.EntityManager.prototype.findSceneByObject = function(object) { + return this.register.reduce( + function(result, component) { + if (component instanceof GameLib.D3.Scene) { + + if (component.meshes.indexOf(object) !== -1) { + result = component; + } + + if (component.lights.indexOf(object) !== -1) { + result = component; + } + } + return result; + }, + null + ); +}; + + +/** + * Adds an entity to this manager + * @param entity GameLib.Entity + */ +GameLib.EntityManager.prototype.addEntity = function(entity) { + entity.parentEntityManager = this; + this.entities.push(entity); +}; + +/** + * Returns entity by name + * @param name + * @returns {*} + */ +GameLib.EntityManager.prototype.queryByName = function(name) { + return this.entities.reduce( + function(result, entity){ + if (entity.name === name) { + result = entity; + } + return result; + }, + null + ) +}; + +/** + * Removes an entity - do we remove all its components as well? + * @param entity GameLib.D3.Entity + * @returns boolean true if successful + */ +GameLib.EntityManager.prototype.removeEntity = function(entity) { + + var index = this.entities.indexOf(entity); + + if (index === -1) { + console.log('failed to remove entity : ', entity); + return false; + } + this.entities.splice(index, 1); + + entity.parentEntityManager = null; + + return true; +}; + +/** + * Returns all the entities with the following components + * @param components GameLib.Component[] + */ +GameLib.EntityManager.prototype.findEntities = function(components) { + + var entities = this.entities.reduce( + function(result, entity) { + + var hasAllComponents = components.reduce( + function(componentResult, component) { + if (!entity.hasComponent(component)) { + componentResult = false; + } + return componentResult; + }, + true + ); + + if (hasAllComponents) { + result.push(entity); + } + + return result; + }, + [] + ); + + return entities; +}; + +/** + * Returns all actual components of all entities that contain this component + * @param constructors (array of constructor or just a single constructor) + */ +GameLib.EntityManager.prototype.queryComponents = function(constructors) { + + return this.register.reduce( + function(result, component) { + + if (constructors instanceof Array) { + constructors.map( + function(constructor) { + if (component instanceof constructor) { + if (result.indexOf(component) === -1) { + result.push(component); + } + } + } + ); + } else { + if (component instanceof constructors) { + if (result.indexOf(component) === -1) { + result.push(component); + } + } + } + + return result; + }, + [] + ); + +}; + +/** + * Converts a GameLib.Entity to GameLib.API.Entity + * @returns {GameLib.API.EntityManager} + */ +GameLib.EntityManager.prototype.toApiObject = function() { + + var apiEntities = this.entities.map( + function (entity) { + return GameLib.Utils.IdOrNull(entity); + } + ); + + var apiEntityManager = new GameLib.API.EntityManager( + this.id, + this.name, + apiEntities, + GameLib.Utils.IdOrNull(this.defaultEntity), + GameLib.Utils.IdOrNull(this.defaultRenderer) + ); + + return apiEntityManager; +}; + +/** + * Returns an EntityManager from an Object entity manager + * @param objectEntityManager Object + * @constructor + */ +GameLib.EntityManager.FromObject = function(objectEntityManager) { + + var apiEntityManager = GameLib.API.EntityManager.FromObject(objectEntityManager); + + var entityManager = new GameLib.EntityManager(apiEntityManager); + + return entityManager; +}; + +/** + * Runtime Entity + * @param apiEntity GameLib.D3.API.Entity + * @constructor + */ +GameLib.Entity = function ( + apiEntity +) { + if (GameLib.Utils.UndefinedOrNull(apiEntity)) { + apiEntity = {}; + } + + if (apiEntity instanceof GameLib.Entity) { + return apiEntity; + } + + GameLib.API.Entity.call( + this, + apiEntity.id, + apiEntity.name, + apiEntity.components, + apiEntity.parentEntity, + apiEntity.parentEntityManager + ); + + this.componentToCreate = 0; + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_ENTITY, + { + 'components' : [GameLib.Component], + 'activeComponent' : GameLib.Component + } + ); +}; + +GameLib.Entity.prototype = Object.create(GameLib.API.Entity.prototype); +GameLib.Entity.prototype.constructor = GameLib.Entity; + +/** + * Creates an entity instance + */ +GameLib.Entity.prototype.createInstance = function() { + /** + * FUCK ecsjs and tiny-ecs - no client-side support and shitty code (only takes constructors as args) + */ + this.instance = true; + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Adds a component to this entity through the instance (should notify the entity manager instance) + * @param component + */ +GameLib.Entity.prototype.addComponent = function(component) { + + GameLib.Utils.PushUnique(this.components, component); + + if (component instanceof GameLib.D3.Mesh) { + + /** + * For meshes, simply get the children components + * @type {Array} + */ + component.getChildrenComponents().map(function(childComponent){ + GameLib.Utils.PushUnique(this.components, childComponent); + childComponent.parentEntity = this; + }.bind(this)) + + } else { + /** + * Here we will dig into this component - find all its 'parentEntity' members - and update them accordingly + */ + component.buildIdToObject(); + + /** + * Also add the child components of this component as components of this entity + */ + for (var property in component.idToObject) { + if (component.idToObject.hasOwnProperty(property) && + component.idToObject[property] !== component && + component.idToObject[property] instanceof GameLib.Component + ) { + GameLib.Utils.PushUnique(this.components, component.idToObject[property]); + component.idToObject[property].parentEntity = this; + } + } + } + + + /** + * Finally, we are the boss component - update my parent entity + * @type {GameLib.Entity} + */ + component.parentEntity = this; + +}; + +/** + * Returns all components of type 'constructor' + * @param constructor + */ +GameLib.Entity.prototype.getComponents = function(constructor) { + + var components = this.components.reduce( + function(result, component) { + if (component instanceof constructor) { + result.push(component); + } + return result; + }, + [] + ); + + return components; +}; + +/** + * Returns the first component or null + * @param constructor + */ +GameLib.Entity.prototype.getFirstComponent = function(constructor) { + + var components = this.getComponents(constructor); + + if (components.length > 0) { + return components[0]; + } + + return null; +}; + +/** + * Returns true when this entity has a certain component, false otherwise + * @param constructor + */ +GameLib.Entity.prototype.hasComponent = function(constructor) { + + var has = this.components.reduce( + function(result, component) { + if (component instanceof constructor) { + result = true; + } + return result; + }, + false + ); + + return has; +}; + +/** + * + * @param component + */ +GameLib.Entity.prototype.removeComponent = function(component) { + + if (GameLib.Utils.UndefinedOrNull(component)) { + component = this.activeComponent; + } + + var childIndex = this.components.indexOf(component); + if (childIndex !== -1) { + this.components.splice(childIndex, 1); + } else { + console.error('component not found'); + } + + /** + * Break the dependency to the parent + */ + component.parentEntity = null; + + return true; +}; + +/** + * Updates an entity instance + */ +GameLib.Entity.prototype.updateInstance = function() { + console.log('entity update instance called'); +}; + +/** + * Converts a GameLib.Entity to GameLib.API.Entity + * @returns {GameLib.API.Entity} + */ +GameLib.Entity.prototype.toApiObject = function() { + + var apiComponents = this.components.map( + function(component) { + return GameLib.Utils.IdOrNull(component); + } + ); + + return new GameLib.API.Entity( + this.id, + this.name, + apiComponents, + GameLib.Utils.IdOrNull(this.parentEntity), + GameLib.Utils.IdOrNull(this.parentEntityManager) + ); + +}; + +/** + * Entity from Object + * @param objectEntity Object + * @param parentEntityManager GameLib.D3.EntityManager + * @returns {GameLib.Entity} + * @constructor + */ +GameLib.Entity.FromObject = function(objectEntity, parentEntityManager) { + + var apiEntity = GameLib.API.Entity.FromObject(objectEntity); + + var entity = new GameLib.Entity( + apiEntity + ); + + if (GameLib.Utils.UndefinedOrNull(parentEntityManager)) { + return entity; + } + + parentEntityManager.addEntity(entity); + + return entity; +}; + +/** + * Stats component for displaying some render statistics (framerate, memory consumption, etc) + * @param gui + * @param id + * @param name + * @param domElement + * @param objects + * @param parentEntity + * @constructor + */ +GameLib.GUI = function( + gui, + id, + name, + domElement, + objects, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(gui)) { + throw new Error('Need GUI object') + } + this.gui = gui; + + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'GUI (' + id + ')'; + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(domElement)) { + console.warn('Need a DOM element for stats'); + throw new Error('Need a DOM element for stats'); + } + this.domElement = domElement; + + if (GameLib.Utils.UndefinedOrNull(objects)) { + objects = []; + } + this.objects = objects; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_GUI, + { + 'domElement': GameLib.DomElement + } + ); +}; + +GameLib.GUI.prototype = Object.create(GameLib.Component.prototype); +GameLib.GUI.prototype.constructor = GameLib.GUI; + +/** + * Creates a helper instance + */ +GameLib.GUI.prototype.createInstance = function() { + this.instance = new dat.GUI( { autoPlace: false } ); + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +GameLib.GUI.prototype.updateInstance = function() { + this.instance = new dat.GUI( { autoPlace: false } ); +}; + +/** + * Removes empty folders from instance + */ +GameLib.GUI.prototype.removeEmtpyFolders = function() { + this.instance.removeEmptyFolders(); +}; + +/** + * Remove all folders from instance + */ +GameLib.GUI.prototype.removeAllFolders = function() { + this.instance.removeAllFolders(); +}; + +/** + * Adds a folder to instance + * @param folderName + * @returns {*} + */ +GameLib.GUI.prototype.addFolder = function(folderName) { + try { + return this.instance.addFolder(folderName); + } catch (e) { + try { + folderName += ' duplicate (' + GameLib.Utils.RandomId() + ')'; + return this.instance.addFolder(folderName); + } catch (e) { + console.log(e.message); + return null; + } + } +}; + +/** + * Runtime Matrix4 + * @param graphics + * @param parentObject + * @param apiMatrix4 + * @param grain + * @constructor + */ +GameLib.Matrix4 = function( + graphics, + apiMatrix4, + parentObject, + grain +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiMatrix4)) { + apiMatrix4 = {}; + } + + if (apiMatrix4 instanceof GameLib.Matrix4) { + return apiMatrix4; + } + + GameLib.API.Matrix4.call( + this, + apiMatrix4.rows[0], + apiMatrix4.rows[1], + apiMatrix4.rows[2], + apiMatrix4.rows[3] + ); + + if (GameLib.Utils.UndefinedOrNull(parentObject)) { + parentObject = null; + } + this.parentObject = parentObject; + + if (GameLib.Utils.UndefinedOrNull(grain)) { + grain = 0.001; + } + this.grain = grain; + + this.rows = this.rows.map( + function(row) { + if (row instanceof GameLib.API.Vector4) { + return new GameLib.Vector4( + this.graphics, + row, + this, + this.grain + ); + } else { + console.warn('Attempted conversion of wrong instance'); + throw new Error('Attempted conversion of wrong instance'); + } + }.bind(this) + ); + + this.forward = new GameLib.Vector4( + this.graphics, + this.forward, + this, + this.grain + ); + + this.left = new GameLib.Vector4( + this.graphics, + this.left, + this, + this.grain + ); + + this.up = new GameLib.Vector4( + this.graphics, + this.up, + this, + this.grain + ); + + this.createInstance(); +}; + +GameLib.Matrix4.prototype = Object.create(GameLib.API.Matrix4.prototype); +GameLib.Matrix4.prototype.constructor = GameLib.Matrix4; + +/** + * Creates a matrix 4 instance (currently from graphics lib) + * @param update + */ +GameLib.Matrix4.prototype.createInstance = function(update) { + + this.instance = new THREE.Matrix4(); + + /** + * We transpose our matrix when we send it to three since we use a different ordering system + * They say they use + */ + this.instance.set( + this.rows[0].x, + this.rows[1].x, + this.rows[2].x, + this.rows[3].x, + this.rows[0].y, + this.rows[1].y, + this.rows[2].y, + this.rows[3].y, + this.rows[0].z, + this.rows[1].z, + this.rows[2].z, + this.rows[3].z, + this.rows[0].w, + this.rows[1].w, + this.rows[2].w, + this.rows[3].w + ); +}; + +/** + * Updates this instance + */ +GameLib.Matrix4.prototype.updateInstance = function() { + + this.instance.set( + this.rows[0].x, + this.rows[1].x, + this.rows[2].x, + this.rows[3].x, + this.rows[0].y, + this.rows[1].y, + this.rows[2].y, + this.rows[3].y, + this.rows[0].z, + this.rows[1].z, + this.rows[2].z, + this.rows[3].z, + this.rows[0].w, + this.rows[1].w, + this.rows[2].w, + this.rows[3].w + ); + + if (this.parentObject && + this.parentObject.updateInstance) { + this.parentObject.updateInstance(); + } +}; + +/** + * GameLib.Matrix4 to GameLib.API.Matrix4 + * @returns {*} + */ +GameLib.Matrix4.prototype.toApiObject = function () { + + return new GameLib.API.Matrix4( + this.rows[0].toApiObject(), + this.rows[1].toApiObject(), + this.rows[2].toApiObject(), + this.rows[3].toApiObject() + ); + +}; + +/** + * Creates a GameLib.Matrix4 from an Object matrix + * @param graphics GameLib.D3.Graphics + * @param objectMatrix Object + * @param parentObject + * @returns {GameLib.Matrix4} + * @constructor + */ +GameLib.Matrix4.FromObject = function(graphics, objectMatrix, parentObject) { + + var apiMatrix = new GameLib.API.Matrix4.FromObject(objectMatrix); + + return new GameLib.Matrix4( + graphics, + parentObject, + apiMatrix + ) +}; + +/** + * Lookat + * @param position + * @param target + * @param up + * @returns {GameLib.Matrix4} + */ +GameLib.Matrix4.prototype.lookAt = function (position, target, up) { + + var pv = new GameLib.API.Vector3(position.x, position.y, position.z); + + var forward = pv.subtract(target).normalize(); + + if (forward.squared() === 0) { + forward.z = 1; + } + + var left = up.cross(forward).normalize(); + + if (left.squared() === 0) { + forward.x += 0.0001; + left = up.cross(forward).normalize(); + } + + var _up = forward.cross(left); + + this.rows[0].x = left.x; + this.rows[0].y = left.y; + this.rows[0].z = left.z; + + this.rows[1].x = _up.x; + this.rows[1].y = _up.y; + this.rows[1].z = _up.z; + + this.rows[2].x = forward.x; + this.rows[2].y = forward.y; + this.rows[2].z = forward.z; + + this.forward.x = forward.x; + this.forward.y = forward.y; + this.forward.z = forward.z; + + this.left.x = left.x; + this.left.y = left.y; + this.left.z = left.z; + + this.up.x = _up.x; + this.up.y = _up.y; + this.up.z = _up.z; + + this.updateInstance(); + + return this; +}; + +/** + * Identity + */ +GameLib.Matrix4.prototype.identity = function () { + this.rows = [ + new GameLib.Vector4( + this.graphics, + new GameLib.API.Vector4(1,0,0,0), + this, + this.grain + ), + new GameLib.Vector4( + this.graphics, + new GameLib.API.Vector4(0,1,0,0), + this, + this.grain + ), + new GameLib.Vector4( + this.graphics, + new GameLib.API.Vector4(0,0,1,0), + this, + this.grain + ), + new GameLib.Vector4( + this.graphics, + new GameLib.API.Vector4(0,0,0,1), + this, + this.grain + ) + ]; +}; + +/** + * Transpose + * @returns {GameLib.Matrix4} + */ +GameLib.Matrix4.prototype.transpose = function () { + + this.temp[0].x = this.rows[0].x; + this.temp[0].y = this.rows[1].x; + this.temp[0].z = this.rows[2].x; + this.temp[0].w = this.rows[3].x; + + this.temp[1].x = this.rows[0].y; + this.temp[1].y = this.rows[1].y; + this.temp[1].z = this.rows[2].y; + this.temp[1].w = this.rows[3].y; + + this.temp[2].x = this.rows[0].z; + this.temp[2].y = this.rows[1].z; + this.temp[2].z = this.rows[2].z; + this.temp[2].w = this.rows[3].z; + + this.temp[3].x = this.rows[0].w; + this.temp[3].y = this.rows[1].w; + this.temp[3].z = this.rows[2].w; + this.temp[3].w = this.rows[3].w; + + this.rows[0].x = this.temp[0].x; + this.rows[0].y = this.temp[0].y; + this.rows[0].z = this.temp[0].z; + this.rows[0].w = this.temp[0].w; + + this.rows[1].x = this.temp[1].x; + this.rows[1].y = this.temp[1].y; + this.rows[1].z = this.temp[1].z; + this.rows[1].w = this.temp[1].w; + + this.rows[2].x = this.temp[2].x; + this.rows[2].y = this.temp[2].y; + this.rows[2].z = this.temp[2].z; + this.rows[2].w = this.temp[2].w; + + this.rows[3].x = this.temp[3].x; + this.rows[3].y = this.temp[3].y; + this.rows[3].z = this.temp[3].z; + this.rows[3].w = this.temp[3].w; + + return this; +}; + +/** + * Runtime mouse for updating instance objects + * @param graphics GameLib.D3.Graphics + * @param apiMouse GameLib.API.Mouse + * @constructor + */ +GameLib.Mouse = function (graphics, apiMouse) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiMouse)){ + apiMouse = {}; + } + + if (apiMouse instanceof GameLib.Mouse) { + return apiMouse; + } + + GameLib.API.Mouse.call( + this, + apiMouse.id, + apiMouse.name, + apiMouse.x, + apiMouse.y, + apiMouse.parentEntity + ); + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_MOUSE + ); +}; + +GameLib.Mouse.prototype = Object.create(GameLib.API.Mouse.prototype); +GameLib.Mouse.prototype.constructor = GameLib.Mouse; + +/** + * Creates an instance mouse + * @param update + * @returns {*} + */ +GameLib.Mouse.prototype.createInstance = function(update) { + this.instance = true; + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance vector, calls updateInstance on the parent object + */ +GameLib.Mouse.prototype.updateInstance = function() { +}; + +/** + * Converts runtime vector to API Vector + * @returns {GameLib.API.Mouse} + */ +GameLib.Mouse.prototype.toApiObject = function() { + return new GameLib.API.Mouse( + this.id, + this.name, + this.x, + this.y, + this.parentEntity + ); +}; + +/** + * Runtime quaternion for updating instance objects + * @param implementation + * @param parentObject GameLib.D3.* + * @param apiQuaternion GameLib.API.Quaternion + * @param grain Number + * @constructor + */ +GameLib.Quaternion = function ( + implementation, + apiQuaternion, + parentObject, + grain +) { + this.implementation = implementation; + + if (implementation instanceof GameLib.D3.Graphics) { + this.physics = null; + this.graphics = implementation; + this.graphics.isNotThreeThrow(); + } else if (implementation instanceof GameLib.D3.Physics) { + this.graphics = null; + this.physics = implementation; + this.physics.isNotCannonThrow(); + } else { + throw new Error('Unhandled implementation : ' + implementation); + } + + if (GameLib.Utils.UndefinedOrNull(apiQuaternion)) { + apiQuaternion = {}; + } + + if (apiQuaternion instanceof GameLib.Quaternion) { + return apiQuaternion; + } + + GameLib.API.Quaternion.call( + this, + apiQuaternion.x, + apiQuaternion.y, + apiQuaternion.z, + apiQuaternion.w, + apiQuaternion.axis, + apiQuaternion.angle + ); + + if (GameLib.Utils.UndefinedOrNull(parentObject)) { + parentObject = null; + } + this.parentObject = parentObject; + + this.axis = new GameLib.Vector3( + this.implementation, + this.axis, + this, + this.grain + ); + + Object.defineProperty( + this, + 'angle', + GameLib.Utils.LimitToPI('angle', this.angle) + ); + + if (GameLib.Utils.UndefinedOrNull(grain)) { + grain = 0.001; + } + this.grain = grain; + + this.createInstance(); +}; + +GameLib.Quaternion.prototype = Object.create(GameLib.API.Quaternion.prototype); +GameLib.Quaternion.prototype.constructor = GameLib.Quaternion; + +/** + * Creates an instance quaternion + * @returns {*} + */ +GameLib.Quaternion.prototype.createInstance = function() { + + if (this.graphics) { + this.instance = new THREE.Quaternion( + this.x, + this.y, + this.z, + this.w + ); + } + + if (this.physics) { + this.instance = new CANNON.Quaternion( + this.x, + this.y, + this.z, + this.w + ); + } +}; + +/** + * Updates the instance vector, calls updateInstance on the parent object + */ +GameLib.Quaternion.prototype.updateInstance = function(property) { + + this.instance.x = this.x; + this.instance.y = this.y; + this.instance.z = this.z; + this.instance.w = this.w; + + if (this.parentObject && + this.parentObject.updateInstance) { + this.parentObject.updateInstance(property); + } +}; + +/** + * Converts runtime quaternion to API quaternion + * @returns {*} + */ +GameLib.Quaternion.prototype.toApiObject = function() { + return new GameLib.API.Quaternion( + this.x, + this.y, + this.z, + this.w, + this.axis.toApiObject(), + this.angle + ); +}; + +/** + * Checks if quaternion is equal to another quaternion + * @param quaternion + * @returns {boolean} + */ +GameLib.Quaternion.prototype.equals = function(quaternion) { + + return ( + this.x === quaternion.x && + this.y === quaternion.y && + this.z === quaternion.z && + this.w === quaternion.w && + this.axis.equals(quaternion.axis) && + this.angle === quaternion.angle + ); + +}; + +GameLib.Quaternion.prototype.setFrom = function(quaternion) { + this.x = quaternion.x; + this.y = quaternion.y; + this.z = quaternion.z; + this.w = quaternion.w; + this.axis.setFrom(quaternion.axis); + this.angle = quaternion.angle; +}; + +GameLib.Quaternion.prototype.copy = function(quaternion) { +console.log('todo'); +}; +/** + * System takes care of updating all the entities (based on their component data) + * @param implementation + * @param apiSystem GameLib.API.System + * @constructor + */ +GameLib.System = function( + apiSystem +) { + + if (GameLib.Utils.UndefinedOrNull(apiSystem)) { + apiSystem = {}; + } + + if (apiSystem instanceof GameLib.System) { + return apiSystem; + } + + GameLib.API.System.call( + this, + apiSystem.id, + apiSystem.name, + apiSystem.systemType, + apiSystem.parentEntity + ); + + this.started = false; + + this.paused = false; + + var componentType = GameLib.Component.COMPONENT_SYSTEM; + var linkedObjects = {}; + + if (apiSystem.systemType === GameLib.System.SYSTEM_TYPE_ANIMATION) { + componentType = GameLib.Component.COMPONENT_SYSTEM_ANIMATION; + } + + if (apiSystem.systemType === GameLib.System.SYSTEM_TYPE_CUSTOM) { + componentType = GameLib.Component.COMPONENT_SYSTEM_CUSTOM_CODE; + } + + if (apiSystem.systemType === GameLib.System.SYSTEM_TYPE_GUI) { + componentType = GameLib.Component.COMPONENT_SYSTEM_GUI; + } + + if (apiSystem.systemType === GameLib.System.SYSTEM_TYPE_INPUT) { + componentType = GameLib.Component.COMPONENT_SYSTEM_INPUT; + linkedObjects.mouseControls = [GameLib.D3.Controls.Mouse]; + linkedObjects.keyboardControls = [GameLib.D3.Controls.Keyboard]; + linkedObjects.touchControls = [GameLib.D3.Controls.Touch]; + linkedObjects.editorControls = [GameLib.D3.Controls.Editor]; + } + + if (apiSystem.systemType === GameLib.System.SYSTEM_TYPE_LINKING) { + componentType = GameLib.Component.COMPONENT_SYSTEM_LINKING; + } + + if (apiSystem.systemType === GameLib.System.SYSTEM_TYPE_PHYSICS) { + componentType = GameLib.Component.COMPONENT_SYSTEM_PHYSICS; + } + + if (apiSystem.systemType === GameLib.System.SYSTEM_TYPE_RENDER) { + componentType = GameLib.Component.COMPONENT_SYSTEM_RENDER; + } + + if (apiSystem.systemType === GameLib.System.SYSTEM_TYPE_STORAGE) { + componentType = GameLib.Component.COMPONENT_SYSTEM_STORAGE; + } + + if (apiSystem.systemType === GameLib.System.SYSTEM_TYPE_VISUALIZATION) { + componentType = GameLib.Component.COMPONENT_SYSTEM_VISUALIZATION; + } + + if (apiSystem.systemType === GameLib.System.SYSTEM_TYPE_PARTICLE) { + componentType = GameLib.Component.COMPONENT_SYSTEM_PARTICLE; + } + + if (apiSystem.systemType === GameLib.System.SYSTEM_TYPE_AUDIO) { + componentType = GameLib.Component.COMPONENT_SYSTEM_AUDIO; + linkedObjects.audioComponents = [GameLib.D3.Audio]; + } + + GameLib.Component.call( + this, + componentType + ); + +}; + +GameLib.System.prototype = Object.create(GameLib.API.System.prototype); +GameLib.System.prototype.constructor = GameLib.System; + +GameLib.System.SYSTEM_TYPE_NONE = 0x0; +GameLib.System.SYSTEM_TYPE_RENDER = 0x1; +GameLib.System.SYSTEM_TYPE_ANIMATION = 0x2; +GameLib.System.SYSTEM_TYPE_INPUT = 0x4; +GameLib.System.SYSTEM_TYPE_STORAGE = 0x8; +GameLib.System.SYSTEM_TYPE_GUI = 0x10; +GameLib.System.SYSTEM_TYPE_PHYSICS = 0x20; +GameLib.System.SYSTEM_TYPE_LINKING = 0x40; +GameLib.System.SYSTEM_TYPE_CUSTOM = 0x80; +GameLib.System.SYSTEM_TYPE_VISUALIZATION = 0x100; +GameLib.System.SYSTEM_TYPE_PARTICLE = 0x200; +GameLib.System.SYSTEM_TYPE_AUDIO = 0x400; +GameLib.System.SYSTEM_TYPE_ALL = 0xFFFF; + +GameLib.System.prototype.createInstance = function() { + this.instance = true; + GameLib.Component.prototype.createInstance.call(this); +}; + +/** + * @callback + * @override + */ +GameLib.System.prototype.start = function() { + this.started = true; + console.log('starting ' + this.name); +}; + +/** + * @callback + * @override + */ +GameLib.System.prototype.stop = function() { + this.started = false; + console.log('stopping ' + this.name); +}; + +/** + * Converts runtime vector to API Vector + * @returns {GameLib.API.System} + */ +GameLib.System.prototype.toApiObject = function() { + return new GameLib.API.System( + this.id, + this.name, + this.systemType, + GameLib.Utils.IdOrNull(this.parentEntity) + ); +}; + +GameLib.System.prototype.restart = function() { + console.log('restarting system : ' + this.name); + this.stop(); + this.start(); +}; +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem GameLib.API.System + * @constructor + */ +GameLib.System.Animation = function( + apiSystem +) { + GameLib.System.call( + this, + apiSystem + ); + + this.animations = {}; + this.latest = {}; + this.textures = {}; + this.textureIds = []; + + this.animationMeshAddedSubscription = null; + this.animationMeshRemovedSubscription = null; + this.instanceCreatedSubscription = null; + this.removeComponentSubscription = null; + this.textureAnimatedSubscription = null; + + /** + * Sometimes we want to animate texture instances directly, without the overhead of a GameLib.Texture + */ + this.animateTextureInstanceSubscription = null; +}; + +GameLib.System.Animation.prototype = Object.create(GameLib.System.prototype); +GameLib.System.Animation.prototype.constructor = GameLib.System.Animation; + +GameLib.System.Animation.prototype.start = function() { + + GameLib.System.prototype.start.call(this); + + this.beforeRenderSubscription = GameLib.Event.Subscribe( + GameLib.Event.BEFORE_RENDER, + this.beforeRender.bind(this) + ); + + var animations = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Animation); + + animations.map(function(animation){ + animation.meshes.map( + function(mesh) { + this.attachAnimation(animation, mesh); + }.bind(this) + ) + }.bind(this)); + + this.animationMeshAddedSubscription = GameLib.Event.Subscribe( + GameLib.Event.ANIMATION_MESH_ADDED, + function(data) { + this.attachAnimation(data.animation, data.mesh); + }.bind(this) + ); + + this.animationMeshRemovedSubscription = GameLib.Event.Subscribe( + GameLib.Event.ANIMATION_MESH_REMOVED, + function(data) { + this.detachAnimation(data.mesh); + }.bind(this) + ); + + this.instanceCreatedSubscription = GameLib.Event.Subscribe( + GameLib.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + this.removeComponentSubscription = GameLib.Event.Subscribe( + GameLib.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + this.textureAnimatedSubscription = GameLib.Event.Subscribe( + GameLib.Event.TEXTURE_ANIMATED_CHANGE, + this.textureAnimatedChange.bind(this) + ); + + this.animateTextureInstanceSubscription = GameLib.Event.Subscribe( + GameLib.Event.ANIMATE_TEXTURE_INSTANCE, + this.animateTextureInstance.bind(this) + ) +}; + +GameLib.System.Animation.prototype.instanceCreated = function(data) { + if ( + data.component instanceof GameLib.D3.Texture && + data.component.animated + ) { + + if (data.component.repeat.x > 1 || data.component.repeat.x < 0) { + console.warn('cannot animate a texture with repeat.x greater than 1 or less than 0'); + data.component.animated = false; + return; + } + + if (data.component.repeat.y > 1 || data.component.repeat.y < 0) { + console.warn('cannot animate a texture with repeat.y greater than 1 or less than 0'); + data.component.animated = false; + return; + } + + this.textures[data.component.id] = data.component; + this.textureIds = Object.keys(this.textures); + } +}; + +GameLib.System.Animation.prototype.removeComponent = function(data) { + if ( + data.component instanceof GameLib.D3.Texture && + data.component.animated + ) { + if (GameLib.Utils.UndefinedOrNull(this.textures[data.component.id])) { + console.warn('tried to remove an animated texture, which should have been in the list but isnt: ' + data.component.name); + } else { + delete this.textures[data.component.id]; + this.textureIds = Object.keys(this.textures); + } + } +}; + +GameLib.System.Animation.prototype.textureAnimatedChange = function(data) { + + if (data.texture.animated) { + + if (data.texture.repeat.x > 1 || data.texture.repeat.x < 0) { + console.warn('cannot animate a texture with repeat.x greater than 1 or less than 0'); + data.texture.animated = false; + return; + } + + if (data.texture.repeat.y > 1 || data.texture.repeat.y < 0) { + console.warn('cannot animate a texture with repeat.y greater than 1 or less than 0'); + data.texture.animated = false; + return; + } + + this.textures[data.texture.id] = data.texture; + this.textureIds = Object.keys(this.textures); + + } else { + + if (GameLib.Utils.UndefinedOrNull(this.textures[data.texture.id])) { + console.warn('tried to remove an animated texture, which should have been in the list but isnt: ' + data.texture.name); + } else { + delete this.textures[data.texture.id]; + this.textureIds = Object.keys(this.textures); + } + } + +}; + +/** + * This adds a texture instance directly on our textures to be animated - to bypass our GameLib component and linking + * system, which adds too much overhead for managing textures + * @param data + */ +GameLib.System.Animation.prototype.animateTextureInstance = function(data) { + + if (data.texture.repeat.x > 1 || data.texture.repeat.x < 0) { + console.warn('cannot animate a texture with repeat.x greater than 1 or less than 0'); + data.texture.userData.animated = false; + return; + } + + if (data.texture.repeat.y > 1 || data.texture.repeat.y < 0) { + console.warn('cannot animate a texture with repeat.y greater than 1 or less than 0'); + data.texture.userData.animated = false; + return; + } + + data.texture.userData.animated = true; + + this.textures[data.texture.id] = data.texture; + this.textureIds = Object.keys(this.textures); +}; + + +GameLib.System.Animation.prototype.beforeRender = function(data) { + + if (this.paused) { + return; + } + + var delta = data.delta; + + for (var property in this.animations) { + if (this.animations.hasOwnProperty(property)) { + + var processing = []; + + if (this.animations[property].length > 0) { + + var rotationDone = false; + var positionDone = false; + var scaleDone = false; + + for (var i = 0; i < this.animations[property].length; i++) { + if (this.animations[property][i].type === 'rotation' && !rotationDone) { + rotationDone = true; + processing.push(this.animations[property][i]); + } + + if (this.animations[property][i].type === 'position' && !positionDone) { + +// if (this.animations[property][i].animation.blocking.position) { + // positionDone = true; + // } + + processing.push(this.animations[property][i]); + } + + if (this.animations[property][i].type === 'scale' && !scaleDone) { + //scaleDone = true; + processing.push(this.animations[property][i]); + } + + if (scaleDone && positionDone && rotationDone) { + break; + } + } + } + + processing.map( + function(__property) { + return function(animationObject) { + + var done = false; + + var increment = 0; + + if (animationObject.type === 'rotation') { + increment = animationObject.animation.rotationSpeed * delta; + } + + if (animationObject.type === 'position') { + increment = animationObject.animation.translationSpeed * delta; + } + + if (animationObject.type === 'scale') { + increment = animationObject.animation.scaleSpeed * delta; + } + + if (animationObject.from < animationObject.to) { + animationObject.from += increment; + } else { + animationObject.from -= increment; + } + + if (Math.abs(animationObject.from - animationObject.to) < increment) { + animationObject.mesh.instance[animationObject.type][animationObject.axis] = animationObject.to; + done = true; + } else { + animationObject.mesh.instance[animationObject.type][animationObject.axis] = animationObject.from; + } + + if (done) { + var index = this.animations[__property].indexOf(animationObject); + this.animations[__property].splice(index, 1); + } + + }.bind(this); + }.bind(this)(property) + ); + } + } + + this.textureIds.map( + function(textureId) { + + var texture = this.textures[textureId]; + + if (texture.reverseAnimation || (texture.userData && texture.userData.reverseAnimation)) { + + if (texture.forward === true || (texture.userData && texture.userData.forward === true)) { + texture.offset.x += texture.repeat.x; + if (texture.offset.x >= (1 - texture.repeat.x)) { + if (texture.offset.y >= (1 - texture.repeat.y)) { + texture.offset.x = (1 - texture.repeat.x); + texture.offset.y = (1 - texture.repeat.y); + + if (texture.userData) { + texture.userData.forward = false; + } else { + texture.forward = false; + } + + } else { + texture.offset.x = 0; + texture.offset.y += texture.repeat.y; + } + } + } + + if (texture.forward === false || (texture.userData && texture.userData.forward === false)) { + texture.offset.x -= texture.repeat.x; + if (texture.offset.x <= 0) { + texture.offset.x = 0; + if (texture.offset.y < texture.repeat.y) { + texture.offset.x = texture.repeat.x; + texture.offset.y = 0; + if (texture.userData) { + texture.userData.forward = true; + } else { + texture.forward = true; + } + } else { + texture.offset.x = (1 - texture.repeat.x); + texture.offset.y -= texture.repeat.y; + } + } + } + + } else { + + texture.offset.x += texture.repeat.x; + + if (texture.offset.x >= (1 - texture.repeat.x)) { + if (texture.offset.y >= (1 - texture.repeat.y)) { + texture.offset.x = 0; + texture.offset.y = 0; + } else { + texture.offset.x = 0; + texture.offset.y += texture.repeat.y; + } + } + + } + + if (!texture.userData) { + texture.updateInstance('offset'); + } + + }.bind(this) + ) +}; + +GameLib.System.Animation.prototype.detachAnimation = function(mesh) { + + var detached = false; + + if (mesh.backupQuaternionAngleDescriptor) { + Object.defineProperty( + mesh.quaternion, + 'angle', + mesh.backupQuaternionAngleDescriptor + ); + + delete mesh.backupQuaternionAngleDescriptor; + + detached = true; + } + + if (mesh.backupQuaternionAxisXDescriptor) { + Object.defineProperty( + mesh.quaternion.axis, + 'x', + mesh.backupQuaternionAxisXDescriptor + ); + + delete mesh.backupQuaternionAxisXDescriptor; + + detached = true; + } + + if (mesh.backupQuaternionAxisYDescriptor) { + Object.defineProperty( + mesh.quaternion.axis, + 'y', + mesh.backupQuaternionAxisYDescriptor + ); + + delete mesh.backupQuaternionAxisYDescriptor; + + detached = true; + } + + if (mesh.backupQuaternionAxisZDescriptor) { + Object.defineProperty( + mesh.quaternion.axis, + 'z', + mesh.backupQuaternionAxisZDescriptor + ); + + delete mesh.backupQuaternionAxisXDescriptor; + + detached = true; + } + + if (mesh.backupRotationXDescriptor) { + Object.defineProperty( + mesh.rotation, + 'x', + mesh.backupRotationXDescriptor + ); + + delete mesh.backupRotationXDescriptor; + + detached = true; + } + + if (mesh.backupRotationYDescriptor) { + Object.defineProperty( + mesh.rotation, + 'y', + mesh.backupRotationYDescriptor + ); + + delete mesh.backupRotationYDescriptor; + + detached = true; + } + + if (mesh.backupRotationZDescriptor) { + Object.defineProperty( + mesh.rotation, + 'z', + mesh.backupRotationZDescriptor + ); + + delete mesh.backupRotationZDescriptor; + + detached = true; + } + + if (mesh.backupPositionXDescriptor) { + Object.defineProperty( + mesh.position, + 'x', + mesh.backupPositionXDescriptor + ); + + delete mesh.backupPositionXDescriptor; + + detached = true; + } + + if (mesh.backupPositionYDescriptor) { + Object.defineProperty( + mesh.position, + 'y', + mesh.backupPositionYDescriptor + ); + + delete mesh.backupPositionYDescriptor; + + detached = true; + } + + if (mesh.backupPositionZDescriptor) { + Object.defineProperty( + mesh.position, + 'z', + mesh.backupPositionZDescriptor + ); + + delete mesh.backupPositionZDescriptor; + + detached = true; + } + + if (mesh.backupScaleXDescriptor) { + Object.defineProperty( + mesh.scale, + 'x', + mesh.backupScaleXDescriptor + ); + + delete mesh.backupScaleXDescriptor; + + detached = true; + } + + if (mesh.backupScaleYDescriptor) { + Object.defineProperty( + mesh.scale, + 'y', + mesh.backupScaleYDescriptor + ); + + delete mesh.backupScaleYDescriptor; + + detached = true; + } + + if (mesh.backupScaleZDescriptor) { + Object.defineProperty( + mesh.scale, + 'z', + mesh.backupScaleZDescriptor + ); + + delete mesh.backupScaleZDescriptor; + + detached = true; + } + + if (this.latest[mesh.id]) { + + mesh.rotation.x = this.latest[mesh.id].rotation.x; + mesh.rotation.y = this.latest[mesh.id].rotation.y; + mesh.rotation.z = this.latest[mesh.id].rotation.z; + + mesh.position.x = this.latest[mesh.id].position.x; + mesh.position.y = this.latest[mesh.id].position.y; + mesh.position.z = this.latest[mesh.id].position.z; + + mesh.scale.x = this.latest[mesh.id].scale.x; + mesh.scale.y = this.latest[mesh.id].scale.y; + mesh.scale.z = this.latest[mesh.id].scale.z; + + mesh.quaternion.axis.x = this.latest[mesh.id].quaternion.axis.x; + mesh.quaternion.axis.y = this.latest[mesh.id].quaternion.axis.y; + mesh.quaternion.axis.z = this.latest[mesh.id].quaternion.axis.z; + + mesh.quaternion.angle = this.latest[mesh.id].quaternion.angle; + + delete this.latest[mesh.id]; + + detached = true; + } + + if (this.animations[mesh.id]) { + delete this.animations[mesh.id]; + + detached = true; + } + + if (detached) { + mesh.updateInstance(); + } + +}; + +GameLib.System.Animation.prototype.attachAnimation = function(animation, mesh) { + + /** + * Initialize the property with the original mesh z value + */ + this.latest[mesh.id] = { + rotation : { + x : mesh.rotation.x, + y : mesh.rotation.y, + z : mesh.rotation.z + }, + position : { + x : mesh.position.x, + y : mesh.position.y, + z : mesh.position.z + }, + scale : { + x : mesh.scale.x, + y : mesh.scale.y, + z : mesh.scale.z + }, + quaternion : { + axis : { + x : mesh.quaternion.axis.x, + y : mesh.quaternion.axis.y, + z : mesh.quaternion.axis.z + }, + angle : mesh.quaternion.angle + } + }; + + this.animations[mesh.id] = []; + + if (mesh.backupRotationXDescriptor) { + throw new Error('already a backed up x descriptor'); + } + + mesh.backupQuaternionAngleDescriptor = Object.getOwnPropertyDescriptor(mesh.quaternion, 'angle'); + mesh.backupQuaternionAxisXDescriptor = Object.getOwnPropertyDescriptor(mesh.quaternion.axis, 'x'); + mesh.backupQuaternionAxisYDescriptor = Object.getOwnPropertyDescriptor(mesh.quaternion.axis, 'y'); + mesh.backupQuaternionAxisZDescriptor = Object.getOwnPropertyDescriptor(mesh.quaternion.axis, 'z'); + mesh.backupRotationXDescriptor = Object.getOwnPropertyDescriptor(mesh.rotation, 'x'); + mesh.backupRotationYDescriptor = Object.getOwnPropertyDescriptor(mesh.rotation, 'y'); + mesh.backupRotationZDescriptor = Object.getOwnPropertyDescriptor(mesh.rotation, 'z'); + mesh.backupPositionXDescriptor = Object.getOwnPropertyDescriptor(mesh.position, 'x'); + mesh.backupPositionYDescriptor = Object.getOwnPropertyDescriptor(mesh.position, 'y'); + mesh.backupPositionZDescriptor = Object.getOwnPropertyDescriptor(mesh.position, 'z'); + mesh.backupScaleXDescriptor = Object.getOwnPropertyDescriptor(mesh.scale, 'x'); + mesh.backupScaleYDescriptor = Object.getOwnPropertyDescriptor(mesh.scale, 'y'); + mesh.backupScaleZDescriptor = Object.getOwnPropertyDescriptor(mesh.scale, 'z'); + + Object.defineProperty( + mesh.quaternion, + 'angle', + { + 'get': this.getProperty(mesh, 'angle', 'quaternion'), + 'set': this.setProperty(mesh, animation, 'angle', 'quaternion'), + 'configurable': true + } + ); + + Object.defineProperty( + mesh.quaternion.axis, + 'x', + { + 'get': this.getSubProperty(mesh, 'x', 'quaternion', 'axis'), + 'set': this.setSubProperty(mesh, animation, 'x', 'quaternion', 'axis'), + 'configurable': true + } + ); + + Object.defineProperty( + mesh.quaternion.axis, + 'y', + { + 'get': this.getSubProperty(mesh, 'y', 'quaternion', 'axis'), + 'set': this.setSubProperty(mesh, animation, 'y', 'quaternion', 'axis'), + 'configurable': true + } + ); + + Object.defineProperty( + mesh.quaternion.axis, + 'z', + { + 'get': this.getSubProperty(mesh, 'z', 'quaternion', 'axis'), + 'set': this.setSubProperty(mesh, animation, 'z', 'quaternion', 'axis'), + 'configurable': true + } + ); + + Object.defineProperty( + mesh.rotation, + 'x', + { + 'get': this.getProperty(mesh, 'x', 'rotation'), + 'set': this.setProperty(mesh, animation, 'x', 'rotation'), + 'configurable': true + } + ); + + Object.defineProperty( + mesh.rotation, + 'y', + { + 'get': this.getProperty(mesh, 'y', 'rotation'), + 'set': this.setProperty(mesh, animation, 'y', 'rotation'), + 'configurable': true + } + ); + + Object.defineProperty( + mesh.rotation, + 'z', + { + 'get': this.getProperty(mesh, 'z', 'rotation'), + 'set': this.setProperty(mesh, animation, 'z', 'rotation'), + 'configurable': true + } + ); + + Object.defineProperty( + mesh.scale, + 'x', + { + 'get': this.getProperty(mesh, 'x', 'scale'), + 'set': this.setProperty(mesh, animation, 'x', 'scale'), + 'configurable': true + } + ); + + Object.defineProperty( + mesh.scale, + 'y', + { + 'get': this.getProperty(mesh, 'y', 'scale'), + 'set': this.setProperty(mesh, animation, 'y', 'scale'), + 'configurable': true + } + ); + + Object.defineProperty( + mesh.scale, + 'z', + { + 'get': this.getProperty(mesh, 'z', 'scale'), + 'set': this.setProperty(mesh, animation, 'z', 'scale'), + 'configurable': true + } + ); + + Object.defineProperty( + mesh.position, + 'x', + { + 'get': this.getProperty(mesh, 'x', 'position'), + 'set': this.setProperty(mesh, animation, 'x', 'position'), + 'configurable': true + } + ); + + Object.defineProperty( + mesh.position, + 'y', + { + 'get': this.getProperty(mesh, 'y', 'position'), + 'set': this.setProperty(mesh, animation, 'y', 'position'), + 'configurable': true + } + ); + + Object.defineProperty( + mesh.position, + 'z', + { + 'get': this.getProperty(mesh, 'z', 'position'), + 'set': this.setProperty(mesh, animation, 'z', 'position'), + 'configurable': true + } + ); +}; + +// GameLib.System.Animation.prototype.getQuaternionAngle = function(mesh, animation) { +// +// return function() { +// return; +// /** +// * TODO: fix this shit.. +// * Back up the current property descriptor +// */ +// mesh.animationObject = { +// backupAngleDescriptor: Object.getOwnPropertyDescriptor(mesh.quaternion, 'angle'), +// targetAngle: mesh.quaternion.angle, +// angleIncrement: true, +// intermediateAngle: mesh.quaternion.angle, +// subscription: null, +// inProcess: false, +// blocking: animation.blocking//, +// // callbacks : [], +// // storedValues : [] +// }; +// +// var getIntermediateAngle = function () { +// return mesh.animationObject.intermediateAngle; +// }; +// +// var getTargetAngle = function () { +// +// // if (mesh.animationObject.storedValues.length > 0) { +// // return mesh.animationObject.storedValues[mesh.animationObject.storedValues.length - 1]; +// // } +// +// return mesh.animationObject.targetAngle; +// }; +// +// var animateRotation = function (value) { +// +// mesh.animationObject.intermediateAngle += value; +// +// var done = false; +// +// if (mesh.animationObject.angleIncrement) { +// /** +// * We are rotating upwards +// */ +// if (mesh.animationObject.intermediateAngle >= mesh.animationObject.targetAngle) { +// /** +// * We need to stop +// */ +// done = true; +// } +// } else { +// /** +// * We are rotating downwards +// */ +// if (mesh.animationObject.intermediateAngle <= mesh.animationObject.targetAngle) { +// /** +// * We need to stop +// */ +// done = true; +// } +// } +// +// if (done) { +// +// /** +// * We clamp to our target angle +// */ +// mesh.animationObject.intermediateAngle = mesh.animationObject.targetAngle; +// +// /** +// * We limit our intermediate angle between values of -pi and pi +// */ +// while (mesh.animationObject.intermediateAngle > Math.PI) { +// mesh.animationObject.intermediateAngle -= (Math.PI * 2); +// } +// +// while (mesh.animationObject.intermediateAngle < -(Math.PI)) { +// mesh.animationObject.intermediateAngle += (Math.PI * 2); +// } +// +// /** +// * We apply our new intermediate angle to our target +// */ +// mesh.animationObject.targetAngle = mesh.animationObject.intermediateAngle; +// } +// +// /** +// * Apply the actual rotation to the mesh +// */ +// mesh.updateInstanceRotationFromAxisAngle(mesh.quaternion.axis, mesh.animationObject.intermediateAngle); +// +// /** +// * Check again if we are done, we need to do some additional work - +// */ +// if (done) { +// +// if (!mesh.animationObject.subscription) { +// var message = 'mesh animation object subscription went missing for '; +// message += mesh.name + ': '; +// message += animation.name; +// console.warn(message); +// throw new Error(message); +// } +// +// /** +// * Stop subscribing to before render events +// */ +// mesh.animationObject.subscription.remove(); +// +// /** +// * @type {null} +// */ +// mesh.animationObject.subscription = null; +// +// /** +// * For some meshes, when we are done with the animation, we want to apply +// * the current state of the mesh to the object data itself (i.e. update +// * its vertices etc) +// */ +// if (animation.applyToMeshWhenDone) { +// /** +// * Now we say that our intermediate angle is zero, because we will apply our rotation +// * and this will prevent us from re-registering a new 'animationRender' event +// */ +// mesh.animationObject.targetAngle = 0; +// mesh.animationObject.intermediateAngle = 0; +// +// /** +// * Apply our position, rotation and scale to the mesh +// */ +// mesh.applyPositionRotationScale(); +// } +// +// /** +// * Tell our animation component that it is no longer in process... +// * @type {boolean} +// */ +// mesh.animationObject.inProcess = false; +// +// // if (mesh.animationObject.callbacks.length > 0) { +// // var callback = mesh.animationObject.callbacks[0]; +// // mesh.animationObject.callbacks.splice(0,1); +// // callback(); +// // } +// +// // mesh.animationObject.storedValues = []; +// } +// }; +// } +// }; +// +// GameLib.System.Animation.prototype.setQuaternionAngle = function(mesh, animation) { +// +// return function(value) { +// return; +// /** +// * TODO: update this shit +// */ +// /** +// * Check if we have work to do +// */ +// if (mesh.animationObject.intermediateAngle === value) { +// +// mesh.animationObject.inProcess = false; +// +// /** +// * Nothing to do +// */ +// return; +// } +// +// /** +// * Check if we have another animation in process +// */ +// if (mesh.animationObject.inProcess && mesh.animationObject.blocking) { +// +// console.log('another animation is already in process'); +// +// // setTargetAngle(value); +// +// // GameLib.Utils.PushUnique(mesh.animationObject.storedValues, value); +// // +// // mesh.animationObject.callbacks.push( +// // function(__value) { +// // return function(){ +// // mesh.quaternion.angle = __value; +// // } +// // }(value) +// // ); +// +// /** +// * Respond that our angle is actually our target angle (it will be that soon) +// */ +// return; +// } +// +// /** +// * We indicate that we now have an animation in process +// * @type {boolean} +// */ +// mesh.animationObject.inProcess = true; +// +// /** +// * Ok - all good - lets start the animation +// */ +// if (mesh.animationObject.intermediateAngle > value) { +// /** +// * We will rotate towards by decrementing +// */ +// mesh.animationObject.angleIncrement = false; +// } else { +// /** +// * We will rotate towards by incrementing +// */ +// mesh.animationObject.angleIncrement = true; +// } +// +// /** +// * We say what our target angle is - when we reach our target angle, we want +// * to stop our animation +// */ +// mesh.animationObject.targetAngle = value; +// +// /** +// * Now we subscribe to 'before render' events, and slowly increment the value +// * @type {{fn, remove}} +// */ +// mesh.animationObject.subscription = GameLib.Event.Subscribe( +// GameLib.Event.BEFORE_RENDER, +// function(data) { +// +// var increment = Math.abs(animation.rotationSpeed); +// +// if (!mesh.animationObject.angleIncrement) { +// increment *= -1; +// } +// +// animateRotation(data.delta * increment); +// } +// ); +// } +// }; +// +// GameLib.System.Animation.prototype.getQuaternionAxisX = function(mesh, animation) { +// return function() { +// return this.latest[mesh.id].quaternion.axis.x; +// }.bind(this); +// }; +// +// GameLib.System.Animation.prototype.setQuaternionAxisX = function(mesh, animation) { +// return function(value) { +// this.latest[mesh.id].quaternion.axis.x = value; +// }.bind(this); +// }; +// +// GameLib.System.Animation.prototype.getQuaternionAxisY = function(mesh, animation) { +// return function() { +// return this.latest[mesh.id].quaternion.axis.y; +// }.bind(this); +// }; +// +// GameLib.System.Animation.prototype.setQuaternionAxisY = function(mesh, animation) { +// return function(value) { +// this.latest[mesh.id].quaternion.axis.y = value; +// }.bind(this); +// }; +// +// GameLib.System.Animation.prototype.getQuaternionAxisZ = function(mesh, animation) { +// return function() { +// return this.latest[mesh.id].quaternion.axis.z; +// }.bind(this); +// }; +// +// GameLib.System.Animation.prototype.setQuaternionAxisZ = function(mesh, animation) { +// return function(value) { +// this.latest[mesh.id].quaternion.axis.z = value; +// }.bind(this); +// }; + +GameLib.System.Animation.prototype.getSubProperty = function(mesh, axis, property, subProperty) { + return function() { + return this.latest[mesh.id][property][subProperty][axis]; + }.bind(this); +}; + +GameLib.System.Animation.prototype.setSubProperty = function(mesh, animation, axis, property, subProperty) { + return function(value) { + + var from = Number(this.latest[mesh.id][property][subProperty][axis]); + + this.latest[mesh.id][property][subProperty][axis] = value; + + if (property === 'position') { + /** + * Look for other position animations + * TODO:check when not super exausted + */ + // var positionAnimationObject = this.animations[mesh.id].reduce( + // function(result, animationObject) { + // + // if (animationObject.type === 'position') { + // result = animationObject; + // } + // + // return result; + // }, + // null + // ); + + /** + * We found another position animation - just update the 'to' property + */ + // if (positionAnimationObject) { + // positionAnimationObject.to = value; + // return; + // } + } + + this.animations[mesh.id].push( + { + type : property, + axis : axis, + from : from, + to : value, + animation : animation, + mesh : mesh + } + ); + + }.bind(this) +}; + +GameLib.System.Animation.prototype.getProperty = function(mesh, axis, property) { + return function() { + return this.latest[mesh.id][property][axis]; + }.bind(this); +}; + +GameLib.System.Animation.prototype.setProperty = function(mesh, animation, axis, property) { + return function(value) { + + var from = Number(this.latest[mesh.id][property][axis]); + + this.latest[mesh.id][property][axis] = value; + + if (property === 'position') { + /** + * Look for other position animations + * TODO:check when not super exausted + */ + // var positionAnimationObject = this.animations[mesh.id].reduce( + // function(result, animationObject) { + // + // if (animationObject.type === 'position') { + // result = animationObject; + // } + // + // return result; + // }, + // null + // ); + + /** + * We found another position animation - just update the 'to' property + */ + // if (positionAnimationObject) { + // positionAnimationObject.to = value; + // return; + // } + } + + this.animations[mesh.id].push( + { + type : property, + axis : axis, + from : from, + to : value, + animation : animation, + mesh : mesh + } + ); + + }.bind(this) +}; + +/** + * Stop Animation System + */ +GameLib.System.Animation.prototype.stop = function() { + + GameLib.System.prototype.stop.call(this); + + this.beforeRenderSubscription.remove(); + + this.animationMeshAddedSubscription.remove(); + + this.animationMeshRemovedSubscription.remove(); + + this.animations = {}; + + var meshes = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Mesh); + + meshes.map( + function(mesh) { + + for (var property in this.latest) { + if ( + this.latest.hasOwnProperty(property) && + property === mesh.id + ) { + this.detachAnimation(mesh); + } + } + }.bind(this) + ); + + this.instanceCreatedSubscription.remove(); + + this.removeComponentSubscription.remove(); + + this.textureAnimatedSubscription.remove(); + + this.animateTextureInstanceSubscription.remove(); +}; + + +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem GameLib.API.System + * @constructor + */ +GameLib.System.Audio = function( + apiSystem +) { + GameLib.System.call( + this, + apiSystem + ); + + this.instanceCreatedSubscription = null; + + this.removeComponentSubscription = null; + + this.playAudioSubscription = null; + + this.pauseAudioSubscription = null; + + this.stopAudioSubscription = null; + + this.stopAllAudioSubscription = null; + + this.audioComponents = []; + + this.toPlay = []; +}; + +GameLib.System.Audio.prototype = Object.create(GameLib.System.prototype); +GameLib.System.Audio.prototype.constructor = GameLib.System.Audio; + +/** + * Start this system (add all event listeners) + */ +GameLib.System.Audio.prototype.start = function() { + + GameLib.System.prototype.start.call(this); + + this.instanceCreatedSubscription = GameLib.Event.Subscribe( + GameLib.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + this.removeComponentSubscription = GameLib.Event.Subscribe( + GameLib.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + this.playAudioSubscription = GameLib.Event.Subscribe( + GameLib.Event.PLAY_AUDIO, + this.playAudio.bind(this) + ); + + this.pauseAudioSubscription = GameLib.Event.Subscribe( + GameLib.Event.PAUSE_AUDIO, + this.pauseAudio.bind(this) + ); + + this.stopAudioSubscription = GameLib.Event.Subscribe( + GameLib.Event.STOP_AUDIO, + this.stopAudio.bind(this) + ); + + this.stopAllAudioSubscription = GameLib.Event.Subscribe( + GameLib.Event.STOP_ALL_AUDIO, + this.stopAllAudio.bind(this) + ); + +}; + +/** + * From now on we want to track everything about a component, only from the systems that are active + * @param data + */ +GameLib.System.Audio.prototype.instanceCreated = function(data) { + if (data.component instanceof GameLib.D3.Audio) { + GameLib.Utils.PushUnique(this.audioComponents, data.component); + + var index = this.toPlay.indexOf(data.component.name); + + if (index !== -1) { + GameLib.Event.Emit( + GameLib.Event.PLAY_AUDIO, + { + name : data.component.name + } + ) + } + } +}; + +/** + * Removes a particle engine from this system + * @param data + */ +GameLib.System.Audio.prototype.playAudio = function(data) { + + var found = false; + + this.audioComponents.map( + function(audio) { + if (audio.name === data.name) { + + found = true; + + if (!audio.instance) { + console.log('audio not ready yet'); + } + + if (audio.instance.isPlaying && audio.overplay) { + audio.instance.stop(); + } + + if (!audio.instance.isPlaying) { + + audio.instance.play(); + + audio.instance.onEnded = function() { + + this.isPlaying = false; + + GameLib.Event.Emit( + GameLib.Event.AUDIO_ENDED, + { + audio : audio + } + ); + } + } + } + } + ); + + if (!found) { + /** + * This audio still has to load + */ + console.log('delaying audio play until loaded for: ' + data.name); + this.toPlay.push(data.name); + } +}; + +GameLib.System.Audio.prototype.pauseAudio = function(data) { + +}; + +GameLib.System.Audio.prototype.stopAllAudio = function(data) { + this.audioComponents.map( + function(audio) { + if (audio.instance.isPlaying) { + audio.instance.stop(); + } + } + ) +}; + + +GameLib.System.Audio.prototype.stopAudio = function(data) { + this.audioComponents.map( + function(audio) { + if (audio.name === data.name) { + if (audio.instance.isPlaying) { + audio.instance.stop(); + } + } + } + ) +}; + + +GameLib.System.Audio.prototype.removeComponent = function(data) { + +}; + + +/** + * Stop this system (remove all event listeners) + */ +GameLib.System.Audio.prototype.stop = function() { + + GameLib.System.prototype.stop.call(this); + + this.instanceCreatedSubscription.remove(); + this.removeComponentSubscription.remove(); + this.playAudioSubscription.remove(); + this.pauseAudioSubscription.remove(); + this.stopAudioSubscription.remove(); + this.stopAllAudioSubscription.remove(); + +}; + +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem GameLib.API.System + * @constructor + */ +GameLib.System.CustomCode = function( + apiSystem +) { + + GameLib.System.call( + this, + apiSystem + ); + + this.instanceCreatedSubscription = null; + this.removeComponentSubscription = null; + this.compileSuccessSubscription = null; + this.compileFailedSubscription = null; + + this.subscriptions = {}; + +}; + +GameLib.System.CustomCode.prototype = Object.create(GameLib.System.prototype); +GameLib.System.CustomCode.prototype.constructor = GameLib.System.CustomCode; + +/** + * Start the rendering system + */ +GameLib.System.CustomCode.prototype.start = function() { + + GameLib.System.prototype.start.call(this); + + GameLib.EntityManager.Instance.queryComponents(GameLib.D3.CustomCode).map( + function(component) { + this.subscriptions[component.id] = GameLib.Event.Subscribe( + component.eventId, + component.instance + ); + }.bind(this) + ); + + this.instanceCreatedSubscription = GameLib.Event.Subscribe( + GameLib.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + this.removeComponentSubscription = GameLib.Event.Subscribe( + GameLib.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + this.compileSuccessSubscription = GameLib.Event.Subscribe( + GameLib.Event.COMPILE_SUCCESS, + this.compileSuccess.bind(this) + ); + + this.compileFailedSubscription = GameLib.Event.Subscribe( + GameLib.Event.COMPILE_FAILED, + this.compileFailed.bind(this) + ); + + +}; + +GameLib.System.CustomCode.prototype.instanceCreated = function(data) { + if (data.component instanceof GameLib.D3.CustomCode) { + + if (this.subscriptions[data.component.id]) { + console.warn('a component already existed'); + this.subscriptions[data.component.id].remove(); + } + + this.subscriptions[data.component.id] = GameLib.Event.Subscribe( + data.component.eventId, + data.component.instance + ); + } +}; + +GameLib.System.CustomCode.prototype.removeComponent = function(data) { + if (data.component instanceof GameLib.D3.CustomCode) { + if (this.subscriptions[data.component.id]) { + this.subscriptions[data.component.id].remove(); + delete this.subscriptions[data.component.id]; + } + } +}; + +GameLib.System.CustomCode.prototype.compileSuccess = function(data) { + + if (this.subscriptions[data.component.id]) { + this.subscriptions[data.component.id].remove(); + } + + this.subscriptions[data.component.id] = GameLib.Event.Subscribe( + data.component.eventId, + data.component.instance + ); +}; + +GameLib.System.CustomCode.prototype.compileFailed = function(data) { + if (this.subscriptions[data.component.id]) { + this.subscriptions[data.component.id].remove(); + delete this.subscriptions[data.component.id]; + } +}; + + +/** + * Stop the rendering system + */ +GameLib.System.CustomCode.prototype.stop = function() { + + GameLib.System.prototype.stop.call(this); + + if (this.instanceCreatedSubscription) { + this.instanceCreatedSubscription.remove(); + this.instanceCreatedSubscription = null; + } + + if (this.removeComponentSubscription) { + this.removeComponentSubscription.remove(); + this.removeComponentSubscription = null; + } + + if (this.compileSuccessSubscription) { + this.compileSuccessSubscription.remove(); + this.compileSuccessSubscription = null; + } + + if (this.compileFailedSubscription) { + this.compileFailedSubscription.remove(); + this.compileFailedSubscription = null; + } + + Object.keys(this.subscriptions).map( + function(componentId) { + if (this.subscriptions[componentId]) { + this.subscriptions[componentId].remove(); + delete this.subscriptions[componentId]; + } + }.bind(this) + ); + +}; + + +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem GameLib.API.System + * @constructor + */ +GameLib.System.GUI = function( + apiSystem +) { + GameLib.System.call( + this, + apiSystem + ); + + this.guis = []; + + this.components = []; + + /** + * When we want to show a specific set of components - we backup the current components and then restore them + * later when we are done. + * @type {null} + */ + this.backupComponents = []; + + this.exclusiveMode = false; + + this.buildGUISubscription = null; + + this.meshDeletedSubscription = null; + + this.meshSelectedSubscription = null; + + this.meshDeselectedSubscription = null; + + this.newEntitySubscription = null; + + this.meshSelectionObjects = {}; + +}; + +GameLib.System.GUI.prototype = Object.create(GameLib.System.prototype); +GameLib.System.GUI.prototype.constructor = GameLib.System.GUI; + +GameLib.System.GUI.prototype.start = function() { + + GameLib.System.prototype.start.call(this); + + this.guis = GameLib.EntityManager.Instance.queryComponents(GameLib.GUI); + + /** + * Add some GUI behaviour + */ + dat.GUI.prototype.removeEmtpyFolders = function() { + for (var property in this.__folders) { + if (this.__folders.hasOwnProperty(property)){ + + var folder = this.__folders[property]; + + if (folder.__listening.length === 0) { + folder.close(); + this.__ul.removeChild(folder.domElement.parentNode); + delete this.__folders[property]; + this.onResize(); + } + } + } + }; + + dat.GUI.prototype.listen = function(controller) { + const init = this.__listening.length === 0; + this.__listening.push(controller); + + delete this.closed; + + Object.defineProperty(this, 'closed', { + get: function() { + return this.params.closed; + }, + set: function(v) { + // console.log('override here too'); + + this.params.closed = v; + if (this.params.closed) { + this.dom.addClass(this.__ul, 'closed'); + + cancelAnimationFrame(this.animationId); + + } else { + this.dom.removeClass(this.__ul, 'closed'); + + this.updateDisplaysCallback = function() { + + /** + * We store the animationFrameId so we can remove this callback later + */ + this.animationId = requestAnimationFrame(this.updateDisplaysCallback.bind(this)); + + this.__listening.map(function(controller){ + controller.updateDisplay(); + }); + + }.bind(this); + + this.animationId = requestAnimationFrame(this.updateDisplaysCallback); + } + // For browsers that aren't going to respect the CSS transition, + // Lets just check our height against the window height right off + // the bat. + this.onResize(); + + if (this.__closeButton) { + this.__closeButton.innerHTML = v ? 'Open Controls' : 'Close Controls'; + } + }, + configurable: true + }); + + }; + + dat.GUI.prototype.removeAllFolders = function() { + for (var property in this.__folders) { + if (this.__folders.hasOwnProperty(property)){ + + var folder = this.__folders[property]; + + /** + * Theres a big 'TODO' in the controller remove() function to actually remove the listener + * That's what we are going to do now.. - because it really fucks with the framerate eventually + */ + cancelAnimationFrame(folder.animationId); + + folder.__controllers.map( + function(controller) { + controller.remove(); + + } + ); + + folder.__controllers = []; + + folder.__listening = []; + + /** + * Call UpdateDisplays with + */ + folder.close(); + + this.__ul.removeChild(folder.domElement.parentNode); + delete this.__folders[property]; + this.onResize(); + } + } + }; + + this.guis.map(function(gui){ + gui.domElement.instance.parentElement.appendChild(gui.instance.domElement); + }); + + this.buildGUISubscription = this.subscribe( + GameLib.Event.BUILD_GUI, + this.buildGUI + ); + + this.meshDeletedSubscription = this.subscribe( + GameLib.Event.REMOVE_MESH, + this.meshDeleted + ); + + this.meshSelectedSubscription = this.subscribe( + GameLib.Event.MESH_SELECTED, + this.meshSelected + ); + + this.meshDeselectedSubscription = this.subscribe( + GameLib.Event.MESH_DESELECTED, + this.meshDeslected + ); + + this.newEntitySubscription = this.subscribe( + GameLib.Event.NEW_ENTITY, + this.newEntity + ); + + this.componentRemovedSubscription = this.subscribe( + GameLib.Event.REMOVE_COMPONENT, + this.removeComponent + ) +}; + +GameLib.System.GUI.prototype.onChange = function(property, subProperty, affected) { + return function(value) { + affected.map(function(component){ + + component[property][subProperty] = value; + + if (component instanceof GameLib.D3.Mesh && property === 'rotation') { + component.useQuaternion = false; + } + + if (component instanceof GameLib.D3.Mesh && property === 'quaternion') { + component.useQuaternion = true; + } + + if (typeof component[property].updateInstance === 'function') { + component[property].updateInstance(property); + } else if (typeof component[property][subProperty].updateInstance === 'function') { + component[property][subProperty].updateInstance(subProperty); + } else { + component.updateInstance(property); + } + + }); + } +}; + +GameLib.System.GUI.prototype.controller = function(folder, object, property, subProperty, step, listen, affected, min, max) { + + if (GameLib.Utils.UndefinedOrNull(min)) { + min = -1000; + } + + if (GameLib.Utils.UndefinedOrNull(max)) { + max = 1000; + } + + if ( + // property === 'chassisConnectionPointLocal' || + property === 'axleLocal' || + property === 'directionLocal' + ) { + min = -1; + max = 1; + step = 1; + } + + if ( + // property === 'chassisConnectionPointLocal' || + property === 'offset' || + property === 'repeat' + ) { + min = -1000; + max = 1000; + step = 0.00001; + } + + var handle = folder.add( + object[property], + subProperty, + min, + max, + step + ).name(property + '.' + subProperty); + + handle.onChange(this.onChange(property, subProperty, affected)); + + if (listen) { + handle.listen(); + } + + return handle; +}; + +GameLib.System.GUI.prototype.buildQuaternionControl = function(folder, componentTemplate, property) { + + var step = 0.1; + + var object = componentTemplate.template; + + var listen = false; + + if (componentTemplate.affected.length === 1) { + /** + * If the template only affects a single object - put the handle on this so we can listen for changes + */ + object = componentTemplate.affected[0]; + + listen = true; + } + + var affected = componentTemplate.affected; + + this.controller(folder, object, property, 'x', step, listen, affected); + this.controller(folder, object, property, 'y', step, listen, affected); + this.controller(folder, object, property, 'z', step, listen, affected); + this.controller(folder, object, property, 'w', step, listen, affected); + this.controller(folder, object, property, 'angle', 0.001, listen, affected, -Math.PI, Math.PI); + + folder.add( + object[property]['axis'], + 'x', + -1, + 1, + 0.01 + ).name('quaternion.axis.x').onChange( + function(value) { + affected.map(function(component){ + component.useQuaternion = true; + component[property]['axis'].x = Number(value); + component.updateInstance('x'); + }) + } + ); + + folder.add( + object[property]['axis'], + 'y', + -1, + 1, + 0.01 + ).name('quaternion.axis.y').onChange( + function(value) { + affected.map(function(component){ + component.useQuaternion = true; + component[property]['axis'].y = Number(value); + component.updateInstance('y'); + }) + } + ); + + folder.add( + object[property]['axis'], + 'z', + -1, + 1, + 0.01 + ).name('quaternion.axis.z').onChange( + function(value) { + affected.map(function(component){ + component.useQuaternion = true; + component[property]['axis'].z = Number(value); + component.updateInstance('z'); + }) + } + ); + +}; + +GameLib.System.GUI.prototype.buildVectorControl = function(folder, componentTemplate, property) { + + var step = 0.01; + + var object = componentTemplate.template; + + var listen = false; + + if (componentTemplate.affected.length === 1) { + /** + * If the template only affects a single object - put the handle on this so we can listen for changes + */ + object = componentTemplate.affected[0]; + + listen = true; + } + + var affected = componentTemplate.affected; + + var controllers = []; + + if (GameLib.Utils.isVector4(object[property])) { + controllers.push(this.controller(folder, object, property, 'w', step, listen, affected)); + } + + controllers.push(this.controller(folder, object, property, 'x', step, listen, affected)); + controllers.push(this.controller(folder, object, property, 'y', step, listen, affected)); + + if ( + GameLib.Utils.isVector3(object[property]) || + GameLib.Utils.isVector4(object[property]) + ) { + controllers.push(this.controller(folder, object, property, 'z', step, listen, affected)); + } + +}; + +/** + * Builds an Entity Selection control + * @param folder + * @param componentTemplate + */ +GameLib.System.GUI.prototype.buildParentSelectionControl = function(folder, componentTemplate, property) { + + var constructor = null; + + if (property === 'parentEntity') { + constructor = GameLib.Entity; + } + + if (property === 'parentMesh') { + constructor = GameLib.D3.Mesh; + } + + if (property === 'parentWorld') { + constructor = GameLib.D3.PhysicsWorld; + } + + if (property === 'parentScene') { + constructor = GameLib.D3.Scene; + } + + var options = GameLib.EntityManager.Instance.queryComponents(constructor).reduce( + function(result, object) { + result[object.name] = object; + return result; + }, + { + 'none' : null + } + ); + + var object = componentTemplate.template; + + var affected = componentTemplate.affected; + + folder.add(object, property, options).listen().onChange( + + function(value) { + + var newComponent = null; + + if (value !== 'null') { + newComponent = GameLib.EntityManager.Instance.findComponentById(value); + } + + affected.map( + function(component) { + + component[property] = newComponent; + + if (property === 'parentEntity') { + GameLib.Event.Emit( + GameLib.Event.PARENT_ENTITY_CHANGE, + { + originalEntity : this.initialValue, + newEntity : newComponent, + object : component + } + ); + } + + if (property === 'parentWorld') { + GameLib.Event.Emit( + GameLib.Event.PARENT_WORLD_CHANGE, + { + originalWorld : this.initialValue, + newWorld : newComponent, + object : component + } + ) + } + + if (property === 'parentScene') { + GameLib.Event.Emit( + GameLib.Event.PARENT_SCENE_CHANGE, + { + originalScene: this.initialValue, + newScene: newComponent, + object: component + } + ); + } + + }.bind(this) + ); + + if (property === 'parentEntity') { + GameLib.Event.Emit( + GameLib.Event.BUILD_GUI, + null + ); + } + + this.initialValue = newComponent; + } + ); +}; + +GameLib.System.GUI.prototype.buildArrayManagerControl = function( + folder, + componentTemplate, + property +) { + + var constructors = componentTemplate.template.linkedObjects[property]; + + if (constructors instanceof Array) { + /** + * All good + */ + } else { + /** + * There is a data mismatch + */ + console.error('data mismatch - something not an array'); + return; + } + + var object = componentTemplate.template; + + var array = object[property]; + + var addArrayItem = function(item, index){ + + var name = 'invalid item'; + + if (item && item.name) { + name = item.name; + } + + var controller = folder.add( + { + 'remove' : function() { + componentTemplate.affected.map(function(component){ + component[property].splice(index, 1); + folder.remove(controller); + }); + } + }, + 'remove' + ).name('remove ' + property + '[' + index + '] - ' + name); + + folder.updateDisplay(); + }; + + array.map(addArrayItem); + + var idObject = {}; + + var selectionObject = GameLib.EntityManager.Instance.queryComponents(constructors).reduce( + function(result, component) { + result[component.name] = component; + idObject[component.id] = component; + return result; + }, + { + 'none' : null + } + ); + + var activeSelection = { + component: null, + add: function () { + + componentTemplate.affected.map(function (component) { + if (component[property].indexOf(activeSelection.component) === -1) { + component[property].push(activeSelection.component); + + GameLib.Event.Emit( + GameLib.Event.ARRAY_ITEM_ADDED, + { + component : component, + property : property, + item : activeSelection.component + } + ); + + // addArrayItem(activeSelection.component, component[property].length - 1); + } + }); + + GameLib.Event.Emit( + GameLib.Event.BUILD_GUI + ); + } + }; + + folder.add(activeSelection, 'component', selectionObject).name('select ' + property).onChange( + function(value){ + if (value === 'null') { + activeSelection['component'] = null; + } else { + activeSelection['component'] = idObject[value]; + } + } + ).listen(); + + folder.add(activeSelection, 'add').name('add to ' + property); + +}; + +GameLib.System.GUI.prototype.buildColorControl = function(folder, componentTemplate, property) { + + var object = componentTemplate.template; + + var tempObject = { + hexColor : object[property].toHex() + }; + + folder.addColor( + tempObject, + 'hexColor' + ).name(property).listen().onChange( + function(value) { + componentTemplate.affected.map( + function(component) { + component[property].fromHex(value); + component[property].updateInstance(property); + } + ) + } + ); + + folder.add( + tempObject, + 'hexColor' + ).name(property).listen().onChange( + function(value) { + componentTemplate.affected.map( + function(component) { + component[property].fromHex(value); + component[property].updateInstance(property); + } + ) + } + ) + +}; + +GameLib.System.GUI.prototype.buildSelectControl = function(folder, componentTemplate, property) { + + /** + * We need to discover the constructor for this component + */ + var constructor = null; + + if (componentTemplate.template[property]) { + constructor = componentTemplate.template[property].constructor; + } else { + if (componentTemplate.template.linkedObjects[property]) { + constructor = componentTemplate.template.linkedObjects[property]; + } + } + + var object = componentTemplate.template; + + var objects = GameLib.EntityManager.Instance.queryComponents(constructor); + + var idObject = {}; + + var options = objects.reduce( + function(result, obj) { + result[obj.name] = obj; + idObject[obj.id] = obj; + return result; + }, + { + 'none' : null + } + ); + + folder.add( + object, + property, + options + ).name(property).listen().onChange( + + function (value) { + + var newComponent = null; + + if (value !== 'null') { + newComponent = idObject[value]; + } + + componentTemplate.affected.map( + function(component) { + component[property] = newComponent; + component.updateInstance(property); + } + ); + + this.initialValue = newComponent; + } + ); +}; + +GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, property) { + + var object = componentTemplate.template; + + var listen = false; + + if (componentTemplate.affected.length === 1) { + /** + * If the template only affects a single object - put the handle on this so we can listen for changes + */ + object = componentTemplate.affected[0]; + + listen = true; + } + + var componentType = componentTemplate.componentType; + + var controllers = []; + + if ( + GameLib.Utils.isString(object[property]) || + GameLib.Utils.isBoolean(object[property]) + ) { + controllers.push(folder.add(object, property)); + } + + if (GameLib.Utils.isNumber(object[property])) { + + var grain = 0.001; + + if (object.grain) { + grain = object.grain; + } + + if (property === 'systemType') { + controllers.push( + folder.add( + object, + property, + { + 'animation' : GameLib.System.SYSTEM_TYPE_ANIMATION, + 'gui' : GameLib.System.SYSTEM_TYPE_GUI, + 'input' : GameLib.System.SYSTEM_TYPE_INPUT, + 'render' : GameLib.System.SYSTEM_TYPE_RENDER, + 'storage' : GameLib.System.SYSTEM_TYPE_STORAGE, + 'linking' : GameLib.System.SYSTEM_TYPE_LINKING, + 'physics' : GameLib.System.SYSTEM_TYPE_PHYSICS, + 'custom code' : GameLib.System.SYSTEM_TYPE_CUSTOM + } + ) + ); + } else if (property === 'opacityType') { + controllers.push( + folder.add( + object, + property, + { + 'constant': GameLib.D3.Particle.OPACITY_TYPE_CONSTANT, + 'decrease': GameLib.D3.Particle.OPACITY_TYPE_DECREASE_LINEAR, + 'increase': GameLib.D3.Particle.OPACITY_TYPE_INCREASE_LINEAR + } + ) + ); + } else if (property === 'positionOffsetType') { + controllers.push( + folder.add( + object, + property, + { + 'constant': GameLib.D3.Particle.POSITION_OFFSET_TYPE_CONSTANT, + 'random': GameLib.D3.Particle.POSITION_OFFSET_TYPE_RANDOM, + 'function': GameLib.D3.Particle.POSITION_OFFSET_TYPE_FUNCTION + } + ) + ); + } else if (property === 'directionType') { + controllers.push( + folder.add( + object, + property, + { + 'constant': GameLib.D3.Particle.DIRECTION_TYPE_CONSTANT, + 'random': GameLib.D3.Particle.DIRECTION_TYPE_RANDOM, + 'random normalized': GameLib.D3.Particle.DIRECTION_TYPE_RANDOM_NORMALIZED, + 'function': GameLib.D3.Particle.DIRECTION_TYPE_FUNCTION + } + ) + ); + } else if (property === 'speedType') { + controllers.push( + folder.add( + object, + property, + { + 'constant': GameLib.D3.Particle.SPEED_TYPE_CONSTANT, + 'linear': GameLib.D3.Particle.SPEED_TYPE_LINEAR, + 'exponential': GameLib.D3.Particle.SPEED_TYPE_EXPONENTIAL, + 'logarithmic': GameLib.D3.Particle.SPEED_TYPE_LOGARITHMIC, + '1 / log': GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_LOG, + 'exp' : GameLib.D3.Particle.SPEED_TYPE_EXP, + '1 / exp' : GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_EXP + } + ) + ); + } else if (property === 'scaleType') { + controllers.push( + folder.add( + object, + property, + { + 'constant': GameLib.D3.Particle.SCALE_TYPE_CONSTANT, + 'linear': GameLib.D3.Particle.SCALE_TYPE_LINEAR, + 'exponential': GameLib.D3.Particle.SCALE_TYPE_EXPONENTIAL, + 'random': GameLib.D3.Particle.SCALE_TYPE_RANDOM, + 'random (x = y)': GameLib.D3.Particle.SCALE_TYPE_RANDOM_X_EQUALS_Y, + 'function': GameLib.D3.Particle.SCALE_TYPE_FUNCTION + } + ) + ); + } else if (property === 'rotationType') { + controllers.push( + folder.add( + object, + property, + { + 'constant': GameLib.D3.Particle.ROTATION_TYPE_CONSTANT, + 'random': GameLib.D3.Particle.ROTATION_TYPE_RANDOM, + 'function': GameLib.D3.Particle.ROTATION_TYPE_FUNCTION + } + ) + ); + } else if (property === 'broadphaseType') { + controllers.push( + folder.add( + object, + property, + { + 'naive': GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE, + 'grid': GameLib.D3.Image.BROADPHASE_TYPE_GRID, + 'sap': GameLib.D3.Image.BROADPHASE_TYPE_SAP + } + ) + ); + } else if (property === 'solverType') { + controllers.push( + folder.add( + object, + property, + { + 'gs': GameLib.D3.Solver.GS_SOLVER, + 'split': GameLib.D3.Solver.SPLIT_SOLVER + } + ) + ); + } else if (property === 'meshType') { + controllers.push( + folder.add( + object, + property, + { + 'normal' : GameLib.D3.Mesh.MESH_TYPE_NORMAL, + 'curve' : GameLib.D3.Mesh.MESH_TYPE_CURVE, + 'skinned' : GameLib.D3.Mesh.MESH_TYPE_SKINNED, + 'plane' : GameLib.D3.Mesh.MESH_TYPE_PLANE, + 'sphere' : GameLib.D3.Mesh.MESH_TYPE_SPHERE, + 'box' : GameLib.D3.Mesh.MESH_TYPE_BOX, + 'cylinder' : GameLib.D3.Mesh.MESH_TYPE_CYLINDER, + 'text' : GameLib.D3.Mesh.MESH_TYPE_TEXT + } + ) + ); + } else if (property === 'cameraType') { + controllers.push( + folder.add( + object, + property, + { + 'perspective' : GameLib.D3.Camera.CAMERA_TYPE_PERSPECTIVE, + 'orthographic' : GameLib.D3.Camera.CAMERA_TYPE_ORTHOGONAL + } + ) + ); + } else if (property === 'materialType') { + controllers.push( + folder.add( + object, + property, + { + 'standard': GameLib.D3.Material.MATERIAL_TYPE_STANDARD, + 'basic': GameLib.D3.Material.MATERIAL_TYPE_BASIC, + 'phong': GameLib.D3.Material.MATERIAL_TYPE_PHONG, + 'points': GameLib.D3.Material.MATERIAL_TYPE_POINTS, + 'line basic' : GameLib.D3.Material.MATERIAL_TYPE_LINE_BASIC + } + ) + ); + } else if (property === 'side') { + controllers.push( + folder.add( + object, + property, + { + 'double': GameLib.D3.Material.TYPE_DOUBLE_SIDE, + 'front': GameLib.D3.Material.TYPE_FRONT_SIDE, + 'back': GameLib.D3.Material.TYPE_BACK_SIDE + } + ) + ); + } else if (property === 'combine') { + controllers.push( + folder.add( + object, + property, + { + 'multiply': GameLib.D3.Material.TYPE_MULTIPLY_OPERATION, + 'mix': GameLib.D3.Material.TYPE_MIX_OPERATION, + 'add': GameLib.D3.Material.TYPE_ADD_OPERATION + } + ) + ); + } else if (property === 'vertexColors') { + controllers.push( + folder.add( + object, + property, + { + 'none': GameLib.D3.Material.TYPE_NO_COLORS, + 'face': GameLib.D3.Material.TYPE_FACE_COLORS, + 'vertex': GameLib.D3.Material.TYPE_VERTEX_COLORS + } + ) + ); + } else if (property === 'blending') { + controllers.push( + folder.add( + object, + property, + { + 'none': GameLib.D3.Material.TYPE_NO_BLENDING, + 'normal': GameLib.D3.Material.TYPE_NORMAL_BLENDING, + 'additive': GameLib.D3.Material.TYPE_ADDITIVE_BLENDING, + 'subtractive': GameLib.D3.Material.TYPE_SUBTRACTIVE_BLENDING, + 'multiply': GameLib.D3.Material.TYPE_MULTIPLY_BLENDING, + 'custom': GameLib.D3.Material.TYPE_CUSTOM_BLENDING + } + ) + ); + } else if (property === 'blendSrc') { + controllers.push( + folder.add( + object, + property, + { + 'zero': GameLib.D3.Material.TYPE_ZERO_FACTOR, + 'one': GameLib.D3.Material.TYPE_ONE_FACTOR, + 'source color': GameLib.D3.Material.TYPE_SRC_COLOR_FACTOR, + 'one minus source color': GameLib.D3.Material.TYPE_ONE_MINUS_SRC_COLOR_FACTOR, + 'source alpha': GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR, + 'one minus source alpha': GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR, + 'destination alpha': GameLib.D3.Material.TYPE_DST_ALPHA_FACTOR, + 'one minus destination alpha': GameLib.D3.Material.TYPE_ONE_MINUS_DST_ALPHA_FACTOR, + 'destination color': GameLib.D3.Material.TYPE_DST_COLOR_FACTOR, + 'one minus destination color': GameLib.D3.Material.TYPE_ONE_MINUS_DST_COLOR_FACTOR, + 'source alpha saturate': GameLib.D3.Material.TYPE_SRC_ALPHA_SATURATE_FACTOR + } + ) + ); + } else if (property === 'blendDst') { + controllers.push( + folder.add( + object, + property, + { + 'zero': GameLib.D3.Material.TYPE_ZERO_FACTOR, + 'one': GameLib.D3.Material.TYPE_ONE_FACTOR, + 'source color': GameLib.D3.Material.TYPE_SRC_COLOR_FACTOR, + 'one minus source color': GameLib.D3.Material.TYPE_ONE_MINUS_SRC_COLOR_FACTOR, + 'source alpha': GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR, + 'one minus source alpha': GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR, + 'destination alpha': GameLib.D3.Material.TYPE_DST_ALPHA_FACTOR, + 'one minus destination alpha': GameLib.D3.Material.TYPE_ONE_MINUS_DST_ALPHA_FACTOR, + 'destination color': GameLib.D3.Material.TYPE_DST_COLOR_FACTOR, + 'one minus destination color': GameLib.D3.Material.TYPE_ONE_MINUS_DST_COLOR_FACTOR, + 'source alpha saturate': GameLib.D3.Material.TYPE_SRC_ALPHA_SATURATE_FACTOR + } + ) + ); + } else if (property === 'blendEquation') { + controllers.push( + folder.add( + object, + property, + { + 'add': GameLib.D3.Material.TYPE_ADD_EQUATION, + 'subtract': GameLib.D3.Material.TYPE_SUBTRACT_EQUATION, + 'reverse subtract': GameLib.D3.Material.TYPE_REVERSE_SUBTRACT_EQUATION, + 'min': GameLib.D3.Material.TYPE_MIN_EQUATION, + 'max': GameLib.D3.Material.TYPE_MAX_EQUATION + } + ) + ); + } else if (property === 'depthFunc') { + controllers.push( + folder.add( + object, + property, + { + 'never': GameLib.D3.Material.TYPE_NEVER_DEPTH, + 'always': GameLib.D3.Material.TYPE_ALWAYS_DEPTH, + 'less depth': GameLib.D3.Material.TYPE_LESS_DEPTH, + 'less equal depth': GameLib.D3.Material.TYPE_LESS_EQUAL_DEPTH, + 'equal depth': GameLib.D3.Material.TYPE_EQUAL_DEPTH, + 'greated equal depth': GameLib.D3.Material.TYPE_GREATER_EQUAL_DEPTH, + 'greated depth': GameLib.D3.Material.TYPE_GREATER_DEPTH, + 'not equal depth': GameLib.D3.Material.TYPE_NOT_EQUAL_DEPTH + } + ) + ); + } else if (property === 'wrapS') { + controllers.push( + folder.add( + object, + property, + { + 'repeat': GameLib.D3.Texture.TYPE_REPEAT_WRAPPING, + 'clamp': GameLib.D3.Texture.TYPE_CLAMP_TO_EDGE_WRAPPING, + 'mirrored repeat': GameLib.D3.Texture.TYPE_MIRRORED_REPEAT_WRAPPING + } + ) + ); + } else if (property === 'wrapT') { + controllers.push( + folder.add( + object, + property, + { + 'repeat': GameLib.D3.Texture.TYPE_REPEAT_WRAPPING, + 'clamp': GameLib.D3.Texture.TYPE_CLAMP_TO_EDGE_WRAPPING, + 'mirrored repeat': GameLib.D3.Texture.TYPE_MIRRORED_REPEAT_WRAPPING + } + ) + ); + } else if (property === 'format') { + controllers.push( + folder.add( + object, + property, + { + 'alpha': GameLib.D3.Texture.TYPE_ALPHA_FORMAT, + 'rgb': GameLib.D3.Texture.TYPE_RGB_FORMAT, + 'rgba': GameLib.D3.Texture.TYPE_RGBA_FORMAT, + 'luminance': GameLib.D3.Texture.TYPE_LUMINANCE_FORMAT, + 'luminance alpha': GameLib.D3.Texture.TYPE_LUMINANCE_ALPHA_FORMAT, + 'depth': GameLib.D3.Texture.TYPE_DEPTH_FORMAT + } + ) + ); + } else if (property === 'mapping') { + controllers.push( + folder.add( + object, + property, + { + 'uv': GameLib.D3.Texture.TYPE_UV_MAPPING, + 'cube reflection': GameLib.D3.Texture.TYPE_CUBE_REFLECTION_MAPPING, + 'cube refraction': GameLib.D3.Texture.TYPE_CUBE_REFRACTION_MAPPING, + 'equi rectangular reflection': GameLib.D3.Texture.TYPE_EQUI_RECTANGULAR_REFLECTION_MAPPING, + 'equi rectangular refraction': GameLib.D3.Texture.TYPE_EQUI_RECTANGULAR_REFRACTION_MAPPING, + 'spherical reflection': GameLib.D3.Texture.TYPE_SPHERICAL_REFLECTION_MAPPING, + 'cube uv reflection': GameLib.D3.Texture.TYPE_CUBE_UV_REFLECTION_MAPPING, + 'cube uv refraction': GameLib.D3.Texture.TYPE_CUBE_UV_REFRACTION_MAPPING + } + ) + ); + } else if (property === 'magFilter') { + controllers.push( + folder.add( + object, + property, + { + 'nearest': GameLib.D3.Texture.TYPE_NEAREST_FILTER, + 'nearest mipmap nearest': GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_NEAREST_FILTER, + 'nearest mipmap linear': GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_LINEAR_FILTER, + 'linear': GameLib.D3.Texture.TYPE_LINEAR_FILTER, + 'linear mipmap nearest': GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_NEAREST_FILTER, + 'linear mipmap linear': GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER + } + ) + ); + } else if (property === 'minFilter') { + controllers.push( + folder.add( + object, + property, + { + 'nearest': GameLib.D3.Texture.TYPE_NEAREST_FILTER, + 'nearest mipmap nearest': GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_NEAREST_FILTER, + 'nearest mipmap linear': GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_LINEAR_FILTER, + 'linear': GameLib.D3.Texture.TYPE_LINEAR_FILTER, + 'linear mipmap nearest': GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_NEAREST_FILTER, + 'linear mipmap linear': GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER + } + ) + ); + } else if (componentType === GameLib.Component.COMPONENT_TEXTURE && property === 'typeId') { + controllers.push( + folder.add( + object, + property, + { + 'normal': GameLib.D3.Texture.TEXTURE_TYPE_NORMAL, + 'cube': GameLib.D3.Texture.TEXTURE_TYPE_CUBE, + 'canvas': GameLib.D3.Texture.TEXTURE_TYPE_CANVAS + } + ) + ); + } else if (property === 'textureType') { + controllers.push( + folder.add( + object, + property, + { + 'unsigned byte': GameLib.D3.Texture.TYPE_UNSIGNED_BYTE, + 'byte': GameLib.D3.Texture.TYPE_BYTE, + 'short': GameLib.D3.Texture.TYPE_SHORT, + 'unsigned short': GameLib.D3.Texture.TYPE_UNSIGNED_SHORT, + 'int': GameLib.D3.Texture.TYPE_INT, + 'unsigned int': GameLib.D3.Texture.TYPE_UNSIGNED_INT, + 'float': GameLib.D3.Texture.TYPE_FLOAT, + 'half float': GameLib.D3.Texture.TYPE_HALF_FLOAT + } + ) + ); + } else if (property === 'encoding') { + controllers.push( + folder.add( + object, + property, + { + 'linear': GameLib.D3.Texture.TYPE_LINEAR_ENCODING, + 'srgb': GameLib.D3.Texture.TYPE_SRGB_ENCODING, + 'gamma': GameLib.D3.Texture.TYPE_GAMMA_ENCODING, + 'rgbe': GameLib.D3.Texture.TYPE_RGBE_ENCODING, + 'log luv': GameLib.D3.Texture.TYPE_LOG_LUV_ENCODING, + 'rgbm7': GameLib.D3.Texture.TYPE_RGBM7_ENCODING, + 'rgbm16': GameLib.D3.Texture.TYPE_RGBM16_ENCODING, + 'rgbd': GameLib.D3.Texture.TYPE_RGBD_ENCODING + } + ) + ); + } else if (property === 'lightType') { + controllers.push( + folder.add( + object, + property, + { + 'ambient': GameLib.D3.Light.LIGHT_TYPE_AMBIENT, + 'directional': GameLib.D3.Light.LIGHT_TYPE_DIRECTIONAL, + 'spot': GameLib.D3.Light.LIGHT_TYPE_SPOT, + 'point': GameLib.D3.Light.LIGHT_TYPE_POINT + } + ) + ); + } else if (property === 'eventId') { + + var options = {}; + + for (var i = 0; i < 200; i++) { + try { + options[GameLib.Event.GetEventName(i)] = i; + } catch (error) { + + } + } + + controllers.push( + folder.add( + object, + property, + options + ) + ); + } else if (property === 'functionType') { + controllers.push( + folder.add( + object, + property, + { + 'rotation': GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_ROTATION, + 'translation': GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_TRANSLATION, + 'scale': GameLib.D3.Animation.ANIMATION_FUNCTION_TYPE_SCALE + } + ) + ); + } else { + + /** + * Try to guess a scale for this property + */ + if ( + property === 'opacity' || + property === 'opacityFactor' || + property === 'metalness' || + property === 'roughness' || + property === 'volume' + ) { + controllers.push(folder.add(object, property, 0, 1.0, 0.001)); + } else if ( + property === 'shininess' || + property === 'fov' + ) { + controllers.push(folder.add(object, property, -255, 255, 1)); + } else if ( + property === 'aspect' || + property === 'wireframeLineWidth' || + property === 'lineWidth' + ) { + controllers.push(folder.add(object, property, 0, 5, 0.001)); + } else if ( + property === 'bumpScale' || + property === 'normalScale' || + property === 'displacementScale' || + property === 'heightMapScale' || + property === 'intensity' + ) { + controllers.push(folder.add(object, property, -10, 10, 0.001)); + } else if ( + property === 'minX' || + property === 'minY' || + property === 'minZ' || + property === 'maxX' || + property === 'maxY' || + property === 'maxZ' || + property === 'offsetX' + ) { + controllers.push(folder.add(object, property, -1000, 1000, 0.01)); + } else if ( + property === 'widthSegments' || + property === 'radiusSegments' || + property === 'heightSegments' || + property === 'particlesPerSecond' + ) { + controllers.push(folder.add(object, property, 1, 1000, 1)); + } else if ( + property === 'width' || + property === 'height' || + property === 'depth' || + property === 'radius' + ) { + controllers.push(folder.add(object, property, 0, 1000, 0.1)); + } else if ( + property === 'near' || + property === 'distanceGrain' || + property === 'envMapIntensity' + ) { + controllers.push(folder.add(object, property, -10, 100, 0.001)); + } else if ( + property === 'bumpScale' + ) { + controllers.push(folder.add(object, property, 0, 20, 0.001)); + } else if ( + property === 'heightOffset' || + property === 'rotationFactor' + ) { + controllers.push(folder.add(object, property, -100, 100, 0.001)); + } else if ( + property === 'friction' + ) { + controllers.push(folder.add(object, property, 0, 1000, 0.01)); + } else if ( + property === 'radiusTop' || + property === 'radiusBottom' + ) { + controllers.push(folder.add(object, property, 0, 100, 0.1)); + } else if ( + property === 'mass' + ) { + controllers.push(folder.add(object, property, 0, 1000, 0.1)); + } else if ( + property === 'sensitivity' + ) { + controllers.push(folder.add(object, property, 1, 50, 1)); + } else if ( + property === 'density' + ) { + controllers.push(folder.add(object, property, 0, 1, 0.000001)); + } else if ( + property === 'thetaLength' || + property === 'angle' + ) { + controllers.push(folder.add(object, property, -Math.PI * 2, Math.PI * 2, 0.01)); + } else { + controllers.push(folder.add(object, property, -1000, 1000, 0.1)); + } + } + } + + controllers.map( + function(controller) { + + if (property === 'name') { + controller.onFinishChange( + function(__handle, __folder) { + return function(value) { + + componentTemplate.affected.map( + function(component){ + component[property] = value; + component.updateInstance(property); + } + ); + + var li = __folder.domElement.getElementsByClassName('title')[0]; + li.innerHTML = value; + } + }(controller, folder) + ); + } else { + controller.onChange( + function (value) { + + if (typeof this.initialValue === 'number') { + value = Number(value); + } + + componentTemplate.affected.map( + function(component){ + component[property] = value; + component.updateInstance(property); + } + ); + } + ); + } + + if (listen) { + controller.listen(); + } + + } + ); + +}; + +/** + * Push the mesh to our backup components, if in exclusiveMode (menu at top is selected), + * otherwise, just to our normal components + * @param data + */ +GameLib.System.GUI.prototype.meshSelected = function(data) { + + if (this.exclusiveMode) { + GameLib.Utils.PushUnique(this.backupComponents, data.mesh); + } else { + GameLib.Utils.PushUnique(this.components, data.mesh); + } + +}; + +/** + * Same as selected above, but removes the mesh from the components + * @param data + */ +GameLib.System.GUI.prototype.meshDeslected = function(data) { + + var index = -1; + + if (this.exclusiveMode) { + index = this.backupComponents.indexOf(data.mesh); + if (index !== -1) { + this.backupComponents.splice(index, 1); + } + } else { + index = this.components.indexOf(data.mesh); + if (index !== -1) { + this.components.splice(index, 1); + } + } + +}; + +/** + * This function responds to the BUILD_GUI event, data contains the components to build a GUI for data. + * + * If we send data with components - go into exclusive mode, backup the currently selected components and rebuild the gui + * + * If we send data without components - go out of exclusive mode, restore the backup of the currently selected components + * and rebuild based on the meshes + * + * If we don't send any data (null or undefined) - some parameters changed and just rebuild the gui. + * + * @param data + */ +GameLib.System.GUI.prototype.buildGUI = function(data) { + + this.guis.map(function(gui){ + + /** + * First, start fresh - remove all folders + */ + gui.instance.destroy(); + + gui.removeAllFolders(); + + // gui.domElement.instance.parentElement.appendChild(gui.instance.domElement); + + if (data) { + + if (data.components) { + + + /** + * Check if we are not already in exclusive mode, because we only want to make a backup if + * it does not already exist + */ + if (!this.exclusiveMode) { + + this.exclusiveMode = true; + + /** + * Backup the current selection + */ + this.backupComponents = this.components.map( + function(component) { + return component; + } + ); + + } + + this.components = data.components.map( + function(component) { + return component; + } + ); + + } else { + + if (this.exclusiveMode) { + this.exclusiveMode = false; + + /** + * Time to restore the backup + */ + this.components = this.backupComponents.map( + function(component) { + return component; + } + ) + } else { + console.log('we are already not in mesh select mode - not doing anything with the backup'); + } + } + } + + /** + * For all mesh components - (if not in exclusive mode) - try to discover all materials, textures, etc + */ + if (!this.exclusiveMode) { + + /** + * We first remove everything which is not a Mesh + */ + this.components = this.components.filter( + function (component) { + return (component instanceof GameLib.D3.Mesh); + } + ); + } + + /** + * Check if we have components to build a GUI for + */ + if (GameLib.Utils.UndefinedOrNull(this.components.length) || this.components.length < 1) { + // console.log('no components selected'); + return; + } + + /** + * Now continue to discover materials, textures, images etc. children of this component + */ + if (!this.exclusiveMode) { + + this.components = this.components.reduce( + function(result, component) { + + var components = component.getChildrenComponents(); + + GameLib.Utils.PushUnique(result, component); + + components.map(function(component){ + GameLib.Utils.PushUnique(result, component); + }); + + return result; + }.bind(this), + [] + ); + } + + /** + * Sort the components by component type + */ + this.components.sort( + + function(a, b) { + + if (a.componentType > b.componentType) { + return 1; + } + + if (a.componentType < b.componentType) { + return -1; + } + + return 0; + } + ); + + /** + * Split the components into groups of componentType + */ + var componentGroups = this.components.reduce( + function(result, component) { + + var componentData = result.pop(); + + if (component.componentType === componentData.componentType) { + /** + * This is the first component + */ + componentData.components.push(component); + result.push(componentData); + return result; + } + + if (component.componentType !== componentData.componentType) { + result.push(componentData); + result.push({ + componentType : component.componentType, + components:[component] + }); + return result; + } + + }, + [ + { + componentType : this.components[0].componentType, + components : [] + } + ] + ); + + /** + * We have all the components split into groups - now add the individual components + */ + this.components.map( + function(component) { + + /** + * Check for possible duplicates + * @type {boolean} + */ + var duplicate = false; + componentGroups.map(function(componentGroup){ + + if ( + componentGroup.componentType === component.componentType && + componentGroup.components.length === 1 && + componentGroup.components[0] === component + ) { + duplicate = true; + } + }); + + if (!duplicate) { + GameLib.Utils.PushUnique( + componentGroups, + { + componentType : component.componentType, + components : [component] + } + ); + } + } + ); + + /** + * componentGroups should now contain the whole list of stuff we want to build GUI for. + */ + componentGroups.map( + + function(componentGroup){ + + if (componentGroup.components.length < 1) { + console.warn('invalid number of components'); + } + + var templateObject = { + template : { + /** + * Doing this here is just to put parentEntity at the top of the gui + */ + 'parentEntity' : componentGroup.components[0].parentEntity + }, + affected : [componentGroup.components[0]], + componentType : componentGroup.componentType + }; + + for (var property in componentGroup.components[0]) { + if ( + componentGroup.components[0].hasOwnProperty(property) || + typeof componentGroup.components[0][property] === 'function' + ) { + + if (typeof componentGroup.components[0][property] === 'function') { + + templateObject.template[property] = function(__property) { + + return function() { + + this.affected.map( + function(component) { + component[__property].bind(component)(); + } + ) + + }.bind(templateObject); + + }(property); + + } else { + + templateObject.template[property] = componentGroup.components[0][property]; + + } + } + } + + var componentTemplate = componentGroup.components.reduce( + + function(result, component) { + + if (component === componentGroup.components[0]) { + /** + * This is the first component, just return + */ + return result; + } + + /** + * Now start to filter out the properties + */ + for (var property in component) { + if ( + component.hasOwnProperty(property) + ) { + if (!result.template.hasOwnProperty(property)) { + continue; + } + + if ( + result.template[property] instanceof GameLib.Vector2 || + result.template[property] instanceof GameLib.Vector3 || + result.template[property] instanceof GameLib.Vector4 || + result.template[property] instanceof GameLib.Quaternion + ) { + if (!result.template[property].equals(component[property])) { + delete result.template[property]; + } + + continue; + } + + if (result.template[property] !== component[property]) { + delete result.template[property]; + } + } + } + + /** + * Store the affected component + */ + result.affected.push(component); + return result; + + }, + templateObject + ); + + /** + * componentTemplate now contains for this particular component type group - all + * the properties which are modifiable, and also the objects affected by this property changes + */ + var name; + + if (GameLib.Utils.UndefinedOrNull(componentTemplate.template.name)) { + name = GameLib.Component.GetComponentName(componentTemplate.componentType) + ' (All Selected (' + componentTemplate.affected.length + '))'; + } else { + name = componentTemplate.template.name; + } + + var folder = gui.addFolder(name); + + if (!folder) { + return; + } + + for (var templateProperty in componentTemplate.template) { + + if ( + componentTemplate.template.hasOwnProperty(templateProperty) || + typeof (componentTemplate.template[templateProperty]) === 'function' + ) { + + if (typeof (componentTemplate.template[templateProperty]) === 'function') { + folder.add(componentTemplate.template, templateProperty); + continue; + } + + /** + * We only want to affect runtime vectors because their onchange will execute updateInstance() + */ + if ( + componentTemplate.template[templateProperty] instanceof GameLib.Vector2 || + componentTemplate.template[templateProperty] instanceof GameLib.Vector3 || + componentTemplate.template[templateProperty] instanceof GameLib.Vector4 + ) { + this.buildVectorControl(folder, componentTemplate, templateProperty); + continue; + } + + if (componentTemplate.template[templateProperty] instanceof GameLib.Quaternion) { + this.buildQuaternionControl(folder, componentTemplate, templateProperty); + } + + if ( + templateProperty === 'parentEntity' || + templateProperty === 'parentWorld' || + templateProperty === 'parentMesh' || + templateProperty === 'parentScene' + ) { + this.buildParentSelectionControl(folder, componentTemplate, templateProperty); + continue; + } + + if (componentTemplate.template[templateProperty] instanceof Array) { + + if ( + templateProperty === 'vertices' || + templateProperty === 'faces' + ) { + continue; + } + + if ( + componentTemplate.template.linkedObjects && + componentTemplate.template.linkedObjects[templateProperty] instanceof Array + ) { + this.buildArrayManagerControl(folder, componentTemplate, templateProperty); + } + + continue; + } + + if (componentTemplate.template[templateProperty] instanceof GameLib.Color) { + this.buildColorControl(folder, componentTemplate, templateProperty); + continue; + } + + if (typeof componentTemplate.template[templateProperty] === 'object') { + + if ( + componentTemplate.template[templateProperty] instanceof GameLib.Component || + ( + componentTemplate.template.linkedObjects && + componentTemplate.template.linkedObjects[templateProperty] + ) + ) { + this.buildSelectControl(folder, componentTemplate, templateProperty) + } else { + //TODO: maybe start including some other types of objects + //console.log('ignored : ' + templateProperty); + } + continue; + } + + this.buildControl(folder, componentTemplate, templateProperty); + // if ( + // component.linkedObjects && + // component.linkedObjects[property] + // ) { + // if (property === 'parentEntity') { + // this.buildEntitySelectionControlFromArray( + // folder, + // component, + // property, + // entityManager + // ) + // } else if (component.linkedObjects[property] instanceof Array) { + // this.buildArrayManager( + // folder, + // component, + // property, + // component.linkedObjects[property], + // entityManager + // ) + // } else { + // this.buildSelectControl(folder, component, property, entityManager, component.linkedObjects[property]); + // } + // + // } else if (typeof (component[property]) === 'object') { + // + // if (this.isColor(component[property])) { + // this.buildControl(folder, component, property); + // } else { + // //console.log('ignored: ' + property); + // } + // } else { + // this.buildControl(folder, component, property, entityManager); + // } + + + } + } + }.bind(this) + ); + }.bind(this)); + +}; + +GameLib.System.GUI.prototype.meshDeleted = function(data) { + + data.meshes.map(function(mesh){ + this.meshDeslected({ + mesh : mesh + }) + }.bind(this)); + + this.buildGUI(null); +}; + +GameLib.System.GUI.prototype.removeComponent = function(data) { + + var index = this.backupComponents.indexOf(data.component); + if (index !== -1) { + this.backupComponents.splice(index, 1); + } + + index = this.components.indexOf(data.component); + if (index !== -1) { + this.components.splice(index, 1); + } + +}; + + +GameLib.System.GUI.prototype.newEntity = function(data) { + +}; + +GameLib.System.GUI.prototype.stop = function() { + + GameLib.System.prototype.stop.call(this); + + this.guis.map(function(gui){ + gui.domElement.instance.parentElement.removeChild(gui.instance.domElement); + }); + + delete dat.GUI.removeEmtpyFolders; + + delete dat.GUI.removeAllFolders; + + this.buildGUISubscription.remove(); + + this.meshDeletedSubscription.remove(); + + this.meshSelectedSubscription.remove(); + + this.meshDeselectedSubscription.remove(); + + this.newEntitySubscription.remove(); + + this.componentRemovedSubscription.remove(); + + this.guis = []; +}; + + +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem GameLib.API.System + * @param graphics + * @constructor + */ +GameLib.System.Input = function( + apiSystem, + graphics +) { + GameLib.System.call( + this, + apiSystem + ); + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + this.selectAll = false; + + this.controlLeft = false; + + this.sensitivityCounter = 0; + + this.editorControls = []; + this.touchControls = []; + this.keyboardControls = []; + this.mouseControls = []; + + /** + * Touch Controls + * @type {null} + */ + this.touchStart = null; + this.touchMove = null; + this.touchEnd = null; + this.touchCancel = null; + + /** + * Keyboard Controls + * @type {null} + */ + this.keyboardKeyUp = null; + this.keyboardKeyDown = null; + + /** + * Mouse Controls + * @type {null} + */ + this.mouseDown = null; + this.mouseMove = null; + this.mouseWheel = null; + this.mouseUp = null; + + /** + * Editor Controls + * @type {null} + */ + this.keyDown = null; + this.keyUp = null; + this.mouseDownEdit = null; + this.mouseMoveEdit = null; + this.mouseWheelEdit = null; + this.mouseUpEdit = null; + + this.delayedInstanceEncounteredSubscription = null; + this.instanceCreatedSubscription = null; + this.removeComponentSubscription = null; + + this.mouse = new GameLib.Mouse( + graphics + ) +}; + +GameLib.System.Input.prototype = Object.create(GameLib.System.prototype); +GameLib.System.Input.prototype.constructor = GameLib.System.Input; + +/** + * + */ +GameLib.System.Input.prototype.start = function() { + + GameLib.System.prototype.start.call(this); + + this.editorControls = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Controls.Editor); + + this.touchControls = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Controls.Touch); + + this.keyboardControls = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Controls.Keyboard); + + this.mouseControls = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Controls.Mouse); + + this.instanceCreatedSubscription = GameLib.Event.Subscribe( + GameLib.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + this.removeComponentSubscription = GameLib.Event.Subscribe( + GameLib.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + this.delayedInstanceEncounteredSubscription = GameLib.Event.Subscribe( + GameLib.Event.DELAYED_INSTANCE_ENCOUNTERED, + this.delayedInstanceEncountered.bind(this) + ); + + /** + * If we have touch controls - inject them first so we can override editor controls if necessary + */ + this.registerTouchControls(); + + this.registerKeyboardControls(); + + this.registerMouseControls(); + + this.registerEditorControls(); + +}; + +/** + * + */ +GameLib.System.Input.prototype.stop = function() { + + GameLib.System.prototype.stop.call(this); + + this.instanceCreatedSubscription.remove(); + + this.removeComponentSubscription.remove(); + + this.delayedInstanceEncounteredSubscription.remove(); + + this.deRegisterEditorControls(); + + this.deRegisterTouchControls(); + + this.deRegisterKeyboardControls(); + + this.deRegisterMouseControls(); + + this.editorControls = []; + + this.touchControls = []; + + this.keyboardControls = []; + + this.mouseControls = []; + +}; + +/** + * From now on we want to track everything about a component, only from the systems that are active + * @param data + */ +GameLib.System.Input.prototype.instanceCreated = function(data) { + + if (data.component instanceof GameLib.D3.Controls.Editor) { + if (this.editorControls.length > 0) { + console.log('ignoring multiple editor controls') + } else { + this.editorControls.push(data.component); + this.registerEditorControls(); + } + } + + if (data.component instanceof GameLib.D3.Controls.Touch) { + if (this.touchControls.length > 0) { + console.log('ignoring multiple touch controls') + } else { + this.touchControls.push(data.component); + this.registerTouchControls(); + } + } + + if (data.component instanceof GameLib.D3.Controls.Keyboard) { + if (this.keyboardControls.length > 0) { + console.log('ignoring multiple keyboard controls') + } else { + this.keyboardControls.push(data.component); + this.registerKeyboardControls(); + } + } + + if (data.component instanceof GameLib.D3.Controls.Mouse) { + if (this.mouseControls.length > 0) { + console.log('ignoring multiple mouse controls') + } else { + this.mouseControls.push(data.component); + this.registerMouseControls(); + } + } + +}; + +/** + * Removes a particle engine from this system + * @param data + */ +GameLib.System.Input.prototype.removeComponent = function(data) { + + if (data.component instanceof GameLib.D3.Controls.Editor) { + + var index = this.editorControls.indexOf(data.component); + + if (index !== -1) { + + console.log('removing editor controls from system'); + + this.deRegisterEditorControls(); + + this.editorControls.splice(index, 1); + + } else { + console.log('failed to find the editor controls in the system - probably it was ignored - ' + data.component.name); + } + + } + +}; + +/** + * Delayed Instance - we need to check if editControls will block the loading process (since only one will be created) + * @param data + */ +GameLib.System.Input.prototype.delayedInstanceEncountered = function(data) { + + if (data.component instanceof GameLib.D3.Controls.Editor) { + + if (this.editorControls.length === 0) { + /** + * We need to register these controls so instance creation can continue + */ + + this.editorControls.push(data.component); + this.registerEditorControls(); + } else { + /** + * There are already another editor controls, these ones will never get created, we need to + * notify our linking system of this problem so loading can continue + */ + data.component.createInstance(); + } + } + +}; + +GameLib.System.Input.prototype.registerTouchControls = function() { + + if (this.touchControls.length !== 1) { + return; + } + + var touchControl = this.touchControls[0]; + + this.touchSensitivity = touchControl.sensitivity; + + this.touchStart = this.onTouchStart.bind(this); + this.touchMove = this.onTouchMove.bind(this); + this.touchEnd = this.onTouchEnd.bind(this); + this.touchCancel = this.onTouchCancel.bind(this); + + touchControl.domElement.instance.addEventListener( + 'touchstart', + this.touchStart, + false + ); + + touchControl.domElement.instance.addEventListener( + 'touchmove', + this.touchMove, + false + ); + touchControl.domElement.instance.addEventListener( + 'touchend', + this.touchEnd, + false + ); + touchControl.domElement.instance.addEventListener( + 'touchcancel', + this.touchCancel, + false + ); +}; + +GameLib.System.Input.prototype.registerKeyboardControls = function() { + + if (this.keyboardControls.length !== 1) { + return; + } + + var keyboardControl = this.keyboardControls[0]; + + this.keyboardKeyUp = this.onKeyboardKeyUp.bind(this); + this.keyboardKeyDown = this.onKeyboardKeyDown.bind(this); + + keyboardControl.domElement.instance.addEventListener( + 'keyup', + this.keyboardKeyUp, + false + ); + + keyboardControl.domElement.instance.addEventListener( + 'keydown', + this.keyboardKeyDown, + false + ); +}; + +GameLib.System.Input.prototype.registerMouseControls = function() { + + if (this.mouseControls.length !== 1) { + return; + } + + var mouseControl = this.mouseControls[0]; + + this.mouseDown = this.onMouseDown.bind(this); + this.mouseMove = this.onMouseMove.bind(this); + this.mouseWheel = this.onMouseWheel.bind(this); + this.mouseUp = this.onMouseUp.bind(this); + + mouseControl.domElement.instance.addEventListener( + 'mousedown', + this.mouseDown, + false + ); + + mouseControl.domElement.instance.addEventListener( + 'mousemove', + this.mouseMove, + false + ); + mouseControl.domElement.instance.addEventListener( + 'wheel', + this.mouseWheel, + false + ); + + mouseControl.domElement.instance.addEventListener( + 'mouseup', + this.mouseUp, + false + ); +}; + +GameLib.System.Input.prototype.registerEditorControls = function() { + + if (this.editorControls.length !== 1) { + return; + } + + var editorControl = this.editorControls[0]; + + /** + * If we already have mouse controls, we don't want to add another event listener onto the DOM + */ + this.mouseDownEdit = this.onMouseDownEdit.bind(this); + this.mouseMoveEdit = this.onMouseMoveEdit.bind(this); + + editorControl.domElement.instance.addEventListener( + 'mousedown', + this.mouseDownEdit, + false + ); + + editorControl.domElement.instance.addEventListener( + 'mousemove', + this.mouseMoveEdit, + false + ); + + /** + * If we already have keyboard controls, we don't want to add another event listener onto the DOM + */ + if (this.keyboardControls.length > 0) { + /** + * Do Nothing + */ + } else { + + this.keyDown = this.onKeyDown.bind(this); + this.keyUp = this.onKeyUp.bind(this); + + editorControl.domElement.instance.addEventListener( + 'keydown', + this.keyDown, + false + ); + + editorControl.domElement.instance.addEventListener( + 'keyup', + this.keyUp, + false + ); + + } + + editorControl.createInstance(); + + this.mouseWheelEdit = this.onMouseWheelEdit.bind(this); + this.mouseUpEdit = this.onMouseUpEdit.bind(this); + + editorControl.domElement.instance.addEventListener( + 'wheel', + this.mouseWheelEdit, + false + ); + + editorControl.domElement.instance.addEventListener( + 'mouseup', + this.mouseUpEdit, + false + ); + + +}; + +GameLib.System.Input.prototype.deRegisterEditorControls = function() { + + if (this.editorControls.length !== 1) { + return; + } + + var editorControl = this.editorControls[0]; + + editorControl.domElement.instance.removeEventListener( + 'mousedown', + this.mouseDownEdit, + false + ); + + editorControl.domElement.instance.removeEventListener( + 'mousemove', + this.mouseMoveEdit, + false + ); + + if (this.keyboardControls.length < 1) { + editorControl.domElement.instance.removeEventListener( + 'keydown', + this.keyDown, + false + ); + + editorControl.domElement.instance.removeEventListener( + 'keyup', + this.keyUp, + false + ); + } + + editorControl.instance.dispose(); + + editorControl.domElement.instance.removeEventListener( + 'wheel', + this.mouseWheelEdit, + false + ); + + editorControl.domElement.instance.removeEventListener( + 'mouseup', + this.mouseUpEdit, + false + ); + +}; + +GameLib.System.Input.prototype.deRegisterTouchControls = function() { + + if (this.touchControls.length !== 1) { + return; + } + + var touchControl = this.touchControls[0]; + + touchControl.domElement.instance.removeEventListener( + 'touchstart', + this.touchStart, + false + ); + + touchControl.domElement.instance.removeEventListener( + 'touchmove', + this.touchMove, + false + ); + + touchControl.domElement.instance.removeEventListener( + 'touchend', + this.touchEnd, + false + ); + + touchControl.domElement.instance.removeEventListener( + 'touchcancel', + this.touchCancel, + false + ); + +}; + +GameLib.System.Input.prototype.deRegisterKeyboardControls = function() { + + if (this.keyboardControls.length !== 1) { + return; + } + + var keyboardControl = this.keyboardControls[0]; + + keyboardControl.domElement.instance.removeEventListener( + 'keydown', + this.keyboardKeyDown, + false + ); + + keyboardControl.domElement.instance.removeEventListener( + 'keyup', + this.keyboardKeyUp, + false + ); + +}; + + +GameLib.System.Input.prototype.deRegisterMouseControls = function() { + + if (this.mouseControls.length !== 1) { + return; + } + + var mouseControl = this.mouseControls[0]; + + mouseControl.domElement.instance.removeEventListener( + 'mousedown', + this.mouseDown, + false + ); + + mouseControl.domElement.instance.removeEventListener( + 'mousemove', + this.mouseMove, + false + ); + mouseControl.domElement.instance.removeEventListener( + 'wheel', + this.mouseWheel, + false + ); + + mouseControl.domElement.instance.removeEventListener( + 'mouseup', + this.mouseUp, + false + ); + +}; + +GameLib.System.Input.prototype.onKeyboardKeyUp = function(event) { + GameLib.Event.Emit( + GameLib.Event.KEY_DOWN, + { + code : event.code + } + ); + +}; + +GameLib.System.Input.prototype.onKeyboardKeyDown = function(event) { + GameLib.Event.Emit( + GameLib.Event.KEY_UP, + { + code : event.code + } + ); + +}; + +GameLib.System.Input.prototype.onTouchStart = function(event) { + + this.sensitivityCounter = 0; + + this.touches = {}; + + for (var t = 0; t < event.touches.length; t++) { + this.touches[event.touches[t].identifier] = { + left : 0, + right : 0, + up : 0, + down : 0, + lastTouchX : event.touches[t].pageX, + lastTouchY : event.touches[t].pageY, + pageX : event.touches[t].pageX, + pageY : event.touches[t].pageY, + cancelled : false, + ended : false + }; + } + + this.touches.event = event; + + GameLib.Event.Emit( + GameLib.Event.TOUCH_START, + this.touches + ) +}; + +GameLib.System.Input.prototype.onTouchMove = function (event) { + + this.sensitivityCounter++; + + var id = null; + + var leftTouch = null; + var rightTouch = null; + + var inward = false; + var outward = false; + + + if (event.changedTouches.length === 2) { + if (event.changedTouches[0].pageX < event.changedTouches[1].pageX) { + leftTouch = event.changedTouches[0]; + rightTouch = event.changedTouches[1]; + } else { + leftTouch = event.changedTouches[1]; + rightTouch = event.changedTouches[0]; + } + } + + for (var t = 0; t < event.changedTouches.length; t++) { + + id = event.changedTouches[t].identifier; + + if (this.touches[id]) { + + var diffX = Math.abs(this.touches[id].lastTouchX - event.changedTouches[t].pageX); + var diffY = Math.abs(this.touches[id].lastTouchY - event.changedTouches[t].pageY); + + var left = 0; + var right = 0; + var up = 0; + var down = 0; + + if (this.touches[id].lastTouchX < event.changedTouches[t].pageX) { + right += diffX; + } + + if (this.touches[id].lastTouchX > event.changedTouches[t].pageX) { + left += diffX; + } + + if (this.touches[id].lastTouchY > event.changedTouches[t].pageY) { + up += diffY; + } + + if (this.touches[id].lastTouchY < event.changedTouches[t].pageY) { + down += diffY; + } + + this.touches[id].right = right; + this.touches[id].left = left; + this.touches[id].up = up; + this.touches[id].down = down; + this.touches[id].lastTouchX = event.changedTouches[t].pageX; + this.touches[id].lastTouchY = event.changedTouches[t].pageY; + this.touches[id].pageX = event.changedTouches[t].pageX; + this.touches[id].pageY = event.changedTouches[t].pageY; + } + } + + if (leftTouch.left && rightTouch.right) { + outward = true; + } + + if (leftTouch.right && rightTouch.left) { + inward = true; + } + + + + this.touches.event = event; + + if (this.sensitivityCounter >= this.touchSensitivity) { + + this.sensitivityCounter = 0; + + GameLib.Event.Emit( + GameLib.Event.TOUCH_MOVE, + this.touches + ); + + } + +}; + +GameLib.System.Input.prototype.onTouchCancel = function(event) { + + this.sensitivityCounter = 0; + + for (var t = 0; t < event.changedTouches.length; t++) { + this.touches[event.changedTouches[t].identifier].cancelled = true; + this.touches[event.changedTouches[t].identifier].event = event; + GameLib.Event.Emit( + GameLib.Event.TOUCH_CANCEL, + this.touches[event.changedTouches[t].identifier] + ); + delete this.touches[event.changedTouches[t].identifier]; + } +}; + +GameLib.System.Input.prototype.onTouchEnd = function(event) { + + this.sensitivityCounter = 0; + + for (var t = 0; t < event.changedTouches.length; t++) { + this.touches[event.changedTouches[t].identifier].ended = true; + this.touches[event.changedTouches[t].identifier].event = event; + GameLib.Event.Emit( + GameLib.Event.TOUCH_END, + this.touches[event.changedTouches[t].identifier] + ); + delete this.touches[event.changedTouches[t].identifier]; + } +}; + +GameLib.System.Input.prototype.onKeyDown = function(event) { + + console.log('input system emitted keypress ' + event.code); + + GameLib.Event.Emit( + GameLib.Event.KEY_DOWN, + { + code : event.code + } + ); + + var meshes = null; + + if (event.code === 'Delete') { + + meshes = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Mesh]); + + var deletedMeshes = []; + + meshes.map( + function(mesh) { + if (mesh.selected) { + + deletedMeshes.push(mesh); + + mesh.removeHelper(); + + var scene = mesh.parentScene; + scene.removeObject(mesh); + scene.buildIdToObject(); + } + }.bind(this) + ); + + GameLib.Event.Emit( + GameLib.Event.REMOVE_MESH, + { + meshes : deletedMeshes + } + ); + + } + + if (event.code === 'ControlLeft') { + this.controlLeft = true; + } + + if (event.code === 'KeyA') { + + this.selectAll = !this.selectAll; + + meshes = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Mesh]); + + meshes.map(function(mesh){ + if (this.selectAll) { + this.selectMesh(mesh); + } else { + this.deSelectMesh(mesh); + } + }.bind(this)); + + GameLib.Event.Emit( + GameLib.Event.BUILD_GUI, + null + ) + + } + + if (event.code === 'KeyP') { + GameLib.Event.Emit(GameLib.Event.PAUSE); + } +}; + +GameLib.System.Input.prototype.onKeyUp = function(event) { + + GameLib.Event.Emit( + GameLib.Event.KEY_UP, + { + code : event.code + } + ); + + if (event.code === 'ControlLeft') { + this.controlLeft = false; + } +}; + +GameLib.System.Input.prototype.onMouseDown = function(event) { +// console.log('mouse down'); + + GameLib.Event.Emit( + GameLib.Event.MOUSE_DOWN, + { + event : event + } + ) +}; + +GameLib.System.Input.prototype.onMouseMove = function(event) { +// console.log('mouse move'); + GameLib.Event.Emit( + GameLib.Event.MOUSE_MOVE, + { + event : event + } + ) +}; + +GameLib.System.Input.prototype.onMouseWheel = function(event) { +// console.log('mouse wheel'); + GameLib.Event.Emit( + GameLib.Event.MOUSE_WHEEL, + { + event : event + } + ) +}; + +GameLib.System.Input.prototype.onMouseUp = function(event) { +// console.log('mouse up'); + GameLib.Event.Emit( + GameLib.Event.MOUSE_UP, + { + event : event + } + ) +}; + +GameLib.System.Input.prototype.onMouseDownEdit = function(event) { + + if (event.button === 2) { + + this.editorControls.map( + + function(editorControl) { + + if (this.controlLeft) { + return; + } + + this.mouse.x = (event.offsetX / event.target.width ) * 2 - 1; + this.mouse.y = -(event.offsetY / event.target.height) * 2 + 1; + + var scenes = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Scene); + + var intersects = scenes.reduce( + + function (result, scene) { + + editorControl.raycaster.instance.setFromCamera( + this.mouse, + editorControl.camera.instance + ); + + intersects = editorControl.raycaster.getIntersectedObjects(scene.meshes); + + intersects.map(function (intersect) { + result.push(intersect); + }); + + return result; + }.bind(this), + [] + ); + + intersects.sort( + function (a, b) { + if (a.distance < b.distance) { + return -1; + } + + if (a.distance > b.distance) { + return 1; + } + + return 0; + } + ); + + var meshes = intersects.map(function (intersect) { + return intersect.mesh; + }); + + var mesh = meshes[0]; + + if (mesh) { + + /** + * Prevent default action (like context menu or whatever) + */ + event.preventDefault(); + + /** + * Prevent other event listeners for 'mousedown' from executing their actions + */ + event.stopImmediatePropagation(); + + if (mesh.selected) { + this.deSelectMesh(mesh); + } else { + this.selectMesh(mesh); + } + + /** + * Notify our GUI system to build a GUI + */ + GameLib.Event.Emit( + GameLib.Event.BUILD_GUI, + null + ) + } + }.bind(this) + ); + } +}; + +/** + * + * @param event + */ +GameLib.System.Input.prototype.onMouseMoveEdit = function(event) { + +}; + +/** + * Update the camera position etc. after mouse up + * @returns {Function} + * @param event + */ +GameLib.System.Input.prototype.onMouseUpEdit = function(event) { + this.editorControls.map( + function(editorControl) { + editorControl.camera.position.x = editorControl.camera.instance.position.x; + editorControl.camera.position.y = editorControl.camera.instance.position.y; + editorControl.camera.position.z = editorControl.camera.instance.position.z; + + editorControl.camera.quaternion.x = editorControl.camera.instance.quaternion.x; + editorControl.camera.quaternion.y = editorControl.camera.instance.quaternion.y; + editorControl.camera.quaternion.z = editorControl.camera.instance.quaternion.z; + editorControl.camera.quaternion.w = editorControl.camera.instance.quaternion.w; + + editorControl.camera.lookAt.x = editorControl.instance.center.x; + editorControl.camera.lookAt.y = editorControl.instance.center.y; + editorControl.camera.lookAt.z = editorControl.instance.center.z; + editorControl.camera.lookAt.instance.copy(editorControl.instance.center); + } + ); +}; + +/** + * Update our camera position after moving the mouse wheel + * @returns {Function} + * @param event + */ +GameLib.System.Input.prototype.onMouseWheelEdit = function(event) { + this.editorControls.map( + function(editorControl) { + editorControl.camera.position.x = editorControl.camera.instance.position.x; + editorControl.camera.position.y = editorControl.camera.instance.position.y; + editorControl.camera.position.z = editorControl.camera.instance.position.z; + } + ); +}; + +GameLib.System.Input.prototype.selectMesh = function(mesh) { + + /** + * If mesh is already selected, do nothing + */ + if (mesh.selected === true) { + return; + } + + /** + * Notify our component as being 'selected' + * @type {boolean} + */ + mesh.selected = true; + + mesh.createHelper(); + + GameLib.Event.Emit( + GameLib.Event.MESH_SELECTED, + { + mesh : mesh + } + ); +}; + +GameLib.System.Input.prototype.deSelectMesh = function(mesh) { + + mesh.selected = false; + + mesh.removeHelper(); + + GameLib.Event.Emit( + GameLib.Event.MESH_DESELECTED, + { + mesh : mesh + } + ); +}; + + + + + + +// +// console.log('keypressed ' + event.code); +// +// if (event.code === 'KeyV') { +// //todo - change view +// } +// +// +// if (event.code == 'KeyG') { +// if (!this.meshMoveMode) { +// console.log('move mode'); +// this.meshMoveMode = true; +// } +// } +// +// if (event.code == 'KeyX') { +// if (this.meshMoveMode) { +// console.log('move along x'); +// this.meshMoveXMode = true; +// this.meshMoveYMode = false; +// this.meshMoveZMode = false; +// } +// } +// +// if (event.code == 'KeyY') { +// if (this.meshMoveMode) { +// console.log('move along y'); +// this.meshMoveXMode = false; +// this.meshMoveYMode = true; +// this.meshMoveZMode = false; +// } +// } +// +// if (event.code == 'KeyZ') { +// if (this.meshMoveMode) { +// console.log('move along z'); +// this.meshMoveXMode = false; +// this.meshMoveYMode = false; +// this.meshMoveZMode = true; +// } +// } +// +// if (event.code == 'Escape') { +// if (this.meshMoveMode) { +// this.meshMoveMode = false; +// console.log('TODO: implement restore positions'); +// } +// } +// +// if (event.code == 'Enter') { +// if (this.meshMoveMode) { +// this.meshMoveMode = false; +// console.log('TODO: implement apply positions'); +// } +// } +// }; + +// GameLib.D3.Input.Editor.prototype.onMouseDown = function(entity) { +// +// return function(event) { +// +// if (event.button === 2) { +// event.cancelBubble = true; +// +// event.preventDefault(); +// +// if (event.stopPropagation) { +// event.stopPropagation(); +// } +// +// var meshes = entity.queryComponents(GameLib.D3.Mesh); +// +// var intersects = this.raycaster.getIntersectedObjects(meshes); +// +// if (intersects.length > 0) { +// +// console.log('object(s) instersected'); +// +// // var index = -1; +// // +// // for (var s = 0; s < this.editor.selectedObjects.length; s++) { +// // if (this.editor.selectedObjects[s].object == intersects[0]) { +// // index = s; +// // break; +// // } +// // } +// // +// // if (index == -1) { +// // /** +// // * The object is not selected, select it +// // */ +// // this.selectObject(intersects[0]); +// // +// // } else { +// // /** +// // * De-select the objec +// // */ +// // var delta = Date.now() - this.editor.selectedObjects[index].lastUpdate; +// // if (delta > this.selectDelayMs) { +// // this.unselectObject(intersects[0]); +// // } +// // } +// // +// // if (this.editor.onSelectionChanged) { +// // this.editor.onSelectionChanged(this.editor); +// // } +// } +// +// return false; +// } +// } +// }; + +// /** +// * Mouse click events +// * @param event +// * @returns {boolean} +// */ +// GameLib.D3.Input.Editor.prototype.onMouseDown = function(event) { +// +// if (event.button === 2) { +// +// +// +// +// +// } +// +// if (event.button == 0) { +// if (this.meshMoveMode) { +// this.meshMoveMode = false; +// this.meshMoveXMode = false; +// this.meshMoveYMode = false; +// this.meshMoveZMode = false; +// } +// } +// }; + +// /** +// * Mouse move events +// * @param event +// */ +// GameLib.D3.Input.Editor.prototype.onMouseMove = function(event) { +// +// // var clientX = event.clientX - this.widthOffset; +// // this.mouse.x = ((clientX / (window.innerWidth - this.widthOffset))) * 2 - 1; +// // this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; +// +// this.mouse.x = event.clientX; +// this.mouse.y = event.clientY; +// +// console.log("mouse (" + this.mouse.x + ", " + this.mouse.y + ")"); +// +// this.raycaster.instance.setFromCamera( +// this.mouse, +// this.camera.instance +// ); +// +// if (this.meshMoveMode) { +// +// var units = event.movementY; +// +// if (this.meshMoveXMode) { +// this.moveSelectedObjects('x', units); +// } +// +// if (this.meshMoveYMode) { +// this.moveSelectedObjects('y', units); +// } +// +// if (this.meshMoveZMode) { +// this.moveSelectedObjects('z', units); +// } +// } +// }; + +// /** +// * Moves selected objects along an axis +// * @param alongAxis +// * @param units +// */ +// GameLib.D3.Input.Editor.prototype.moveSelectedObjects = function(alongAxis, units) { +// +// for (var s = 0; s < this.editor.selectedObjects.length; s++) { +// +// var object = this.editor.selectedObjects[s].object; +// +// if (object.position) { +// if (alongAxis == 'x') { +// object.position.x += units; +// } +// if (alongAxis == 'y') { +// object.position.y += units; +// } +// if (alongAxis == 'z') { +// object.position.z += units; +// } +// +// if (object.updateInstance) { +// object.updateInstance(); +// } +// } +// } +// }; + + +/** + * Linking System takes care of linking components and dependencies (after they have loaded) - + * and managing the relationships between objects - ex. what happens when a parent entity changes, + * or a parent scene changes. + * @param apiSystem GameLib.API.System + * @constructor + */ +GameLib.System.Linking = function( + apiSystem +) { + GameLib.System.call( + this, + apiSystem + ); + + /** + * The dependencies of each component is tracked through this dependencies object - + * it maps the id of the object on which a component depends back to the component which depends on it, + * ex. texture.image = 'abcdefghi', then this.dependencies = {'abcdefghi' : [texture]} + * @type {{}} + */ + this.dependencies = {}; + + this.resolved = []; + + /** + * Components + */ + this.componentCreatedSubscription = null; + this.componentClonedSubscription = null; + this.registerDependenciesSubscription = null; + this.componentRemoveSubscription = null; + + /** + * Parents + */ + this.parentSceneChangeSubscription = null; + this.parentWorldChangeSubscription = null; + this.parentEntityChangeSubscription = null; + + /** + * Instances + */ + this.instanceCreatedSubscription = null; + this.instanceClonedSubscription = null; + + /** + * Meshes + */ + this.removeMeshSubscription = null; + + /** + * Images + */ + this.imageChangedSubscription = null; + + /** + * Materials + */ + this.materialTypeChangedSubscription = null; + + /** + * Arrays + */ + this.arrayItemAddedSubscription = null; +}; + +GameLib.System.Linking.prototype = Object.create(GameLib.System.prototype); +GameLib.System.Linking.prototype.constructor = GameLib.System.Linking; + +GameLib.System.Linking.prototype.start = function() { + + GameLib.System.prototype.start.call(this); + + /** + * Components + */ + this.componentCreatedSubscription = this.subscribe( + GameLib.Event.COMPONENT_CREATED, + this.componentCreated.bind(this) + ); + + this.componentClonedSubscription = this.subscribe( + GameLib.Event.COMPONENT_CLONED, + this.componentCloned.bind(this) + ); + + this.registerDependenciesSubscription = this.subscribe( + GameLib.Event.REGISTER_DEPENDENCIES, + this.registerDependenciesDirect + ); + + this.componentRemoveSubscription = this.subscribe( + GameLib.Event.REMOVE_COMPONENT, + this.removeComponent + ); + + /** + * Parents + */ + this.parentSceneChangeSubscription = this.subscribe( + GameLib.Event.PARENT_SCENE_CHANGE, + this.onParentSceneChange + ); + + this.parentWorldChangeSubscription = this.subscribe( + GameLib.Event.PARENT_WORLD_CHANGE, + this.onParentWorldChange + ); + + this.parentEntityChangeSubscription = this.subscribe( + GameLib.Event.PARENT_ENTITY_CHANGE, + this.onParentEntityChange + ); + + /** + * Instances + */ + this.instanceCreatedSubscription = this.subscribe( + GameLib.Event.INSTANCE_CREATED, + this.instanceCreated + ); + + this.instanceClonedSubscription = this.subscribe( + GameLib.Event.INSTANCE_CLONED, + this.instanceCloned + ); + + /** + * Meshes + */ + this.removeMeshSubscription = this.subscribe( + GameLib.Event.REMOVE_MESH, + this.removeMesh + ); + + /** + * Images + */ + this.imageChangedSubscription = this.subscribe( + GameLib.Event.IMAGE_CHANGED, + this.imageChanged + ); + + /** + * Materials + */ + this.materialTypeChangedSubscription = this.subscribe( + GameLib.Event.MATERIAL_TYPE_CHANGED, + this.materialTypeChanged + ); + + /** + * Arrays + */ + this.arrayItemAddedSubscription = this.subscribe( + GameLib.Event.ARRAY_ITEM_ADDED, + this.arrayItemAdded + ); + +}; + +GameLib.System.Linking.prototype.link = function(component, data) { + for (var property in component.linkedObjects) { + if (component.linkedObjects.hasOwnProperty(property)) { + if (component.linkedObjects[property] instanceof Array) { + + var linked = []; + + component[property] = component[property].map(function (entry) { + if (entry === data.component.id) { + + linked.push({ + parent : component, + property : property, + child : data.component + }); + + return data.component; + } else { + return entry; + } + }); + + linked.map(function(link) { + GameLib.Event.Emit( + GameLib.Event.COMPONENT_LINKED, + link + ); + }) + + } else { + if (component[property] && + component[property] === data.component.id) { + component[property] = data.component; + + GameLib.Event.Emit( + GameLib.Event.COMPONENT_LINKED, + { + parent : component, + property : property, + child : data.component + } + ); + } + } + } + } +}; + +GameLib.System.Linking.prototype.resolveDependencies = function(component) { + + if (!component.loaded) { + /** + * This component has not fully loaded - we should resolve dependencies to it later + */ + return false; + } + + /** + * Now find all the components which depend on this component + */ + var parentComponents = this.dependencies[component.id]; + + /** + * If we don't have any components which depend on this component, simply return + */ + if (GameLib.Utils.UndefinedOrNull(parentComponents)) { + + /** + * We don't know about components which depend on this component - but it could still load. + * However, it is stored in the register and dependency list for later use + */ + return false; + } + + /** + * Otherwise, process them all + */ + parentComponents.map( + + function (parentComponent) { + + /** + * Link the parent component to this component + */ + this.link(parentComponent, {component: component}); + + /** + * We record that we linked a child component to a parent component + */ + GameLib.Utils.PushUnique(this.resolved, component); + + /** + * First check if the dependencies have already been met + */ + if ( + GameLib.Utils.UndefinedOrNull(parentComponent.dependencies) || + ( + parentComponent.dependencies instanceof Array && + parentComponent.dependencies.length === 0 + ) + ) { + + /** + * This means - a parent component instance could maybe have been delayed to be created + * because the component constructor or linking system did not know at time of 'createInstance' + * that it required another object to fully become active + */ + if ( + !parentComponent.loaded || + GameLib.Utils.UndefinedOrNull(parentComponent.instance) + ) { + + try { + + parentComponent.performInstanceCreation(); + + } catch (error) { + console.error(error); + } + + } else { + /** + * These dependencies have already been met - the parentComponent properties have changed. + * It is time to 'update' this instance with this information (if any of it is relevant - depends + * on the component) + */ + // parentComponent.updateInstance(); + } + + } else { + + /** + * Remove the actual dependency + */ + var index = parentComponent.dependencies.indexOf(component.id); + if (index !== -1) { + parentComponent.dependencies.splice(index, 1); + } + + /** + * If we now managed to link the objects, and this object has no more dependencies + */ + if (parentComponent.dependencies.length === 0) { + parentComponent.performInstanceCreation(); + } + } + + }.bind(this) + ); + + /** + * We now linked all the components which depends on this component, to this component. Time to cleanup our + * dependencies + */ + delete this.dependencies[component.id]; + + /** + * For now this essentially only notifies the Editor - We have some more work to do however + */ + GameLib.Event.Emit( + GameLib.Event.UNRESOLVED_DEPENDENCIES_UPDATE, + { + dependencies : this.dependencies + } + ); + + /** + * If we happen to have no more dependencies - we linked a bunch of components which are ready to use + */ + if (GameLib.Utils.IsEmpty(this.dependencies)) { + + /** + * This also only notifies the Editor - We still have some more work to here + */ + GameLib.Event.Emit( + GameLib.Event.COMPONENTS_LINKED, + { + components: this.resolved.map( + function(component) { + return component; + } + ) + } + ); + + this.resolved = []; + + } + //else { + + // var keys = Object.keys(this.dependencies); + + /** + * And this is it - we need to check if the dependencies array contains any 'resolved' components - + * If it does - resolve the dependencies of this newly 'resolved' component + */ + // this.resolved = this.resolved.reduce( + // + // function(result, component) { + // + // if (keys.indexOf(component.id) !== -1) { + // /** + // * We found a resolved component - which is a dependency for another component. + // * Resolve the dependencies of this component - this is recursive and should be done carefully + // */ + // this.resolveDependencies(component); + // } else { + // result.push(component); + // } + // + // return result; + // + // }.bind(this), + // [] + // ); + //} + +}; + +GameLib.System.Linking.prototype.registerDependencies = function(component) { + + /** + * We only care about components with unloaded dependencies - + * other components will have already had their instance objects created + */ + if (component.dependencies && + component.dependencies.length > 0) { + + component.dependencies = component.dependencies.reduce( + + function(result, id) { + + /** + * Check if we already processed a component on which this component is dependent + */ + var processedComponent = GameLib.EntityManager.Instance.findComponentById(id); + + if (processedComponent && processedComponent.loaded) { + + /** + * Link the component + */ + this.link(component, {component: processedComponent}); + + GameLib.Utils.PushUnique(this.resolved, processedComponent); + + } else { + + /** + * Create a new link if none exists + */ + if (GameLib.Utils.UndefinedOrNull(this.dependencies[id])) { + this.dependencies[id] = []; + } + + /** + * Don't store duplicate dependencies + */ + if (this.dependencies[id].indexOf(component) === -1) { + this.dependencies[id].push(component); + GameLib.Event.Emit( + GameLib.Event.UNRESOLVED_DEPENDENCIES_UPDATE, + { + dependencies : this.dependencies + } + ); + } + + /** + * Also - we remember that this component has a dependency + */ + result.push(id); + } + + return result; + + }.bind(this), + [] + ); + + if (component.dependencies.length === 0) { + component.performInstanceCreation(); + } + } +}; + +/** + * When a component is created, register its dependencies, and try to resolve them + * @param data + */ +GameLib.System.Linking.prototype.componentCreated = function(data) { + + /** + * Shorthand + */ + var component = data.component; + + /** + * Register any dependencies of this component + */ + this.registerDependencies(component); + + /** + * Resolve any dependencies to this component + */ + this.resolveDependencies(component); + +}; + +GameLib.System.Linking.prototype.componentCloned = function(data) { + + this.componentCreated(data); + + if (data.component instanceof GameLib.D3.Mesh) { + + if (!(data.parent instanceof GameLib.D3.Mesh)){ + throw new Error('no scene parent'); + } + + if (data.parent.parentScene) { + data.parent.parentScene.addClone(data.component); + } + } + +}; + +/** + * When you want to register dependencies directly - Component constructor does this when it knows the + * component instance cannot be created because it has a bunch of dependencies. So it tells the linking + * system about it, so the linking system can create the instance when the dependency loads or already exists + * @param data + */ +GameLib.System.Linking.prototype.registerDependenciesDirect = function(data) { + this.registerDependencies(data.component); +}; + +GameLib.System.Linking.prototype.removeComponent = function(data) { + + if (!data.component) { + console.error('no component to remove'); + return; + } + + var component = data.component; + + if (component.parentEntity instanceof GameLib.Entity) { + component.parentEntity.removeComponent(component); + } + + if (component instanceof GameLib.D3.Mesh && + component.parentScene instanceof GameLib.D3.Scene) { + + component.removeHelper(); + + component.parentScene.removeObject(component); + } + + if (component instanceof GameLib.D3.Light && + component.parentScene instanceof GameLib.D3.Scene) { + component.parentScene.removeObject(component); + } + + if (component instanceof GameLib.Entity) { + GameLib.EntityManager.Instance.removeEntity(component); + } + + // if (component instanceof GameLib.D3.Particle) { + // // component.mesh.parentScene.removeObject(component.mesh); + // } +}; + +GameLib.System.Linking.prototype.imageChanged = function(data) { + + var materials = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Material); + + materials.map(function(material){ + + var textures = material.getTextures(); + + if (textures.indexOf(data.texture) !== -1) { + material.updateInstance(); + } + + }); + +}; + +GameLib.System.Linking.prototype.arrayItemAdded = function(data) { + if ( + data.component instanceof GameLib.D3.PhysicsWorld && + data.item instanceof GameLib.D3.RigidBody + ) { + data.component.addRigidBody(data.item); + } + + if (data.component instanceof GameLib.D3.Mesh && + data.item instanceof GameLib.D3.Material + ) { + data.component.addMaterial(data.item); + } +}; + +GameLib.System.Linking.prototype.instanceCloned = function(data) { + + // if (data.component instanceof GameLib.D3.Particle) { + // + // var mesh = data.component.mesh; + // + // if (mesh.parentScene && mesh.parentScene.instance) { + // data.instance.userData.scene = mesh.parentScene.instance; + // mesh.parentScene.instance.add(data.instance); + // } + // } + +}; + +GameLib.System.Linking.prototype.instanceCreated = function(data) { + + this.resolveDependencies(data.component); + + if (data.component instanceof GameLib.D3.Image) { + /** + * Find all textures which use this image + */ + GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Texture).map( + function(texture) { + if (texture.image === data.component || + texture.images.indexOf(data.component) !== -1 + ) { + + /** + * Ok - this image is in use - this should notify materials when its image changes + */ + texture.updateInstance('image'); + } + } + ); + } + + /** + * Link all scenes + */ + if (data.component instanceof GameLib.D3.Scene) { + /** + * Check ALL components for 'parentScenes' - this is expensive so it checks the register directly + */ + GameLib.EntityManager.Instance.register.map( + function(component) { + if (component.parentScene === data.component.id) { + component.parentScene = data.component; + } + } + ); + } + + if ( + data.component.parentScene && + typeof data.component.parentScene === 'string' + ) { + GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Scene).map( + function (scene) { + if (data.component.parentScene === scene.id) { + data.component.parentScene = scene; + scene.addObject(data.component); + } + } + ); + } + + if ( + data.component.parentEngine && + typeof data.component.parentEngine === 'string' + ) { + GameLib.EntityManager.Instance.queryComponents(GameLib.D3.ParticleEngine).map( + function (particleEngine) { + if (data.component.parentEngine === particleEngine.id) { + data.component.parentEngine = particleEngine; + } + } + ); + } + + /** + * Link all meshes + */ + if (data.component instanceof GameLib.D3.Mesh) { + + /** + * Check if this mesh is a parentMesh to any component- this is an expensive call, so check if we should call it + * Also - it inspects the register directly instead of querying it twice (since it checks ALL components) + */ + if (!data.preventParentMeshCheck) { + GameLib.EntityManager.Instance.register.map( + function (component) { + if (component.parentMesh && + component.parentMesh === data.component.id ) { + + component.parentMesh = data.component; + + /** + * Check if a component has this mesh as a parent + */ + if (component instanceof GameLib.D3.Mesh) { + component.setParentMesh(data.component); + } + } + } + ); + } + + } + + /** + * Maybe this component has a parent mesh + */ + if ( + data.component.parentMesh && + typeof data.component.parentMesh === 'string' + ) { + GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Mesh).map( + function (mesh) { + if (data.component.parentMesh === mesh.id) { + + data.component.parentMesh = mesh; + + if (data.component instanceof GameLib.D3.Mesh) { + data.component.setParentMesh(mesh); + } + } + } + ); + } + + if ( + data.component.parentWorld && + typeof data.component.parentWorld === 'string' + ) { + GameLib.EntityManager.Instance.queryComponents(GameLib.D3.PhysicsWorld).map( + function (world) { + if (data.component.parentWorld === world.id) { + data.component.parentWorld = world; + + if (typeof data.component.instance.addToWorld === 'function') { + data.component.instance.addToWorld(world.instance); + console.log('instance added to physics world'); + } + } + } + ); + } + +}; + +GameLib.System.Linking.prototype.materialTypeChanged = function(data) { + + var meshes = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Mesh); + + meshes.map( + function(mesh){ + var inUse = mesh.materials.reduce( + function(result, material) { + if (material === data.material) { + result = true; + } + return result; + }, + false + ); + + if (inUse) { + + if (mesh.materials.length === 1) { + mesh.instance.material = mesh.materials[0].instance + } else { + mesh.instance.material = mesh.materials.map( + function(material) { + return material.instance; + } + ) + } + + mesh.instance.geometry.uvsNeedUpdate = true; + mesh.instance.material.needsUpdate = true; + } + + } + ); + +}; + +/** + * + * @param data + */ +GameLib.System.Linking.prototype.onParentWorldChange = function(data) { + + if ( + data.object instanceof GameLib.D3.RigidBody + ) { + + + if (data.originalWorld instanceof GameLib.D3.PhysicsWorld) { + data.originalWorld.removeRigidBody(data.object); + } + + if (data.newWorld instanceof GameLib.D3.PhysicsWorld) { + data.newWorld.addRigidBody(data.object); + } + } + +}; + +/** + * Defines what should happen when a parent scene changes + * @param data + */ +GameLib.System.Linking.prototype.onParentSceneChange = function(data) { + + if ( + data.object instanceof GameLib.D3.Mesh || + data.object instanceof GameLib.D3.Light + ) { + + /** + * We remove the helper (if any) from the old scene and add it to the new scene + */ + var helper = GameLib.EntityManager.Instance.findHelperByObject(data.object); + if (helper) { + + if (data.originalScene && data.originalScene.instance) { + data.originalScene.instance.remove(helper.instance); + } + data.newScene.instance.add(helper.instance); + } + + /** + * We remove the mesh from the old scene and add it to the new scene + */ + if (data.originalScene && data.originalScene.removeObject) { + data.originalScene.removeObject(data.object); + } + + if (data.newScene) { + data.newScene.addObject(data.object); + } + } + +}; + +/** + * Change parent entity + * @param data + */ +GameLib.System.Linking.prototype.onParentEntityChange = function(data) { + + if (data.originalEntity instanceof GameLib.Entity) { + data.originalEntity.removeComponent(data.object); + } + + if (data.newEntity instanceof GameLib.Entity) { + data.newEntity.addComponent(data.object); + } + + GameLib.Event.Emit( + GameLib.Event.PARENT_ENTITY_CHANGED, + { + originalEntity : data.originalEntity, + newEntity : data.newEntity, + component : data.object + } + ) +}; + +/** + * When a mesh is deleted - build a list of all the mesh children objects - also - find out if any of these + * children objects are in use by another object - if it is - don't delete it, otherwise, do + * @param data + */ +GameLib.System.Linking.prototype.removeMesh = function(data) { + + /** + * First we get the list of all components we would like to delete + */ + var componentsToDelete = data.meshes.reduce( + function(result, mesh) { + + result.push(mesh); + + var components = mesh.getChildrenComponents(); + + components.map(function(component){ + result.push(component); + }); + + return result; + }, + [] + ); + + /** + * Now, we want to get a list of all the meshes which we don't want to delete, and all their children + */ + var meshes = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Mesh); + meshes = meshes.filter(function(mesh){ + return data.meshes.indexOf(mesh) === -1; + }); + + /** + * Now we have a list of meshes still in use in meshes, now find all their children + */ + var componentsInUse = meshes.reduce( + function(result, mesh) { + + result.push(mesh); + + var components = mesh.getChildrenComponents(); + + components.map(function(component){ + result.push(component); + }); + + return result; + }, + [] + ); + + /** + * Now we don't want to remove any children in use, so filter out the components in use + */ + componentsToDelete = componentsToDelete.filter( + function(component) { + return componentsInUse.indexOf(component) === -1; + } + ); + + /** + * componentsToDelete should now be the final list of components to delete + */ + componentsToDelete.map( + function(component){ + component.remove(); + } + ); +}; + +GameLib.System.Linking.prototype.stop = function() { + GameLib.System.prototype.stop.call(this); + /** + * Components + */ + this.componentCreatedSubscription.remove(); + this.componentClonedSubscription.remove(); + this.registerDependenciesSubscription.remove(); + this.componentRemoveSubscription.remove(); + + /** + * Parents + */ + this.parentSceneChangeSubscription.remove(); + this.parentWorldChangeSubscription.remove(); + this.parentEntityChangeSubscription.remove(); + + /** + * Instances + */ + this.instanceCreatedSubscription.remove(); + this.instanceClonedSubscription.remove(); + + /** + * Meshes + */ + this.removeMeshSubscription.remove(); + + /** + * Images + */ + this.imageChangedSubscription.remove(); + + /** + * Materials + */ + this.materialTypeChangedSubscription.remove(); + + /** + * Arrays + */ + this.arrayItemAddedSubscription.remove(); +}; + + +/** + * System takes care of updating all the entities (based on their component data) + * @param graphics + * @param camera + * @param apiSystem GameLib.API.System + * @constructor + */ +GameLib.System.Particle = function( + graphics, + camera, + apiSystem +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + GameLib.System.call( + this, + apiSystem + ); + + /** + * this holds a reference to engine components and does some initial setup work so we don't have to do it during render + * like calculate frequency etc.. + * @type {Array} + */ + this.engines = []; + + this.camera = camera; + + this.totalTime = 0; + + this.instanceCreatedSubscription = null; + + this.removeComponentSubscription = null; + + this.beforeRenderSubscription = null; +}; + +GameLib.System.Particle.prototype = Object.create(GameLib.System.prototype); +GameLib.System.Particle.prototype.constructor = GameLib.System.Particle; + +/** + * Start this system (add all event listeners) + */ +GameLib.System.Particle.prototype.start = function() { + + GameLib.System.prototype.start.call(this); + + this.particleEngines = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.ParticleEngine); + + this.instanceCreatedSubscription = GameLib.Event.Subscribe( + GameLib.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + this.removeComponentSubscription = GameLib.Event.Subscribe( + GameLib.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + this.beforeRenderSubscription = GameLib.Event.Subscribe( + GameLib.Event.BEFORE_RENDER, + this.beforeRender.bind(this) + ); + +}; + +/** + * From now on we want to track everything about a component, only from the systems that are active + * @param data + */ +GameLib.System.Particle.prototype.instanceCreated = function(data) { + + if (data.component instanceof GameLib.D3.ParticleEngine) { + console.log('new particle engine'); + this.particleEngines.push(data.component); + } + + if (data.component instanceof GameLib.D3.Camera) { + console.log('new camera'); + this.camera = data.component; + } + +}; + +/** + * Removes a particle engine from this system + * @param data + */ +GameLib.System.Particle.prototype.removeComponent = function(data) { + + if (data.component instanceof GameLib.D3.ParticleEngine) { + + var index = this.particleEngines.indexOf(data.component); + + if (index !== -1) { + console.log('removing particle engine from system' + data.component.name); + + this.particleEngines.splice(index, 1); + + } else { + console.log('failed to find the particle engine in the system : ' + data.component.name); + } + } + +}; + +/** + * This is what actually happens to all particles before render + * @param data + */ +GameLib.System.Particle.prototype.beforeRender = function(data) { + + this.totalTime += data.delta; + + this.particleEngines.map( + function(particleEngine) { + + if ( + GameLib.Utils.UndefinedOrNull(particleEngine.camera) || + GameLib.Utils.UndefinedOrNull(particleEngine.templateParticle) || + GameLib.Utils.UndefinedOrNull(particleEngine.templateParticle.mesh) || + GameLib.Utils.UndefinedOrNull(particleEngine.templateParticle.mesh.parentScene) || + GameLib.Utils.UndefinedOrNull(particleEngine.templateParticle.mesh.parentScene.instance)) { + return; + } + + particleEngine.elapsed += data.delta; + + particleEngine.particles = particleEngine.particles.reduce( + + function(result, particle){ + + var speed = particle.userData.speed; + + if (particle.userData.speedType === GameLib.D3.Particle.SPEED_TYPE_CONSTANT) { + speed = data.delta * particle.userData.speed; + } + + if (particle.userData.speedType === GameLib.D3.Particle.SPEED_TYPE_LINEAR) { + speed = data.delta * particle.userData.speed; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === GameLib.D3.Particle.SPEED_TYPE_EXPONENTIAL) { + speed = Math.pow(particle.userData.speed, 2) * data.delta; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === GameLib.D3.Particle.SPEED_TYPE_LOGARITHMIC) { + speed = Math.log(particle.userData.speed) * data.delta; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_LOG) { + speed = 1 / Math.log(particle.userData.speed) * data.delta; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === GameLib.D3.Particle.SPEED_TYPE_EXP) { + speed = Math.exp(particle.userData.speed) * data.delta; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_EXP) { + speed = 1 / Math.exp(particle.userData.speed) * data.delta; + particle.userData.speed += speed; + } + + particle.position.x += particle.userData.direction.x * speed; + particle.position.y += particle.userData.direction.y * speed; + particle.position.z += particle.userData.direction.z * speed; + + if (particleEngine.templateParticle.scaleType === GameLib.D3.Particle.SCALE_TYPE_CONSTANT) { + /** + * Do nothing - scale should already be set + */ + /* particle.scale.x = particle.userData.scale.x; + particle.scale.y = particle.userData.scale.y; + particle.scale.z = particle.userData.scale.z; + */ + } + + if (particleEngine.templateParticle.scaleType === GameLib.D3.Particle.SCALE_TYPE_LINEAR) { + particle.scale.x += particle.userData.scale.x * data.delta; + particle.scale.y += particle.userData.scale.x * data.delta; + particle.scale.z += particle.userData.scale.x * data.delta; + } + + particle.quaternion.copy(particleEngine.camera.instance.quaternion); + + if (particleEngine.templateParticle.opacityType === GameLib.D3.Particle.OPACITY_TYPE_INCREASE_LINEAR) { + particle.material.opacity += particleEngine.templateParticle.opacityFactor; + } + + if (particleEngine.templateParticle.opacityType === GameLib.D3.Particle.OPACITY_TYPE_DECREASE_LINEAR) { + particle.material.opacity -= particleEngine.templateParticle.opacityFactor; + } + + particle.userData.elapsed += data.delta; + if ( + particle.userData.elapsed > particle.userData.lifeTime || + particle.material.opacity < 0 + ) { + particle.userData.scene.remove(particle); + particle.geometry.dispose(); + //particle.material.map.dispose(); + particle.material.dispose(); + } else { + result.push(particle); + } + + return result; + }, + [] + ); + + if (particleEngine.disabledForRemoval && particleEngine.particles.length === 0) { + GameLib.Event.Emit( + GameLib.Event.REMOVE_PARTICLE_ENGINE, + { + component : particleEngine + } + ) + } + + if (particleEngine.enabled && !particleEngine.disabledForRemoval) { + + var instanceClone = null; + + if (particleEngine.pulse) { + + if (particleEngine.particles.length === 0) { + + particleEngine.elapsed = 0; + + /** + * This is a 'pulse' engine - so spawn all the particles at once and spawn again when all particles + * are gone + */ + for (var i = 0; i < particleEngine.particlesPerSecond; i++) { + instanceClone = particleEngine.templateParticle.cloneInstance(); + particleEngine.particles.push(instanceClone); + } + + } + + } else { + + /** + * This is a 'stream' engine - spawn particles one at a time when its time to do so + */ + if (particleEngine.elapsed > particleEngine.frequency) { + + particleEngine.elapsed = 0; + + instanceClone = particleEngine.templateParticle.cloneInstance(); + particleEngine.particles.push(instanceClone); + } + } + } + + }.bind(this) + ) + +}; + + +/** + * Stop this system (remove all event listeners) + */ +GameLib.System.Particle.prototype.stop = function() { + + GameLib.System.prototype.stop.call(this); + + this.instanceCreatedSubscription.remove(); + this.removeComponentSubscription.remove(); + this.beforeRenderSubscription.remove(); + +}; + +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem GameLib.API.System + * @constructor + */ +GameLib.System.Physics = function( + apiSystem +) { + + GameLib.System.call( + this, + apiSystem + ); + + this.worlds = []; + // this.rigidBodies = []; + // this.wheels = []; + // this.vehicles = []; + + // this.worldSubscription = null; + // this.rigidBodySubscription = null; + this.beforeRenderSubscription = null; + this.afterRenderSubscription = null; + + + + +}; + +GameLib.System.Physics.prototype = Object.create(GameLib.System.prototype); +GameLib.System.Physics.prototype.constructor = GameLib.System.Physics; + +GameLib.System.Physics.prototype.start = function() { + + GameLib.System.prototype.start.call(this); + + this.worlds = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.PhysicsWorld); + // this.rigidBodies = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.RigidBody); + // this.wheels = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.RaycastWheel); + // this.vehicles = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.RaycastVehicle); + + + + // this.worlds.map( + // function(world) { + // world.instance.addEventListener( + // 'postStep', + // function() { + // + // this.vehicles.map( + // function(vehicle) { + // vehicle.instance.wheelInfos.map( + // function(wheelInfo, index) { + // vehicle.instance.updateWheelTransform(index); + // var t = wheelInfo.worldTransform; + // // vehicle.wheels[index].instance.position.copy(t.position); + // // vehicle.wheels[index].instance.quaternion.copy(t.quaternion); + // + // // vehicle.raycastWheels[index].parentMesh.localPosition.x = t.position.x; + // // vehicle.raycastWheels[index].parentMesh.localPosition.y = t.position.y; + // // vehicle.raycastWheels[index].parentMesh.localPosition.z = t.position.z; + // + // // vehicle.raycastWheels[index].parentMesh.updateInstance(); + // } + // ); + // } + // ); + // + // + // }.bind(this) + // ) + // }.bind(this) + // ); + + this.beforeRenderSubscription = this.subscribe( + GameLib.Event.BEFORE_RENDER, + this.beforeRender + ); +}; + +/** + * Update script + */ +GameLib.System.Physics.prototype.beforeRender = function(data) { + + this.worlds.map( + function(world) { + + if (world.instance) { + + world.instance.step(data.delta); + + world.rigidBodies.map( + function(rigidBody){ + rigidBody.position.x = rigidBody.instance.position.x; + rigidBody.position.y = rigidBody.instance.position.y; + rigidBody.position.z = rigidBody.instance.position.z; + + rigidBody.quaternion.x = rigidBody.instance.quaternion.x; + rigidBody.quaternion.y = rigidBody.instance.quaternion.y; + rigidBody.quaternion.z = rigidBody.instance.quaternion.z; + rigidBody.quaternion.w = rigidBody.instance.quaternion.w; + + rigidBody.parentMesh.position.x = rigidBody.instance.position.x; + rigidBody.parentMesh.position.y = rigidBody.instance.position.y; + rigidBody.parentMesh.position.z = rigidBody.instance.position.z; + + rigidBody.parentMesh.quaternion.x = rigidBody.instance.quaternion.x; + rigidBody.parentMesh.quaternion.y = rigidBody.instance.quaternion.y; + rigidBody.parentMesh.quaternion.z = rigidBody.instance.quaternion.z; + rigidBody.parentMesh.quaternion.w = rigidBody.instance.quaternion.w; + + rigidBody.instance.getVelocityAtWorldPoint(new CANNON.Vec3(0,0,0), rigidBody.velocity.instance); + + rigidBody.velocity.x = rigidBody.velocity.instance.x; + rigidBody.velocity.y = rigidBody.velocity.instance.y; + rigidBody.velocity.z = rigidBody.velocity.instance.z; + + rigidBody.parentMesh.updateRotationFromAxisAngle = false; + + rigidBody.parentMesh.updateInstance(); + + rigidBody.parentMesh.updateRotationFromAxisAngle = true; + } + ) + } + + }.bind(this) + ); +}; + + +GameLib.System.Physics.prototype.stop = function() { + + GameLib.System.prototype.stop.call(this); + + this.worlds = []; + this.rigidBodies = []; + this.wheels = []; + this.vehicles = []; + + if (this.beforeRenderSubscription) { + this.beforeRenderSubscription.remove(); + } + + if (this.afterRenderSubscription) { + this.afterRenderSubscription.remove(); + } + +}; + + +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem GameLib.API.System + * @constructor + */ +GameLib.System.Render = function( + apiSystem +) { + + GameLib.System.call( + this, + apiSystem + ); + + this.renderSubscription = null; + +}; + +GameLib.System.Render.prototype = Object.create(GameLib.System.prototype); +GameLib.System.Render.prototype.constructor = GameLib.System.Render; + +/** + * Start the rendering system + */ +GameLib.System.Render.prototype.start = function() { + + GameLib.System.prototype.start.call(this); + + this.renderers = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Renderer); + + this.statistics = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Stats); + + this.instanceCreatedSubscription = GameLib.Event.Subscribe( + GameLib.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + this.removeComponentSubscription = GameLib.Event.Subscribe( + GameLib.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + this.renderSubscription = this.subscribe( + GameLib.Event.RENDER, + this.render + ); + +}; + +/** + * From now on we want to track everything about a component, only from the systems that are active + * @param data + */ +GameLib.System.Render.prototype.instanceCreated = function(data) { + + if (data.component instanceof GameLib.D3.Renderer) { + console.log('new renderer'); + this.renderers.push(data.component); + } + +}; + +/** + * Removes a particle engine from this system + * @param data + */ +GameLib.System.Render.prototype.removeComponent = function(data) { + + if (data.component instanceof GameLib.D3.Renderer) { + + var index = this.renderers.indexOf(data.component); + + if (index !== -1) { + console.log('removing renderer from system'); + + this.renderers.splice(index, 1); + + } else { + console.log('failed to find the renderer in the system : ' + data.component.name); + } + } + +}; + +/** + * Render subscription script + */ +GameLib.System.Render.prototype.render = function(data) { + + if (this.statistics) { + this.statistics.map( + function (statistics) { + statistics.start(); + } + ); + } + + GameLib.Event.Emit( + GameLib.Event.BEFORE_RENDER, + data + ); + + if (this.renderers.length < 1) { + /** + * Do nothing + */ + } else if (this.renderers.length === 1) { + /** + * Quite simple - we have a renderer - it wants to render its stuff + */ + this.renderers[0].render(data.delta); + + } else { + + /** + * If we have multiple renderers, we have a problem - they don't share the same webGL context - + * So, we need to get their scenes and render them individually instead of trying to have both renderers render + * to the same canvas (sharing the same webgl context does not work) + */ + var scenes = this.renderers.reduce( + function(result, renderer) { + renderer.scenes.map( + function(scene){ + result.push(scene); + } + ); + return result; + }, + [] + ); + + var renderer = GameLib.EntityManager.Instance.defaultRenderer; + + if (GameLib.Utils.UndefinedOrNull(renderer)) { + /** + * No default renderer, using first one + */ + renderer = this.renderers[0]; + } + + renderer.render(data.delta, scenes); + + } + + GameLib.Event.Emit( + GameLib.Event.AFTER_RENDER, + data + ); + + if (this.statistics) { + this.statistics.map( + function (statistics) { + statistics.end(); + } + ); + } +}; + +/** + * Stop the rendering system + */ +GameLib.System.Render.prototype.stop = function() { + + GameLib.System.prototype.stop.call(this); + + this.instanceCreatedSubscription.remove(); + + this.removeComponentSubscription.remove(); + + this.renderSubscription.remove(); + + this.renderers.map( + function(renderer) { + if (renderer.statistics) { + renderer.statistics.resize(); + renderer.domElement.instance.parentElement.removeChild(renderer.statistics.instance.dom); + } + } + ); + + this.renderers = []; + +}; + + +/** + * Storage System takes care loading and linking components and dependencies + * @param graphics + * @param apiSystem GameLib.API.System + * @param token + * @param apiUploadUrl + * @param onImageLoaded + * @param onImageProgress + * @param onImageError + * @param onComponentLoaded + * @param onComponentProgress + * @param onComponentError + * @constructor + */ +GameLib.System.Storage = function( + graphics, + apiSystem, + token, + apiUploadUrl, + onImageLoaded, + onImageProgress, + onImageError, + onComponentLoaded, + onComponentProgress, + onComponentError +) { + GameLib.System.call( + this, + apiSystem + ); + + if (GameLib.Utils.UndefinedOrNull(token)) { + token = null; + } + this.token = token; + + if (GameLib.Utils.UndefinedOrNull(apiUploadUrl)) { + console.warn('Need an API Upload URL for a storage system'); + apiUploadUrl = ''; + } + this.apiUploadUrl = apiUploadUrl; + + if (GameLib.Utils.UndefinedOrNull(onImageLoaded)) { + onImageLoaded = null; + } + this.onImageLoaded = onImageLoaded; + + if (GameLib.Utils.UndefinedOrNull(onImageProgress)) { + onImageProgress = null; + } + this.onImageProgress = onImageProgress; + + if (GameLib.Utils.UndefinedOrNull(onImageError)) { + onImageError = null; + } + this.onImageError = onImageError; + + if (GameLib.Utils.UndefinedOrNull(onComponentLoaded)) { + onComponentLoaded = null; + } + this.onComponentLoaded = onComponentLoaded; + + if (GameLib.Utils.UndefinedOrNull(onComponentProgress)) { + onComponentProgress = null; + } + this.onComponentProgress = onComponentProgress; + + if (GameLib.Utils.UndefinedOrNull(onComponentError)) { + onComponentError = null; + } + this.onComponentError = onComponentError; + + this.loaded = []; + this.loading = []; + this.failed = []; + this.otherDependencies = []; + + this.loginSubscription = null; + this.saveSubscription = null; + this.loadSubscription = null; + this.loadImageSubscription = null; + this.blenderDataSubscription = null; + this.imageUploadCompleteSubscription = null; + + this.fetchComponentTypesSubscription = null; + this.fetchComponentsSubscription = null; +}; + +GameLib.System.Storage.prototype = Object.create(GameLib.System.prototype); +GameLib.System.Storage.prototype.constructor = GameLib.System.Storage; + +GameLib.System.Storage.prototype.start = function() { + + GameLib.System.prototype.start.call(this); + + GameLib.Event.Emit( + GameLib.Event.GET_GRAPHICS_IMPLEMENTATION, + null, + function(graphics) { + this.graphics = graphics; + }.bind(this), + function() { + this.graphics = null; + }.bind(this) + ); + + GameLib.Event.Emit( + GameLib.Event.GET_PHYSICS_IMPLEMENTATION, + null, + function(physics) { + this.physics = physics; + }.bind(this), + function() { + this.physics = null; + }.bind(this) + ); + + GameLib.Event.Emit( + GameLib.Event.GET_CODER_IMPLEMENTATION, + null, + function(coder) { + this.coder = coder; + }.bind(this), + function() { + this.coder = null; + }.bind(this) + ); + + this.loginSubscription = this.subscribe( + GameLib.Event.LOGGED_IN, + function(data) { + this.token = data.token; + } + ); + + this.saveSubscription = this.subscribe( + GameLib.Event.SAVE_COMPONENT, + this.save + ); + + this.loadSubscription = this.subscribe( + GameLib.Event.LOAD_COMPONENT, + this.load + ); + + this.deleteSubscription = this.subscribe( + GameLib.Event.DELETE_COMPONENT, + this.delete + ); + + this.loadImageSubscription = this.subscribe( + GameLib.Event.LOAD_IMAGE, + this.loadImage + ); + + this.loadFontSubscription = this.subscribe( + GameLib.Event.LOAD_FONT, + this.loadFont + ); + + this.blenderDataSubscription = this.subscribe( + GameLib.Event.BLENDER_DATA_RECEIVED, + this.processBlenderData + ); + + this.imageUploadCompleteSubscription = this.subscribe( + GameLib.Event.IMAGE_UPLOAD_COMPLETE, + this.imageUploadComplete + ); + + this.fetchComponentTypesSubscription = this.subscribe( + GameLib.Event.FETCH_COMPONENT_TYPES, + this.fetchComponentTypes + ); + + this.fetchComponentsSubscription = this.subscribe( + GameLib.Event.FETCH_COMPONENTS, + this.fetchComponents + ); + +}; + + +GameLib.System.Storage.prototype.delete = function(data) { + + this.publish( + GameLib.Event.GET_API_URL, + null, + function(urlData) { + + if (typeof XMLHttpRequest === 'undefined') { + console.log('Implement server side delete here'); + return; + } + + data.ids.map(function(id){ + + var xhr = new XMLHttpRequest(); + + xhr.open( + 'POST', + urlData.apiUrl + '/component/delete/' + id + ); + + xhr.setRequestHeader("Accept", "application/json"); + xhr.setRequestHeader("Content-Type", "application/json"); + xhr.setRequestHeader("x-authorization", urlData.passwoid); + + xhr.onreadystatechange = function () { + if (this.readyState === 4) { + try { + var response = JSON.parse(this.responseText) + } catch (error) { + GameLib.Event.Emit( + GameLib.Event.DELETE_COMPONENT_ERROR, + { + message: this.responseText + } + ) + } + + if (response.result === 'success') { + GameLib.Event.Emit( + GameLib.Event.COMPONENT_DELETED, + { + message: response.message || 'Successfully saved the component' + } + ) + } else { + GameLib.Event.Emit( + GameLib.Event.DELETE_COMPONENT_ERROR, + { + message: response.message || 'The server responded but failed to save the component' + } + ) + } + } + }; + + xhr.send(JSON.stringify({ + session : this.token + })); + + }.bind(this)); + }.bind(this), + function(error) { + console.error(error.message); + throw new Error(error.message); + } + ); + + +}; + +/** + * 'Saves' data to somewhere + */ +GameLib.System.Storage.prototype.save = function(data) { + + var event = GameLib.Event.GET_API_URL; + + if (data.remote) { + event = GameLib.Event.GET_REMOTE_API_URL + } + + this.publish( + event, + null, + function(urlData) { + if (typeof XMLHttpRequest === 'undefined') { + console.log('Implement server side save here'); + return; + } + + var xhr = new XMLHttpRequest(); + + xhr.open( + 'POST', + urlData.apiUrl + '/component/create' + ); + + xhr.setRequestHeader("Accept", "application/json"); + xhr.setRequestHeader("Content-Type", "application/json"); + xhr.setRequestHeader("x-authorization", urlData.passwoid); + + xhr.onreadystatechange = function () { + if (this.readyState === 4) { + try { + var response = JSON.parse(this.responseText) + } catch (error) { + GameLib.Event.Emit( + GameLib.Event.SAVE_COMPONENT_ERROR, + { + message: this.responseText, + component : data.apiObject + } + ) + } + + if (response.result === 'success') { + GameLib.Event.Emit( + GameLib.Event.COMPONENT_SAVED, + { + message: response.message || 'Successfully saved the component', + component : data.apiObject + } + ) + } else { + GameLib.Event.Emit( + GameLib.Event.SAVE_COMPONENT_ERROR, + { + message: response.message || 'The server responded but failed to save the component', + component : data.apiObject + } + ) + } + } + }; + + xhr.send(JSON.stringify({ + component : data.apiObject, + session : this.token + })); + } + ); + +}; + +GameLib.System.Storage.prototype.createRuntimeObject = function(responseText, clientErrorCallback) { + + try { + var object = JSON.parse(responseText); + } catch (errorObject) { + + if (this.onComponentError) { + this.onComponentError(errorObject); + } + + if (clientErrorCallback) { + clientErrorCallback({ + message : errorObject.message || 'JSON parse error' + }) + } + + GameLib.Event.Emit( + GameLib.Event.LOAD_COMPONENT_ERROR, + {error: errorObject} + ); + + return null; + } + + if (object.result !== 'success') { + + if (this.onComponentError) { + this.onComponentError(id, object); + } + + if (clientErrorCallback) { + clientErrorCallback({ + message : object.message || 'Server load error' + }) + } + + GameLib.Event.Emit( + GameLib.Event.LOAD_COMPONENT_ERROR, + {error : object} + ); + + return null; + } + + var runtimeComponent = null; + + /** + * Now we need to create the runtime component - this happens systematically. + * First, we create an API object from the Object, then a Runtime object from the API object + * Each component has a function 'FromObject' which essentially does this for you + */ + var component = object.component[0]; + + var componentName = GameLib.Component.GetComponentName(component.componentType); + + var componentClass = eval(componentName); + + var fn = componentClass['FromObject']; + + if (component.componentType === GameLib.Component.COMPONENT_ENTITY) { + + runtimeComponent = fn(component, GameLib.EntityManager.Instance); + + } else { + + try { + + runtimeComponent = fn(component); + + } catch (error) { + + if (this.coder) { + + try { + runtimeComponent = fn(this.coder, component); + } catch (error) { + + } + + } + + if (!runtimeComponent && this.graphics) { + try { + runtimeComponent = fn(this.graphics, component); + } catch (error) { + + } + } + + if (!runtimeComponent && this.physics) { + try { + runtimeComponent = fn(this.physics, component); + } catch (error) { + /** + * ok - we don't cannot create this component + */ + } + } + + } + + if (!runtimeComponent) { + if (clientErrorCallback) { + clientErrorCallback({ + result: 'failure', + message: 'Could not create a runtime component: ' + component.name + }); + } + } + + } + + return runtimeComponent; +}; + +GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, includeDependencies, clientCallback, clientErrorCallback) { + + /** + * We just do an initial check if these components to process are already in the register - + * if so we remove them since we probably want to overwrite them with stale DB versions. + * + * We don't override runtime versions of the dependencies of the loading components - since they could be later. + * But we do override runtime versions of the loading component since the user actually selected them and clicked 'load' + */ + toProcess.map( + function(id) { + + GameLib.Utils.PushUnique(this.loading, id); + + var component = GameLib.EntityManager.Instance.findComponentById(id); + + if (component) { + component.remove(); + } + }.bind(this) + ); + + toProcess.map( + + function(id) { + + var xhr = new XMLHttpRequest(); + + xhr.onload = function(__system) { + + return function () { + + var runtimeComponent = __system.createRuntimeObject.bind(__system)(this.responseText); + + if (!runtimeComponent) { + __system.failed.push(id); + return; + } + + if ( + runtimeComponent.parentEntity && + typeof runtimeComponent.parentEntity === 'string' + ) { + GameLib.EntityManager.Instance.queryComponents(GameLib.Entity).map( + function (entity) { + if (runtimeComponent.parentEntity === entity.id) { + runtimeComponent.parentEntity = entity; + } + } + ); + } + + GameLib.Event.Emit( + GameLib.Event.COMPONENT_CREATED, + { + component: runtimeComponent + } + ); + + __system.loaded.push(runtimeComponent.id); + + if (includeDependencies) { + + /** + * Before we announce the creation of this component, we should get + * a list of all dependencies of this component, because once we announce + * the creation of this component - the linking system will attempt to resolve + * all dependencies + */ + var dependencies = runtimeComponent.getDependencies(); + + __system.otherDependencies.map( + function(id) { + + var index = dependencies.indexOf(id); + + if (index !== -1) { + dependencies.splice(index, 1); + } + } + ); + + dependencies.map( + function(id) { + GameLib.Utils.PushUnique(this.otherDependencies, id); + }.bind(__system) + ); + + /** + * Don't try to download failed components again + */ + dependencies = dependencies.reduce( + function(result, id) { + if (__system.failed.indexOf(id) === -1) { + result.push(id); + } else { + console.log('ignoring failed component : ' + id); + } + return result; + }.bind(__system), + [] + ); + + /** + * Now - we should systematically check if we have the dependency already + * loaded (in our runtime environment) - if we have - we just ignore loading this dependency (for now) + * + * We don't override runtime versions of the same component in the database because the user + * could be working with it and it should be the latest version. + */ + dependencies = dependencies.reduce( + + function (result, dependency) { + + if (GameLib.EntityManager.Instance.findComponentById(dependency)) { + /** + * Don't add the dependency + */ + } else { + result.push(dependency); + } + + return result; + }, + [] + ); + + /** + * Also check if this dependency is not already in our loaded + */ + dependencies = dependencies.reduce( + function (result, dependency) { + + if (__system.loaded.indexOf(dependency) === -1) { + result.push(dependency); + } + + return result; + }, + [] + ); + + /** + * We should now check our 'loading' list and add all dependencies which are not already in there + */ + dependencies.map( + function (dependency) { + GameLib.Utils.PushUnique(__system.loading, dependency); + } + ); + + __system.loadComponent(apiUrl, dependencies, includeDependencies, clientCallback, clientErrorCallback); + + GameLib.Event.Emit( + GameLib.Event.LOAD_PROGRESS, + { + loaded : __system.loaded.length, + toProcess : dependencies.length + } + ); + } + + // GameLib.Event.Emit( + // GameLib.Event.COMPONENT_DOWNLOAD_COMPLETE, + // { + // loaded: __system.loaded + // } + // ); + + if (__system.onComponentLoaded) { + __system.onComponentLoaded(runtimeComponent); + } + + } + + }(this); + + xhr.onprogress = function(__id) { + return function (progressEvent) { + + var progress = 0; + + if (progressEvent.total !== 0) { + progress = Math.round(Number(progressEvent.loaded / progressEvent.total) * 100); + } + + if (this.onComponentProgress) { + this.onComponentProgress(__id, progress) + } + }.bind(this); + }(id); + + xhr.onerror = function(__id) { + return function (error) { + console.warn('component load failed for component ID ' + __id); + + if (this.onComponentError) { + this.onComponentError(__id, error) + } + + if (clientErrorCallback) { + clientErrorCallback({ + message : 'xhr request failure' + }) + } + }.bind(this); + }(id); + + xhr.open( + 'GET', + apiUrl + '/component/load/' + id + ); + + + xhr.send(); + + }.bind(this) + + ); + + +}; + +/** + * 'Loads' data from a url + */ +GameLib.System.Storage.prototype.load = function(data, clientCallback, clientErrorCallback) { + + this.publish( + GameLib.Event.GET_API_URL, + null, + function(urlData) { + if (typeof XMLHttpRequest === 'undefined') { + console.log('Implement server side load here'); + return; + } + + if (data.ids && data.ids.length > 0) { + this.loadComponent( + urlData.apiUrl, + data.ids, + data.includeDependencies, + clientCallback, + clientErrorCallback + ); + } else { + console.log('No components selected'); + } + }.bind(this), + function(error) { + console.error(error.message); + throw new Error(error.message); + } + ); + +}; + +GameLib.System.Storage.prototype.xhrLoad = function( + url, + callback, + errorCallback +) { + + if (typeof XMLHttpRequest === 'undefined') { + console.log('Implement server side load here'); + return; + } + + console.log("Loading...", 'success'); + + var xhr = new XMLHttpRequest(); + xhr.open("GET", url); + xhr.setRequestHeader("Accept", "application/json"); + xhr.setRequestHeader("Content-Type", "application/json"); + + xhr.onreadystatechange = function() { + + if (xhr.readyState === 4) { + + if (!xhr.responseText) { + console.log('Invalid response from server'); + errorCallback({message : 'Invalid response from server'}); + return; + } + + try { + var response = JSON.parse(xhr.responseText); + } catch (error) { + error.message = 'Could not parse JSON'; + errorCallback(error); + } + + if (response.result !== 'success') { + return errorCallback({message : response.message || 'Unknown Error Occurred'}); + } + + callback(response); + } + }; + + + xhr.onerror = errorCallback; + + // TODO: authentication data append + // var object = {}; + // object.session = this.session; + // var string = JSON.stringify(object); + // xhr.send(string); + + xhr.send(); +}; + +/** + * Fetches all component types from the provided API url + * @param data + * @param clientCallback + * @param clientErrorCallback + */ +GameLib.System.Storage.prototype.fetchComponentTypes = function(data, clientCallback, clientErrorCallback) { + this.xhrLoad( + data.url, + function(response) { + clientCallback({ + ids : response.ids + }) + }, + clientErrorCallback + ); +}; + +/** + * Fetches all components with the specified type from the provided API url + * @param data + * @param clientCallback + * @param clientErrorCallback + */ +GameLib.System.Storage.prototype.fetchComponents = function(data, clientCallback, clientErrorCallback) { + this.xhrLoad( + data.url, + function(response) { + clientCallback({ + components : response.component + }) + }, + clientErrorCallback + ); +}; + + +/** + * Once we have an image uploaded - we should load them all again - if their runtime version already exist, do nothing, + * otherwise, create the runtime version of it + * @param data + */ +GameLib.System.Storage.prototype.imageUploadComplete = function(data) { + + var runtimeImages = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Image); + + /** + * Process all images - we have to load them in addition to creating their runtime components + */ + data.images.map(function(imageData){ + + var image = null; + + if (imageData) { + /** + * Overrride this image if possible + * @type {GameLib.D3.Image} + */ + GameLib.D3.Image.FromObject(this.graphics, imageData); + + } else { + image = runtimeImages.reduce( + + function(result, runtimeImage){ + + if (imageData.id === runtimeImage.id) { + result = runtimeImage; + } + + return result; + + }, + null + ); + + image.updateInstance(); + } + + }.bind(this)); +}; + +/** + * Process Blender Data - Basically does what 'load' does - but because we already have the data we don't have + * a complicated load pattern - we create the runtime components in the best order we can (images load async unfortunately) + * and announce their creation so the linking system can link them + * @param data + */ +GameLib.System.Storage.prototype.processBlenderData = function(data) { + + console.log('loading blender data'); + + /** + * Process all images - we have to load them in addition to creating their runtime components + */ + data.images.map(function(imageData){ + var image = GameLib.D3.Image.FromObject(this.graphics, imageData); + GameLib.Event.Emit( + GameLib.Event.COMPONENT_CREATED, + { + component: image + } + ); + + }.bind(this)); + + /** + * Process all textures + */ + data.textures.map(function(textureData){ + var texture = GameLib.D3.Texture.FromObject(this.graphics, textureData); + GameLib.Event.Emit( + GameLib.Event.COMPONENT_CREATED, + { + component: texture + } + ); + }.bind(this)); + + /** + * Process all materials + */ + data.materials.map(function(materialData){ + + var material = GameLib.D3.Material.FromObject(this.graphics, materialData); + + GameLib.Event.Emit( + GameLib.Event.COMPONENT_CREATED, + { + component: material + } + ); + }.bind(this)); + + /** + * Now process all meshes + */ + data.meshes.map(function(meshData){ + var mesh = GameLib.D3.Mesh.FromObject(this.graphics, meshData); + GameLib.Event.Emit( + GameLib.Event.COMPONENT_CREATED, + { + component: mesh + } + ); + }.bind(this)); + + /** + * And that should be it... + */ +}; + +GameLib.System.Storage.prototype.loadFont = function(data) { + + console.log('loading font : ' + data.font.name); + + this.publish( + GameLib.Event.GET_API_URL, + null, + function(urlData) { + + var url = urlData.apiUrl + '/fonts/' + data.font.url + '?ts=' + Date.now(); + + var loader = new THREE.FontLoader(); + + loader.load( + url, + function ( font ) { + + if (GameLib.Utils.IsEmpty(font.data)) { + GameLib.Event.Emit( + GameLib.Event.FONT_NOT_FOUND, + { + font: data.font + } + ); + } else { + data.font.instance = font; + data.font.createInstance(); + } + } + ); + + }.bind(this), + function(error) { + console.error(error.message); + throw new Error(error.message); + } + ); + + +}; + +GameLib.System.Storage.prototype.loadImage = function(data) { + + console.log('loading image : ' + data.image.name); + + this.publish( + GameLib.Event.GET_API_URL, + null, + function(urlData) { + + var onLoaded = this.onImageLoaded; + + var onProgress = this.onImageProgress; + + var onError = this.onImageError; + + var image = data.image; + + var url = urlData.apiUrl + image.path + image.fileName + image.extension + '?ts=' + Date.now(); + + var preflight = new XMLHttpRequest(); + + preflight.withCredentials = true; + + preflight.open( + 'OPTIONS', + url + ); + + preflight.setRequestHeader('Content-Type', 'application/json'); + + preflight.onload = function() { + + var xhr = new XMLHttpRequest(); + + xhr.withCredentials = true; + + xhr.open('GET', url); + + xhr.setRequestHeader('Content-Type', image.contentType); + + xhr.responseType = 'blob'; + + xhr.onload = function() { + + var objectUrl = false; + + var url = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QoWEQMQBXD4hQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAABRSURBVGje7c8xDQAwCAAwmA3koA/PU8FB0jpo1nRc9uI4AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBgX0fjEoBa8xN1z4AAAAASUVORK5CYII='; + + try { + if (this.response.type !== 'application/json') { + url = window.URL.createObjectURL(this.response); + objectUrl = true; + } + } catch (error) { + /** + * Do Nothing + */ + } + + var img = document.createElement('img'); + + img.onload = function () { + + if (objectUrl) { + window.URL.revokeObjectURL(url); + } + + image.instance = img; + + image.createInstance(); + + if (onLoaded) { + onLoaded(image, data.createTexture); + } + }; + + img.src = url; + }; + + xhr.onprogress = function(progressEvent) { + + var progress = 0; + + if (progressEvent.total !== 0) { + progress = Math.round(Number(progressEvent.loaded / progressEvent.total) * 100); + } + + if (onProgress) { + onProgress(image, progress); + } + + image.size = progressEvent.total; + }; + + xhr.onerror = function(error) { + console.warn('image load failed for image ' + image.name); + if (onError) { + onError(image, error) + } + }; + + xhr.send(); + }; + + preflight.onerror = function(error) { + console.warn('image pre-flight request failed for image ' + image.name); + if (onError) { + onError(image, error); + } + }; + + preflight.send(); + }.bind(this), + function(error) { + console.error(error.message); + throw new Error(error.message); + } + ); + + +}; + +GameLib.System.Storage.prototype.stop = function() { + + GameLib.System.prototype.stop.call(this); + + this.loginSubscription.remove(); + this.loadSubscription.remove(); + this.saveSubscription.remove(); + this.loadImageSubscription.remove(); + this.loadFontSubscription.remove(); + this.blenderDataSubscription.remove(); + this.imageUploadCompleteSubscription.remove(); + this.deleteSubscription.remove(); + this.fetchComponentTypesSubscription.remove(); + this.fetchComponentsSubscription.remove(); +}; + + +/** + * System takes care of updating all the entities (based on their component data) + * Visualization System takes care of visualizing all objects which are not meshes (like physics data) + * + * @param apiSystem GameLib.API.System + * @param graphics + * @param physics + * @constructor + */ +GameLib.System.Visualization = function( + apiSystem, + graphics, + physics +) { + + GameLib.System.call( + this, + apiSystem + ); + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + this.physics = physics; + this.physics.isNotCannonThrow(); + + this.visualizationSubscription = null; + this.stopVisualizationSubscription = null; + +}; + +GameLib.System.Visualization.prototype = Object.create(GameLib.System.prototype); +GameLib.System.Visualization.prototype.constructor = GameLib.System.Visualization; + +GameLib.System.Visualization.prototype.start = function() { + + GameLib.System.prototype.start.call(this); + + this.visualizationSubscription = this.subscribe( + GameLib.Event.VISUALIZE, + this.visualize + ); + + this.stopVisualizationSubscription = this.subscribe( + GameLib.Event.STOP_VISUALIZE, + this.stopVisualize + ) +}; + + +GameLib.System.Visualization.prototype.visualize = function(data) { + + var shape = data.shape; + + var parentMesh = shape.parentMesh; + + shape.setFromMesh(); + + var apiMesh = new GameLib.D3.API.Mesh(); + + apiMesh.name = 'Visualization Mesh for Shape ' + shape.name; + + if (shape instanceof GameLib.D3.Shape.HeightMap) { + var v0 = new CANNON.Vec3(); + var v1 = new CANNON.Vec3(); + var v2 = new CANNON.Vec3(); + for (var xi = 0; xi < shape.heightData.length - 1; xi++) { + for (var yi = 0; yi < shape.heightData[xi].length - 1; yi++) { + for (var k = 0; k < 2; k++) { + shape.instance.getConvexTrianglePillar(xi, yi, k===0); + v0.copy(shape.instance.pillarConvex.vertices[0]); + v1.copy(shape.instance.pillarConvex.vertices[1]); + v2.copy(shape.instance.pillarConvex.vertices[2]); + v0.vadd(shape.instance.pillarOffset, v0); + v1.vadd(shape.instance.pillarOffset, v1); + v2.vadd(shape.instance.pillarOffset, v2); + apiMesh.vertices.push( + new GameLib.D3.API.Vertex( + new GameLib.API.Vector3(v0.x, v0.y, v0.z) + ), + new GameLib.D3.API.Vertex( + new GameLib.API.Vector3(v1.x, v1.y, v1.z) + ), + new GameLib.D3.API.Vertex( + new GameLib.API.Vector3(v2.x, v2.y, v2.z) + ) + ); + var i = apiMesh.vertices.length - 3; + apiMesh.faces.push( + new GameLib.D3.API.Face( + null, + null, + i, + i+1, + i+2 + ) + ); + } + } + } + } + + new GameLib.D3.Mesh( + this.graphics, + apiMesh + ); + +}; + +GameLib.System.Visualization.prototype.stopVisualize = function(data) { +}; + +GameLib.System.Visualization.prototype.stop = function() { + + GameLib.System.prototype.stop.call(this); + + if (this.visualizationSubscription) { + this.visualizationSubscription.remove(); + } + + if (this.stopVisualizationSubscription) { + this.stopVisualizationSubscription.remove(); + } + +}; + + +/** + * Runtime vector2 for updating instance objects + * @param graphics GameLib.D3.Graphics + * @param parentObject GameLib.D3.* + * @param apiVector2 GameLib.API.Vector2 + * @param grain Number + * @constructor + */ +GameLib.Vector2 = function ( + graphics, + apiVector2, + parentObject, + grain +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiVector2)) { + apiVector2 = {}; + apiVector2 = {}; + } + + if (apiVector2 instanceof GameLib.Vector2) { + return apiVector2; + } + + GameLib.API.Vector2.call( + this, + apiVector2.x, + apiVector2.y + ); + + if (GameLib.Utils.UndefinedOrNull(parentObject)) { + parentObject = null; + } + this.parentObject = parentObject; + + if (GameLib.Utils.UndefinedOrNull(grain)) { + grain = 0.001; + } + this.grain = grain; + + this.createInstance(); +}; + +GameLib.Vector2.prototype = Object.create(GameLib.API.Vector2.prototype); +GameLib.Vector2.prototype.constructor = GameLib.Vector2; + + +/** + * Creates an instance vector2 + * @returns {*} + */ +GameLib.Vector2.prototype.createInstance = function() { + this.instance = new THREE.Vector2(this.x, this.y); +}; + +/** + * Updates the instance vector, calls updateInstance on the parent object + */ +GameLib.Vector2.prototype.updateInstance = function(property) { + + this.instance.x = this.x; + this.instance.y = this.y; + + if (this.parentObject && + this.parentObject.updateInstance) { + this.parentObject.updateInstance(property); + } +}; + +/** + * Converts runtime vector to API Vector + * @returns {GameLib.API.Vector2} + */ +GameLib.Vector2.prototype.toApiObject = function() { + return new GameLib.API.Vector2( + this.x, + this.y + ); +}; + +/** + * Copy + * TODO: Test + * @param v optional + * @returns {GameLib.Vector2} + */ +GameLib.Vector2.prototype.copy = function (v) { + + if (GameLib.Utils.UndefinedOrNull(v)) { + + return new GameLib.Vector2( + this.graphics, + new GameLib.API.Vector2( + this.x, + this.y + ), + this.parentObject, + this.grain + ); + + } else { + + this.x = v.x; + this.y = v.y; + + return this; + } +}; + +/** + * Equals + * TODO: Test + * @param v + * @returns {boolean} + */ +GameLib.Vector2.prototype.equals = function(v) { + + if ((this.x == v.x) && + (this.y == v.y)) { + return true; + } else { + return false; + } + +}; + +/** + * Add + * TODO: Test + * @param v + */ +GameLib.Vector2.prototype.add = function(v) { + + if ( + v instanceof GameLib.API.Vector2 || + v instanceof GameLib.API.Vector3 || + v instanceof GameLib.API.Vector4 || + v instanceof GameLib.API.Quaternion + ) { + this.x += v.x; + this.y += v.y; + } else { + console.warn('Could not add Vector2'); + throw new Error('Could not add Vector2'); + } + +}; + +/** + * Subtract + * TODO: Test + * @param v + */ +GameLib.Vector2.prototype.subtract = function(v) { + + if ( + v instanceof GameLib.API.Vector2 || + v instanceof GameLib.API.Vector3 || + v instanceof GameLib.API.Vector4 || + v instanceof GameLib.API.Quaternion + ) { + this.x -= v.x; + this.y -= v.y; + } else { + console.warn('Could not subtract Vector2'); + throw new Error('Could not subtract Vector2'); + } + +}; + +/** + * Multiply + * TODO: Test + * @param v + */ +GameLib.Vector2.prototype.multiply = function(v) { + + if ( + v instanceof GameLib.API.Vector2 || + v instanceof GameLib.API.Vector3 || + v instanceof GameLib.API.Vector4 || + v instanceof GameLib.API.Quaternion + ) { + this.x *= v.x; + this.y *= v.y; + } else if (typeof v == 'number') { + this.x *= v; + this.y *= v; + } else { + console.warn('Could not multiply Vector2'); + throw new Error('Could not multiply Vector2'); + } + +}; + +/** + * Divide + * TODO: Test + * @param v + */ +GameLib.Vector2.prototype.divide = function(v) { + + if ( + v instanceof GameLib.API.Vector2 || + v instanceof GameLib.API.Vector3 || + v instanceof GameLib.API.Vector4 || + v instanceof GameLib.API.Quaternion + ) { + this.x *= (1.0 / v.x); + this.y *= (1.0 / v.y); + } else if (typeof v == 'number') { + this.x *= 1.0 / v; + this.y *= 1.0 / v; + } else { + console.warn('Could not divide Vector2'); + throw new Error('Could not divide Vector2'); + } + +}; + +/** + * Clamp + * TODO: Test + * @param min GameLib.API.Vector2 + * @param max GameLib.API.Vector2 + * @returns {GameLib.Vector2} + */ +GameLib.Vector2.prototype.clamp = function(min, max) { + + this.x = Math.max(min.x, Math.min(max.x, this.x)); + this.y = Math.max(min.y, Math.min(max.y, this.y)); + + return this; + +}; + +/** + * Length + * TODO: Test + * @returns {number} + */ +GameLib.Vector2.prototype.length = function() { + return Math.sqrt( + this.x * this.x + this.y * this.y + ); +}; + +/** + * Dot product + * TODO: Test + * @param v + * @returns {number} + */ +GameLib.Vector2.prototype.dot = function(v) { + return this.x * v.x + this.y * v.y; +}; + +/** + * Normalize + * TODO: Test + */ +GameLib.Vector2.prototype.normalize = function() { + return this.multiply(1.0 / this.length()); +}; + +/** + * TODO: Test + * Angle between this vector and origin + * @returns {number} + */ +GameLib.Vector2.prototype.angle = function() { + var angle = Math.atan2(this.y, this.x); + if ( angle < 0 ) angle += 2 * Math.PI; + return angle; +}; + +/** + * Interpolate to v from here + * TODO: Test + * @param v + * @param alpha + * @returns {GameLib.Vector2} + */ +GameLib.Vector2.prototype.lerp = function ( v, alpha ) { + return new GameLib.Vector2( + this.x + ( v.x - this.x ) * alpha, + this.y + ( v.y - this.y ) * alpha + ); +}; +/** + * Runtime apiVector3 for updating instance objects + * @param implementation GameLib.D3.Graphics + * @param apiVector3 GameLib.API.Vector3 + * @param parentObject GameLib.* + * @param grain Number + * @constructor + */ +GameLib.Vector3 = function ( + implementation, + apiVector3, + parentObject, + grain +) { + + this.implementation = implementation; + + if (implementation instanceof GameLib.D3.Graphics) { + this.physics = null; + this.graphics = implementation; + this.graphics.isNotThreeThrow(); + } else if (implementation instanceof GameLib.D3.Physics) { + this.graphics = null; + this.physics = implementation; + this.physics.isNotCannonThrow(); + } else { + throw new Error('Unhandled implementation : ' + implementation); + } + + if (GameLib.Utils.UndefinedOrNull(apiVector3)) { + apiVector3 = {}; + } + + if (apiVector3 instanceof GameLib.Vector3) { + return apiVector3; + } + + GameLib.API.Vector3.call( + this, + apiVector3.x, + apiVector3.y, + apiVector3.z + ); + + if (GameLib.Utils.UndefinedOrNull(parentObject)) { + parentObject = this; + } + this.parentObject = parentObject; + + if (GameLib.Utils.UndefinedOrNull(grain)) { + grain = 0.001; + } + this.grain = grain; + + this.createInstance(); +}; + +GameLib.Vector3.prototype = Object.create(GameLib.API.Vector3.prototype); +GameLib.Vector3.prototype.constructor = GameLib.Vector3; + +/** + * Creates an instance vector3 + * @returns {*} + */ +GameLib.Vector3.prototype.createInstance = function() { + + if (this.graphics) { + this.instance = new THREE.Vector3( + this.x, + this.y, + this.z + ); + } else if (this.physics) { + this.instance = new CANNON.Vec3( + this.x, + this.y, + this.z + ) + } + +}; + +/** + * Updates the instance vector, calls updateInstance on the parent object + */ +GameLib.Vector3.prototype.updateInstance = function(property, preventParentUpdate) { + + this.instance.x = this.x; + this.instance.y = this.y; + this.instance.z = this.z; + + if (!preventParentUpdate && + this.parentObject && + this.parentObject !== this && + this.parentObject.updateInstance) { + this.parentObject.updateInstance(property); + } +}; + +/** + * Converts runtime vector to API Vector + */ +GameLib.Vector3.prototype.toApiObject = function() { + return new GameLib.API.Vector3( + this.x, + this.y, + this.z + ); +}; + +/** + * Creates a new copy of this Vector3 + */ +GameLib.Vector3.prototype.copy = function() { + return new GameLib.Vector3( + this.implementation, + new GameLib.API.Vector3( + this.x, + this.y, + this.z + ), + this.parentObject, + this.grain + ) +}; + +GameLib.Vector3.prototype.clone = function() { + return new GameLib.Vector3( + this.implementation, + new GameLib.API.Vector3( + this.x, + this.y, + this.z + ), + this.parentObject, + this.grain + ) +}; + +/** + * Create a negative version of this vector + * @returns {GameLib.Vector3} + */ +GameLib.Vector3.prototype.negativeCopy = function() { + return new GameLib.Vector3( + this.implementation, + new GameLib.API.Vector3( + -this.x, + -this.y, + -this.z + ), + this.parentObject, + this.grain + ) +}; + +/** + * Applies rotation specified by axis / angle to this vector - its a wrapper for three.. + * @param axis + * @param angle + */ +GameLib.Vector3.prototype.applyAxisAngle = function(axis, angle) { + + this.instance.applyAxisAngle( + new THREE.Vector3( + axis.x, + axis.y, + axis.z + ), + angle + ); + + this.x = this.instance.x; + this.y = this.instance.y; + this.z = this.instance.z; +}; + +GameLib.Vector3.prototype.setFrom = function(vector3) { + this.x = vector3.x; + this.y = vector3.y; + this.z = vector3.z; +}; + +/** + * Runtime apiVector4 for updating instance objects + * @param graphics GameLib.D3.Graphics + * @param apiVector4 GameLib.API.Vector4 + * @param parentObject GameLib.* + * @param grain Number + * @constructor + */ +GameLib.Vector4 = function ( + graphics, + apiVector4, + parentObject, + grain +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiVector4)) { + apiVector4 = {}; + } + + if (apiVector4 instanceof GameLib.Vector4) { + return apiVector4; + } + + GameLib.API.Vector4.call( + this, + apiVector4.x, + apiVector4.y, + apiVector4.z, + apiVector4.w + ); + + if (GameLib.Utils.UndefinedOrNull(parentObject)) { + parentObject = null; + } + this.parentObject = parentObject; + + if (GameLib.Utils.UndefinedOrNull(grain)) { + grain = 0.001; + } + this.grain = grain; + + this.createInstance(); +}; + +GameLib.Vector4.prototype = Object.create(GameLib.API.Vector4.prototype); +GameLib.Vector4.prototype.constructor = GameLib.Vector4; + +/** + * Creates an instance vector4 + * @returns {*} + */ +GameLib.Vector4.prototype.createInstance = function() { + this.instance = new THREE.Quaternion( + this.x, + this.y, + this.z, + this.w + ); +}; + +/** + * Updates the instance vector, calls updateInstance on the parent object + */ +GameLib.Vector4.prototype.updateInstance = function(property) { + + this.instance.x = this.x; + this.instance.y = this.y; + this.instance.z = this.z; + this.instance.w = this.w; + + if (this.parentObject && + this.parentObject.updateInstance) { + this.parentObject.updateInstance(property); + } +}; + +/** + * Converts runtime vector to API Vector + */ +GameLib.Vector4.prototype.toApiObject = function() { + return new GameLib.API.Vector4( + this.x, + this.y, + this.z, + this.w + ); +}; + + +GameLib.EntityManager.Instance = new GameLib.EntityManager(); + +if (typeof module !== 'undefined') { + module.exports = GameLib; +} +//EXTENDING INTERFACES (Generated via gulp) +//END EXTENDING