if (typeof require != 'undefined') { var Maths3D = require('./game-lib-maths.js'); } if (typeof require != 'undefined') { var Controls = require('./game-lib-controls.js'); } function GameLib() {} /** * GameLib.D3 connects our GameLib.D3 assets to a graphics library like THREE.js, but could technically be any graphics * lib * @param config * @param Q Q * @param THREE THREE.js * @param apiUrl * @param editorUrl * @constructor */ GameLib.D3 = function( config, Q, THREE, apiUrl, editorUrl ){ this.config = config; this.Q = Q; this.THREE = THREE; this.textureLoader = new this.THREE.TextureLoader(); this.apiUrl = apiUrl || this.config.api16.url; this.editorUrl = editorUrl || this.config.editor.url; }; if (typeof require == 'undefined' && typeof Maths3D == 'undefined') { console.warn("You need a proper Maths3D library in order to use this library"); } if (typeof require == 'undefined' && typeof Controls == 'undefined') { console.warn("You need a proper Control library in order to use this library"); } GameLib.D3.Controls = Controls; GameLib.D3.Vector2 = Maths3D.Vector2; GameLib.D3.Vector3 = Maths3D.Vector3; GameLib.D3.Vector4 = Maths3D.Vector4; GameLib.D3.Matrix4 = Maths3D.Matrix4; GameLib.D3.Color = Maths3D.Color; /** * Texture Superset * @param id * @param path * @param name * @param image * @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 * @constructor */ GameLib.D3.Texture = function( id, path, name, image, wrapS, wrapT, repeat, data, format, mapping, magFilter, minFilter, textureType, anisotropy, offset, generateMipmaps, flipY, mipmaps, unpackAlignment, premultiplyAlpha, encoding ) { this.id = id; this.path = path; this.name = name; this.image = image; if (typeof wrapS == 'undefined') { wrapS = GameLib.D3.Texture.TYPE_REPEAT_WRAPPING; } this.wrapS = wrapS; if (typeof wrapT == 'undefined') { wrapT = GameLib.D3.Texture.TYPE_REPEAT_WRAPPING; } this.wrapT = wrapT; if (typeof repeat == 'undefined') { repeat = new GameLib.D3.Vector2(1, 1); } this.repeat = repeat; if (typeof data == 'undefined') { data = null; } this.data = data; if (typeof format == 'undefined') { format = GameLib.D3.Texture.TYPE_RGBA_FORMAT; } this.format = format; if (typeof mapping == 'undefined') { mapping = GameLib.D3.Texture.TYPE_UV_MAPPING; } this.mapping = mapping; if (typeof magFilter == 'undefined') { magFilter = GameLib.D3.Texture.TYPE_LINEAR_FILTER; } this.magFilter = magFilter; if (typeof minFilter == 'undefined') { minFilter = GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER; } this.minFilter = minFilter; if (typeof textureType == 'undefined') { textureType = GameLib.D3.Texture.TYPE_UNSIGNED_BYTE; } this.textureType = textureType; if (typeof anisotropy == 'undefined') { anisotropy = 1; } this.anisotropy = anisotropy; if (typeof offset == 'undefined') { offset = new GameLib.D3.Vector2(0, 0); } this.offset = offset; if (typeof generateMipmaps == 'undefined') { generateMipmaps = true; } this.generateMipmaps = generateMipmaps; if (typeof flipY == 'undefined') { flipY = true; } this.flipY = flipY; if (typeof mipmaps == 'undefined') { mipmaps = []; } this.mipmaps = mipmaps; if (typeof unpackAlignment == 'undefined') { unpackAlignment = 4; } this.unpackAlignment = unpackAlignment; if (typeof premultiplyAlpha == 'undefined') { premultiplyAlpha = false; } this.premultiplyAlpha = premultiplyAlpha; if (typeof encoding == 'undefined') { encoding = GameLib.D3.Texture.TYPE_LINEAR_ENCODING; } this.encoding = encoding; }; /** * 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. /** * Light Superset * @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 * @constructor */ GameLib.D3.Light = function( id, lightType, name, color, intensity, position, targetPosition, quaternion, rotation, scale, distance, decay, power, angle, penumbra ) { this.id = id; this.lightType = lightType; this.name = name; this.color = color; this.intensity = intensity; if (typeof position == 'undefined') { position = new GameLib.D3.Vector3(0,0,0); } this.position = position; if (typeof targetPosition == 'undefined') { targetPosition = new GameLib.D3.Vector3(0,0,0); } this.targetPosition = targetPosition; if (typeof quaternion == 'undefined'){ quaternion = new GameLib.D3.Vector4(); } this.quaternion = quaternion; if (typeof rotation == 'undefined'){ rotation = new GameLib.D3.Vector3(0,0,0); } this.rotation = rotation; if (typeof scale == 'undefined'){ scale = new GameLib.D3.Vector3(1,1,1); } this.scale = scale; if (typeof distance == 'undefined'){ distance = 0; } this.distance = distance; if (typeof decay == 'undefined'){ decay = 1; } this.decay = decay; if (typeof power == 'undefined'){ power = 4 * Math.PI; } this.power = power; if (typeof angle == 'undefined'){ angle = Math.PI / 3; } this.angle = angle; if (typeof penumbra == 'undefined'){ penumbra = 0; } this.penumbra = penumbra; }; /** * Material Superset * @param id * @param path * @param name * @param materialType * @param opacity * @param side * @param transparent * @param maps * @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 shading * @param bumpScale * @param normalScale * @param displacementScale * @param displacementBias * @param roughness * @param metalness * @param pointSize * @param pointSizeAttenuation * @param spriteRotation * @param envMapIntensity * @constructor */ GameLib.D3.Material = function( id, path, name, materialType, opacity, side, transparent, maps, 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, shading, bumpScale, normalScale, displacementScale, displacementBias, roughness, metalness, pointSize, pointSizeAttenuation, spriteRotation, envMapIntensity ) { this.id = id; this.path = path; this.name = name; if (typeof materialType == 'undefined') { materialType = GameLib.D3.Material.TYPE_MESH_STANDARD; } this.materialType = materialType; if (typeof opacity == 'undefined') { opacity = 1.0; } this.opacity = opacity; if (typeof side == 'undefined') { side = GameLib.D3.Material.TYPE_FRONT_SIDE; } this.side = side; if (typeof transparent == 'undefined') { transparent = false; } this.transparent = transparent; if (typeof maps == 'undefined') { maps = { alpha: null, ao: null, bump: null, diffuse: null, displacement: null, emissive: null, environment: null, light: null, metalness: null, normal: null, roughness: null, specular: null }; } this.maps = maps; if (typeof specular == 'undefined') { specular = new GameLib.D3.Color(0.06, 0.06, 0.06, 0.06); } this.specular = specular; if (typeof lightMapIntensity == 'undefined') { lightMapIntensity = 1; } this.lightMapIntensity = lightMapIntensity; if (typeof aoMapIntensity == 'undefined') { aoMapIntensity = 1; } this.aoMapIntensity = aoMapIntensity; if (typeof color == 'undefined') { color = new GameLib.D3.Color(1, 1, 1, 1) } this.color = color; if (typeof emissive == 'undefined') { emissive = new GameLib.D3.Color(0, 0, 0, 0); } this.emissive = emissive; if (typeof emissiveIntensity == 'undefined') { emissiveIntensity = 1; } this.emissiveIntensity = emissiveIntensity; if (typeof combine == 'undefined') { combine = GameLib.D3.Material.TYPE_MULTIPLY_OPERATION; } this.combine = combine; if (typeof shininess == 'undefined') { shininess = 30; } this.shininess = shininess; if (typeof reflectivity == 'undefined') { reflectivity = 1; } this.reflectivity = reflectivity; if (typeof refractionRatio == 'undefined') { refractionRatio = 0.98; } this.refractionRatio = refractionRatio; if (typeof fog == 'undefined') { fog = true; } this.fog = fog; if (typeof wireframe == 'undefined') { wireframe = false; } this.wireframe = wireframe; if (typeof wireframeLineWidth == 'undefined') { wireframeLineWidth = 1; } this.wireframeLineWidth = wireframeLineWidth; if (typeof wireframeLineCap == 'undefined') { wireframeLineCap = 'round'; } this.wireframeLineCap = wireframeLineCap; if (typeof wireframeLineJoin == 'undefined') { wireframeLineJoin = 'round'; } this.wireframeLineJoin = wireframeLineJoin; if (typeof vertexColors == 'undefined') { vertexColors = GameLib.D3.Material.TYPE_NO_COLORS; } this.vertexColors = vertexColors; if (typeof skinning == 'undefined') { skinning = false; } this.skinning = skinning; if (typeof morphTargets == 'undefined') { morphTargets = false; } this.morphTargets = morphTargets; if (typeof morphNormals == 'undefined') { morphNormals = false; } this.morphNormals = morphNormals; if (typeof overdraw == 'undefined') { overdraw = 0; } this.overdraw = overdraw; if (typeof lineWidth == 'undefined') { lineWidth = 1; } this.lineWidth = lineWidth; if (typeof lineCap == 'undefined') { lineCap = 'round'; } this.lineCap = lineCap; if (typeof lineJoin == 'undefined') { lineJoin = 'round'; } this.lineJoin = lineJoin; if (typeof dashSize == 'undefined') { dashSize = 3; } this.dashSize = dashSize; if (typeof gapWidth == 'undefined') { gapWidth = 1; } this.gapWidth = gapWidth; if (typeof blending == 'undefined') { blending = GameLib.D3.Material.TYPE_NORMAL_BLENDING; } this.blending = blending; if (typeof blendSrc == 'undefined') { blendSrc = GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR; } this.blendSrc = blendSrc; if (typeof blendDst == 'undefined') { blendDst = GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR; } this.blendDst = blendDst; if (typeof blendEquation == 'undefined') { blendEquation = GameLib.D3.Material.TYPE_ADD_EQUATION; } this.blendEquation = blendEquation; if (typeof depthTest == 'undefined') { depthTest = true; } this.depthTest = depthTest; if (typeof depthFunc == 'undefined') { depthFunc = GameLib.D3.Material.TYPE_LESS_EQUAL_DEPTH; } this.depthFunc = depthFunc; if (typeof depthWrite == 'undefined') { depthWrite = true; } this.depthWrite = depthWrite; if (typeof polygonOffset == 'undefined') { polygonOffset = false; } this.polygonOffset = polygonOffset; if (typeof polygonOffsetFactor == 'undefined') { polygonOffsetFactor = 1; } this.polygonOffsetFactor = polygonOffsetFactor; if (typeof polygonOffsetUnits == 'undefined') { polygonOffsetUnits = 1; } this.polygonOffsetUnits = polygonOffsetUnits; if (typeof alphaTest == 'undefined') { alphaTest = 0; } this.alphaTest = alphaTest; if (typeof clippingPlanes == 'undefined') { clippingPlanes = []; } this.clippingPlanes = clippingPlanes; if (typeof clipShadows == 'undefined') { clipShadows = false; } this.clipShadows = clipShadows; if (typeof visible == 'undefined') { visible = true; } this.visible = visible; if (typeof shading == 'undefined') { shading = GameLib.D3.Material.TYPE_FLAT_SHADING; } this.shading = shading; if (typeof bumpScale == 'undefined') { bumpScale = 1; } this.bumpScale = bumpScale; if (typeof normalScale == 'undefined') { normalScale = 1; } this.normalScale = normalScale; if (typeof displacementScale == 'undefined') { displacementScale = 1; } this.displacementScale = displacementScale; if (typeof displacementBias == 'undefined') { displacementBias = 0; } this.displacementBias = displacementBias; if (typeof roughness == 'undefined') { roughness = 0.5; } this.roughness = roughness; if (typeof metalness == 'undefined') { metalness = 0.5; } this.metalness = metalness; if (typeof pointSize == 'undefined') { pointSize = 1; } this.pointSize = pointSize; if (typeof pointSizeAttenuation == 'undefined') { pointSizeAttenuation = true; } this.pointSizeAttenuation = pointSizeAttenuation; if (typeof spriteRotation == 'undefined') { spriteRotation = 0; } this.spriteRotation = spriteRotation; if (typeof envMapIntensity == 'undefined') { envMapIntensity = 1.0; } this.envMapIntensity = envMapIntensity; }; /** * 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_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.TYPE_LINE_BASIC = "LineBasicMaterial"; GameLib.D3.Material.TYPE_LINE_DASHED = "LineDashedMaterial"; GameLib.D3.Material.TYPE_MESH_BASIC = "MeshBasicMaterial"; GameLib.D3.Material.TYPE_MESH_DEPTH = "MeshDepthMaterial"; GameLib.D3.Material.TYPE_MESH_LAMBERT = "MeshLambertMaterial"; GameLib.D3.Material.TYPE_MESH_NORMAL = "MeshNormalMaterial"; GameLib.D3.Material.TYPE_MESH_PHONG = "MeshPhongMaterial"; GameLib.D3.Material.TYPE_MESH_STANDARD = "MeshStandardMaterial"; GameLib.D3.Material.TYPE_POINTS = "PointsMaterial"; GameLib.D3.Material.TYPE_SPRITE = "SpriteMaterial"; GameLib.D3.Material.TYPE_MULTI_MATERIAL= "MultiMaterial"; /** * Skeleton Superset * @param id * @param bones GameLib.D3.Bone * @param boneInverses * @param useVertexTexture * @param boneTextureWidth * @param boneTextureHeight * @param boneMatrices * @param boneTexture * @constructor */ GameLib.D3.Skeleton = function( id, bones, boneInverses, useVertexTexture, boneTextureWidth, boneTextureHeight, boneMatrices, boneTexture ) { this.id = id; this.bones = bones; /** * An array of Matrix4s that represent the inverse of the matrixWorld of the individual bones. * @type GameLib.D3.Matrix4[] */ if (typeof boneInverses == 'undefined') { boneInverses = []; } this.boneInverses = boneInverses; /** * Use a vertex texture in the shader - allows for more than 4 bones per vertex, not supported by all devices * @type {boolean} */ if (typeof useVertexTexture == 'undefined') { useVertexTexture = false; } this.useVertexTexture = useVertexTexture; if (this.useVertexTexture == true) { console.warn('support for vertex texture bones is not supported yet - something could break somewhere'); } if (typeof boneTextureWidth == 'undefined') { boneTextureWidth = 0; } this.boneTextureWidth = boneTextureWidth; if (typeof boneTextureHeight == 'undefined') { boneTextureHeight = 0; } this.boneTextureHeight = boneTextureHeight; if (typeof boneMatrices == 'undefined') { boneMatrices = []; } this.boneMatrices = boneMatrices; if (typeof boneTexture == 'undefined') { boneTexture = []; } this.boneTexture = boneTexture; }; /** * Mesh Superset * @param id * @param path * @param name * @param meshType * @param vertices * @param faces * @param skeleton * @param faceVertexUvs * @param skinIndices * @param skinWeights * @param materials * @param position * @param quaternion * @param rotation * @param scale * @param up * @param physics * @param parentMeshId * @param parentSceneId * @param rawData * @constructor */ GameLib.D3.Mesh = function( id, path, name, meshType, vertices, faces, skeleton, faceVertexUvs, skinIndices, skinWeights, materials, position, quaternion, rotation, scale, up, physics, parentMeshId, parentSceneId, rawData ) { this.id = id; this.path = path; this.name = name; this.meshType = meshType; this.vertices = vertices; this.faces = faces; if (typeof skeleton == 'undefined') { skeleton = null; } this.skeleton = skeleton; if (typeof faceVertexUvs == 'undefined') { faceVertexUvs = []; } this.faceVertexUvs = faceVertexUvs; if (typeof skinIndices == 'undefined') { skinIndices = []; } this.skinIndices = skinIndices; if (typeof skinWeights == 'undefined') { skinWeights = []; } this.skinWeights = skinWeights; if (typeof materials == 'undefined') { materials = []; } this.materials = materials; if (typeof position == 'undefined') { position = new GameLib.D3.Vector3(0,0,0); } this.position = position; if (typeof quaternion == 'undefined') { new GameLib.D3.Vector4(); } this.quaternion = quaternion; if (typeof rotation == 'undefined') { rotation = new GameLib.D3.Vector3(0,0,0); } this.rotation = rotation; if (typeof scale == 'undefined') { scale = new GameLib.D3.Vector3(1,1,1); } this.scale = scale; if (typeof up == 'undefined') { up = new GameLib.D3.Vector3(0,1,0); } this.up = up; this.physics = physics; this.parentMeshId = parentMeshId; this.parentSceneId = parentSceneId; this.rawData = null;// rawData; }; /** * Mesh Type * @type {number} */ GameLib.D3.Mesh.TYPE_NORMAL = 0; GameLib.D3.Mesh.TYPE_SKINNED = 1; /** * Bone Superset * @param id * @param name string * @param boneId * @param childBoneIds * @param parentBoneId * @param quaternion * @param position * @param rotation * @param scale GameLib.D3.Vector3 * @param up * @param rawData * @constructor */ GameLib.D3.Bone = function( id, boneId, name, childBoneIds, parentBoneId, quaternion, position, rotation, scale, up, rawData ) { this.id = id; this.name = name; this.boneId = boneId; if (typeof childBoneIds == 'undefined') { childBoneIds = []; } this.childBoneIds = childBoneIds; if (typeof parentBoneId == 'undefined') { parentBoneId = null; } this.parentBoneId = parentBoneId; if (typeof quaternion == 'undefined') { quaternion = new GameLib.D3.Vector4(); } this.quaternion = quaternion; if (typeof position == 'undefined') { position = new GameLib.D3.Vector3(0,0,0); } this.position = position; if (typeof rotation == 'undefined') { rotation = new GameLib.D3.Vector3(0,0,0); } this.rotation = rotation; if (typeof scale == 'undefined') { scale = new GameLib.D3.Vector3(1,1,1); } this.scale = scale; if (typeof up == 'undefined') { up = new GameLib.D3.Vector3(0,1,0); } this.up = up; this.rawData = null;//rawData; }; GameLib.D3.Physics = function() {}; /** * Physics Engine Superset * @param id * @param name * @param engineType * @param engine * @constructor */ GameLib.D3.Physics.Engine = function( id, name, engineType, engine ) { this.id = id; this.name = name; this.engineType = engineType; this.engine = engine; }; /** * Physics Engine Types * @type {number} */ GameLib.D3.Physics.Engine.TYPE_CANNON = 0x1; GameLib.D3.Physics.Engine.TYPE_AMMO = 0x2; GameLib.D3.Physics.Engine.TYPE_GOBLIN = 0x3; /** * Physics World Superset * @param id * @param name * @param gravity * @param rigidBodies GameLib.D3.Physics.RigidBody[] * @param engine GameLib.D3.Physics.Engine * @constructor */ GameLib.D3.Physics.World = function( id, name, engine, gravity, rigidBodies ) { this.id = id; this.name = name; this.engine = engine; if (typeof gravity == 'undefined'){ gravity = 9.8; } this.gravity = gravity; if (typeof rigidBodies == 'undefined'){ rigidBodies = []; } this.rigidBodies = rigidBodies; }; /** * Physics Rigid Body Superset * @param id * @param name * @param position * @param rotation * @param scale * @param shapes GameLib.D3.Physics.Shape[] * @constructor */ GameLib.D3.Physics.RigidBody = function( id, name, position, rotation, scale, shapes ) { this.position = new this.Vector3(0,0,0); }; /** * Physics Rigid Body Vehicle Superset * @constructor */ GameLib.D3.Physics.RigidBody.Vehicle = function() { }; /** * Physics Shape Superset * @constructor */ GameLib.D3.Physics.Shape = function() {}; /** * Physics Convex Hull Shape Superset * @param id * @param name * @constructor */ GameLib.D3.Physics.Shape.ConvexHull = function( id, name ) { this.id = id; this.name = name; }; /** * Physics Triangle Mesh Shape Superset * @param id * @param name * @constructor */ GameLib.D3.Physics.Shape.TriangleMesh = function( id, name ) { this.id = id; this.name = name; }; /** * TriangleFace * @param v0 * @param v1 * @param v2 * @param materialIndex * @param v0uv * @param v1uv * @param v2uv * @param color * @param vertexColors * @param vertexNormals * @param normal * @constructor */ GameLib.D3.TriangleFace = function( v0, v1, v2, materialIndex, v0uv, v1uv, v2uv, color, vertexColors, vertexNormals, normal ) { this.v0 = v0; this.v1 = v1; this.v2 = v2; this.materialIndex = materialIndex; this.v0uv = v0uv; this.v1uv = v1uv; this.v2uv = v2uv; if (!color) { color = new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff); } this.color = color; if (!vertexColors) { vertexColors = [ new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff), new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff), new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff) ]; } this.vertexColors = vertexColors; if (!vertexNormals) { vertexNormals = [ new GameLib.D3.Vector3(), new GameLib.D3.Vector3(), new GameLib.D3.Vector3() ] } this.vertexNormals = vertexNormals; if (!normal) { normal = new GameLib.D3.Vector3(0); } this.normal = normal; }; /** * TriangleEdge * @param triangle * @param edge * @constructor */ GameLib.D3.TriangleEdge = function( triangle, edge ) { this.triangle = triangle; this.edge = edge; }; /** * Contains a Poly vertex data structure * @param localIndex * @param mvertIndex * @param uv GameLib.D3.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; }; /** * BoneWeight object - associates a vertex to a bone with some weight * @param boneIndex int * @param weight float * @constructor */ GameLib.D3.BoneWeight = function( boneIndex, weight ) { this.boneIndex = boneIndex; this.weight = weight; }; /** * The normal gets assigned when the face calculates its normal * @param position * @param boneWeights GameLib.D3.BoneWeight[] * @constructor */ GameLib.D3.Vertex = function( position, boneWeights ) { this.position = position; this.boneWeights = boneWeights; }; /** * Image * @param id * @param textureLink * @param filename * @param uploadPath * @param apiPath * @param size * @param contentType * @constructor */ GameLib.D3.Image = function( id, textureLink, filename, uploadPath, apiPath, size, contentType ) { this.id = id; this.filename = filename; this.textureLink = textureLink; if (typeof uploadPath == 'undefined') { uploadPath = null; } this.uploadPath = uploadPath; if (typeof apiPath == 'undefined') { apiPath = null; } this.apiPath = apiPath; if (typeof size == 'undefined') { size = 0; } this.size = size; if (typeof contentType == 'undefined') { contentType = 'application/octet-stream'; if (this.filename.match(/(png)$/i)) { contentType = 'image/png'; } if (this.filename.match(/(jpg|jpeg)$/i)) { contentType = 'image/jpeg'; } if (this.filename.match(/(gif)$/i)) { contentType = 'image/gif'; } } this.contentType = contentType; }; /** * Scenes are objects putting meshes into 'world space' * @param id * @param path String * @param name String * @param meshes GameLib.D3.Mesh[] * @param quaternion * @param position * @param rotation * @param scale * @param parentSceneId * @param lights * @constructor */ GameLib.D3.Scene = function( id, path, name, meshes, quaternion, position, rotation, scale, parentSceneId, lights ) { this.id = id; this.path = path; this.name = name; if (this.name.trim() == "") { this.name = 'unnamed'; } this.meshes = meshes; if (typeof quaternion == 'undefined') { quaternion = new GameLib.D3.Vector4(); } this.quaternion = quaternion; if (typeof position == 'undefined') { position = new GameLib.D3.Vector3(0,0,0); } this.position = position; if (typeof rotation == 'undefined') { rotation = new GameLib.D3.Vector3(0,0,0); } this.rotation = rotation; if (typeof scale == 'undefined') { scale = new GameLib.D3.Vector3(1,1,1); } this.scale = scale; if (typeof parentSceneId == 'undefined') { parentSceneId = null; } this.parentSceneId = parentSceneId; if (typeof lights == 'undefined') { lights = []; } this.lights = lights; }; /** * 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 ) }; /** * Clone a TriangleFace * @returns {GameLib.D3.TriangleFace} */ GameLib.D3.TriangleFace.prototype.clone = function(){ return new GameLib.D3.TriangleFace( this.v0, this.v1, this.v2, this.materialIndex, this.v0uv.copy(), this.v1uv.copy(), this.v2uv.copy() ); }; /** * Associates bones with their child bones, based on parent bone references */ GameLib.D3.prototype.createChildBoneIds = function() { for (var bi = 0; bi < this.bones.length; bi++) { var childBoneIds = []; for (var sbi = 0; sbi < this.bones.length; sbi++) { if (this.bones[sbi] == this.bones[bi]) { continue; } if (this.bones[sbi].parentBoneId !== null && this.bones[sbi].parentBoneId == this.bones[bi].boneId) { childBoneIds.push(this.bones[sbi].boneId); } } this.bones[bi].childBoneIds = childBoneIds; } }; /** * 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.D3.prototype.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.D3.Vector4.Points(); for (var i = 0; i < verticesFlat.length; i += 3) { points.add(new GameLib.D3.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; }; /** * 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.TriangleFace[] * @param orientationEdge GameLib.D3.Vector2 * @returns {Array} */ GameLib.D3.prototype.fixWindingOrder = function(faces, orientationEdge) { /** * Checks if a TriangleFace belonging to a TriangleEdge has already been processed * @param processed TriangleEdge[] * @param triangle TriangleFace * @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.D3.Vector2 * @param faces GameLib.D3.TriangleFace[] * @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.TriangleFace( faces[i].v0, faces[i].v1, faces[i].v2, faces[i].materialIndex, faces[i].v0uv, faces[i].v1uv, faces[i].v2uv ); if (triangle.equals(currentTriangle)) { continue; } return new GameLib.D3.TriangleEdge( triangle, edge ); } } return null; } var toProcess = [ new GameLib.D3.TriangleEdge( new GameLib.D3.TriangleFace( faces[0].v0, faces[0].v1, faces[0].v2, faces[0].materialIndex, faces[0].v0uv, faces[0].v1uv, faces[0].v2uv ), 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.v0 == triangleEdge.edge.x && triangleEdge.triangle.v1 == triangleEdge.edge.y) || (triangleEdge.triangle.v1 == triangleEdge.edge.x && triangleEdge.triangle.v2 == triangleEdge.edge.y) || (triangleEdge.triangle.v2 == triangleEdge.edge.x && triangleEdge.triangle.v0 == triangleEdge.edge.y) ) { var backupV = triangleEdge.triangle.v1; triangleEdge.triangle.v1 = triangleEdge.triangle.v2; triangleEdge.triangle.v2 = backupV; var backupUV = triangleEdge.triangle.v1uv; triangleEdge.triangle.v1uv = triangleEdge.triangle.v2uv; triangleEdge.triangle.v2uv = backupUV; } processed.push(triangleEdge); var edges = [ new GameLib.D3.Vector2( triangleEdge.triangle.v0, triangleEdge.triangle.v1 ), new GameLib.D3.Vector2( triangleEdge.triangle.v1, triangleEdge.triangle.v2 ), new GameLib.D3.Vector2( triangleEdge.triangle.v2, triangleEdge.triangle.v0 ) ]; 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; }; /** * Returns true if two triangles are equal (their vertex indices match in some order) * @param triangle * @returns {boolean} */ GameLib.D3.TriangleFace.prototype.equals = function(triangle) { return !!( ( (this.v0 == triangle.v0) && (this.v1 == triangle.v1) && (this.v2 == triangle.v2) ) || ( (this.v0 == triangle.v0) && (this.v1 == triangle.v2) && (this.v2 == triangle.v1) ) || ( (this.v0 == triangle.v1) && (this.v1 == triangle.v0) && (this.v2 == triangle.v2) ) || ( (this.v0 == triangle.v1) && (this.v1 == triangle.v2) && (this.v2 == triangle.v0) ) || ( (this.v0 == triangle.v2) && (this.v1 == triangle.v0) && (this.v2 == triangle.v1) ) || ( (this.v0 == triangle.v2) && (this.v1 == triangle.v1) && (this.v2 == triangle.v0) )); }; GameLib.D3.prototype.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; }; /** * This function resets a the winding order of a mesh from a reference point V (the average center of the mesh) */ GameLib.D3.prototype.resetWindingOrder = function(faces, vertices) { var vertexList = new GameLib.D3.Vector3.Points(); for (var v = 0; v < vertices.length; v++) { vertexList.add(new GameLib.D3.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.D3.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; }; /** * Defers loading of an image and resolves once image is loaded * @param gameLibTexture * @param threeMaterial * @param threeMaterialMapType * @returns {Promise} */ GameLib.D3.prototype.loadMap = function(gameLibTexture, threeMaterial, threeMaterialMapType) { var q = this.Q.defer(); var imagePath = null; if (gameLibTexture && gameLibTexture.image && gameLibTexture.image.apiPath && gameLibTexture.image.filename) { /** * Load the image from API here if apiPath is defined */ imagePath = this.apiUrl + gameLibTexture.image.uploadPath + '/' + gameLibTexture.image.filename; } if (gameLibTexture && gameLibTexture.image && gameLibTexture.image.uploadPath && gameLibTexture.image.filename) { /** * Else, load from upload source */ imagePath = this.editorUrl + gameLibTexture.image.uploadPath + '/' + gameLibTexture.image.filename; } if (imagePath) { this.textureLoader.crossOrigin = ''; this.textureLoader.load( imagePath, function(texture) { /** * onLoad */ threeMaterial[threeMaterialMapType] = texture; threeMaterial[threeMaterialMapType].name = gameLibTexture.name; threeMaterial[threeMaterialMapType].anisotropy = gameLibTexture.anisotropy; threeMaterial[threeMaterialMapType].encoding = gameLibTexture.encoding; threeMaterial[threeMaterialMapType].flipY = gameLibTexture.flipY; /** * We don't restore the format since this changing from OS to OS and breaks the implementation sometimes */ threeMaterial[threeMaterialMapType].generateMipmaps = gameLibTexture.generateMipmaps; threeMaterial[threeMaterialMapType].magFilter = gameLibTexture.magFilter; threeMaterial[threeMaterialMapType].minFilter = gameLibTexture.minFilter; threeMaterial[threeMaterialMapType].mapping = gameLibTexture.mapping; threeMaterial[threeMaterialMapType].mipmaps = gameLibTexture.mipmaps; threeMaterial[threeMaterialMapType].offset = new this.THREE.Vector2( gameLibTexture.offset.x, gameLibTexture.offset.y ); threeMaterial[threeMaterialMapType].premultiplyAlpha = gameLibTexture.premultiplyAlpha; threeMaterial[threeMaterialMapType].textureType = gameLibTexture.textureType; threeMaterial[threeMaterialMapType].wrapS = gameLibTexture.wrapS; threeMaterial[threeMaterialMapType].wrapT = gameLibTexture.wrapT; threeMaterial[threeMaterialMapType].unpackAlignment = gameLibTexture.unpackAlignment; threeMaterial.needsUpdate = true; q.resolve(true); }, function(xhr) { /** * onProgress */ if (this.editor) { this.editor.setServerStatus(Math.round(xhr.loaded / xhr.total * 100) + '% complete', 'success'); } }, function(error) { /** * onError */ console.log("an error occurred while trying to load the image : " + imagePath); q.resolve(null); } ); } else { q.resolve(null); } return q.promise; }; /** * Creates a THREE Mesh from GameLib.D3.Mesh * @param gameLibMesh * @param threeGeometry * @param threeMaterial * @returns {*} */ GameLib.D3.prototype.createThreeMesh = function(gameLibMesh, threeGeometry, threeMaterial) { var threeMesh = null; if (gameLibMesh.meshType == GameLib.D3.Mesh.TYPE_NORMAL) { threeMesh = new this.THREE.Mesh(threeGeometry, threeMaterial); } if (gameLibMesh.meshType == GameLib.D3.Mesh.TYPE_SKINNED) { var bones = gameLibMesh.skeleton.bones; var skinIndices = gameLibMesh.skinIndices; var skinWeights = gameLibMesh.skinWeights; var threeBones = []; for (var bi = 0; bi < bones.length; bi++) { var bone = new this.THREE.Bone(); bone.name = bones[bi].name; bone.position.x = bones[bi].position.x; bone.position.y = bones[bi].position.y; bone.position.z = bones[bi].position.z; bone.rotation.x = bones[bi].rotation.x; bone.rotation.y = bones[bi].rotation.y; bone.rotation.z = bones[bi].rotation.z; bone.quaternion.x = bones[bi].quaternion.x; bone.quaternion.y = bones[bi].quaternion.y; bone.quaternion.z = bones[bi].quaternion.z; bone.quaternion.w = bones[bi].quaternion.w; bone.scale.x = bones[bi].scale.x; bone.scale.y = bones[bi].scale.y; bone.scale.z = bones[bi].scale.z; bone.up.x = bones[bi].up.x; bone.up.y = bones[bi].up.y; bone.up.z = bones[bi].up.z; threeBones.push(bone); } /** * Setup the bone relationships */ for (var br = 0; br < bones.length; br++) { for (var cbi = 0; cbi < bones[br].childBoneIds.length; cbi++) { threeBones[br].add(threeBones[bones[br].childBoneIds[cbi]]); } } /** * Setup bones (indexes) */ for (var si = 0; si < skinIndices.length; si++) { threeGeometry.skinIndices.push( new this.THREE.Vector4( skinIndices[si].x, skinIndices[si].y, skinIndices[si].z, skinIndices[si].w ) ); } /** * Setup bones (weights) */ for (var sw = 0; sw < skinWeights.length; sw++) { threeGeometry.skinWeights.push( new this.THREE.Vector4( skinWeights[sw].x, skinWeights[sw].y, skinWeights[sw].z, skinWeights[sw].w ) ); } threeMesh = new this.THREE.SkinnedMesh(threeGeometry, threeMaterial); var skeleton = new this.THREE.Skeleton(threeBones); skeleton.useVertexTexture = gameLibMesh.skeleton.useVertexTexture; for (var i = 0; i < bones.length; i++) { if (bones[i].parentBoneId === null) { threeMesh.add(threeBones[i]); break; } } threeMesh.bind(skeleton); threeMesh.pose(); threeMesh.skeleton.skeletonHelper = new this.THREE.SkeletonHelper(threeMesh); threeMesh.skeleton.skeletonHelper.material.linewidth = 5; } if (threeMesh == null) { console.log('cannot handle meshes of type ' + gameLibMesh.meshType + ' yet.'); } gameLibMesh.threeMeshId = threeMesh.id; return threeMesh; }; /** * Returns an array of image loading Promises * @param blenderMaterial * @param blenderMaps * @param threeMaterial * @returns Q[] */ GameLib.D3.prototype.loadMaps = function(blenderMaterial, blenderMaps, threeMaterial) { var textureMaps = []; for (var ti = 0; ti < blenderMaps.length; ti++) { var map = blenderMaps[ti]; if (blenderMaterial.maps.hasOwnProperty(map)) { var blenderTexture = blenderMaterial.maps[map]; if ( blenderTexture && blenderTexture.image && blenderTexture.image.filename && blenderTexture.image.uploadPath ) { var threeMap = null; if (map == 'alpha') { threeMap = 'alhpaMap'; } if (map == 'ao') { threeMap = 'aoMap'; } if (map == 'bump') { threeMap = 'bumpMap'; } if (map == 'displacement') { threeMap = 'displacementMap'; } if (map == 'emissive') { threeMap = 'emissiveMap'; } if (map == 'environment') { threeMap = 'envMap'; } if (map == 'light') { threeMap = 'lightMap'; } if (map == 'specular') { threeMap = 'specularMap'; } if (map == 'diffuse') { threeMap = 'map'; } if (map == 'roughness') { threeMap = 'roughnessMap'; } if (map == 'metalness') { threeMap = 'metalnessMap'; } if (threeMap == null) { console.warn("unsupported map type : " + map); } textureMaps.push(this.loadMap(blenderMaterial.maps[map], threeMaterial, threeMap)); } } } return textureMaps; }; /** * Creates a this.THREE.Material from a GameLib.D3.Material * @param blenderMaterial GameLib.D3.Material */ GameLib.D3.prototype.createThreeMaterial = function(blenderMaterial) { var defer = this.Q.defer(); var threeMaterial = null; var blenderMaps = []; if (blenderMaterial.materialType == GameLib.D3.Material.TYPE_MESH_STANDARD) { threeMaterial = new this.THREE.MeshStandardMaterial({ name: blenderMaterial.name, opacity: blenderMaterial.opacity, transparent: blenderMaterial.transparent, blending: blenderMaterial.blending, blendSrc: blenderMaterial.blendSrc, blendDst: blenderMaterial.blendDst, blendEquation: blenderMaterial.blendEquation, depthTest: blenderMaterial.depthTest, depthFunc: blenderMaterial.depthFunc, depthWrite: blenderMaterial.depthWrite, polygonOffset: blenderMaterial.polygonOffset, polygonOffsetFactor: blenderMaterial.polygonOffsetFactor, polygonOffsetUnits: blenderMaterial.polygonOffsetUnits, alphaTest: blenderMaterial.alphaTest, clippingPlanes: blenderMaterial.clippingPlanes, clipShadows: blenderMaterial.clipShadows, overdraw: blenderMaterial.overdraw, visible: blenderMaterial.visible, side: blenderMaterial.side, color: new this.THREE.Color( blenderMaterial.color.r, blenderMaterial.color.g, blenderMaterial.color.b ), roughness: blenderMaterial.roughness, metalness: blenderMaterial.metalness, lightMapIntensity: blenderMaterial.lightMapIntensity, aoMapIntensity: blenderMaterial.aoMapIntensity, emissive: new this.THREE.Color( blenderMaterial.emissive.r, blenderMaterial.emissive.g, blenderMaterial.emissive.b ), emissiveIntensity: blenderMaterial.emissiveIntensity, bumpScale: blenderMaterial.bumpScale, normalScale: blenderMaterial.normalScale, displacementScale: blenderMaterial.displacementScale, refractionRatio: blenderMaterial.refractionRatio, fog: blenderMaterial.fog, shading: blenderMaterial.shading, wireframe: blenderMaterial.wireframe, wireframeLinewidth: blenderMaterial.wireframeLineWidth, wireframeLinecap: blenderMaterial.wireframeLineCap, wireframeLinejoin: blenderMaterial.wireframeLineJoin, vertexColors: blenderMaterial.vertexColors, skinning: blenderMaterial.skinning, morphTargets: blenderMaterial.morphTargets, morphNormals: blenderMaterial.morphNormals }); blenderMaps.push( 'diffuse', 'light', 'ao', 'emissive', 'bump', 'normal', 'displacement', 'roughness', 'metalness', 'alpha', 'environment' ); } else if (blenderMaterial.materialType == GameLib.D3.Material.TYPE_MESH_PHONG) { threeMaterial = new this.THREE.MeshPhongMaterial({ name: blenderMaterial.name, opacity: blenderMaterial.opacity, transparent: blenderMaterial.transparent, blending: blenderMaterial.blending, blendSrc: blenderMaterial.blendSrc, blendDst: blenderMaterial.blendDst, blendEquation: blenderMaterial.blendEquation, depthTest: blenderMaterial.depthTest, depthFunc: blenderMaterial.depthFunc, depthWrite: blenderMaterial.depthWrite, polygonOffset: blenderMaterial.polygonOffset, polygonOffsetFactor: blenderMaterial.polygonOffsetFactor, polygonOffsetUnits: blenderMaterial.polygonOffsetUnits, alphaTest: blenderMaterial.alphaTest, clippingPlanes: blenderMaterial.clippingPlanes, clipShadows: blenderMaterial.clipShadows, overdraw: blenderMaterial.overdraw, visible: blenderMaterial.visible, side: blenderMaterial.side, color: new this.THREE.Color( blenderMaterial.color.r, blenderMaterial.color.g, blenderMaterial.color.b ), specular: new this.THREE.Color( blenderMaterial.specular.r, blenderMaterial.specular.g, blenderMaterial.specular.b ), shininess: blenderMaterial.shininess, lightMapIntensity: blenderMaterial.lightMapIntensity, aoMapIntensity: blenderMaterial.aoMapIntensity, emissive: new this.THREE.Color( blenderMaterial.emissive.r, blenderMaterial.emissive.g, blenderMaterial.emissive.b ), emissiveIntensity: blenderMaterial.emissiveIntensity, bumpScale: blenderMaterial.bumpScale, normalScale: blenderMaterial.normalScale, displacementScale: blenderMaterial.displacementScale, combine: blenderMaterial.combine, refractionRatio: blenderMaterial.refractionRatio, fog: blenderMaterial.fog, shading: blenderMaterial.shading, wireframe: blenderMaterial.wireframe, wireframeLinewidth: blenderMaterial.wireframeLineWidth, wireframeLinecap: blenderMaterial.wireframeLineCap, wireframeLinejoin: blenderMaterial.wireframeLineJoin, vertexColors: blenderMaterial.vertexColors, skinning: blenderMaterial.skinning, morphTargets: blenderMaterial.morphTargets, morphNormals: blenderMaterial.morphNormals }); blenderMaps.push( 'diffuse', 'light', 'ao', 'emissive', 'bump', 'normal', 'displacement', 'specular', 'alpha', 'environment' ); } else { console.log("material type is not implemented yet: " + blenderMaterial.materialType + " - material indexes could be screwed up"); } if (blenderMaps.length > 0) { var textureMaps = this.loadMaps(blenderMaterial, blenderMaps, threeMaterial); Q.all(textureMaps).then( function(){ defer.resolve(threeMaterial); } ).catch( function(error){ console.log(error); defer.reject(error); } ) } else { defer.resolve(threeMaterial); } return defer.promise; }; /** * Loads a scene directly from the API * @param sceneName * @param onLoaded callback */ GameLib.D3.prototype.loadSceneFromApi = function(sceneName, onLoaded) { /** * First check if this is a client or server side request */ if (typeof XMLHttpRequest == 'undefined') { console.warn('implement server side loading from API here'); return onLoaded(null, new Error('not implemented')); } var xhr = new XMLHttpRequest(); xhr.open( 'GET', this.apiUrl + '/scene/' + sceneName ); xhr.onreadystatechange = function(xhr, gameLibD3) { return function() { if (xhr.readyState == 4) { var response = JSON.parse(xhr.responseText); gameLibD3.loadScene(response.scene[0], onLoaded, false); } } }(xhr, this); xhr.send(); }; /** * Loads a GameLib.D3.Scene object into a ThreeJS Scene object * @param gameLibScene GameLib.D3.Scene * @param onLoaded callback when all meshes have loaded * @param computeNormals set to true to compute new face and vertex normals during load */ GameLib.D3.prototype.loadScene = function(gameLibScene, onLoaded, computeNormals) { console.log("loading scene " + gameLibScene.name); var meshQ = []; for (var m = 0; m < gameLibScene.meshes.length; m++) { var mesh = gameLibScene.meshes[m]; console.log("loading mesh " + mesh.name); var geometry = new this.THREE.Geometry(); var vertices = mesh.vertices; var faces = mesh.faces; var faceVertexUvs = mesh.faceVertexUvs; var materials = mesh.materials; /** * Setup vertices */ for (var v = 0; v < vertices.length; v++) { geometry.vertices.push( new this.THREE.Vector3( vertices[v].position.x, vertices[v].position.y, vertices[v].position.z ) ) } /** * Setup faces */ for (var f = 0; f < faces.length; f++) { var face = new this.THREE.Face3( faces[f].v0, faces[f].v1, faces[f].v2, new this.THREE.Vector3( faces[f].normal.x, faces[f].normal.y, faces[f].normal.z ), new this.THREE.Color( faces[f].color.r, faces[f].color.g, faces[f].color.b ), faces[f].materialIndex ); face.vertexColors = [ new this.THREE.Color( faces[f].vertexColors[0].r, faces[f].vertexColors[0].g, faces[f].vertexColors[0].b ), new this.THREE.Color( faces[f].vertexColors[1].r, faces[f].vertexColors[1].g, faces[f].vertexColors[1].b ), new this.THREE.Color( faces[f].vertexColors[2].r, faces[f].vertexColors[2].g, faces[f].vertexColors[2].b ) ]; face.normal = new this.THREE.Vector3( faces[f].normal.x, faces[f].normal.y, faces[f].normal.z ); face.vertexNormals = [ new this.THREE.Vector3( faces[f].vertexNormals[0].x, faces[f].vertexNormals[0].y, faces[f].vertexNormals[0].z ), new this.THREE.Vector3( faces[f].vertexNormals[1].x, faces[f].vertexNormals[1].y, faces[f].vertexNormals[1].z ), new this.THREE.Vector3( faces[f].vertexNormals[2].x, faces[f].vertexNormals[2].y, faces[f].vertexNormals[2].z ) ]; geometry.faces.push(face); } geometry.faceVertexUvs = []; /** * Setup face UVs */ for (var fm = 0; fm < faceVertexUvs.length; fm++) { var faceMaterialVertexUvs = faceVertexUvs[fm]; geometry.faceVertexUvs[fm] = []; for (var fuv = 0; fuv < faceMaterialVertexUvs.length; fuv++) { geometry.faceVertexUvs[fm][fuv] = []; geometry.faceVertexUvs[fm][fuv].push( new this.THREE.Vector2( faceMaterialVertexUvs[fuv][0].x, faceMaterialVertexUvs[fuv][0].y ), new this.THREE.Vector2( faceMaterialVertexUvs[fuv][1].x, faceMaterialVertexUvs[fuv][1].y ), new this.THREE.Vector2( faceMaterialVertexUvs[fuv][2].x, faceMaterialVertexUvs[fuv][2].y ) ); } } /** * Re-calculate normals (if we have to) * @type {Array} */ if (computeNormals) { geometry.computeFaceNormals(); geometry.computeVertexNormals(); } var threeMaterialLoaders = []; /** * Setup materials */ for (var mi = 0; mi < materials.length; mi++) { threeMaterialLoaders.push(this.createThreeMaterial(materials[mi])); } var result = this.Q.all(threeMaterialLoaders).then( function(gl3d, mesh, geometry) { return function(materials) { console.log("loaded all materials maps (" + materials.length + ")"); /** * We don't support MultiMaterial atm - it doesn't work with raycasting */ var material = materials[0]; var threeMesh = gl3d.createThreeMesh(mesh, geometry, material); threeMesh.name = mesh.name; threeMesh.position.x = mesh.position.x; threeMesh.position.y = mesh.position.y; threeMesh.position.z = mesh.position.z; threeMesh.rotation.x = mesh.rotation.x; threeMesh.rotation.y = mesh.rotation.y; threeMesh.rotation.z = mesh.rotation.z; threeMesh.scale.x = mesh.scale.x; threeMesh.scale.y = mesh.scale.y; threeMesh.scale.z = mesh.scale.z; threeMesh.quaternion.x = mesh.quaternion.x; threeMesh.quaternion.y = mesh.quaternion.y; threeMesh.quaternion.z = mesh.quaternion.z; threeMesh.quaternion.w = mesh.quaternion.w; return threeMesh; }; }(this, mesh, geometry) ).catch(function(error){ console.log(error); }); meshQ.push(result); } this.Q.all(meshQ).then(function(threeMeshes){ console.log("all meshes have loaded"); if (typeof onLoaded != 'undefined') { var threeLights = []; for (var sli = 0; sli < gameLibScene.lights.length; sli++) { var blenderLight = gameLibScene.lights[sli]; var light = null; if (blenderLight.lightType == 'AmbientLight') { light = new this.THREE.AmbientLight(blenderLight.color, blenderLight.intensity); } if (blenderLight.lightType == 'DirectionalLight') { light = new this.THREE.DirectionalLight(blenderLight.color, blenderLight.intensity); } if (blenderLight.lightType == 'PointLight') { light = new this.THREE.PointLight(blenderLight.color, blenderLight.intensity); light.distance = blenderLight.distance; light.decay = blenderLight.decay; } if (blenderLight.lightType == 'SpotLight') { light = new this.THREE.SpotLight(blenderLight.color, blenderLight.intensity); light.distance = blenderLight.distance; light.angle = blenderLight.angle; light.penumbra = blenderLight.penumbra; light.decay = blenderLight.decay; } light.position.x = blenderLight.position.x; light.position.y = blenderLight.position.y; light.position.z = blenderLight.position.z; light.rotation.x = blenderLight.rotation.x; light.rotation.y = blenderLight.rotation.y; light.rotation.z = blenderLight.rotation.z; // light.scale.x = blenderLight.scale.x; // light.scale.y = blenderLight.scale.y; // light.scale.z = blenderLight.scale.z; if (light == null) { console.warn('Does not support lights of type :' + blenderLight.lightType + ', not imported'); } else { light.name = blenderLight.name; threeLights.push(light); } } onLoaded(threeMeshes, threeLights); } }).catch(function(error){ console.log(error); }); }; // --------------- // Physics // --------------- GameLib.D3.Physics.World.GetIndexedVertices = function( triangleMeshShape ) { if(this.engine.engineType == GameLib.D3.Physics.Engine.TYPE_CANNON) { return { vertices : triangleMeshShape.vertices, indices : triangleMeshShape.indices }; } else { // todo: implement this for other physics engines. return null; } }; GameLib.D3.Physics.World.GenerateWireframeViewMesh = function( triangleMeshShape, normalLength, scale, opacity, wireframeColor ) { var geometryTHREE = new THREE.Geometry(); var wireframeTHREEMesh = new THREE.Mesh ( geometryTHREE, new THREE.MeshBasicMaterial({ color: wireframeColor ? wireframeColor : 0xfefefe, wireframe: true, opacity: opacity ? opacity : 0.5 }) ); var data = this.GetIndexedVertices(triangleMeshShape); for(var i = 0, l = data.vertices.length / 3; i < l; i++) { geometryTHREE.vertices.push(new THREE.Vector3(data.vertices[i * 3], data.vertices[i * 3 + 1], data.vertices[i * 3 + 2])); } for(var i = 0, l = data.indices.length / 3; i < l; i++) { var i0 = data.indices[i * 3]; var i1 = data.indices[i * 3 + 1]; var i2 = data.indices[i * 3 + 2]; geometryTHREE.faces.push(new THREE.Face3(i0, i1, i2)); // Create debug view for normals // Center point on the mesh itself var centroid = new THREE.Vector3() .add(geometryTHREE.vertices[i0]) .add(geometryTHREE.vertices[i1]) .add(geometryTHREE.vertices[i2]) .divideScalar(3); var normal = null; if(this.engine.engineType == GameLib.D3.Physics.Engine.TYPE_CANNON) { var normal = new CANNON.Vec3(); triangleMeshShape.getNormal(i, normal); } else { // todo: calculate the normal for v0, v1 & v2 here. } var arrow = new THREE.ArrowHelper(new THREE.Vector3(normal.x, normal.y, normal.z), centroid, normalLength, new THREE.Color(normal.x, normal.y, normal.z)); wireframeTHREEMesh.add( arrow ); } wireframeTHREEMesh.scale.x = scale.x; wireframeTHREEMesh.scale.y = scale.y; wireframeTHREEMesh.scale.z = scale.z; return wireframeTHREEMesh; }; GameLib.D3.Physics.World.GenerateTriangleCollisionMesh = function( threeMesh, mass, // default = 0 friction, // default = 10 createCollisionSubMeshes, // boolean. default = false facesPerSubsection, // int. default = 0 subsectionsToMerge // int. default = 0 ) { var processedFaces = 0; var facesPerSubSection = facesPerSubsection || 0; var subMeshesToMerge = subsectionsToMerge || 0; var totalAmtFaces = threeMesh.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; if(this.engine.engineType == GameLib.D3.Physics.Engine.TYPE_CANNON) { var meshShape = new CANNON.Trimesh(vertices, indicies); meshShape.setScale(new CANNON.Vec3(threeMesh.scale.x, threeMesh.scale.y, threeMesh.scale.z)); meshShape.updateAABB(); meshShape.updateNormals(); meshShape.updateEdges(); meshShape.updateBoundingSphereRadius(); meshShape.updateTree(); body = new CANNON.Body({ mass: mass ? mass : 0, friction: friction ? friction : 10 }); body.addShape(meshShape); } else if (this.engine.engineType == GameLib.D3.Physics.Engine.TYPE_AMMO) { } else if (this.engine.engineType == GameLib.D3.Physics.Engine.TYPE_GOBLIN) { } pairs.push({ threeObject : createCollisionSubMeshes ? null : threeMesh, physicsObject : body }); vertices = []; indicies = []; processedFaces = 0; if(i == totalAmtFaces) { return pairs; } } var face = threeMesh.geometry.faces[i]; indicies.push(indicies.length); indicies.push(indicies.length); indicies.push(indicies.length); var v0 = threeMesh.geometry.vertices[face.a]; var v1 = threeMesh.geometry.vertices[face.b]; var v2 = threeMesh.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++; } }; if (typeof module != 'undefined') { module.exports = GameLib.D3; }