From ed9c19b2d53b20d3667dc38315d8c69ecbe148cd Mon Sep 17 00:00:00 2001 From: Theunis Johannes Botha Date: Mon, 9 Apr 2018 09:35:04 +0200 Subject: [PATCH] rename --- src/r3-a-0.js | 59 + src/r3-a-1-event.js | 486 ++++ src/r3-a-2-utils.js | 990 +++++++ src/r3-a-api-component.js | 19 + src/r3-a-component-a.js | 2003 ++++++++++++++ src/r3-api-box3.js | 45 + src/r3-api-canvas.js | 87 + src/r3-api-clock.js | 47 + src/r3-api-color.js | 51 + src/r3-api-controls-0.js | 115 + src/r3-api-controls-d3-editor.js | 44 + src/r3-api-controls-d3-first-person.js | 136 + src/r3-api-controls-d3-orbit.js | 147 ++ src/r3-api-controls-keyboard.js | 30 + src/r3-api-controls-mouse.js | 31 + src/r3-api-controls-touch.js | 37 + src/r3-api-curve-a.js | 89 + src/r3-api-curve-path-a.js | 44 + src/r3-api-curve-path-d2-a.js | 35 + src/r3-api-curve-path-d2-shape.js | 27 + src/r3-api-custom-code.js | 45 + src/r3-api-dom-element.js | 53 + src/r3-api-draw-range.js | 45 + src/r3-api-entity-manager.js | 67 + src/r3-api-entity.js | 52 + src/r3-api-graphics-runtime-a.js | 64 + src/r3-api-graphics-runtime-impact.js | 30 + src/r3-api-graphics-runtime-three.js | 30 + src/r3-api-group.js | 52 + src/r3-api-gui.js | 64 + src/r3-api-image.js | 100 + src/r3-api-matrix4.js | 159 ++ src/r3-api-mouse.js | 45 + src/r3-api-number.js | 34 + src/r3-api-plane.js | 53 + src/r3-api-quaternion-a.js | 237 ++ src/r3-api-quaternion-points.js | 224 ++ src/r3-api-render-configuration.js | 117 + src/r3-api-renderer-a.js | 122 + src/r3-api-renderer-d2.js | 35 + src/r3-api-renderer-d3.js | 266 ++ src/r3-api-server.js | 79 + src/r3-api-socket-0.js | 93 + src/r3-api-socket-cast.js | 78 + src/r3-api-socket-receive.js | 77 + src/r3-api-sphere.js | 20 + src/r3-api-stats.js | 64 + src/r3-api-system.js | 104 + src/r3-api-vector2.js | 42 + src/r3-api-vector3.js | 277 ++ src/r3-api-vector4.js | 46 + src/r3-box3.js | 97 + src/r3-canvas.js | 335 +++ src/r3-clock.js | 96 + src/r3-coder-runtime.js | 60 + src/r3-color.js | 152 ++ src/r3-controls-0.js | 100 + src/r3-controls-d3-editor.js | 116 + src/r3-controls-d3-first-person.js | 220 ++ src/r3-controls-d3-orbit.js | 235 ++ src/r3-controls-keyboard.js | 79 + src/r3-controls-mouse.js | 79 + src/r3-controls-touch.js | 82 + src/r3-curve-a.js | 87 + src/r3-curve-path-a.js | 109 + src/r3-curve-path-d2-a.js | 101 + src/r3-curve-path-d2-shape.js | 74 + src/r3-custom-code.js | 173 ++ src/r3-d3-api-a-object.js | 173 ++ src/r3-d3-api-animation.js | 121 + src/r3-d3-api-audio.js | 104 + src/r3-d3-api-bone-weight.js | 26 + src/r3-d3-api-bone.js | 93 + src/r3-d3-api-broadphase.js | 54 + src/r3-d3-api-camera-a.js | 52 + src/r3-d3-api-camera-cube.js | 59 + src/r3-d3-api-camera-orthographic.js | 144 + src/r3-d3-api-camera-perspective.js | 84 + src/r3-d3-api-camera-stereo-a.js | 40 + src/r3-d3-api-composer.js | 73 + src/r3-d3-api-effect-a.js | 100 + src/r3-d3-api-effect-anaglyph.js | 34 + src/r3-d3-api-effect-parallax.js | 34 + src/r3-d3-api-effect-stereo.js | 41 + src/r3-d3-api-face.js | 243 ++ src/r3-d3-api-fog.js | 67 + src/r3-d3-api-font.js | 52 + src/r3-d3-api-friction-contact-material.js | 102 + src/r3-d3-api-friction-material.js | 62 + src/r3-d3-api-geometry-a.js | 413 +++ src/r3-d3-api-geometry-buffer-a.js | 69 + src/r3-d3-api-geometry-buffer-box.js | 74 + src/r3-d3-api-geometry-buffer-circle.js | 60 + src/r3-d3-api-geometry-buffer-cone.js | 81 + src/r3-d3-api-geometry-buffer-cylinder.js | 88 + src/r3-d3-api-geometry-buffer-dodecahedron.js | 46 + src/r3-d3-api-geometry-buffer-extrude.js | 104 + src/r3-d3-api-geometry-buffer-icosahedron.js | 46 + src/r3-d3-api-geometry-buffer-instanced.js | 39 + src/r3-d3-api-geometry-buffer-lathe.js | 60 + src/r3-d3-api-geometry-buffer-octahedron.js | 46 + src/r3-d3-api-geometry-buffer-parametric.js | 53 + src/r3-d3-api-geometry-buffer-plane.js | 60 + src/r3-d3-api-geometry-buffer-polyhedron.js | 60 + src/r3-d3-api-geometry-buffer-ring.js | 74 + src/r3-d3-api-geometry-buffer-shape.js | 46 + src/r3-d3-api-geometry-buffer-sphere.js | 81 + src/r3-d3-api-geometry-buffer-tetrahedron.js | 46 + src/r3-d3-api-geometry-buffer-text.js | 95 + src/r3-d3-api-geometry-buffer-torus-knot.js | 74 + src/r3-d3-api-geometry-buffer-torus.js | 67 + src/r3-d3-api-geometry-buffer-tube.js | 67 + src/r3-d3-api-geometry-normal-a.js | 125 + src/r3-d3-api-geometry-normal-box.js | 82 + src/r3-d3-api-geometry-normal-circle.js | 68 + src/r3-d3-api-geometry-normal-cone.js | 89 + src/r3-d3-api-geometry-normal-cylinder.js | 96 + src/r3-d3-api-geometry-normal-dodecahedron.js | 54 + src/r3-d3-api-geometry-normal-edges.js | 54 + src/r3-d3-api-geometry-normal-extrude.js | 112 + src/r3-d3-api-geometry-normal-icosahedron.js | 54 + src/r3-d3-api-geometry-normal-lathe.js | 68 + src/r3-d3-api-geometry-normal-octahedron.js | 54 + src/r3-d3-api-geometry-normal-parametric.js | 61 + src/r3-d3-api-geometry-normal-plane.js | 68 + src/r3-d3-api-geometry-normal-polyhedron.js | 68 + src/r3-d3-api-geometry-normal-ring.js | 82 + src/r3-d3-api-geometry-normal-shape.js | 54 + src/r3-d3-api-geometry-normal-sphere.js | 89 + src/r3-d3-api-geometry-normal-tetrahedron.js | 54 + src/r3-d3-api-geometry-normal-text.js | 103 + src/r3-d3-api-geometry-normal-torus-knot.js | 82 + src/r3-d3-api-geometry-normal-torus.js | 75 + src/r3-d3-api-geometry-normal-tube.js | 75 + src/r3-d3-api-geometry-normal-wireframe.js | 47 + src/r3-d3-api-light-a.js | 127 + src/r3-d3-api-light-ambient.js | 33 + src/r3-d3-api-light-directional.js | 68 + src/r3-d3-api-light-hemisphere.js | 50 + src/r3-d3-api-light-point.js | 80 + src/r3-d3-api-light-rect-area.js | 91 + src/r3-d3-api-light-spot.js | 111 + src/r3-d3-api-material-a.js | 464 ++++ src/r3-d3-api-material-basic.js | 190 ++ src/r3-d3-api-material-phong.js | 281 ++ src/r3-d3-api-material-points.js | 92 + src/r3-d3-api-material-shader-a.js | 193 ++ src/r3-d3-api-material-shader-raw.js | 43 + src/r3-d3-api-material-standard.js | 281 ++ src/r3-d3-api-mesh-0.js | 159 ++ src/r3-d3-api-particle-engine.js | 157 ++ src/r3-d3-api-particle.js | 229 ++ src/r3-d3-api-pass-0.js | 95 + src/r3-d3-api-pass-bloom.js | 72 + src/r3-d3-api-pass-fxaa.js | 51 + src/r3-d3-api-pass-render.js | 44 + src/r3-d3-api-pass-ssao.js | 72 + src/r3-d3-api-physics-world.js | 111 + src/r3-d3-api-raycast-vehicle.js | 78 + src/r3-d3-api-raycast-wheel.js | 166 ++ src/r3-d3-api-raycaster.js | 46 + src/r3-d3-api-render-target-a.js | 149 ++ src/r3-d3-api-render-target-cube.js | 52 + src/r3-d3-api-rigid-body.js | 190 ++ src/r3-d3-api-scene.js | 110 + src/r3-d3-api-shader-a.js | 105 + src/r3-d3-api-shader-fragment.js | 32 + src/r3-d3-api-shader-vertex.js | 32 + src/r3-d3-api-shadow-a.js | 133 + src/r3-d3-api-shadow-directional.js | 34 + src/r3-d3-api-shadow-spot.js | 47 + src/r3-d3-api-shape.js | 154 ++ src/r3-d3-api-skeleton.js | 121 + src/r3-d3-api-solver.js | 77 + src/r3-d3-api-spline.js | 56 + src/r3-d3-api-text.js | 66 + src/r3-d3-api-texture-a.js | 327 +++ src/r3-d3-api-texture-canvas.js | 61 + src/r3-d3-api-texture-cube.js | 68 + src/r3-d3-api-texture-image.js | 61 + src/r3-d3-api-vertex.js | 21 + src/r3-d3-api-viewport.js | 78 + src/r3-d3-api-z-animation.js | 290 +++ src/r3-d3-api-z-object.js | 332 +++ src/r3-d3-audio.js | 160 ++ src/r3-d3-bone-weight.js | 40 + src/r3-d3-bone.js | 158 ++ src/r3-d3-broadphase.js | 118 + src/r3-d3-camera-a.js | 110 + src/r3-d3-camera-cube.js | 182 ++ src/r3-d3-camera-orthographic.js | 289 +++ src/r3-d3-camera-perspective.js | 146 ++ src/r3-d3-camera-stereo.js | 87 + src/r3-d3-composer.js | 212 ++ src/r3-d3-effect-a.js | 155 ++ src/r3-d3-effect-anaglyph.js | 80 + src/r3-d3-effect-parallax.js | 80 + src/r3-d3-effect-stereo.js | 90 + src/r3-d3-face.js | 280 ++ src/r3-d3-fog.js | 134 + src/r3-d3-font.js | 97 + src/r3-d3-friction-contact-material.js | 129 + src/r3-d3-friction-material.js | 90 + src/r3-d3-geometry-a.js | 221 ++ src/r3-d3-geometry-buffer-a.js | 571 ++++ src/r3-d3-geometry-buffer-box.js | 108 + src/r3-d3-geometry-buffer-circle.js | 110 + src/r3-d3-geometry-buffer-cone.js | 117 + src/r3-d3-geometry-buffer-cylinder.js | 121 + src/r3-d3-geometry-buffer-dodecahedron.js | 103 + src/r3-d3-geometry-buffer-extrude.js | 146 ++ src/r3-d3-geometry-buffer-icosahedron.js | 103 + src/r3-d3-geometry-buffer-instanced.js | 82 + src/r3-d3-geometry-buffer-lathe.js | 118 + src/r3-d3-geometry-buffer-octahedron.js | 103 + src/r3-d3-geometry-buffer-parametric.js | 107 + src/r3-d3-geometry-buffer-plane.js | 100 + src/r3-d3-geometry-buffer-polyhedron.js | 116 + src/r3-d3-geometry-buffer-ring.js | 113 + src/r3-d3-geometry-buffer-shape.js | 112 + src/r3-d3-geometry-buffer-sphere.js | 117 + src/r3-d3-geometry-buffer-tetrahedron.js | 103 + src/r3-d3-geometry-buffer-text.js | 142 + src/r3-d3-geometry-buffer-torus-knot.js | 113 + src/r3-d3-geometry-buffer-torus.js | 109 + src/r3-d3-geometry-buffer-tube.js | 109 + src/r3-d3-geometry-normal-a.js | 511 ++++ src/r3-d3-geometry-normal-box.js | 97 + src/r3-d3-geometry-normal-circle.js | 105 + src/r3-d3-geometry-normal-cone.js | 117 + src/r3-d3-geometry-normal-cylinder.js | 121 + src/r3-d3-geometry-normal-dodecahedron.js | 97 + src/r3-d3-geometry-normal-edges.js | 108 + src/r3-d3-geometry-normal-extrude.js | 141 + src/r3-d3-geometry-normal-icosahedron.js | 97 + src/r3-d3-geometry-normal-lathe.js | 113 + src/r3-d3-geometry-normal-octahedron.js | 97 + src/r3-d3-geometry-normal-parametric.js | 101 + src/r3-d3-geometry-normal-plane.js | 100 + src/r3-d3-geometry-normal-polyhedron.js | 116 + src/r3-d3-geometry-normal-ring.js | 113 + src/r3-d3-geometry-normal-shape.js | 112 + src/r3-d3-geometry-normal-sphere.js | 117 + src/r3-d3-geometry-normal-tetrahedron.js | 97 + src/r3-d3-geometry-normal-text.js | 141 + src/r3-d3-geometry-normal-torus-knot.js | 113 + src/r3-d3-geometry-normal-torus.js | 109 + src/r3-d3-geometry-normal-tube.js | 109 + src/r3-d3-geometry-normal-wireframe.js | 104 + src/r3-d3-helper.js | 159 ++ src/r3-d3-light-a.js | 130 + src/r3-d3-light-ambient.js | 64 + src/r3-d3-light-directional.js | 177 ++ src/r3-d3-light-hemisphere.js | 100 + src/r3-d3-light-point.js | 151 ++ src/r3-d3-light-rect-area.js | 156 ++ src/r3-d3-light-spot.js | 208 ++ src/r3-d3-material-a.js | 1068 ++++++++ src/r3-d3-material-basic.js | 245 ++ src/r3-d3-material-phong.js | 378 +++ src/r3-d3-material-points.js | 114 + src/r3-d3-material-shader-a.js | 263 ++ src/r3-d3-material-shader-raw.js | 100 + src/r3-d3-material-standard.js | 376 +++ src/r3-d3-mesh-0.js | 666 +++++ src/r3-d3-particle-engine.js | 272 ++ src/r3-d3-particle.js | 354 +++ src/r3-d3-pass-0.js | 114 + src/r3-d3-pass-bloom.js | 138 + src/r3-d3-pass-fxaa.js | 113 + src/r3-d3-pass-render.js | 130 + src/r3-d3-pass-ssao.js | 160 ++ src/r3-d3-physics-world.js | 1044 ++++++++ src/r3-d3-poly-vertex.js | 36 + src/r3-d3-raycast-vehicle.js | 173 ++ src/r3-d3-raycast-wheel.js | 170 ++ src/r3-d3-raycaster.js | 250 ++ src/r3-d3-render-target-a.js | 335 +++ src/r3-d3-render-target-cube.js | 73 + src/r3-d3-rigid-body.js | 288 ++ src/r3-d3-scene.js | 577 ++++ src/r3-d3-shader-a.js | 97 + src/r3-d3-shader-fragment.js | 59 + src/r3-d3-shader-vertex.js | 59 + src/r3-d3-shadow-a.js | 136 + src/r3-d3-shadow-directional.js | 90 + src/r3-d3-shadow-spot.js | 83 + src/r3-d3-shape-0.js | 108 + src/r3-d3-shape-box.js | 115 + src/r3-d3-shape-convex-hull-0.js | 281 ++ src/r3-d3-shape-convex-hull-cylinder.js | 133 + src/r3-d3-shape-height-map.js | 171 ++ src/r3-d3-shape-plane.js | 53 + src/r3-d3-shape-sphere.js | 71 + src/r3-d3-shape-tri-mesh.js | 70 + src/r3-d3-skeleton.js | 236 ++ src/r3-d3-solver.js | 111 + src/r3-d3-spline.js | 143 + src/r3-d3-text.js | 116 + src/r3-d3-texture-a.js | 387 +++ src/r3-d3-texture-canvas.js | 96 + src/r3-d3-texture-cube.js | 140 + src/r3-d3-texture-image.js | 138 + src/r3-d3-triangle-edge.js | 13 + src/r3-d3-vertex.js | 59 + src/r3-d3-viewport.js | 88 + src/r3-dom-element.js | 119 + src/r3-draw-range.js | 89 + src/r3-entity-manager.js | 418 +++ src/r3-entity.js | 286 ++ src/r3-graphics-runtime-a.js | 71 + src/r3-graphics-runtime-impact.js | 116 + src/r3-graphics-runtime-three.js | 63 + src/r3-group.js | 97 + src/r3-gui-runtime.js | 59 + src/r3-gui.js | 116 + src/r3-image.js | 205 ++ src/r3-matrix-4.js | 311 +++ src/r3-mouse.js | 67 + src/r3-number.js | 76 + src/r3-physics-runtime.js | 59 + src/r3-plane.js | 101 + src/r3-quaternion.js | 157 ++ src/r3-render-configuration.js | 255 ++ src/r3-renderer-a.js | 156 ++ src/r3-renderer-d2.js | 94 + src/r3-renderer-d3.js | 540 ++++ src/r3-server.js | 87 + src/r3-socket-0.js | 115 + src/r3-socket-cast.js | 119 + src/r3-socket-receive.js | 123 + src/r3-sockets-runtime.js | 66 + src/r3-sphere.js | 86 + src/r3-statistics-runtime.js | 59 + src/r3-stats.js | 103 + src/r3-system-0.js | 104 + src/r3-system-animation.js | 1162 +++++++++ src/r3-system-audio.js | 292 +++ src/r3-system-custom-code.js | 157 ++ src/r3-system-gui.js | 2311 +++++++++++++++++ src/r3-system-input.js | 1793 +++++++++++++ src/r3-system-linking.js | 930 +++++++ src/r3-system-particle.js | 325 +++ src/r3-system-physics.js | 151 ++ src/r3-system-render.js | 827 ++++++ src/r3-system-socket.js | 176 ++ src/r3-system-storage.js | 996 +++++++ src/r3-system-visualization.js | 148 ++ src/r3-vector2.js | 291 +++ src/r3-vector3.js | 193 ++ src/r3-vector4.js | 86 + src/r3-z.js | 10 + 352 files changed, 55309 insertions(+) create mode 100644 src/r3-a-0.js create mode 100644 src/r3-a-1-event.js create mode 100644 src/r3-a-2-utils.js create mode 100644 src/r3-a-api-component.js create mode 100644 src/r3-a-component-a.js create mode 100644 src/r3-api-box3.js create mode 100644 src/r3-api-canvas.js create mode 100644 src/r3-api-clock.js create mode 100644 src/r3-api-color.js create mode 100644 src/r3-api-controls-0.js create mode 100644 src/r3-api-controls-d3-editor.js create mode 100644 src/r3-api-controls-d3-first-person.js create mode 100644 src/r3-api-controls-d3-orbit.js create mode 100644 src/r3-api-controls-keyboard.js create mode 100644 src/r3-api-controls-mouse.js create mode 100644 src/r3-api-controls-touch.js create mode 100644 src/r3-api-curve-a.js create mode 100644 src/r3-api-curve-path-a.js create mode 100644 src/r3-api-curve-path-d2-a.js create mode 100644 src/r3-api-curve-path-d2-shape.js create mode 100644 src/r3-api-custom-code.js create mode 100644 src/r3-api-dom-element.js create mode 100644 src/r3-api-draw-range.js create mode 100644 src/r3-api-entity-manager.js create mode 100644 src/r3-api-entity.js create mode 100644 src/r3-api-graphics-runtime-a.js create mode 100644 src/r3-api-graphics-runtime-impact.js create mode 100644 src/r3-api-graphics-runtime-three.js create mode 100644 src/r3-api-group.js create mode 100644 src/r3-api-gui.js create mode 100644 src/r3-api-image.js create mode 100644 src/r3-api-matrix4.js create mode 100644 src/r3-api-mouse.js create mode 100644 src/r3-api-number.js create mode 100644 src/r3-api-plane.js create mode 100644 src/r3-api-quaternion-a.js create mode 100644 src/r3-api-quaternion-points.js create mode 100644 src/r3-api-render-configuration.js create mode 100644 src/r3-api-renderer-a.js create mode 100644 src/r3-api-renderer-d2.js create mode 100644 src/r3-api-renderer-d3.js create mode 100644 src/r3-api-server.js create mode 100644 src/r3-api-socket-0.js create mode 100644 src/r3-api-socket-cast.js create mode 100644 src/r3-api-socket-receive.js create mode 100644 src/r3-api-sphere.js create mode 100644 src/r3-api-stats.js create mode 100644 src/r3-api-system.js create mode 100644 src/r3-api-vector2.js create mode 100644 src/r3-api-vector3.js create mode 100644 src/r3-api-vector4.js create mode 100644 src/r3-box3.js create mode 100644 src/r3-canvas.js create mode 100644 src/r3-clock.js create mode 100644 src/r3-coder-runtime.js create mode 100644 src/r3-color.js create mode 100644 src/r3-controls-0.js create mode 100644 src/r3-controls-d3-editor.js create mode 100644 src/r3-controls-d3-first-person.js create mode 100644 src/r3-controls-d3-orbit.js create mode 100644 src/r3-controls-keyboard.js create mode 100644 src/r3-controls-mouse.js create mode 100644 src/r3-controls-touch.js create mode 100644 src/r3-curve-a.js create mode 100644 src/r3-curve-path-a.js create mode 100644 src/r3-curve-path-d2-a.js create mode 100644 src/r3-curve-path-d2-shape.js create mode 100644 src/r3-custom-code.js create mode 100644 src/r3-d3-api-a-object.js create mode 100644 src/r3-d3-api-animation.js create mode 100644 src/r3-d3-api-audio.js create mode 100644 src/r3-d3-api-bone-weight.js create mode 100644 src/r3-d3-api-bone.js create mode 100644 src/r3-d3-api-broadphase.js create mode 100644 src/r3-d3-api-camera-a.js create mode 100644 src/r3-d3-api-camera-cube.js create mode 100644 src/r3-d3-api-camera-orthographic.js create mode 100644 src/r3-d3-api-camera-perspective.js create mode 100644 src/r3-d3-api-camera-stereo-a.js create mode 100644 src/r3-d3-api-composer.js create mode 100644 src/r3-d3-api-effect-a.js create mode 100644 src/r3-d3-api-effect-anaglyph.js create mode 100644 src/r3-d3-api-effect-parallax.js create mode 100644 src/r3-d3-api-effect-stereo.js create mode 100644 src/r3-d3-api-face.js create mode 100644 src/r3-d3-api-fog.js create mode 100644 src/r3-d3-api-font.js create mode 100644 src/r3-d3-api-friction-contact-material.js create mode 100644 src/r3-d3-api-friction-material.js create mode 100644 src/r3-d3-api-geometry-a.js create mode 100644 src/r3-d3-api-geometry-buffer-a.js create mode 100644 src/r3-d3-api-geometry-buffer-box.js create mode 100644 src/r3-d3-api-geometry-buffer-circle.js create mode 100644 src/r3-d3-api-geometry-buffer-cone.js create mode 100644 src/r3-d3-api-geometry-buffer-cylinder.js create mode 100644 src/r3-d3-api-geometry-buffer-dodecahedron.js create mode 100644 src/r3-d3-api-geometry-buffer-extrude.js create mode 100644 src/r3-d3-api-geometry-buffer-icosahedron.js create mode 100644 src/r3-d3-api-geometry-buffer-instanced.js create mode 100644 src/r3-d3-api-geometry-buffer-lathe.js create mode 100644 src/r3-d3-api-geometry-buffer-octahedron.js create mode 100644 src/r3-d3-api-geometry-buffer-parametric.js create mode 100644 src/r3-d3-api-geometry-buffer-plane.js create mode 100644 src/r3-d3-api-geometry-buffer-polyhedron.js create mode 100644 src/r3-d3-api-geometry-buffer-ring.js create mode 100644 src/r3-d3-api-geometry-buffer-shape.js create mode 100644 src/r3-d3-api-geometry-buffer-sphere.js create mode 100644 src/r3-d3-api-geometry-buffer-tetrahedron.js create mode 100644 src/r3-d3-api-geometry-buffer-text.js create mode 100644 src/r3-d3-api-geometry-buffer-torus-knot.js create mode 100644 src/r3-d3-api-geometry-buffer-torus.js create mode 100644 src/r3-d3-api-geometry-buffer-tube.js create mode 100644 src/r3-d3-api-geometry-normal-a.js create mode 100644 src/r3-d3-api-geometry-normal-box.js create mode 100644 src/r3-d3-api-geometry-normal-circle.js create mode 100644 src/r3-d3-api-geometry-normal-cone.js create mode 100644 src/r3-d3-api-geometry-normal-cylinder.js create mode 100644 src/r3-d3-api-geometry-normal-dodecahedron.js create mode 100644 src/r3-d3-api-geometry-normal-edges.js create mode 100644 src/r3-d3-api-geometry-normal-extrude.js create mode 100644 src/r3-d3-api-geometry-normal-icosahedron.js create mode 100644 src/r3-d3-api-geometry-normal-lathe.js create mode 100644 src/r3-d3-api-geometry-normal-octahedron.js create mode 100644 src/r3-d3-api-geometry-normal-parametric.js create mode 100644 src/r3-d3-api-geometry-normal-plane.js create mode 100644 src/r3-d3-api-geometry-normal-polyhedron.js create mode 100644 src/r3-d3-api-geometry-normal-ring.js create mode 100644 src/r3-d3-api-geometry-normal-shape.js create mode 100644 src/r3-d3-api-geometry-normal-sphere.js create mode 100644 src/r3-d3-api-geometry-normal-tetrahedron.js create mode 100644 src/r3-d3-api-geometry-normal-text.js create mode 100644 src/r3-d3-api-geometry-normal-torus-knot.js create mode 100644 src/r3-d3-api-geometry-normal-torus.js create mode 100644 src/r3-d3-api-geometry-normal-tube.js create mode 100644 src/r3-d3-api-geometry-normal-wireframe.js create mode 100644 src/r3-d3-api-light-a.js create mode 100644 src/r3-d3-api-light-ambient.js create mode 100644 src/r3-d3-api-light-directional.js create mode 100644 src/r3-d3-api-light-hemisphere.js create mode 100644 src/r3-d3-api-light-point.js create mode 100644 src/r3-d3-api-light-rect-area.js create mode 100644 src/r3-d3-api-light-spot.js create mode 100644 src/r3-d3-api-material-a.js create mode 100644 src/r3-d3-api-material-basic.js create mode 100644 src/r3-d3-api-material-phong.js create mode 100644 src/r3-d3-api-material-points.js create mode 100644 src/r3-d3-api-material-shader-a.js create mode 100644 src/r3-d3-api-material-shader-raw.js create mode 100644 src/r3-d3-api-material-standard.js create mode 100644 src/r3-d3-api-mesh-0.js create mode 100644 src/r3-d3-api-particle-engine.js create mode 100644 src/r3-d3-api-particle.js create mode 100644 src/r3-d3-api-pass-0.js create mode 100644 src/r3-d3-api-pass-bloom.js create mode 100644 src/r3-d3-api-pass-fxaa.js create mode 100644 src/r3-d3-api-pass-render.js create mode 100644 src/r3-d3-api-pass-ssao.js create mode 100644 src/r3-d3-api-physics-world.js create mode 100644 src/r3-d3-api-raycast-vehicle.js create mode 100644 src/r3-d3-api-raycast-wheel.js create mode 100644 src/r3-d3-api-raycaster.js create mode 100644 src/r3-d3-api-render-target-a.js create mode 100644 src/r3-d3-api-render-target-cube.js create mode 100644 src/r3-d3-api-rigid-body.js create mode 100644 src/r3-d3-api-scene.js create mode 100644 src/r3-d3-api-shader-a.js create mode 100644 src/r3-d3-api-shader-fragment.js create mode 100644 src/r3-d3-api-shader-vertex.js create mode 100644 src/r3-d3-api-shadow-a.js create mode 100644 src/r3-d3-api-shadow-directional.js create mode 100644 src/r3-d3-api-shadow-spot.js create mode 100644 src/r3-d3-api-shape.js create mode 100644 src/r3-d3-api-skeleton.js create mode 100644 src/r3-d3-api-solver.js create mode 100644 src/r3-d3-api-spline.js create mode 100644 src/r3-d3-api-text.js create mode 100644 src/r3-d3-api-texture-a.js create mode 100644 src/r3-d3-api-texture-canvas.js create mode 100644 src/r3-d3-api-texture-cube.js create mode 100644 src/r3-d3-api-texture-image.js create mode 100644 src/r3-d3-api-vertex.js create mode 100644 src/r3-d3-api-viewport.js create mode 100644 src/r3-d3-api-z-animation.js create mode 100644 src/r3-d3-api-z-object.js create mode 100644 src/r3-d3-audio.js create mode 100644 src/r3-d3-bone-weight.js create mode 100644 src/r3-d3-bone.js create mode 100644 src/r3-d3-broadphase.js create mode 100644 src/r3-d3-camera-a.js create mode 100644 src/r3-d3-camera-cube.js create mode 100644 src/r3-d3-camera-orthographic.js create mode 100644 src/r3-d3-camera-perspective.js create mode 100644 src/r3-d3-camera-stereo.js create mode 100644 src/r3-d3-composer.js create mode 100644 src/r3-d3-effect-a.js create mode 100644 src/r3-d3-effect-anaglyph.js create mode 100644 src/r3-d3-effect-parallax.js create mode 100644 src/r3-d3-effect-stereo.js create mode 100644 src/r3-d3-face.js create mode 100644 src/r3-d3-fog.js create mode 100644 src/r3-d3-font.js create mode 100644 src/r3-d3-friction-contact-material.js create mode 100644 src/r3-d3-friction-material.js create mode 100644 src/r3-d3-geometry-a.js create mode 100644 src/r3-d3-geometry-buffer-a.js create mode 100644 src/r3-d3-geometry-buffer-box.js create mode 100644 src/r3-d3-geometry-buffer-circle.js create mode 100644 src/r3-d3-geometry-buffer-cone.js create mode 100644 src/r3-d3-geometry-buffer-cylinder.js create mode 100644 src/r3-d3-geometry-buffer-dodecahedron.js create mode 100644 src/r3-d3-geometry-buffer-extrude.js create mode 100644 src/r3-d3-geometry-buffer-icosahedron.js create mode 100644 src/r3-d3-geometry-buffer-instanced.js create mode 100644 src/r3-d3-geometry-buffer-lathe.js create mode 100644 src/r3-d3-geometry-buffer-octahedron.js create mode 100644 src/r3-d3-geometry-buffer-parametric.js create mode 100644 src/r3-d3-geometry-buffer-plane.js create mode 100644 src/r3-d3-geometry-buffer-polyhedron.js create mode 100644 src/r3-d3-geometry-buffer-ring.js create mode 100644 src/r3-d3-geometry-buffer-shape.js create mode 100644 src/r3-d3-geometry-buffer-sphere.js create mode 100644 src/r3-d3-geometry-buffer-tetrahedron.js create mode 100644 src/r3-d3-geometry-buffer-text.js create mode 100644 src/r3-d3-geometry-buffer-torus-knot.js create mode 100644 src/r3-d3-geometry-buffer-torus.js create mode 100644 src/r3-d3-geometry-buffer-tube.js create mode 100644 src/r3-d3-geometry-normal-a.js create mode 100644 src/r3-d3-geometry-normal-box.js create mode 100644 src/r3-d3-geometry-normal-circle.js create mode 100644 src/r3-d3-geometry-normal-cone.js create mode 100644 src/r3-d3-geometry-normal-cylinder.js create mode 100644 src/r3-d3-geometry-normal-dodecahedron.js create mode 100644 src/r3-d3-geometry-normal-edges.js create mode 100644 src/r3-d3-geometry-normal-extrude.js create mode 100644 src/r3-d3-geometry-normal-icosahedron.js create mode 100644 src/r3-d3-geometry-normal-lathe.js create mode 100644 src/r3-d3-geometry-normal-octahedron.js create mode 100644 src/r3-d3-geometry-normal-parametric.js create mode 100644 src/r3-d3-geometry-normal-plane.js create mode 100644 src/r3-d3-geometry-normal-polyhedron.js create mode 100644 src/r3-d3-geometry-normal-ring.js create mode 100644 src/r3-d3-geometry-normal-shape.js create mode 100644 src/r3-d3-geometry-normal-sphere.js create mode 100644 src/r3-d3-geometry-normal-tetrahedron.js create mode 100644 src/r3-d3-geometry-normal-text.js create mode 100644 src/r3-d3-geometry-normal-torus-knot.js create mode 100644 src/r3-d3-geometry-normal-torus.js create mode 100644 src/r3-d3-geometry-normal-tube.js create mode 100644 src/r3-d3-geometry-normal-wireframe.js create mode 100644 src/r3-d3-helper.js create mode 100644 src/r3-d3-light-a.js create mode 100644 src/r3-d3-light-ambient.js create mode 100644 src/r3-d3-light-directional.js create mode 100644 src/r3-d3-light-hemisphere.js create mode 100644 src/r3-d3-light-point.js create mode 100644 src/r3-d3-light-rect-area.js create mode 100644 src/r3-d3-light-spot.js create mode 100644 src/r3-d3-material-a.js create mode 100644 src/r3-d3-material-basic.js create mode 100644 src/r3-d3-material-phong.js create mode 100644 src/r3-d3-material-points.js create mode 100644 src/r3-d3-material-shader-a.js create mode 100644 src/r3-d3-material-shader-raw.js create mode 100644 src/r3-d3-material-standard.js create mode 100644 src/r3-d3-mesh-0.js create mode 100644 src/r3-d3-particle-engine.js create mode 100644 src/r3-d3-particle.js create mode 100644 src/r3-d3-pass-0.js create mode 100644 src/r3-d3-pass-bloom.js create mode 100644 src/r3-d3-pass-fxaa.js create mode 100644 src/r3-d3-pass-render.js create mode 100644 src/r3-d3-pass-ssao.js create mode 100644 src/r3-d3-physics-world.js create mode 100644 src/r3-d3-poly-vertex.js create mode 100644 src/r3-d3-raycast-vehicle.js create mode 100644 src/r3-d3-raycast-wheel.js create mode 100644 src/r3-d3-raycaster.js create mode 100644 src/r3-d3-render-target-a.js create mode 100644 src/r3-d3-render-target-cube.js create mode 100644 src/r3-d3-rigid-body.js create mode 100644 src/r3-d3-scene.js create mode 100644 src/r3-d3-shader-a.js create mode 100644 src/r3-d3-shader-fragment.js create mode 100644 src/r3-d3-shader-vertex.js create mode 100644 src/r3-d3-shadow-a.js create mode 100644 src/r3-d3-shadow-directional.js create mode 100644 src/r3-d3-shadow-spot.js create mode 100644 src/r3-d3-shape-0.js create mode 100644 src/r3-d3-shape-box.js create mode 100644 src/r3-d3-shape-convex-hull-0.js create mode 100644 src/r3-d3-shape-convex-hull-cylinder.js create mode 100644 src/r3-d3-shape-height-map.js create mode 100644 src/r3-d3-shape-plane.js create mode 100644 src/r3-d3-shape-sphere.js create mode 100644 src/r3-d3-shape-tri-mesh.js create mode 100644 src/r3-d3-skeleton.js create mode 100644 src/r3-d3-solver.js create mode 100644 src/r3-d3-spline.js create mode 100644 src/r3-d3-text.js create mode 100644 src/r3-d3-texture-a.js create mode 100644 src/r3-d3-texture-canvas.js create mode 100644 src/r3-d3-texture-cube.js create mode 100644 src/r3-d3-texture-image.js create mode 100644 src/r3-d3-triangle-edge.js create mode 100644 src/r3-d3-vertex.js create mode 100644 src/r3-d3-viewport.js create mode 100644 src/r3-dom-element.js create mode 100644 src/r3-draw-range.js create mode 100644 src/r3-entity-manager.js create mode 100644 src/r3-entity.js create mode 100644 src/r3-graphics-runtime-a.js create mode 100644 src/r3-graphics-runtime-impact.js create mode 100644 src/r3-graphics-runtime-three.js create mode 100644 src/r3-group.js create mode 100644 src/r3-gui-runtime.js create mode 100644 src/r3-gui.js create mode 100644 src/r3-image.js create mode 100644 src/r3-matrix-4.js create mode 100644 src/r3-mouse.js create mode 100644 src/r3-number.js create mode 100644 src/r3-physics-runtime.js create mode 100644 src/r3-plane.js create mode 100644 src/r3-quaternion.js create mode 100644 src/r3-render-configuration.js create mode 100644 src/r3-renderer-a.js create mode 100644 src/r3-renderer-d2.js create mode 100644 src/r3-renderer-d3.js create mode 100644 src/r3-server.js create mode 100644 src/r3-socket-0.js create mode 100644 src/r3-socket-cast.js create mode 100644 src/r3-socket-receive.js create mode 100644 src/r3-sockets-runtime.js create mode 100644 src/r3-sphere.js create mode 100644 src/r3-statistics-runtime.js create mode 100644 src/r3-stats.js create mode 100644 src/r3-system-0.js create mode 100644 src/r3-system-animation.js create mode 100644 src/r3-system-audio.js create mode 100644 src/r3-system-custom-code.js create mode 100644 src/r3-system-gui.js create mode 100644 src/r3-system-input.js create mode 100644 src/r3-system-linking.js create mode 100644 src/r3-system-particle.js create mode 100644 src/r3-system-physics.js create mode 100644 src/r3-system-render.js create mode 100644 src/r3-system-socket.js create mode 100644 src/r3-system-storage.js create mode 100644 src/r3-system-visualization.js create mode 100644 src/r3-vector2.js create mode 100644 src/r3-vector3.js create mode 100644 src/r3-vector4.js create mode 100644 src/r3-z.js diff --git a/src/r3-a-0.js b/src/r3-a-0.js new file mode 100644 index 0000000..33c0616 --- /dev/null +++ b/src/r3-a-0.js @@ -0,0 +1,59 @@ +/** + * R3 Namespace + */ +if (typeof R3 === 'undefined') { + function R3() {} +} + +/** + * R3.D3 Namespace + */ +if (typeof R3.D3 === 'undefined') { + R3.D3 = function(){}; +} + +/** + * R3.D3.API Namespace + * @constructor + */ +if (typeof R3.D3.API === 'undefined') { + R3.D3.API = function(){}; +} + +/** + * R3.API Namespace + */ +if (typeof R3.API === 'undefined') { + R3.API = function(){}; +} + +/** + * R3.D3.Runtime Namespace + * @constructor + */ +if (typeof R3.D3.Runtime === 'undefined') { + R3.D3.Runtime = function(){}; +} + +// if (typeof Q === 'undefined') { +// +// if (typeof require === 'undefined') { +// console.warn('You need the Q promise library for the R3.D3'); +// throw new Error('You need the Q promise library for the R3.D3'); +// } +// +// var Q = require('q'); +// } +// +// if (typeof _ === 'undefined') { +// +// if (typeof require === 'undefined') { +// console.warn('You need the lodash library for the R3.D3'); +// throw new Error('You need the lodash library for the R3.D3'); +// } +// +// var _ = require('lodash'); +// } + +// This gets injected by gulp +console.log("Loading R3 compiled at: " + __DATE__); diff --git a/src/r3-a-1-event.js b/src/r3-a-1-event.js new file mode 100644 index 0000000..808c064 --- /dev/null +++ b/src/r3-a-1-event.js @@ -0,0 +1,486 @@ +/** + * Event Core + * @constructor + */ +R3.Event = function() { +}; + +/** + * Some nice Events handling + * @type {{}} + */ +R3.Event.Subscriptions = {}; +R3.Event.OnceSubscriptions = {}; + +/** + * Events we can subscribe to and publish + */ +R3.Event.WINDOW_RESIZE = 0x1; +R3.Event.PARENT_SCENE_CHANGE = 0x2; +R3.Event.EXCLUDE_FROM_ENVIRONMENT = 0x3; +R3.Event.INSTANCE_CLONED = 0x4; +R3.Event.LOAD_IMAGE = 0x5; +R3.Event.NEW_ENTITY = 0x6; +R3.Event.MATERIAL_TYPE_CHANGED = 0x7; +R3.Event.SAVE_COMPONENT = 0x8; +R3.Event.SAVE_COMPONENT_ERROR = 0x9; +R3.Event.COMPONENT_SAVED = 0xa; +R3.Event.LOAD_COMPONENT = 0xb; +R3.Event.LOAD_COMPONENT_ERROR = 0xc; +R3.Event.LOGGED_IN = 0xd; +R3.Event.COMPONENT_CREATED = 0xe; +R3.Event.COMPONENT_CLONED = 0xf; +R3.Event.TEXTURE_ANIMATED_CHANGE = 0x10; +R3.Event.ANIMATE_TEXTURE_INSTANCE = 0x11; +R3.Event.REMOVE_PARTICLE_ENGINE = 0x12; +R3.Event.GAME_PAUSE = 0x13; +R3.Event.SHADER_UPDATE = 0x14; +R3.Event.PLAY_AUDIO = 0x15; +R3.Event.MATERIAL_INSTANCE_UPDATED = 0x16; +R3.Event.PAUSE_AUDIO = 0x17; +R3.Event.MESH_INSTANCE_UPDATED = 0x18; +R3.Event.STOP_AUDIO = 0x19; +R3.Event.LIGHT_INSTANCE_UPDATED = 0x1a; +R3.Event.DELETE_COMPONENT = 0x1b; +R3.Event.COMPONENT_DOWNLOAD_COMPLETE = 0x1c; +R3.Event.COMPONENTS_LINKED = 0x1d; +R3.Event.UNRESOLVED_DEPENDENCIES_UPDATE = 0x1e; +R3.Event.REGISTER_UPDATE = 0x1f; +R3.Event.BUILD_GUI = 0x20; +R3.Event.REMOVE_MESH = 0x21; +R3.Event.MESH_SELECTED = 0x22; +R3.Event.MESH_DESELECTED = 0x23; +R3.Event.COMPONENT_REGISTER = 0x24; +R3.Event.IMAGE_NOT_FOUND = 0x25; +R3.Event.BLENDER_DATA_RECEIVED = 0x26; +R3.Event.IMAGE_UPLOAD_COMPLETE = 0x27; +R3.Event.REMOVE_COMPONENT = 0x28; +R3.Event.KEY_DOWN = 0x29; +R3.Event.KEY_UP = 0x2a; +R3.Event.RENDER = 0x2b; +R3.Event.EVENT_LIST = 0x2c; +R3.Event.COMPILE_SUCCESS = 0x2d; +R3.Event.COMPILE_FAILED = 0x2e; +R3.Event.TEXTURE_INSTANCE_UPDATED = 0x2f; +R3.Event.EVENT_ID_UPDATE = 0x30; +R3.Event.MATERIAL_TEXTURES_UPDATED = 0x31; +R3.Event.DELETE_COMPONENT_ERROR = 0x32; +R3.Event.COMPONENT_DELETED = 0x33; +R3.Event.COMPONENT_TYPES_FETCHED = 0x34; +R3.Event.AUDIO_ENDED = 0x35; +R3.Event.COMPONENT_LINKED = 0x36; +R3.Event.DONE_SAVING = 0x37; +R3.Event.BEFORE_RENDER = 0x38; +R3.Event.AFTER_RENDER = 0x39; +R3.Event.ARRAY_ITEM_ADDED = 0x3a; +R3.Event.INSTANCE_CREATED = 0x3b; +R3.Event.VISUALIZE = 0x3c; +R3.Event.STOP_VISUALIZE = 0x3d; +R3.Event.FETCH_COMPONENT_TYPES = 0x3e; +R3.Event.FETCH_COMPONENTS = 0x3f; +R3.Event.GET_API_URL = 0x40; +R3.Event.GET_RUNTIME = 0x41; +R3.Event.PARENT_WORLD_CHANGE = 0x42; +R3.Event.ANIMATE = 0x43; +R3.Event.ANIMATION_COMPILE_SUCCESS = 0x44; +R3.Event.ANIMATION_COMPILE_FAILED = 0x45; +R3.Event.SAVING = 0x46; +R3.Event.GAME_OVER = 0x47; +R3.Event.GAME_START = 0x48; +R3.Event.TOUCH_START = 0x49; +R3.Event.TOUCH_END = 0x4a; +R3.Event.TOUCH_MOVE = 0x4b; +R3.Event.TOUCH_CANCEL = 0x4c; +R3.Event.GET_REMOTE_API_URL = 0x4d; +R3.Event.COMPONENT_TYPES_UPDATE = 0x4e; +R3.Event.DELAYED_INSTANCE_ENCOUNTERED = 0x4f; +R3.Event.CAST_SOURCE_CHANGED = 0x50; +R3.Event.RESOLVE_DEPENDENCIES = 0x51; +R3.Event.NAME_UPDATE = 0x52; +R3.Event.CANVAS_CHANGE = 0x53; +R3.Event.AFTER_WINDOW_RESIZE = 0x54; +R3.Event.LOAD_FONT = 0x55; +R3.Event.FONT_NOT_FOUND = 0x56; +R3.Event.STOP_ALL_AUDIO = 0x57; +R3.Event.REGISTER_DEPENDENCIES = 0x58; +R3.Event.GAME_LOADED = 0x59; +R3.Event.COMPONENT_UPDATE = 0x5a; +R3.Event.LOAD_PROGRESS = 0x5b; +R3.Event.ENTITY_LOADED = 0x5c; +R3.Event.MOUSE_DOWN = 0x5d; +R3.Event.MOUSE_MOVE = 0x5e; +R3.Event.MOUSE_WHEEL = 0x5f; +R3.Event.MOUSE_UP = 0x60; +R3.Event.PARTICLE_INSTANCE_UPDATED = 0x61; +R3.Event.GAME_DATA = 0x62; +R3.Event.PAUSE_ALL_AUDIO = 0x63; +R3.Event.CONTINUE_ALL_AUDIO = 0x64; +R3.Event.MUTE_AUDIO = 0x65; +R3.Event.GAME_STARTED = 0x66; +R3.Event.GAME_PAUSED = 0x67; +R3.Event.GAME_RESUMED = 0x68; +R3.Event.CUSTOM_GAME_START = 0x69; +R3.Event.AUDIO_MUTED = 0x6a; +R3.Event.AUDIO_UNMUTED = 0x6b; +R3.Event.RECEIVE_DESTINATION_CHANGED = 0x6c; +R3.Event.SELECTION_MODE_CHANGE = 0x6d; +R3.Event.MESH_FACE_SELECTED = 0x6e; +R3.Event.MESH_FACE_DESELECTED = 0x6f; +R3.Event.BEFORE_WINDOW_RESIZE = 0x70; +R3.Event.GET_WINDOW_SIZE = 0x71; +R3.Event.GET_RENDER_CONFIGURATION = 0x72; +R3.Event.SET_ACTIVE_RENDER_CONFIGURATION = 0x73; +R3.Event.REPLACE_COMPONENT = 0x74; +R3.Event.COMPONENT_REPLACED = 0x75; +R3.Event.ENGINE_FIRED_PARTICLES_ZERO = 0x76; + +/** + * Returns string name of event ID + * @param number + * @returns {*} + * @constructor + */ +R3.Event.GetEventName = function(number) { + + switch(number) { + case 0x1 : return 'window_resize'; + case 0x2 : return 'parent_scene_change'; + case 0x3 : return 'unused'; + case 0x4 : return 'instance_cloned'; + case 0x5 : return 'load_image'; + case 0x6 : return 'new_entity'; + case 0x7 : return 'material_type_changed'; + case 0x8 : return 'save_component'; + case 0x9 : return 'save_component_error'; + case 0xa : return 'component_saved'; + case 0xb : return 'load_component'; + case 0xc : return 'load_component_error'; + case 0xd : return 'logged_in'; + case 0xe : return 'component_created'; + case 0xf : return 'component_cloned'; + case 0x10 : return 'texture_animated_change'; + case 0x11 : return 'animate_texture_instance'; + case 0x12 : return 'remove_particle_engine'; + case 0x13 : return 'pause'; + case 0x14 : return 'shader_update'; + case 0x15 : return 'play_audio'; + case 0x16 : return 'material_instance_updated'; + case 0x17 : return 'pause_audio'; + case 0x18 : return 'mesh_instance_updated'; + case 0x19 : return 'stop_audio'; + case 0x1a : return 'light_instance_updated'; + case 0x1b : return 'delete_component'; + case 0x1c : return 'component_download_complete'; + case 0x1d : return 'components_linked'; + case 0x1e : return 'unresolved_dependencies_update'; + case 0x1f : return 'register_update'; + case 0x20 : return 'build_gui'; + case 0x21 : return 'remove_mesh'; + case 0x22 : return 'mesh_selected'; + case 0x23 : return 'mesh_deselected'; + case 0x24 : return 'component_register'; + case 0x25 : return 'image_not_found'; + case 0x26 : return 'blender_data_received'; + case 0x27 : return 'image_upload_complete'; + case 0x28 : return 'remove_component'; + case 0x29 : return 'key_down'; + case 0x2a : return 'key_up'; + case 0x2b : return 'render'; + case 0x2c : return 'event_list'; + case 0x2d : return 'compile_success'; + case 0x2e : return 'compile_failed'; + case 0x2f : return 'texture_image_updated'; + case 0x30 : return 'event_id_update'; + case 0x31 : return 'material_textures_updated'; + case 0x32 : return 'delete_component_error'; + case 0x33 : return 'component_deleted'; + case 0x34 : return 'component_types_updated'; + case 0x35 : return 'audio_ended'; + case 0x36 : return 'component_linked'; + case 0x37 : return 'done_saving'; + case 0x38 : return 'before_render'; + case 0x39 : return 'after_render'; + case 0x3a : return 'array_item_added'; + case 0x3b : return 'instance_created'; + case 0x3c : return 'visualize'; + case 0x3d : return 'stop_visualize'; + case 0x3e : return 'fetch_component_types'; + case 0x3f : return 'fetch_components'; + case 0x40 : return 'get_api_url'; + case 0x41 : return 'get_runtime'; + case 0x42 : return 'parent_world_change'; + case 0x43 : return 'animate'; + case 0x44 : return 'animation_compile_success'; + case 0x45 : return 'animation_compile_failed'; + case 0x46 : return 'saving'; + case 0x47 : return 'game_over'; + case 0x48 : return 'game_start'; + case 0x49 : return 'touch_start'; + case 0x4a : return 'touch_end'; + case 0x4b : return 'touch_move'; + case 0x4c : return 'touch_cancel'; + case 0x4d : return 'get_remote_api_url'; + case 0x4e : return 'component_types_update'; + case 0x4f : return 'delayed_instance_encountered'; + case 0x50 : return 'cast_source_changed'; + case 0x51 : return 'resolve_dependencies';; + case 0x52 : return 'name_update'; + case 0x53 : return 'dom_element_change'; + case 0x54 : return 'after_window_resize'; + case 0x55 : return 'load_font'; + case 0x56 : return 'font_not_found'; + case 0x57 : return 'stop_all_audio'; + case 0x58 : return 'register_dependencies'; + case 0x59 : return 'game_loaded'; + case 0x5a : return 'component_update'; + case 0x5b : return 'load_progress'; + case 0x5c : return 'entity_loaded'; + case 0x5d : return 'mouse_down'; + case 0x5e : return 'mouse_move'; + case 0x5f : return 'mouse_wheel'; + case 0x60 : return 'mouse_up'; + case 0x61 : return 'particle_instance_updated'; + case 0x62 : return 'game_data'; + case 0x63 : return 'pause_all_audio'; + case 0x64 : return 'continue_all_audio'; + case 0x65 : return 'mute_audio'; + case 0x66 : return 'game_started'; + case 0x67 : return 'game_paused'; + case 0x68 : return 'game_resumed'; + case 0x69 : return 'custom_game_start'; + case 0x6a : return 'audio_muted'; + case 0x6b : return 'audio_unmuted'; + case 0x6c : return 'receive_destination_changed'; + case 0x6d : return 'selection_mode_change'; + case 0x6e : return 'mesh_face_selected'; + case 0x6f : return 'mesh_face_deselected'; + case 0x70 : return 'before_window_resize'; + case 0x71 : return 'get_window_size'; + case 0x72 : return 'get_render_configuration'; + case 0x73 : return 'set_active_render_configuration'; + case 0x74 : return 'replace_component'; + case 0x75 : return 'component_replaced'; + case 0x76 : return 'engine_fired_particles_zero'; + break; + } + + throw new error('unknown event id: ' + number ); +}; + +/** + * Subscribe to some events + * @param eventName + * @param callback + */ +R3.Event.prototype.subscribe = function( + eventName, + callback +) { + return R3.Event.Subscribe(eventName, callback.bind(this)); +}; + + +// /** +// * Stop listening for this event after the callback returns true +// * @param eventName +// * @param callback +// * @returns {{fn, remove: remove}} +// */ +// R3.Event.prototype.subscribeOnce = function( +// eventName, +// callback +// ) { +// throw new Error('implement first properly'); +// // var fn = callback.bind(this); +// // +// // if (R3.Event.OnceSubscriptions.hasOwnProperty(eventName)) { +// // R3.Event.OnceSubscriptions[eventName].push(fn); +// // } else { +// // R3.Event.OnceSubscriptions[eventName] = []; +// // R3.Event.OnceSubscriptions[eventName].push(fn); +// // } +// // +// // /** +// // * Return a handle to the caller to allow us to unsubscribe to this event +// // */ +// // return { +// // fn : fn, +// // remove : function() { +// // R3.Event.Subscriptions[eventName].splice( +// // R3.Event.Subscriptions[eventName].indexOf(fn), +// // 1 +// // ); +// // } +// // } +// }; + +/** + * + * @param eventName + * @param data + */ +/** + * Publish some event happened with some data + * @param eventName + * @param data + * @param clientCallback + * @param clientErrorCallback + * @returns {number} of callbacks executed + */ +R3.Event.prototype.publish = function( + eventName, + data, + clientCallback, + clientErrorCallback +) { + return R3.Event.Emit( + eventName, + data, + clientCallback, + clientErrorCallback + ); +}; + +/** + * Static method call + * @param eventName + * @param data + * @param clientCallback is executed ideally when the event completed + * @param clientErrorCallback + * @returns {number} of callbacks executed + * @constructor + */ +R3.Event.Emit = function( + eventName, + data, + clientCallback, + clientErrorCallback +) { + + var count = 0; + + if (R3.Event.Subscriptions.hasOwnProperty(eventName)) { + + if (R3.Event.Subscriptions[eventName].length === 0) { + + if (clientCallback) { + /** + * We execute the client callback immediately since there are no subscriptions to this event + */ + clientCallback(); + } + + if (clientErrorCallback) { + clientErrorCallback({ + message : 'No subscriptions for event ' + eventName + }) + } + } + + /** + * We need to execute all the callbacks, but not execute them twice, but also keep in mind they can remove + * themselves during execution + */ + // var length = R3.Event.Subscriptions[eventName].length; + // + // for (var i = 0; i < length; i++) { + // + // var object = R3.Event.Subscriptions[eventName][i]; + // + // if (object.fn && object.executed === false) { + // object.fn(data, clientCallback, clientErrorCallback); + // object.executed = true; + // } + // + // if (length !== R3.Event.Subscriptions[eventName].length) { + // /** + // * this callback removed a subscription - reset i and reset the length + // */ + // i = 0; + // length = R3.Event.Subscriptions[eventName].length; + // } + // } + // + // R3.Event.Subscriptions[eventName].map( + // function(object){ + // object.executed = false; + // } + // ) + + R3.Event.Subscriptions[eventName].map( + function(callback) { + if (callback) { + callback(data, clientCallback, clientErrorCallback); + count++; + } + } + ) + } else { + if (clientCallback) { + /** + * We execute the client callback immediately since there are no subscriptions to this event + */ + clientCallback(); + } + + if (clientErrorCallback) { + clientErrorCallback({ + message : 'No subscriptions for event ' + eventName + }) + } + } + + return count; +}; + +R3.Event.Subscribe = function( + eventName, + fn +) { + + if (R3.Event.Subscriptions.hasOwnProperty(eventName)) { + R3.Event.Subscriptions[eventName].push(fn); + // { + // fn : fn, + // executed : false + // } + // ); + } else { + R3.Event.Subscriptions[eventName] = []; + R3.Event.Subscriptions[eventName].push(fn); + // { + // fn : fn, + // executed : false + // } + // ); + } + + /** + * Return a handle to the caller to allow us to unsubscribe to this event + */ + return { + fn : fn, + remove : function() { + + var index = R3.Event.Subscriptions[eventName].indexOf(fn); + // reduce( + // function(result, object, index) { + // if (object.fn === fn) { + // result = index; + // } + // return result; + // }, + // -1 + // ); + + if (index === -1) { + throw new Error('could not remove subscription'); + } + + R3.Event.Subscriptions[eventName].splice( + index, + 1 + ); + } + } +}; \ No newline at end of file diff --git a/src/r3-a-2-utils.js b/src/r3-a-2-utils.js new file mode 100644 index 0000000..5c59a5e --- /dev/null +++ b/src/r3-a-2-utils.js @@ -0,0 +1,990 @@ +R3.Utils = function() {}; + +/** + * Strips image extension from given path + * @param imagePath + * @constructor + */ +R3.Utils.StripImageExtension = function(imagePath) { + return imagePath.replace(/(\.png$|\.gif$|\.jpeg$|\.jpg$)/,'') +}; + +R3.Utils.BuildVectorSource = function(result, name, dimension) { + + if (dimension === 2) { + result[name] = {}; + result[name].x = false; + result[name].y = false; + return; + } + + if (dimension === 3) { + result[name] = {}; + result[name].x = false; + result[name].y = false; + result[name].y = false; + return; + } + + if (dimension === 4) { + result[name] = {}; + result[name].x = false; + result[name].y = false; + result[name].z = false; + result[name].w = false; + return; + } + + console.warn('unknown dimension : ' + dimension); +}; + +/** + * Returns all 'instances' of the array, or null if an 'instance' is undefined + * @constructor + * @param array + */ +R3.Utils.GetArrayInstances = function(array) { + return array.reduce( + function(result, object) { + + if (result === null) { + return result; + } + + if (R3.Utils.UndefinedOrNull(object.instance)) { + result = null; + } else { + result.push(object.instance); + } + + return result; + }, + [] + ); +}; + +R3.Utils.SortFacesByMaterialIndex = function(faces) { + + /** + * Sorts faces according to material index because later we will create + * groups for each vertice group + */ + faces.sort(function (a, b) { + + if (a.materialIndex < b.materialIndex) { + return -1; + } + + if (a.materialIndex > b.materialIndex) { + return 1; + } + + return 0; + }); + + return faces; +}; + +R3.Utils.BuildQuaternionSource = function(result, name) { + result[name] = {}; + result[name].axis = {}; + result[name].axis.x = false; + result[name].axis.y = false; + result[name].axis.z = false; + result[name].angle = false; + result[name].x = false; + result[name].y = false; + result[name].z = false; + result[name].w = false; +}; + +R3.Utils.ObjectPropertiesAsBoolean = function(object) { + return Object.keys(object).reduce( + function(result, propertyId) { + + if (typeof object[propertyId] === 'function') { + return result; + } + + result[propertyId] = false; + + // if (object[propertyId] instanceof R3.Vector2) { + // R3.Utils.BuildVectorSource(result, propertyId, 2); + // } + // + // if (object[propertyId] instanceof R3.Vector3) { + // R3.Utils.BuildVectorSource(result, propertyId, 3); + // } + // + // if (object[propertyId] instanceof R3.Vector4) { + // R3.Utils.BuildVectorSource(result, propertyId, 4); + // } + // + // if (object[propertyId] instanceof R3.Quaternion) { + // R3.Utils.BuildQuaternionSource(result, propertyId); + // } + + return result; + + }.bind(this), + {} + ); +}; + +R3.Utils.GetRuntime = function() { + + var result = null; + + R3.Event.Emit( + R3.Event.GET_RUNTIME, + null, + function(runtime) { + result = runtime; + } + ); + + return result; +}; + +/** + * Returns the window size or null + * @returns {*} + * @constructor + */ +R3.Utils.GetWindowSize = function() { + + var size = null; + + R3.Event.Emit( + R3.Event.GET_WINDOW_SIZE, + null, + function (data) { + size = data; + }.bind(this) + ); + + return size; + +}; + +/** + * Convenience function to update object width and height members with window size + * @param object + * @constructor + */ +R3.Utils.UpdateWindowSize = function(object) { + var size = R3.Utils.GetWindowSize(); + object.width = size.width; + object.height = size.height; +}; + + +/** + * Returns id of object with the name if it exists in the array, otherwise null + * @param name + * @param array + * @returns {*} + * @constructor + */ +R3.Utils.ObjectIdWithNameInArray = function(name, array) { + + return array.reduce( + function(result, object) { + + if (result) { + return result; + } + + if (name === object.name) { + return object.id; + } + + return null; + }, + null + ); +}; + +// R3.Utils.ObjectFactory = function() { +// +// var promiseList = {}; +// +// return function(objectId) { +// +// if (!objectId) { +// console.log('No Object ID specified ' + objectId); +// throw new Error('No Object ID specified ' + objectId); +// } +// +// if (promiseList[objectId]) { +// return promiseList[objectId]; +// } +// +// var defer = Q.defer(); +// +// promiseList[objectId] = defer.promise; +// +// R3.Utils.ObjectFactory.Link(idToObject, objectId, defer); +// +// return promiseList[objectId]; +// } +// }; + +R3.Utils.LoadIdsFromArrayToIdObject = function(array, idToObject) { + +}; + +R3.Utils.LoadIdsFromObjectToIdObject = function(object, idToObject) { + + +}; + +/** + * Gets random int exclusive of maximum but inclusive of minimum + * @param min + * @param max + * @returns {*} + * @constructor + */ +R3.Utils.GetRandomInt = function(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive +}; + +/** + * Gets random int inclusive of minimum and maximum + * @param min + * @param max + * @returns {*} + * @constructor + */ +R3.Utils.GetRandomIntInclusive = function(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive +}; + +R3.Utils.InterpolateArray = function(data, fitCount) { + + var linearInterpolate = function (before, after, atPoint) { + return before + (after - before) * atPoint; + }; + + var newData = []; + + var springFactor = Number((data.length - 1) / (fitCount - 1)); + + newData[0] = data[0]; // for new allocation + + for ( var i = 1; i < fitCount - 1; i++) { + var tmp = i * springFactor; + var before = Number(Math.floor(tmp)).toFixed(); + var after = Number(Math.ceil(tmp)).toFixed(); + var atPoint = tmp - before; + newData[i] = linearInterpolate(data[before], data[after], atPoint); + } + + newData[fitCount - 1] = data[data.length - 1]; // for new allocation + + return newData; +}; + +/** + * Undefined or null check + * @param variable + * @returns {boolean} + * @constructor + */ +R3.Utils.UndefinedOrNull = function ( + variable +) { + return typeof variable === 'undefined' || variable === null; +}; + +/** + * The variable is not undefined and not null + * @param variable + * @returns {boolean} + * @constructor + */ +R3.Utils.Defined = function ( + variable +) { + return typeof variable !== 'undefined' && variable !== null; +}; + +/** + * Gets function parameters + * @param fn + * @constructor + */ +R3.Utils.GetParameters = function(fn) { + + var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; + var FN_ARG_SPLIT = /,/; + var FN_ARG = /^\s*(_?)(.+?)\1\s*$/; + var STRIP_COMMENTS = /(\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s*=[^,\)]*(('(?:\\'|[^'\r\n])*')|("(?:\\"|[^"\r\n])*"))|(\s*=[^,\)]*))/mg; + + var parameters, + fnText, + argDecl; + + if (typeof fn !== 'function') { + parameters = []; + fnText = fn.toString().replace(STRIP_COMMENTS, ''); + argDecl = fnText.match(FN_ARGS); + argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) { + arg.replace(FN_ARG, function(all, underscore, name) { + parameters.push(name); + }); + }); + } else { + throw Error("not a function") + } + + return parameters; +}; + +/** + * Returns either an ID of the object or Null + * @param object + * @returns {null} + * @constructor + */ +R3.Utils.IdOrNull = function (object) { + if (R3.Utils.UndefinedOrNull(object)) { + return null; + } else { + if (R3.Utils.UndefinedOrNull(object.id)) { + console.warn('saving an object reference with no ID : ', object); + return null; + } + return object.id; + } +}; + +/** + * Limit a property to values between -pi and +pi + * @param property + * @param objectProperty + * @returns {{configurable?: boolean, enumerable?: boolean, value?, writable?: boolean, get?: Function, set?: Function}} + * @constructor + */ +R3.Utils.LimitToPI = function(property, objectProperty) { + + var store = objectProperty; + + return { + get : function() { + return store; + }, + set : function(value) { + while (value > 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 + */ +R3.Utils.IdArrayOrEmptyArray = function (array) { + if (R3.Utils.UndefinedOrNull(array)) { + return []; + } else { + + return array.map(function(item) { + + if (R3.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 + */ +R3.Utils.Link = function(propertyString, idToObject, parentObject, id) { + + if (!R3.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 + */ +R3.Utils.RandomId = function(length) { + + if (R3.Utils.UndefinedOrNull(length)) { + length = 10; + } + + return Math.random().toString(36).substr(2, length); +}; + +R3.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 R3.D3.Mesh + * @returns {*} + * @constructor + */ +R3.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) + */ +R3.Utils.ResetWindingOrder = function(faces, vertices) { + + var vertexList = new R3.API.Vector3.Points(); + + for (var v = 0; v < vertices.length; v++) { + vertexList.add(new R3.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 ( + R3.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 R3.D3.Face[] + * @param orientationEdge R3.API.Vector2 + * @returns {Array} + */ +R3.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 R3.API.Vector2 + * @param faces R3.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 R3.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 R3.D3.TriangleEdge( + triangle, + edge + ); + } + } + + return null; + } + + var toProcess = [ + new R3.D3.TriangleEdge( + new R3.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 R3.API.Vector2( + triangleEdge.triangle.v0index, + triangleEdge.triangle.v1index + ), + new R3.API.Vector2( + triangleEdge.triangle.v1index, + triangleEdge.triangle.v2index + ), + new R3.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 [] + */ +R3.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 R3.API.Quaternion.Points(); + + for (var i = 0; i < verticesFlat.length; i += 3) { + points.add(new R3.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; +}; + +R3.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); + } +}; + +R3.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; + } + ); +}; + +R3.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 + */ +R3.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 + */ +R3.Utils.IsEmpty = function(obj) { + return (Object.keys(obj).length === 0 && obj.constructor === Object); +}; + +R3.Utils.isString = function(member) { + return (typeof member === 'string'); +}; + +R3.Utils.isBoolean = function(member) { + return (member === true || member === false); +}; + +R3.Utils.isColor = function(member) { + return (member instanceof R3.Color); +}; + +R3.Utils.isNumber = function(member) { + return (typeof member === 'number'); +}; + +R3.Utils.isVector2 = function(member) { + return ( + member instanceof R3.API.Vector2 || + member instanceof R3.Vector2 + ); +}; + +R3.Utils.isVector3 = function(member) { + return ( + member instanceof R3.API.Vector3 || + member instanceof R3.Vector3 + ); +}; + +R3.Utils.isVector4 = function(member) { + return ( + member instanceof R3.API.Vector4 || + member instanceof R3.Vector4 || + member instanceof R3.API.Quaternion || + member instanceof R3.Quaternion + ); +}; + +/** + * @return {string} + */ +R3.Utils.LowerUnderscore = function(name) { + return name.toLowerCase().replace(/\s+/, '_'); +}; + +R3.Utils.UpperCaseWordsSpaces = function(input) { + + var word = input.replace(/[-_]/g, ' '); + + word = word.replace(/\s+/, ' '); + + var words = word.split(' '); + + return words.reduce( + function(result, word) { + result += word[0].toUpperCase() + word.substr(1); + return result + ' '; + }, + '' + ).trim(); +}; + +/** + * @return {string} + */ +R3.Utils.UpperCaseUnderscore = function(word) { + + var str = ''; + + word.split('').map(function(letter){ + if (letter == letter.toUpperCase()) { + str += '_' + letter; + } else { + str += letter.toUpperCase(); + } + }); + + str = str.replace(new RegExp('^_'),''); + + return str; +}; + +/** + * Returns Left Padded Text - ex. length 5, padchar 0, string abc = '00abc' + * @param length + * @param padChar + * @param string + * @returns {string} + * @constructor + */ +R3.Utils.PaddedText = function(length, padChar, string) { + + var pad = ""; + + for (var x = 0; x < length; x++) { + pad += padChar; + } + + return pad.substring(0, pad.length - string.length) + string; +}; \ No newline at end of file diff --git a/src/r3-a-api-component.js b/src/r3-a-api-component.js new file mode 100644 index 0000000..36c2159 --- /dev/null +++ b/src/r3-a-api-component.js @@ -0,0 +1,19 @@ +/** + * API Component Interface - Do not construct objects of this type directly + * @param componentType + * @param parentEntity + * @constructor + */ +R3.API.Component = function( + componentType, + parentEntity +) { + this.componentType = componentType; + + if (R3.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +R3.API.Component.prototype.constructor = R3.API.Component; \ No newline at end of file diff --git a/src/r3-a-component-a.js b/src/r3-a-component-a.js new file mode 100644 index 0000000..13dae37 --- /dev/null +++ b/src/r3-a-component-a.js @@ -0,0 +1,2003 @@ +/** + * Component Interface + * @constructor + * @param linkedObjects + * @param delayed + */ +R3.Component = function( + linkedObjects, + delayed +) { + if (R3.Utils.UndefinedOrNull(linkedObjects)) { + linkedObjects = {}; + } + this.linkedObjects = linkedObjects; + this.linkedObjects.parentEntity = R3.Entity; + + this.idToObject = {}; + + this.selected = false; + + this.building = false; + + this.loaded = false; + + this.linked = false; + + this.cloneNumber = 0; + + this.isClone = false; + + this.generateNewImageIds = false; + + if (R3.Utils.UndefinedOrNull(delayed)) { + delayed = false; + } + this.delayed = delayed; + + this.dependencies = this.getDependencies(); + + R3.Event.Emit( + R3.Event.COMPONENT_REGISTER, + { + component : this + } + ); + + if (this.dependencies.length === 0) { + + this.performInstanceCreation(); + + } else { + R3.Event.Emit( + R3.Event.REGISTER_DEPENDENCIES, + { + component : this + } + ); + } + + +}; + +R3.Component.prototype = Object.create(R3.Event.prototype); +R3.Component.prototype.constructor = R3.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 + */ +R3.Component.prototype.performInstanceCreation = function() { + + var dependencies = true; + + if (R3.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 an instance creation at an exact time, like System.Input for Edit Controls - + * we need to give them the opportunity to handle this situation + */ + R3.Event.Emit( + R3.Event.DELAYED_INSTANCE_ENCOUNTERED, + { + component : this + } + ) + } + } +}; + +R3.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; + + R3.Event.Emit( + R3.Event.INSTANCE_CREATED, + { + component: this + } + ); + + R3.Event.Emit( + R3.Event.RESOLVE_DEPENDENCIES, + { + component: this + } + ); + } + + if (this instanceof R3.Entity) { + R3.Event.Emit( + R3.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} + */ +R3.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') { + R3.Utils.PushUnique(dependencies, this[property]); + } + + if (this[property] instanceof Array) { + this[property].map( + function(arrayProperty) { + + if (typeof arrayProperty === 'string') { + R3.Utils.PushUnique(dependencies, arrayProperty); + } + + if (arrayProperty && + arrayProperty instanceof R3.Component + ) { + R3.Utils.PushUnique(dependencies, arrayProperty.id); + } + } + ); + } + + if (this[property] && + this[property] instanceof R3.Component + ) { + R3.Utils.PushUnique(dependencies, this[property].id); + } + } + } + + return dependencies; +}; + +R3.Component.prototype.updateInstance = function(property) { + + if (property === 'parentEntity') { + + if (this.parentEntity instanceof R3.Entity) { + this.parentEntity.addComponent(this); + + this.buildIdToObject(); + + Object.keys(this.idToObject).map( + function(componentId) { + + if (this.id !== componentId) { + this.parentEntity.addComponent(this.idToObject[componentId]); + } + + }.bind(this) + ) + } + + } + +}; + +R3.Component.prototype.toString = function() { + return this.id; +}; + +R3.Component.SOCKET_RECEIVE = 0x1; +R3.Component.MATERIAL_STANDARD = 0x2; +R3.Component.RENDERER = 0x3; +R3.Component.SERVER = 0x4; +R3.Component.CAMERA_PERSPECTIVE = 0x5; +R3.Component.SOCKET = 0x6; +R3.Component.MESH = 0x7; +R3.Component.SPLINE = 0x8; +R3.Component.SHADOW_DIRECTIONAL = 0x9; +R3.Component.PLANE = 0xa; +R3.Component.COMPOSER = 0xb; +R3.Component.RENDER_TARGET = 0xc; +R3.Component.PASS_RENDER = 0xd; +R3.Component.SCENE = 0xe; +R3.Component.RAYCASTER = 0xf; +R3.Component.TEXT = 0x10; +R3.Component.FACE = 0x11; +R3.Component.VIEWPORT = 0x12; +R3.Component.SYSTEM = 0x13; +R3.Component.GRAPHICS = 0x14; +R3.Component.HELPER = 0x15; +R3.Component.CUSTOM_CODE = 0x16; +R3.Component.MOUSE = 0x17; +R3.Component.SKELETON = 0x18; +R3.Component.TEXTURE_IMAGE = 0x19; +R3.Component.ENTITY_MANAGER = 0x1a; +R3.Component.DOM_ELEMENT = 0x1b; +R3.Component.SHADOW_SPOT = 0x1c; +R3.Component.STATS = 0x1d; +R3.Component.GUI = 0x1e; +R3.Component.IMAGE = 0x1f; +R3.Component.ENTITY = 0x20; +R3.Component.OBJECT = 0x21; +R3.Component.RENDERER_D2 = 0x22; +R3.Component.RENDERER_D3 = 0x23; +R3.Component.PHYSICS_WORLD = 0x24; +R3.Component.BROADPHASE = 0x25; +R3.Component.SOLVER = 0x26; +R3.Component.RIGID_BODY = 0x27; +R3.Component.SHAPE = 0x28; +R3.Component.SHAPE_BOX = 0x29; +R3.Component.SHAPE_SPHERE = 0x2a; +R3.Component.SHAPE_TRI_MESH = 0x2b; +R3.Component.SHAPE_CONVEX_HULL = 0x2c; +R3.Component.SHAPE_CONVEX_HULL_CYLINDER = 0x2d; +R3.Component.SHAPE_HEIGHT_MAP = 0x2e; +R3.Component.SHAPE_PLANE = 0x2f; +R3.Component.CONTROLS = 0x30; +R3.Component.CONTROLS_EDITOR = 0x31; +R3.Component.CONTROLS_TOUCH = 0x32; +R3.Component.FRICTION_MATERIAL = 0x33; +R3.Component.FRICTION_CONTACT_MATERIAL = 0x34; +R3.Component.RAYCAST_VEHICLE = 0x35; +R3.Component.RAYCAST_WHEEL = 0x36; +R3.Component.CLOCK = 0x37; +R3.Component.ANIMATION = 0x38; +R3.Component.CONTROLS_KEYBOARD = 0x39; +R3.Component.CONTROLS_MOUSE = 0x3a; +R3.Component.GRAPHICS_THREE = 0x3b; +R3.Component.FONT = 0x3c; +R3.Component.CANVAS = 0x3d; +R3.Component.BONE = 0x3e; +R3.Component.GRAPHICS_IMPACT = 0x3f; +R3.Component.CONTROLS_FIRST_PERSON = 0x40; +R3.Component.SYSTEM_ANIMATION = 0x41; +R3.Component.SYSTEM_CUSTOM_CODE = 0x42; +R3.Component.SYSTEM_GUI = 0x43; +R3.Component.SYSTEM_INPUT = 0x44; +R3.Component.SYSTEM_LINKING = 0x45; +R3.Component.SYSTEM_PHYSICS = 0x46; +R3.Component.SYSTEM_RENDER = 0x47; +R3.Component.SYSTEM_STORAGE = 0x48; +R3.Component.SYSTEM_VISUALIZATION = 0x49; +R3.Component.LIGHT_AMBIENT = 0x4a; +R3.Component.LIGHT_DIRECTIONAL = 0x4b; +R3.Component.LIGHT_HEMISPHERE = 0x4c; +R3.Component.LIGHT_POINT = 0x4d; +R3.Component.LIGHT_RECT_AREA = 0x4e; +R3.Component.LIGHT_SPOT = 0x4f; +R3.Component.FOG = 0x50; +R3.Component.CONTROLS_ORBIT = 0x51; +R3.Component.PARTICLE_ENGINE = 0x52; +R3.Component.SYSTEM_PARTICLE = 0x53; +R3.Component.PARTICLE = 0x54; +R3.Component.AUDIO = 0x55; +R3.Component.SYSTEM_AUDIO = 0x56; +R3.Component.SOCKET_CAST = 0x57; +R3.Component.CAMERA_ORTHOGRAPHIC = 0x58; +R3.Component.CAMERA_STEREO = 0x59; +R3.Component.CAMERA_CUBE = 0x5a; +R3.Component.SHADOW = 0x5b; +R3.Component.RENDER_TARGET_CUBE = 0x5c; +R3.Component.TEXTURE_CUBE = 0x5d; +R3.Component.TEXTURE_CANVAS = 0x5e; +R3.Component.EFFECT_STEREO = 0x5f; +R3.Component.EFFECT_ANAGLYPH = 0x60; +R3.Component.EFFECT_PARALLAX = 0x61; +R3.Component.PASS_SSAO = 0x62; +R3.Component.PASS_BLOOM = 0x63; +R3.Component.PASS_FXAA = 0x64; +R3.Component.RENDER_CONFIGURATION = 0x65; +R3.Component.MATERIAL_BASIC = 0x66; +R3.Component.TEXTURE = 0x67; +R3.Component.MATERIAL_PHONG = 0x68; + +R3.Component.GEOMETRY_NORMAL = 0x69; +R3.Component.GEOMETRY_NORMAL_BOX = 0x6a; +R3.Component.GEOMETRY_NORMAL_CIRCLE = 0x6b; +R3.Component.GEOMETRY_NORMAL_CONE = 0x6c; +R3.Component.GEOMETRY_NORMAL_CYLINDER = 0x6d; +R3.Component.GEOMETRY_NORMAL_DODECAHEDRON = 0x6e; +R3.Component.GEOMETRY_NORMAL_EDGES = 0x6f; +R3.Component.GEOMETRY_NORMAL_EXTRUDE = 0x70; +R3.Component.GEOMETRY_NORMAL_ICOSAHEDRON = 0x71; +R3.Component.GEOMETRY_NORMAL_LATHE = 0x72; +R3.Component.GEOMETRY_NORMAL_OCTAHEDRON = 0x73; +R3.Component.GEOMETRY_NORMAL_PARAMETRIC = 0x74; +R3.Component.GEOMETRY_NORMAL_PLANE = 0x75; +R3.Component.GEOMETRY_NORMAL_POLYHEDRON = 0x76; +R3.Component.GEOMETRY_NORMAL_RING = 0x77; +R3.Component.GEOMETRY_NORMAL_SHAPE = 0x78; +R3.Component.GEOMETRY_NORMAL_SPHERE = 0x79; +R3.Component.GEOMETRY_NORMAL_TETRAHEDRON = 0x7a; +R3.Component.GEOMETRY_NORMAL_TEXT = 0x7b; +R3.Component.GEOMETRY_NORMAL_TORUS = 0x7c; +R3.Component.GEOMETRY_NORMAL_TORUS_KNOT = 0x7d; +R3.Component.GEOMETRY_NORMAL_TUBE = 0x7e; +R3.Component.GEOMETRY_NORMAL_WIREFRAME = 0x7f; + +R3.Component.GEOMETRY_BUFFER = 0x80; +R3.Component.GEOMETRY_BUFFER_BOX = 0x81; +R3.Component.GEOMETRY_BUFFER_CIRCLE = 0x82; +R3.Component.GEOMETRY_BUFFER_CONE = 0x83; +R3.Component.GEOMETRY_BUFFER_CYLINDER = 0x84; +R3.Component.GEOMETRY_BUFFER_DODECAHEDRON = 0x85; +R3.Component.GEOMETRY_BUFFER_EXTRUDE = 0x86; +R3.Component.GEOMETRY_BUFFER_ICOSAHEDRON = 0x87; +R3.Component.GEOMETRY_BUFFER_LATHE = 0x88; +R3.Component.GEOMETRY_BUFFER_OCTAHEDRON = 0x89; +R3.Component.GEOMETRY_BUFFER_PARAMETRIC = 0x8a; +R3.Component.GEOMETRY_BUFFER_PLANE = 0x8b; +R3.Component.GEOMETRY_BUFFER_POLYHEDRON = 0x8c; +R3.Component.GEOMETRY_BUFFER_RING = 0x8d; +R3.Component.GEOMETRY_BUFFER_SHAPE = 0x8e; +R3.Component.GEOMETRY_BUFFER_SPHERE = 0x8f; +R3.Component.GEOMETRY_BUFFER_TETRAHEDRON = 0x90; +R3.Component.GEOMETRY_BUFFER_TEXT = 0x91; +R3.Component.GEOMETRY_BUFFER_TORUS = 0x92; +R3.Component.GEOMETRY_BUFFER_TORUS_KNOT = 0x93; +R3.Component.GEOMETRY_BUFFER_TUBE = 0x94; + +R3.Component.GEOMETRY = 0x95; + +R3.Component.CURVE = 0x96; +R3.Component.CURVE_PATH = 0x97; +R3.Component.CURVE_PATH_D2 = 0x98; +R3.Component.CURVE_PATH_D2_SHAPE = 0x99; +R3.Component.BOX3 = 0x9a; +R3.Component.DRAW_RANGE = 0x9b; +R3.Component.GROUP = 0x9c; + +R3.Component.MATERIAL_SHADER = 0x9d; + +R3.Component.SHADER = 0x9e; +R3.Component.SHADER_VERTEX = 0x9f; +R3.Component.SHADER_FRAGMENT = 0xa0; +R3.Component.GEOMETRY_BUFFER_INSTANCED = 0xa1; +R3.Component.MATERIAL_SHADER_RAW = 0xa2; +R3.Component.MATERIAL_POINTS = 0xa3; + +R3.Component.MAX_COMPONENTS = 0xa4; + +R3.Component.GRAPHICS_RUNTIME = 0x1; +R3.Component.PHYSICS_RUNTIME = 0x2; +R3.Component.SOCKET_RUNTIME = 0x3; +R3.Component.STATISTICS_RUNTIME = 0x4; +R3.Component.DEFAULT_RUNTIME = 0x5; +R3.Component.GUI_RUNTIME = 0x6; +R3.Component.CODER_RUNTIME = 0x7; + +R3.Component.GetCompentTypes = function(constructor) { + + if (constructor === R3.Component) { + + } +}; + +/** + * Returns string name for component number + * @param number + * @returns {*} + * @constructor + */ +R3.Component.GetComponentInfo = function(number) { + switch(number) { + case 0x1 : return { + name : 'R3.Socket.Receive', + runtime : R3.Component.SOCKET_RUNTIME, + constructor : R3.Socket.Receive, + apiConstructor : R3.API.Socket.Receive + }; + case 0x2 : return { + name : 'R3.D3.Material.Standard', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Material.Standard, + apiConstructor : R3.D3.API.Material.Standard + }; + case 0x3 : return { + name : 'R3.Renderer', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Renderer, + apiConstructor : R3.API.Renderer + }; + case 0x4 : return { + name : 'R3.Server', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.Server, + apiConstructor : R3.API.Server + }; + case 0x5 : return { + name : 'R3.D3.Camera.Perspective', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Camera.Perspective, + apiConstructor : R3.D3.API.Camera.Perspective + }; + case 0x6 : return { + name : 'R3.Socket', + runtime : R3.Component.SOCKET_RUNTIME, + constructor : R3.Socket, + apiConstructor : R3.API.Socket + }; + case 0x7 : return { + name : 'R3.D3.Mesh', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Mesh, + apiConstructor : R3.D3.API.Mesh + }; + case 0x8 : return { + name : 'R3.D3.Spline', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Spline, + apiConstructor : R3.D3.API.Spline + }; + case 0x9 : return { + name : 'R3.D3.Shadow.Directional', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Shadow.Directional, + apiConstructor : R3.D3.API.Shadow.Directional + }; + case 0xa : return { + name : 'R3.Plane', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Plane, + apiConstructor : R3.API.Plane + }; + case 0xb : return { + name : 'R3.D3.Composer', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Composer, + apiConstructor : R3.D3.API.Composer + }; + case 0xc : return { + name : 'R3.D3.RenderTarget', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.RenderTarget, + apiConstructor : R3.D3.API.RenderTarget + }; + case 0xd : return { + name : 'R3.D3.Pass.Render', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Pass.Render, + apiConstructor : R3.D3.API.Pass.Render + }; + case 0xe : return { + name : 'R3.D3.Scene', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Scene + }; + case 0xf : return { + name : 'R3.D3.Raycaster', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Raycaster, + apiConstructor : R3.D3.API.Raycaster + }; + case 0x10 : return { + name : 'R3.D3.Text', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Text, + apiConstructor : R3.D3.API.Text + }; + case 0x11 : return { + name : 'R3.D3.Face', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Face, + apiConstructor : R3.D3.API.Face + }; + case 0x12 : return { + name : 'R3.D3.Viewport', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Viewport, + apiConstructor : R3.D3.API.Viewport + }; + case 0x13 : return { + name : 'R3.System', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.System, + apiConstructor : R3.API.System + }; + case 0x14 : return { + name : 'R3.GraphicsRuntime', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.GraphicsRuntime + }; + case 0x15 : return { + name : 'R3.D3.Helper', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Helper + }; + case 0x16 : return { + name : 'R3.CustomCode', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.CustomCode, + apiConstructor : R3.API.CustomCode + }; + case 0x17 : return { + name : 'R3.Mouse', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.Mouse, + apiConstructor : R3.API.Mouse + }; + case 0x18 : return { + name : 'R3.D3.Skeleton', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Skeleton, + apiConstructor : R3.D3.API.Skeleton + }; + case 0x19 : return { + name : 'R3.D3.Texture.Image', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Texture.Image, + apiConstructor : R3.D3.API.Texture.Image + }; + case 0x1a : return { + name : 'R3.EntityManager', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.EntityManager, + apiConstructor : R3.API.EntityManager + }; + case 0x1b : return { + name : 'R3.DomElement', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.DomElement, + apiConstructor : R3.API.DomElement + }; + case 0x1c : return { + name : 'R3.D3.Shadow.Spot', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Shadow.Spot, + apiConstructor : R3.D3.API.Shadow.Spot + }; + case 0x1d : return { + name : 'R3.Stats', + runtime : R3.Component.STATISTICS_RUNTIME, + constructor : R3.Stats, + apiConstructor : R3.API.Stats + }; + case 0x1e : return { + name : 'R3.GUI', + runtime : R3.Component.GUI_RUNTIME, + constructor : R3.GUI, + apiConstructor : R3.API.GUI + }; + case 0x1f : return { + name : 'R3.Image', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.Image + }; + case 0x20 : return { + name : 'R3.Entity', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.Entity, + apiConstructor : R3.API.Entity + }; + case 0x21 : return { + name : 'R3.D3.Object', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Object, + apiConstructor : R3.D3.API.Object + }; + case 0x22 : return { + name : 'R3.Renderer.D2', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Renderer.D2, + apiConstructor : R3.API.Renderer.D2 + }; + case 0x23 : return { + name : 'R3.Renderer.D3', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Renderer.D3, + apiConstructor : R3.API.Renderer.D3 + }; + case 0x24 : return { + name : 'R3.D3.PhysicsWorld', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.PhysicsWorld, + apiConstructor : R3.D3.API.PhysicsWorld + }; + case 0x25 : return { + name : 'R3.D3.Broadphase', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.Broadphase, + apiConstructor : R3.D3.API.Broadphase + }; + case 0x26 : return { + name : 'R3.D3.Solver', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.Solver, + apiConstructor : R3.D3.API.Solver + }; + case 0x27 : return { + name : 'R3.D3.RigidBody', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.RigidBody, + apiConstructor : R3.D3.API.RigidBody + }; + case 0x28 : return { + name : 'R3.D3.Shape', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.Shape, + apiConstructor : R3.D3.API.Shape + }; + case 0x29 : return { + name : 'R3.D3.Shape.Box', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.Shape.Box, + apiConstructor : R3.D3.API.Shape + }; + case 0x2a : return { + name : 'R3.D3.Shape.Sphere', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.Shape.Sphere, + apiConstructor : R3.D3.API.Shape + }; + case 0x2b : return { + name : 'R3.D3.Shape.TriMesh', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.Shape.TriMesh, + apiConstructor : R3.D3.API.Shape + }; + case 0x2c : return { + name : 'R3.D3.Shape.ConvexHull', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.Shape.ConvexHull, + apiConstructor : R3.D3.API.Shape + }; + case 0x2d : return { + name : 'R3.D3.Shape.ConvexHull.Cylinder', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.Shape.ConvexHull.Cylinder, + apiConstructor : R3.D3.API.Shape + }; + case 0x2e : return { + name : 'R3.D3.Shape.HeightMap', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.D3.Shape.HeightMap, + apiConstructor : R3.D3.API.Shape + }; + case 0x2f : return { + name : 'R3.D3.Shape.Plane', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.Shape.Plane, + apiConstructor : R3.D3.API.Shape + }; + case 0x30 : return { + name : 'R3.Controls', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.Controls, + apiConstructor : R3.API.Controls + }; + case 0x31 : return { + name : 'R3.Controls.D3.Editor', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Controls.D3.Editor, + apiConstructor : R3.API.Controls + }; + case 0x32 : return { + name : 'R3.Controls.Touch', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.Controls.Touch, + apiConstructor : R3.API.Controls + }; + case 0x33 : return { + name : 'R3.D3.FrictionMaterial', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.FrictionMaterial, + apiConstructor : R3.D3.API.FrictionMaterial + }; + case 0x34 : return { + name : 'R3.D3.FrictionContactMaterial', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.FrictionContactMaterial, + apiConstructor : R3.D3.API.FrictionContactMaterial + }; + case 0x35 : return { + name : 'R3.D3.RaycastVehicle', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.RaycastVehicle, + apiConstructor : R3.D3.API.RaycastVehicle + }; + case 0x36 : return { + name : 'R3.D3.RaycastWheel', + runtime : R3.Component.PHYSICS_RUNTIME, + constructor : R3.D3.RaycastWheel, + apiConstructor : R3.D3.API.RaycastWheel + }; + case 0x37 : return { + name : 'R3.Clock', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Clock, + apiConstructor : R3.API.Clock + }; + case 0x38 : return { + name : 'R3.D3.Animation', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.D3.Animation, + apiConstructor : R3.D3.API.Animation + }; + case 0x39 : return { + name : 'R3.Controls.Keyboard', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.Controls.Keyboard, + apiConstructor : R3.API.Controls + }; + case 0x3a : return { + name : 'R3.Controls.Mouse', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.Controls.Mouse, + apiConstructor : R3.API.Controls + }; + case 0x3b : return { + name : 'R3.GraphicsRuntime.Three', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.GraphicsRuntime.Three, + apiConstructor : R3.API.GraphicsRuntime.Three + }; + case 0x3c : return { + name : 'R3.D3.Font', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Font, + apiConstructor : R3.D3.API.Font + }; + case 0x3d : return { + name : 'R3.Canvas', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Canvas, + apiConstructor : R3.API.Canvas + }; + case 0x3e : return { + name : 'R3.D3.Bone', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Bone, + apiConstructor : R3.D3.API.Bone + }; + case 0x3f : return { + name : 'R3.GraphicsRuntime.Impact', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.GraphicsRuntime.Impact, + apiConstructor : R3.API.GraphicsRuntime.Impact + }; + case 0x40 : return { + name : 'R3.Controls.D3.FirstPerson', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Controls.D3.FirstPerson, + apiConstructor : R3.API.Controls.D3.FirstPerson + }; + case 0x41 : return { + name : 'R3.System.Animation', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.System.Animation, + apiConstructor : R3.API.System + }; + case 0x42 : return { + name : 'R3.System.CustomCode', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.System.CustomCode, + apiConstructor : R3.API.System + }; + case 0x43 : return { + name : 'R3.System.GUI', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.System.GUI, + apiConstructor : R3.API.System + }; + case 0x44 : return { + name : 'R3.System.Input', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.System.Input, + apiConstructor : R3.API.System + }; + case 0x45 : return { + name : 'R3.System.Linking', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.System.Linking, + apiConstructor : R3.API.System + }; + case 0x46 : return { + name : 'R3.System.Physics', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.System.Physics, + apiConstructor : R3.API.System + }; + case 0x47 : return { + name : 'R3.System.Render', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.System.Render, + apiConstructor : R3.API.System + }; + case 0x48 : return { + name : 'R3.System.Storage', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.System.Storage, + apiConstructor : R3.API.System + }; + case 0x49 : return { + name : 'R3.System.Visualization', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.System.Visualization, + apiConstructor : R3.API.System + }; + case 0x4a : return { + name : 'R3.D3.Light.Ambient', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Light.Ambient, + apiConstructor : R3.D3.API.Light.Ambient + }; + case 0x4b : return { + name : 'R3.D3.Light.Directional', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Light.Directional, + apiConstructor : R3.D3.API.Light.Directional + }; + case 0x4c : return { + name : 'R3.D3.Light.Hemisphere', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Light.Hemisphere, + apiConstructor : R3.D3.API.Light.Hemisphere + }; + case 0x4d : return { + name : 'R3.D3.Light.Point', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Light.Point, + apiConstructor : R3.D3.API.Light.Point + }; + case 0x4e : return { + name : 'R3.D3.Light.RectArea', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Light.RectArea, + apiConstructor : R3.D3.API.Light.RectArea + }; + case 0x4f : return { + name : 'R3.D3.Light.Spot', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Light.Spot, + apiConstructor : R3.D3.API.Light.Spot + }; + case 0x50 : return { + name : 'R3.D3.Fog', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Fog, + apiConstructor : R3.D3.API.Fog + }; + case 0x51 : return { + name : 'R3.Controls.D3.Orbit', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Controls.D3.Orbit, + apiConstructor : R3.API.Controls.D3.Orbit + }; + case 0x52 : return { + name : 'R3.D3.ParticleEngine', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.ParticleEngine, + apiConstructor : R3.D3.API.ParticleEngine + }; + case 0x53 : return { + name : 'R3.System.Particle', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.System.Particle, + apiConstructor : R3.API.System + }; + case 0x54 : return { + name : 'R3.D3.Particle', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Particle, + apiConstructor : R3.D3.API.Particle + }; + case 0x55 : return { + name : 'R3.D3.Audio', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Audio, + apiConstructor : R3.D3.API.Audio + }; + case 0x56 : return { + name : 'R3.System.Audio', + runtime : R3.Component.DEFAULT_RUNTIME, + constructor : R3.System.Audio, + apiConstructor : R3.API.System + }; + case 0x57 : return { + name : 'R3.Socket.Cast', + runtime : R3.Component.SOCKET_RUNTIME, + constructor : R3.Socket.Cast, + apiConstructor : R3.API.Socket.Cast + }; + case 0x58 : return { + name : 'R3.D3.Camera.Orthographic', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Camera.Orthographic, + apiConstructor : R3.D3.API.Camera.Orthographic + }; + case 0x59 : return { + name : 'R3.D3.Camera.Stereo', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Camera.Stereo, + apiConstructor : R3.D3.API.Camera.Stereo + }; + case 0x5a : return { + name : 'R3.D3.Camera.Cube', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Camera.Cube, + apiConstructor : R3.D3.API.Camera.Cube + }; + case 0x5b : return { + name : 'R3.D3.Shadow', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Shadow, + apiConstructor : R3.D3.API.Shadow + }; + case 0x5c : return { + name : 'R3.D3.RenderTarget.Cube', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.RenderTarget.Cube, + apiConstructor : R3.D3.API.RenderTarget.Cube + }; + case 0x5d : return { + name : 'R3.D3.Texture.Cube', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Texture.Cube, + apiConstructor : R3.D3.API.Texture.Cube + }; + case 0x5e : return { + name : 'R3.D3.Texture.Canvas', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Texture.Canvas, + apiConstructor : R3.D3.API.Texture.Canvas + }; + case 0x5f : return { + name : 'R3.D3.Effect.Stereo', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Effect.Stereo, + apiConstructor : R3.D3.API.Effect.Stereo + }; + case 0x60 : return { + name : 'R3.D3.Effect.Anaglyph', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Effect.Anaglyph, + apiConstructor : R3.D3.API.Effect.Anaglyph + }; + case 0x61 : return { + name : 'R3.D3.Effect.Parallax', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Effect.Parallax, + apiConstructor : R3.D3.API.Effect.Parallax + }; + case 0x62 : return { + name : 'R3.D3.Pass.SSAO', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Pass.SSAO, + apiConstructor : R3.D3.API.Pass.SSAO + }; + case 0x63 : return { + name : 'R3.D3.Pass.Bloom', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Pass.Bloom, + apiConstructor : R3.D3.API.Pass.Bloom + }; + case 0x64 : return { + name : 'R3.D3.Pass.FXAA', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Pass.FXAA, + apiConstructor : R3.D3.API.Pass.FXAA + }; + case 0x65 : return { + name : 'R3.RenderConfiguration', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.RenderConfiguration, + apiConstructor : R3.API.RenderConfiguration + }; + case 0x66 : return { + name : 'R3.D3.Material.Basic', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Material.Basic, + apiConstructor : R3.D3.API.Material.Basic + }; + case 0x67 : return { + name : 'R3.D3.Texture', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Texture, + apiConstructor : R3.D3.API.Texture + }; + case 0x68 : return { + name : 'R3.D3.Material.Phong', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Material.Phong, + apiConstructor : R3.D3.API.Material.Phong + }; + case 0x69 : return { + name : 'R3.D3.Geometry.Normal', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal, + apiConstructor : R3.D3.API.Geometry.Normal + }; + case 0x6a : return { + name : 'R3.D3.Geometry.Normal.Box', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Box, + apiConstructor : R3.D3.API.Geometry.Normal.Box + }; + case 0x6b : return { + name : 'R3.D3.Geometry.Normal.Circle', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Circle, + apiConstructor : R3.D3.API.Geometry.Normal.Circle + }; + case 0x6c : return { + name : 'R3.D3.Geometry.Normal.Cone', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Cone, + apiConstructor : R3.D3.API.Geometry.Normal.Cone + }; + case 0x6d : return { + name : 'R3.D3.Geometry.Normal.Cylinder', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Cylinder, + apiConstructor : R3.D3.API.Geometry.Normal.Cylinder + }; + case 0x6e : return { + name : 'R3.D3.Geometry.Normal.Dodecahedron', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Dodecahedron, + apiConstructor : R3.D3.API.Geometry.Normal.Dodecahedron + }; + case 0x6f : return { + name : 'R3.D3.Geometry.Normal.Edges', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Edges, + apiConstructor : R3.D3.API.Geometry.Normal.Edges + }; + case 0x70 : return { + name : 'R3.D3.Geometry.Normal.Extrude', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Extrude, + apiConstructor : R3.D3.API.Geometry.Normal.Extrude + }; + case 0x71 : return { + name : 'R3.D3.Geometry.Normal.Icosahedron', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Icosahedron, + apiConstructor : R3.D3.API.Geometry.Normal.Icosahedron + }; + case 0x72 : return { + name : 'R3.D3.Geometry.Normal.Lathe', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Lathe, + apiConstructor : R3.D3.API.Geometry.Normal.Lathe + }; + case 0x73 : return { + name : 'R3.D3.Geometry.Normal.Octahedron', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Octahedron, + apiConstructor : R3.D3.API.Geometry.Normal.Octahedron + }; + case 0x74 : return { + name : 'R3.D3.Geometry.Normal.Parametric', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Parametric, + apiConstructor : R3.D3.API.Geometry.Normal.Parametric + }; + case 0x75 : return { + name : 'R3.D3.Geometry.Normal.Plane', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Plane, + apiConstructor : R3.D3.API.Geometry.Normal.Plane + }; + case 0x76 : return { + name : 'R3.D3.Geometry.Normal.Polyhedron', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Polyhedron, + apiConstructor : R3.D3.API.Geometry.Normal.Polyhedron + }; + case 0x77 : return { + name : 'R3.D3.Geometry.Normal.Ring', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Ring, + apiConstructor : R3.D3.API.Geometry.Normal.Ring + }; + case 0x78 : return { + name : 'R3.D3.Geometry.Normal.Shape', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Shape, + apiConstructor : R3.D3.API.Geometry.Normal.Shape + }; + case 0x79 : return { + name : 'R3.D3.Geometry.Normal.Sphere', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Sphere, + apiConstructor : R3.D3.API.Geometry.Normal.Sphere + }; + case 0x7a : return { + name : 'R3.D3.Geometry.Normal.Tetrahedron', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Tetrahedron, + apiConstructor : R3.D3.API.Geometry.Normal.Tetrahedron + }; + case 0x7b : return { + name : 'R3.D3.Geometry.Normal.Text', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Text, + apiConstructor : R3.D3.API.Geometry.Normal.Text + }; + case 0x7c : return { + name : 'R3.D3.Geometry.Normal.Torus', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Torus, + apiConstructor : R3.D3.API.Geometry.Normal.Torus + }; + case 0x7d : return { + name : 'R3.D3.Geometry.Normal.TorusKnot', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.TorusKnot, + apiConstructor : R3.D3.API.Geometry.Normal.TorusKnot + }; + case 0x7e : return { + name : 'R3.D3.Geometry.Normal.Tube', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Tube, + apiConstructor : R3.D3.API.Geometry.Normal.Tube + }; + case 0x7f : return { + name : 'R3.D3.Geometry.Normal.Wireframe', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Normal.Wireframe, + apiConstructor : R3.D3.API.Geometry.Normal.Wireframe + }; + case 0x80 : return { + name : 'R3.D3.Geometry.Buffer', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer, + apiConstructor : R3.D3.API.Geometry.Buffer + }; + case 0x81 : return { + name : 'R3.D3.Geometry.Buffer.Box', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Box, + apiConstructor : R3.D3.API.Geometry.Buffer.Box + }; + case 0x82 : return { + name : 'R3.D3.Geometry.Buffer.Circle', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Circle, + apiConstructor : R3.D3.API.Geometry.Buffer.Circle + }; + case 0x83 : return { + name : 'R3.D3.Geometry.Buffer.Cone', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Cone, + apiConstructor : R3.D3.API.Geometry.Buffer.Cone + }; + case 0x84 : return { + name : 'R3.D3.Geometry.Buffer.Cylinder', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Cylinder, + apiConstructor : R3.D3.API.Geometry.Buffer.Cylinder + }; + case 0x85 : return { + name : 'R3.D3.Geometry.Buffer.Dodecahedron', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Dodecahedron, + apiConstructor : R3.D3.API.Geometry.Buffer.Dodecahedron + }; + case 0x86 : return { + name : 'R3.D3.Geometry.Buffer.Extrude', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Extrude, + apiConstructor : R3.D3.API.Geometry.Buffer.Extrude + }; + case 0x87 : return { + name : 'R3.D3.Geometry.Buffer.Icosahedron', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Icosahedron, + apiConstructor : R3.D3.API.Geometry.Buffer.Icosahedron + }; + case 0x88 : return { + name : 'R3.D3.Geometry.Buffer.Lathe', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Lathe, + apiConstructor : R3.D3.API.Geometry.Buffer.Lathe + }; + case 0x89 : return { + name : 'R3.D3.Geometry.Buffer.Octahedron', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Octahedron, + apiConstructor : R3.D3.API.Geometry.Buffer.Octahedron + }; + case 0x8a : return { + name : 'R3.D3.Geometry.Buffer.Parametric', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Parametric, + apiConstructor : R3.D3.API.Geometry.Buffer.Parametric + }; + case 0x8b : return { + name : 'R3.D3.Geometry.Buffer.Plane', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Plane, + apiConstructor : R3.D3.API.Geometry.Buffer.Plane + }; + case 0x8c : return { + name : 'R3.D3.Geometry.Buffer.Polyhedron', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Polyhedron, + apiConstructor : R3.D3.API.Geometry.Buffer.Polyhedron + }; + case 0x8d : return { + name : 'R3.D3.Geometry.Buffer.Ring', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Ring, + apiConstructor : R3.D3.API.Geometry.Buffer.Ring + }; + case 0x8e : return { + name : 'R3.D3.Geometry.Buffer.Shape', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Shape, + apiConstructor : R3.D3.API.Geometry.Buffer.Shape + }; + case 0x8f : return { + name : 'R3.D3.Geometry.Buffer.Sphere', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Sphere, + apiConstructor : R3.D3.API.Geometry.Buffer.Sphere + }; + case 0x90 : return { + name : 'R3.D3.Geometry.Buffer.Tetrahedron', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Tetrahedron, + apiConstructor : R3.D3.API.Geometry.Buffer.Tetrahedron + }; + case 0x91 : return { + name : 'R3.D3.Geometry.Buffer.Text', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Text, + apiConstructor : R3.D3.API.Geometry.Buffer.Text + }; + case 0x92 : return { + name : 'R3.D3.Geometry.Buffer.Torus', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Torus, + apiConstructor : R3.D3.API.Geometry.Buffer.Torus + }; + case 0x93 : return { + name : 'R3.D3.Geometry.Buffer.TorusKnot', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.TorusKnot, + apiConstructor : R3.D3.API.Geometry.Buffer.TorusKnot + }; + case 0x94 : return { + name : 'R3.D3.Geometry.Buffer.Tube', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Tube, + apiConstructor : R3.D3.API.Geometry.Buffer.Tube + }; + case 0x95 : return { + name : 'R3.D3.Geometry', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry, + apiConstructor : R3.D3.API.Geometry + }; + case 0x96 : return { + name : 'R3.Curve', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Curve, + apiConstructor : R3.API.Curve + }; + case 0x97 : return { + name : 'R3.Curve.Path', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Curve.Path, + apiConstructor : R3.API.Curve.Path + }; + case 0x98 : return { + name : 'R3.Curve.Path.D2', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Curve.Path.D2, + apiConstructor : R3.API.Curve.Path.D2 + }; + case 0x99 : return { + name : 'R3.Curve.Path.D2.Shape', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Curve.Path.D2.Shape, + apiConstructor : R3.API.Curve.Path.D2.Shape + }; + case 0x9a : return { + name : 'R3.Box3', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Box3, + apiConstructor : R3.API.Box3 + }; + case 0x9b : return { + name : 'R3.DrawRange', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.DrawRange, + apiConstructor : R3.API.DrawRange + }; + case 0x9c : return { + name : 'R3.Group', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.Group, + apiConstructor : R3.API.Group + }; + case 0x9d : return { + name : 'R3.D3.Material.Shader', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Material.Shader, + apiConstructor : R3.D3.API.Material.Shader + }; + case 0x9e : return { + name : 'R3.D3.Shader', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Shader, + apiConstructor : R3.D3.API.Shader + }; + case 0x9f : return { + name : 'R3.D3.Shader.Vertex', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Shader.Vertex, + apiConstructor : R3.D3.API.Shader.Vertex + }; + case 0xa0 : return { + name : 'R3.D3.Shader.Fragment', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Shader.Fragment, + apiConstructor : R3.D3.API.Shader.Fragment + }; + case 0xa1 : return { + name : 'R3.D3.Geometry.Buffer.Instanced', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Geometry.Buffer.Instanced, + apiConstructor : R3.D3.API.Geometry.Buffer.Instanced + }; + case 0xa2 : return { + name : 'R3.D3.Material.Shader.Raw', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Material.Shader.Raw, + apiConstructor : R3.D3.API.Material.Shader.Raw + }; + case 0xa3 : return { + name : 'R3.D3.Material.Points', + runtime : R3.Component.GRAPHICS_RUNTIME, + constructor : R3.D3.Material.Points, + apiConstructor : R3.D3.API.Material.Points + }; + break; + } + + throw new Error('Unknown component type: ' + number ); +}; + +/** + * Returns the runtime friendly name + * @param runtime + * @returns {*} + * @constructor + */ +R3.Component.GetRuntimeName = function(runtime) { + + if (runtime === R3.Component.GRAPHICS_RUNTIME) { + return 'Graphics'; + } + + if (runtime === R3.Component.PHYSICS_RUNTIME) { + return 'Physics'; + } + + if (runtime === R3.Component.GUI_RUNTIME) { + return 'GUI'; + } + + if (runtime === R3.Component.STATISTICS_RUNTIME) { + return 'Statistics'; + } + + if (runtime === R3.Component.SOCKET_RUNTIME) { + return 'Sockets'; + } + + if (runtime === R3.Component.CODER_RUNTIME) { + return 'Coder'; + } + + return 'Default'; +}; + +/** + * @return {string} + */ +R3.Component.GetComponentName = function(componentType) { + + var info = R3.Component.GetComponentInfo(componentType); + + if (info) { + return info.name; + } + + return 'unused'; +}; + +/** + * @return {null || Object} + */ +R3.Component.GetComponentRuntime = function(componentType) { + + var info = R3.Component.GetComponentInfo(componentType); + + if (info) { + return info.runtime; + } + return null; +}; + + +/** + * @return {null || Object} + */ +R3.Component.GetComponentConstructor = function(componentType) { + + var info = R3.Component.GetComponentInfo(componentType); + + if (info) { + return info.constructor; + } + + return null; +}; + + +/** + * Components are linked at runtime - for storing, we just store the ID + * @returns {*} + */ +R3.Component.prototype.toApiObject = function() { + + var info = R3.Component.GetComponentInfo(this.componentType); + + var apiConstructor = info.apiConstructor; + + console.warn('implement generic component toApiObject'); + + var parameters = R3.Utils.GetParameters(apiConstructor); + + throw new Error(parameters); + + return this.id; + // return new info.apiConstructor() + +}; + +/** + * Gets all children components of this Object (all linked objects only - no object references i.e. string ids) + * @returns {Array} + */ +R3.Component.prototype.getChildrenComponents = function() { + + var components = []; + + this.buildIdToObject(); + + Object.keys(this.idToObject).map( + function (objectId) { + if (this.id !== objectId) { + components.push(this.idToObject[objectId]); + } + }.bind(this) + ); + + return components; +}; + +R3.Component.prototype.processComponent = function(object) { + if (object instanceof R3.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 + */ +R3.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 R3.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; +}; + +R3.Component.prototype.generateNewIds = function() { + + this.buildIdToObject(); + + var codeComponents = R3.EntityManager.Instance.queryComponents(R3.Component.CUSTOM_CODE); + + for (var property in this.idToObject) { + if (this.idToObject.hasOwnProperty(property)) { + + var oldId = this.idToObject[property].id; + var newId = R3.Utils.RandomId(); + + this.idToObject[property].id = newId; + this.idToObject[property].name = this.idToObject[property].name.replace(oldId,newId); + + if (this.generateNewImageIds) { + + // TODO: replace image filenames - but then also copy them server side? + if (this.idToObject[property].fileName) { + this.idToObject[property].fileName = this.idToObject[property].fileName.replace(oldId,newId); + } + } + + codeComponents.map(function(codeComponent){ + codeComponent.code = codeComponent.code.replace(oldId,newId); + }); + } + } + +}; + +/** + * TODO: don't remove components which are still in use elsewhere - this is important to prevent 'register out + * of sync' messages + */ +R3.Component.prototype.remove = function() { + + this.buildIdToObject(); + + Object.keys(this.idToObject).map( + function(componentId){ + R3.Event.Emit( + R3.Event.REMOVE_COMPONENT, + { + component : this.idToObject[componentId] + } + ) + }.bind(this) + ); + +}; + +R3.Component.prototype.replace = function(componentType) { + + var replacement = R3.Component.Construct(componentType); + + R3.Event.Emit( + R3.Event.REPLACE_COMPONENT, + { + current : this, + replacement : replacement + } + ); + + if (this.parentEntity && this.parentEntity.loaded) { + this.parentEntity.addComponent(replacement); + } + + this.remove(); + + R3.Event.Emit( + R3.Event.COMPONENT_REPLACED + ); +}; + + +R3.Component.prototype.clone = function() { + + var apiObject = this.toApiObject(); + + this.cloneNumber += 1; + + apiObject.id = R3.Utils.RandomId(); + + apiObject.name = this.name + ' Clone (' + this.cloneNumber + ')'; + + var runtimeComponent = R3.Component.ConstructFromObject(apiObject); + + runtimeComponent.isClone = true; + + R3.Event.Emit( + R3.Event.COMPONENT_CLONED, + { + parent : this, + component : runtimeComponent + } + ); + + runtimeComponent.parentEntity = null; + + return runtimeComponent; +}; + +/** + * Clones only the instance + */ +R3.Component.prototype.cloneInstance = function() { + + var clone = null; + + if ( + this.instance && + this.instance.clone && + typeof (this.instance.clone === 'function')) { + + clone = this.instance.clone(); + + R3.Event.Emit( + R3.Event.INSTANCE_CLONED, + { + component : this, + instance : clone + } + ) + } + + return clone; +}; + +R3.Component.prototype.saveToRemoteAPI = function() { + this.save(true); +}; + +R3.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; + } + + R3.Event.Emit( + R3.Event.SAVING, + { + component: this + } + ); + + this.saveSubscription = R3.Event.Subscribe( + R3.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; + + R3.Event.Emit( + R3.Event.DONE_SAVING, + { + failed: failed, + saved: saved + } + ) + } + + }.bind(this) + ); + + this.saveErrorSubscription = R3.Event.Subscribe( + R3.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; + + R3.Event.Emit( + R3.Event.DONE_SAVING, + { + failed: failed, + saved: saved + } + ) + } + + }.bind(this) + ); + + + + Object.keys(this.idToObject).map( + function(componentId) { + + var component = this.idToObject[componentId]; + + if (this instanceof R3.Entity) { + + /** + * We don't store children objects of entities which are not explicitly defined as children of this entity. + */ + if ( + this.components.indexOf(component) === -1 && + this !== component + ) { + + /** + * We don't want to store this component - but other components may depend on it + */ + console.warn(component.name + ' is being stored because a component depends on it - even though it was not explicitly added to this entity.'); + } + } + + var apiObject = component.toApiObject(); + + toSave.push(apiObject); + + this.publish( + R3.Event.SAVE_COMPONENT, + { + apiObject: apiObject, + remote: remote + }, + function success(result) { + console.log(result); + }, + function error(error) { + console.log(error); + } + ); + + }.bind(this) + ); +}; + +/** + * @return {null|Object} + */ +R3.Component.GetRuntimeObject = function(runtimeInfo) { + + var runtime = null; + + R3.Event.Emit( + R3.Event.GET_RUNTIME, + null, + function(runtimeObject) { + runtime = runtimeObject; + } + ); + + if (runtimeInfo === R3.Component.GRAPHICS_RUNTIME) { + + if (R3.Utils.UndefinedOrNull(runtime.graphics)) { + console.warn('no runtime graphics'); + return null; + } + + return runtime.graphics; + + } else if (runtimeInfo === R3.Component.PHYSICS_RUNTIME) { + + if (R3.Utils.UndefinedOrNull(runtime.physics)) { + console.warn('no runtime physics'); + return null; + } + + return runtime.physics; + + } else if (runtimeInfo === R3.Component.GUI_RUNTIME) { + + if (R3.Utils.UndefinedOrNull(runtime.gui)) { + console.warn('no runtime gui'); + return null; + } + + return runtime.gui; + + } else if (runtimeInfo === R3.Component.SOCKET_RUNTIME) { + + if (R3.Utils.UndefinedOrNull(runtime.sockets)) { + console.warn('no runtime sockets'); + return null; + } + + return runtime.sockets; + + } else if (runtimeInfo === R3.Component.STATISTICS_RUNTIME) { + + if (R3.Utils.UndefinedOrNull(runtime.statistics)) { + console.warn('no runtime statistics'); + return null; + } + + return runtime.statistics; + + } else if (runtimeInfo === R3.Component.DEFAULT_RUNTIME) { + + } else { + console.log('unknown runtime object found : ' + info.runtime); + } + + return null; +}; + +R3.Component.Construct = function(componentType) { + + var info = R3.Component.GetComponentInfo(componentType); + + var componentClass = info.constructor; + + var runtime = R3.Component.GetRuntimeObject(info.runtime); + + if (runtime) { + return new componentClass(runtime); + } else { + return new componentClass(); + } + +}; + +R3.Component.ConstructFromObject = function(rawComponentObject) { + + var runtimeComponent = null; + + // if ( + // rawComponentObject.componentType === 34 && + // rawComponentObject.name.indexOf('Mesh') !== -1 + // ) { + // rawComponentObject.componentType = 7; + // } + + var info = R3.Component.GetComponentInfo(rawComponentObject.componentType); + + var runtime = R3.Component.GetRuntimeObject(info.runtime); + + if (runtime) { + runtimeComponent = new info.constructor(runtime, rawComponentObject); + } else { + runtimeComponent = new info.constructor(rawComponentObject); + } + + return runtimeComponent; +}; \ No newline at end of file diff --git a/src/r3-api-box3.js b/src/r3-api-box3.js new file mode 100644 index 0000000..a16d2fd --- /dev/null +++ b/src/r3-api-box3.js @@ -0,0 +1,45 @@ +/** + * R3.API.Box3 + * @param id + * @param name + * @param parentEntity + * @param min + * @param max + * @constructor + */ +R3.API.Box3 = function ( + id, + name, + parentEntity, + min, + max +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Box (' + id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(min)) { + min = new R3.API.Vector3(0,0,0); + } + this.min = min; + + if (R3.Utils.UndefinedOrNull(max)) { + max = new R3.API.Vector3(1,1,1); + } + this.max = max; + + R3.API.Component.call( + this, + R3.Component.BOX3, + parentEntity + ) +}; + +R3.API.Box3.prototype = Object.create(R3.API.Component.prototype); +R3.API.Box3.prototype.constructor = R3.API.Box3; diff --git a/src/r3-api-canvas.js b/src/r3-api-canvas.js new file mode 100644 index 0000000..e714e8e --- /dev/null +++ b/src/r3-api-canvas.js @@ -0,0 +1,87 @@ +/** + * R3.API.Canvas + * @param id + * @param name + * @param parentEntity + * @param parentTexture + * @param autoUpdateSize + * @param width + * @param height + * @param offset + * @param tabIndex + * @param texts + * @param textBaseline + * @constructor + */ +R3.API.Canvas = function( + id, + name, + parentEntity, + parentTexture, + autoUpdateSize, + width, + height, + offset, + tabIndex, + texts, + textBaseline +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Canvas (' + id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(parentTexture)) { + parentTexture = null; + } + this.parentTexture = parentTexture; + + if (R3.Utils.UndefinedOrNull(autoUpdateSize)) { + autoUpdateSize = true; + } + this.autoUpdateSize = autoUpdateSize; + + if (R3.Utils.UndefinedOrNull(width)) { + width = 512; + } + this.width = width; + + if (R3.Utils.UndefinedOrNull(height)) { + height = 512; + } + this.height = height; + + if (R3.Utils.UndefinedOrNull(offset)) { + offset = new R3.API.Vector2(0,0); + } + this.offset = offset; + + if (R3.Utils.UndefinedOrNull(tabIndex)) { + tabIndex = 1; + } + this.tabIndex = tabIndex; + + if (R3.Utils.UndefinedOrNull(texts)) { + texts = []; + } + this.texts = texts; + + if (R3.Utils.UndefinedOrNull(textBaseline)) { + textBaseline = 'middle'; + } + this.textBaseline = textBaseline; + + R3.API.Component.call( + this, + R3.Component.CANVAS, + parentEntity + ); +}; + +R3.API.Canvas.prototype = Object.create(R3.API.Component.prototype); +R3.API.Canvas.prototype.constructor = R3.API.Canvas; diff --git a/src/r3-api-clock.js b/src/r3-api-clock.js new file mode 100644 index 0000000..4a4e902 --- /dev/null +++ b/src/r3-api-clock.js @@ -0,0 +1,47 @@ +/** + * Raw Clock API object - should always correspond with the Clock Schema + * @constructor + * @param id + * @param name + * @param parentEntity + */ +R3.API.Clock = function( + id, + name, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Clock (' + this.id + ')'; + } + this.name = name; + + R3.API.Component.call( + this, + R3.Component.CLOCK, + parentEntity + ); +}; + +R3.API.Clock.prototype = Object.create(R3.API.Component.prototype); +R3.API.Clock.prototype.constructor = R3.API.Clock; + +/** + * Creates an API camera from an Object camera + * @param objectClock + * @constructor + */ +R3.API.Clock.FromObject = function(objectClock) { + + return new R3.API.Clock( + objectClock.id, + objectClock.name, + objectClock.parentEntity + ); + +}; diff --git a/src/r3-api-color.js b/src/r3-api-color.js new file mode 100644 index 0000000..8fa9e86 --- /dev/null +++ b/src/r3-api-color.js @@ -0,0 +1,51 @@ +/** + * API Color + * @param r + * @param g + * @param b + * @param a + * @constructor + */ +R3.API.Color = function (r, g, b, a) { + + if (R3.Utils.UndefinedOrNull(r)) { + r = 1; + } + this.r = r; + + if (R3.Utils.UndefinedOrNull(g)) { + g = 1; + } + this.g = g; + + if (R3.Utils.UndefinedOrNull(b)) { + b = 1; + } + this.b = b; + + if (R3.Utils.UndefinedOrNull(a)) { + a = 0; + } + this.a = a; + +}; + +/** + * Returns an API color from an Object color + * @param objectColor + * @constructor + */ +R3.API.Color.FromObject = function(objectColor) { + + if (R3.Utils.UndefinedOrNull(objectColor)){ + objectColor = {}; + } + + return new R3.API.Color( + objectColor.r, + objectColor.g, + objectColor.b, + objectColor.a + ); + +}; diff --git a/src/r3-api-controls-0.js b/src/r3-api-controls-0.js new file mode 100644 index 0000000..c34eca2 --- /dev/null +++ b/src/r3-api-controls-0.js @@ -0,0 +1,115 @@ +/** + * Raw Controls API object + * @param id + * @param controlsType + * @param name + * @param canvas + * @param parentEntity + * @property controlsType + * @constructor + */ +R3.API.Controls = function( + id, + name, + controlsType, + canvas, + parentEntity +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(controlsType)) { + controlsType = R3.API.Controls.CONTROLS_TYPE_NONE; + } + this.controlsType = controlsType; + + if (R3.Utils.UndefinedOrNull(name)) { + + name = 'Controls'; + + switch (this.controlsType) { + case R3.API.Controls.CONTROLS_TYPE_TOUCH : + name = 'Controls Editor'; + break; + case R3.API.Controls.CONTROLS_TYPE_KEYBOARD : + name = 'Controls Keyboard'; + break; + case R3.API.Controls.CONTROLS_TYPE_MOUSE : + name = 'Controls Mouse'; + break; + case R3.API.Controls.CONTROLS_TYPE_EDITOR : + name = 'Controls Editor'; + break; + case R3.API.Controls.CONTROLS_TYPE_FIRST_PERSON : + name = 'Controls First Person'; + break; + case R3.API.Controls.CONTROLS_TYPE_ORBIT : + name = 'Controls Orbit'; + break; + } + + name += ' (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(canvas)) { + canvas = null; + } + this.canvas = canvas; + + R3.API.Component.call( + this, + R3.API.Controls.GetComponentType(this.controlsType), + parentEntity + ); +}; + +R3.API.Controls.prototype = Object.create(R3.API.Component.prototype); +R3.API.Controls.prototype.constructor = R3.API.Controls; + +R3.API.Controls.GetComponentType = function(controlsType) { + + var componentType = null; + + switch (controlsType) { + case R3.API.Controls.CONTROLS_TYPE_NONE : + componentType = R3.Component.CONTROLS; + break; + case R3.API.Controls.CONTROLS_TYPE_TOUCH : + componentType = R3.Component.CONTROLS_TOUCH; + break; + case R3.API.Controls.CONTROLS_TYPE_KEYBOARD : + componentType = R3.Component.CONTROLS_KEYBOARD; + break; + case R3.API.Controls.CONTROLS_TYPE_MOUSE : + componentType = R3.Component.CONTROLS_MOUSE; + break; + case R3.API.Controls.CONTROLS_TYPE_EDITOR : + componentType = R3.Component.CONTROLS_EDITOR; + break; + case R3.API.Controls.CONTROLS_TYPE_ORBIT : + componentType = R3.Component.CONTROLS_ORBIT; + break; + default : + throw new Error('unhandled controls type: ' + controlsType); + break; + } + + return componentType; +}; + +R3.API.Controls.D3 = function() {}; + +/** + * Controls Type + * @type {number} + */ +R3.API.Controls.CONTROLS_TYPE_NONE = 0x0; +R3.API.Controls.CONTROLS_TYPE_TOUCH = 0x1; +R3.API.Controls.CONTROLS_TYPE_KEYBOARD = 0x2; +R3.API.Controls.CONTROLS_TYPE_MOUSE = 0x3; +R3.API.Controls.CONTROLS_TYPE_EDITOR = 0x4; +R3.API.Controls.CONTROLS_TYPE_FIRST_PERSON = 0x5; +R3.API.Controls.CONTROLS_TYPE_ORBIT = 0x6; diff --git a/src/r3-api-controls-d3-editor.js b/src/r3-api-controls-d3-editor.js new file mode 100644 index 0000000..086ef11 --- /dev/null +++ b/src/r3-api-controls-d3-editor.js @@ -0,0 +1,44 @@ +/** + * @param apiControls + * @param raycaster + * @param camera + * @constructor + */ +R3.API.Controls.D3.Editor = function( + apiControls, + raycaster, + camera +) { + + if (R3.Utils.UndefinedOrNull(apiControls)) { + apiControls = { + controlsType : R3.API.Controls.CONTROLS_TYPE_EDITOR + }; + } + + if (R3.Utils.UndefinedOrNull(apiControls.controlsType)) { + apiControls.controlsType = R3.API.Controls.CONTROLS_TYPE_EDITOR; + } + + if (R3.Utils.UndefinedOrNull(raycaster)) { + raycaster = new R3.D3.API.Raycaster(); + } + this.raycaster = raycaster; + + if (R3.Utils.UndefinedOrNull(camera)) { + camera = null; + } + this.camera = camera; + + R3.API.Controls.call( + this, + apiControls.id, + apiControls.name, + apiControls.controlsType, + apiControls.canvas, + apiControls.parentEntity + ); +}; + +R3.API.Controls.D3.Editor.prototype = Object.create(R3.API.Controls.prototype); +R3.API.Controls.D3.Editor.prototype.constructor = R3.API.Controls.D3.Editor; diff --git a/src/r3-api-controls-d3-first-person.js b/src/r3-api-controls-d3-first-person.js new file mode 100644 index 0000000..6822d19 --- /dev/null +++ b/src/r3-api-controls-d3-first-person.js @@ -0,0 +1,136 @@ +/** + * R3.API.Controls.D3.FirstPerson + * @param apiControls + * @param camera + * @param enabled + * @param movementSpeed + * @param lookSpeed + * @param lookVertical + * @param autoForward + * @param activeLook + * @param heightSpeed + * @param heightCoef + * @param heightMin + * @param heightMax + * @param constrainVertical + * @param verticalMin + * @param verticalMax + * @param autoSpeedFactor + * @constructor + */ +R3.API.Controls.D3.FirstPerson = function( + apiControls, + camera, + enabled, + movementSpeed, + lookSpeed, + lookVertical, + autoForward, + activeLook, + heightSpeed, + heightCoef, + heightMin, + heightMax, + constrainVertical, + verticalMin, + verticalMax, + autoSpeedFactor +) { + + if (R3.Utils.UndefinedOrNull(apiControls)) { + apiControls = { + controlsType : R3.API.Controls.CONTROLS_TYPE_FIRST_PERSON + }; + } + + if (R3.Utils.UndefinedOrNull(apiControls.controlsType)) { + apiControls.controlsType = R3.API.Controls.CONTROLS_TYPE_FIRST_PERSON; + } + + if (R3.Utils.UndefinedOrNull(camera)) { + camera = null; + } + this.camera = camera; + + if (R3.Utils.UndefinedOrNull(enabled)) { + enabled = true; + } + this.enabled = enabled; + + if (R3.Utils.UndefinedOrNull(movementSpeed)) { + movementSpeed = 1.0; + } + this.movementSpeed = movementSpeed; + + if (R3.Utils.UndefinedOrNull(lookSpeed)) { + lookSpeed = 0.005; + } + this.lookSpeed = lookSpeed; + + if (R3.Utils.UndefinedOrNull(lookVertical)) { + lookVertical = true; + } + this.lookVertical = lookVertical; + + if (R3.Utils.UndefinedOrNull(autoForward)) { + autoForward = false; + } + this.autoForward = autoForward; + + if (R3.Utils.UndefinedOrNull(activeLook)) { + activeLook = false; + } + this.activeLook = activeLook; + + if (R3.Utils.UndefinedOrNull(heightSpeed)) { + heightSpeed = false; + } + this.heightSpeed = heightSpeed; + + if (R3.Utils.UndefinedOrNull(heightCoef)) { + heightCoef = 1.0; + } + this.heightCoef = heightCoef; + + if (R3.Utils.UndefinedOrNull(heightMin)) { + heightMin = 0.0; + } + this.heightMin = heightMin; + + if (R3.Utils.UndefinedOrNull(heightMax)) { + heightMax = 1.0; + } + this.heightMax = heightMax; + + if (R3.Utils.UndefinedOrNull(constrainVertical)) { + constrainVertical = false; + } + this.constrainVertical = constrainVertical; + + if (R3.Utils.UndefinedOrNull(verticalMin)) { + verticalMin = 0; + } + this.verticalMin = verticalMin; + + if (R3.Utils.UndefinedOrNull(verticalMax)) { + verticalMax = Math.PI; + } + this.verticalMax = verticalMax; + + if (R3.Utils.UndefinedOrNull(autoSpeedFactor)) { + autoSpeedFactor = 0; + } + this.autoSpeedFactor = autoSpeedFactor; + + R3.API.Controls.call( + this, + apiControls.id, + apiControls.name, + apiControls.controlsType, + apiControls.canvas, + apiControls.parentEntity + ); +}; + +R3.API.Controls.D3.FirstPerson.prototype = Object.create(R3.API.Controls.prototype); +R3.API.Controls.D3.FirstPerson.prototype.constructor = R3.API.Controls.D3.FirstPerson; diff --git a/src/r3-api-controls-d3-orbit.js b/src/r3-api-controls-d3-orbit.js new file mode 100644 index 0000000..38c39a1 --- /dev/null +++ b/src/r3-api-controls-d3-orbit.js @@ -0,0 +1,147 @@ +/** + * R3.API.Controls.D3.Orbit + * @param apiControls + * @param camera + * @param target + * @param enabled + * @param minDistance + * @param maxDistance + * @param minZoom + * @param maxZoom + * @param minPolarAngle + * @param maxPolarAngle + * @param enableDamping + * @param dampingFactor + * @param enableZoom + * @param zoomSpeed + * @param enableRotate + * @param rotateSpeed + * @param enablePan + * @param keyPanSpeed + * @param autoRotate + * @param autoRotateSpeed + * @param enableKeys + * @constructor + */ +R3.API.Controls.D3.Orbit = function( + apiControls, + camera, + target, + enabled, + minPolarAngle, + maxPolarAngle, + enableDamping, + dampingFactor, + enableZoom, + zoomSpeed, + enableRotate, + rotateSpeed, + enablePan, + keyPanSpeed, + autoRotate, + autoRotateSpeed, + enableKeys +) { + + if (R3.Utils.UndefinedOrNull(apiControls)) { + apiControls = { + controlsType : R3.API.Controls.CONTROLS_TYPE_ORBIT + }; + } + + if (R3.Utils.UndefinedOrNull(apiControls.controlsType)) { + apiControls.controlsType = R3.API.Controls.CONTROLS_TYPE_ORBIT; + } + + if (R3.Utils.UndefinedOrNull(camera)) { + camera = null; + } + this.camera = camera; + + if (R3.Utils.UndefinedOrNull(target)) { + target = null; + } + this.target = target; + + if (R3.Utils.UndefinedOrNull(enabled)) { + enabled = true; + } + this.enabled = enabled; + + if (R3.Utils.UndefinedOrNull(minPolarAngle)) { + minPolarAngle = 0; + } + this.minPolarAngle = minPolarAngle; + + if (R3.Utils.UndefinedOrNull(maxPolarAngle)) { + maxPolarAngle = Math.PI; + } + this.maxPolarAngle = maxPolarAngle; + + if (R3.Utils.UndefinedOrNull(enableDamping)) { + enableDamping = false; + } + this.enableDamping = enableDamping; + + if (R3.Utils.UndefinedOrNull(dampingFactor)) { + dampingFactor = 0.25; + } + this.dampingFactor = dampingFactor; + + if (R3.Utils.UndefinedOrNull(enableZoom)) { + enableZoom = true; + } + this.enableZoom = enableZoom; + + if (R3.Utils.UndefinedOrNull(zoomSpeed)) { + zoomSpeed = 1.0; + } + this.zoomSpeed = zoomSpeed; + + if (R3.Utils.UndefinedOrNull(enableRotate)) { + enableRotate = true; + } + this.enableRotate = enableRotate; + + if (R3.Utils.UndefinedOrNull(rotateSpeed)) { + rotateSpeed = 1.0; + } + this.rotateSpeed = rotateSpeed; + + if (R3.Utils.UndefinedOrNull(enablePan)) { + enablePan = true; + } + this.enablePan = enablePan; + + if (R3.Utils.UndefinedOrNull(keyPanSpeed)) { + keyPanSpeed = 7.0; + } + this.keyPanSpeed = keyPanSpeed; + + if (R3.Utils.UndefinedOrNull(autoRotate)) { + autoRotate = false; + } + this.autoRotate = autoRotate; + + if (R3.Utils.UndefinedOrNull(autoRotateSpeed)) { + autoRotateSpeed = 2.0; + } + this.autoRotateSpeed = autoRotateSpeed; + + if (R3.Utils.UndefinedOrNull(enableKeys)) { + enableKeys = false; + } + this.enableKeys = enableKeys; + + R3.API.Controls.call( + this, + apiControls.id, + apiControls.name, + apiControls.controlsType, + apiControls.canvas, + apiControls.parentEntity + ); +}; + +R3.API.Controls.D3.Orbit.prototype = Object.create(R3.API.Controls.prototype); +R3.API.Controls.D3.Orbit.prototype.constructor = R3.API.Controls.D3.Orbit; diff --git a/src/r3-api-controls-keyboard.js b/src/r3-api-controls-keyboard.js new file mode 100644 index 0000000..132fbeb --- /dev/null +++ b/src/r3-api-controls-keyboard.js @@ -0,0 +1,30 @@ +/** + * @param apiControls + * @constructor + */ +R3.API.Controls.Keyboard = function( + apiControls +) { + + if (R3.Utils.UndefinedOrNull(apiControls)) { + apiControls = { + controlsType : R3.API.Controls.CONTROLS_TYPE_KEYBOARD + }; + } + + if (R3.Utils.UndefinedOrNull(apiControls.controlsType)) { + apiControls.controlsType = R3.API.Controls.CONTROLS_TYPE_KEYBOARD; + } + + R3.API.Controls.call( + this, + apiControls.id, + apiControls.name, + apiControls.controlsType, + apiControls.canvas, + apiControls.parentEntity + ); +}; + +R3.API.Controls.Keyboard.prototype = Object.create(R3.API.Controls.prototype); +R3.API.Controls.Keyboard.prototype.constructor = R3.API.Controls.Keyboard; diff --git a/src/r3-api-controls-mouse.js b/src/r3-api-controls-mouse.js new file mode 100644 index 0000000..2b46176 --- /dev/null +++ b/src/r3-api-controls-mouse.js @@ -0,0 +1,31 @@ +/** + * @param apiControls + * @constructor + */ +R3.API.Controls.Mouse = function( + apiControls +) { + + if (R3.Utils.UndefinedOrNull(apiControls)) { + apiControls = { + controlsType : R3.API.Controls.CONTROLS_TYPE_MOUSE + }; + } + + if (R3.Utils.UndefinedOrNull(apiControls.controlsType)) { + apiControls.controlsType = R3.API.Controls.CONTROLS_TYPE_MOUSE; + } + + R3.API.Controls.call( + this, + apiControls.id, + apiControls.name, + apiControls.controlsType, + apiControls.canvas, + apiControls.parentEntity + ); +}; + +R3.API.Controls.Mouse.prototype = Object.create(R3.API.Controls.prototype); +R3.API.Controls.Mouse.prototype.constructor = R3.API.Controls.Mouse; + diff --git a/src/r3-api-controls-touch.js b/src/r3-api-controls-touch.js new file mode 100644 index 0000000..bdedc7f --- /dev/null +++ b/src/r3-api-controls-touch.js @@ -0,0 +1,37 @@ +/** + * @param apiControls + * @param sensitivity + * @constructor + */ +R3.API.Controls.Touch = function( + apiControls, + sensitivity +) { + + if (R3.Utils.UndefinedOrNull(apiControls)) { + apiControls = { + controlsType : R3.API.Controls.CONTROLS_TYPE_TOUCH + }; + } + + if (R3.Utils.UndefinedOrNull(apiControls.controlsType)) { + apiControls.controlsType = R3.API.Controls.CONTROLS_TYPE_TOUCH; + } + + if (R3.Utils.UndefinedOrNull(sensitivity)) { + sensitivity = 5; + } + this.sensitivity = sensitivity; + + R3.API.Controls.call( + this, + apiControls.id, + apiControls.name, + apiControls.controlsType, + apiControls.canvas, + apiControls.parentEntity + ); +}; + +R3.API.Controls.Touch.prototype = Object.create(R3.API.Controls.prototype); +R3.API.Controls.Touch.prototype.constructor = R3.API.Controls.Touch; diff --git a/src/r3-api-curve-a.js b/src/r3-api-curve-a.js new file mode 100644 index 0000000..0c804df --- /dev/null +++ b/src/r3-api-curve-a.js @@ -0,0 +1,89 @@ +/** + * R3.API.Curve + * @param id + * @param name + * @param curveType + * @param parentEntity + * @param arcLenghDivisions + * @constructor + */ +R3.API.Curve = function ( + id, + name, + curveType, + parentEntity, + arcLenghDivisions +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(curveType)) { + curveType = R3.API.Curve.CURVE_TYPE_NONE; + } + this.curveType = curveType; + + if (R3.Utils.UndefinedOrNull(name)) { + + switch (this.curveType) { + case R3.API.Curve.CURVE_TYPE_NONE : + name = 'Curve'; + break; + case R3.API.Curve.CURVE_TYPE_PATH : + name = 'Curve Path'; + break; + default: + console.log('no nice name for curve'); + } + + name += ' (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(arcLenghDivisions)) { + arcLenghDivisions = 200; + } + this.arcLenghDivisions = arcLenghDivisions; + + R3.API.Component.call( + this, + R3.API.Curve.GetComponentType(this.curveType), + parentEntity + ); +}; + +R3.API.Curve.prototype = Object.create(R3.API.Curve.prototype); +R3.API.Curve.prototype.constructor = R3.API.Curve; + +R3.API.Curve.GetComponentType = function(curveType) { + + var componentType = null; + + switch (curveType) { + case R3.API.Curve.CURVE_TYPE_NONE : + componentType = R3.Component.CURVE; + break; + case R3.API.Curve.CURVE_TYPE_PATH : + componentType = R3.Component.CURVE_PATH; + break; + case R3.API.Curve.CURVE_TYPE_PATH_2D : + componentType = R3.Component.CURVE_PATH_D2; + break; + case R3.API.Curve.CURVE_TYPE_PATH_2D_SHAPE : + componentType = R3.Component.CURVE_PATH_D2_SHAPE; + break; + default : + throw new Error('unhandled curve type'); + } + + return componentType; +}; + +R3.API.Curve.CURVE_TYPE_NONE = 0x0; +R3.API.Curve.CURVE_TYPE_PATH = 0x1; +R3.API.Curve.CURVE_TYPE_PATH_2D = 0x2; +R3.API.Curve.CURVE_TYPE_PATH_2D_SHAPE = 0x3; + + diff --git a/src/r3-api-curve-path-a.js b/src/r3-api-curve-path-a.js new file mode 100644 index 0000000..e1f93a8 --- /dev/null +++ b/src/r3-api-curve-path-a.js @@ -0,0 +1,44 @@ +/** + * R3.API.Curve.Path + * @constructor + * @param apiCurve + * @param curves + * @param autoClose + */ +R3.API.Curve.Path = function ( + apiCurve, + curves, + autoClose +) { + if (R3.Utils.UndefinedOrNull(apiCurve)) { + apiCurve = { + curveType: R3.API.Curve.CURVE_TYPE_PATH + }; + } + + if (R3.Utils.UndefinedOrNull(apiCurve.curveType)) { + apiCurve.curveType = R3.API.Curve.CURVE_TYPE_PATH; + } + + if (R3.Utils.UndefinedOrNull(curves)) { + curves = []; + } + this.curves = curves; + + if (R3.Utils.UndefinedOrNull(autoClose)) { + autoClose = false; + } + this.autoClose = autoClose; + + R3.API.Curve.call( + this, + apiCurve.id, + apiCurve.name, + apiCurve.curveType, + apiCurve.parentEntity, + apiCurve.arcLenghDivisions + ); +}; + +R3.API.Curve.Path.prototype = Object.create(R3.API.Curve.prototype); +R3.API.Curve.Path.prototype.constructor = R3.API.Curve.Path; diff --git a/src/r3-api-curve-path-d2-a.js b/src/r3-api-curve-path-d2-a.js new file mode 100644 index 0000000..e8f1cfc --- /dev/null +++ b/src/r3-api-curve-path-d2-a.js @@ -0,0 +1,35 @@ +/** + * R3.API.Curve.Path.D2 + * @constructor + * @param apiCurvePath + * @param points + */ +R3.API.Curve.Path.D2 = function ( + apiCurvePath, + points +) { + if (R3.Utils.UndefinedOrNull(apiCurvePath)) { + apiCurvePath = { + curveType: R3.API.Curve.CURVE_TYPE_PATH_2D + }; + } + + if (R3.Utils.UndefinedOrNull(apiCurvePath.curveType)) { + apiCurvePath.curveType = R3.API.Curve.CURVE_TYPE_PATH_2D; + } + + if (R3.Utils.UndefinedOrNull(points)) { + points = []; + } + this.points = points; + + R3.API.Curve.Path.call( + this, + apiCurvePath, + apiCurvePath.curves, + apiCurvePath.autoClose + ); +}; + +R3.API.Curve.Path.D2.prototype = Object.create(R3.API.Curve.Path.prototype); +R3.API.Curve.Path.D2.prototype.constructor = R3.API.Curve.Path.D2; diff --git a/src/r3-api-curve-path-d2-shape.js b/src/r3-api-curve-path-d2-shape.js new file mode 100644 index 0000000..bec2134 --- /dev/null +++ b/src/r3-api-curve-path-d2-shape.js @@ -0,0 +1,27 @@ +/** + * R3.API.Curve.Path.D2.Shape + * @constructor + * @param apiCurvePathD2 + */ +R3.API.Curve.Path.D2.Shape = function ( + apiCurvePathD2 +) { + if (R3.Utils.UndefinedOrNull(apiCurvePathD2)) { + apiCurvePathD2 = { + curveType : R3.API.Curve.CURVE_TYPE_PATH_2D_SHAPE + }; + } + + if (R3.Utils.UndefinedOrNull(apiCurvePathD2.curveType)) { + apiCurvePathD2.curveType = R3.API.Curve.CURVE_TYPE_PATH_2D_SHAPE ; + } + + R3.API.Curve.Path.call( + this, + apiCurvePathD2, + apiCurvePathD2.points + ); +}; + +R3.API.Curve.Path.D2.Shape.prototype = Object.create(R3.API.Curve.Path.D2.prototype); +R3.API.Curve.Path.D2.Shape.prototype.constructor = R3.API.Curve.Path.D2.Shape; diff --git a/src/r3-api-custom-code.js b/src/r3-api-custom-code.js new file mode 100644 index 0000000..ad004b4 --- /dev/null +++ b/src/r3-api-custom-code.js @@ -0,0 +1,45 @@ +/** + * Custom Code Component + * @param id + * @param name + * @param eventId + * @param code + * @param parentEntity + * @constructor + */ +R3.API.CustomCode = function ( + id, + name, + eventId, + code, + parentEntity +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'CustomCode (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(eventId)) { + eventId = 42; + } + this.eventId = eventId; + + if (R3.Utils.UndefinedOrNull(code)) { + code = "return null;\n//@ sourceURL=" + this.name + ".js"; + } + this.code = code; + + R3.API.Component.call( + this, + R3.Component.CUSTOM_CODE, + parentEntity + ); +}; + +R3.API.CustomCode.prototype = Object.create(R3.API.Component.prototype); +R3.API.CustomCode.prototype.constructor = R3.API.CustomCode; diff --git a/src/r3-api-dom-element.js b/src/r3-api-dom-element.js new file mode 100644 index 0000000..5e570ab --- /dev/null +++ b/src/r3-api-dom-element.js @@ -0,0 +1,53 @@ +/** + * API DomElement + * @param id + * @param name + * @param domElementId + * @param parentEntity + * @constructor + */ +R3.API.DomElement = function( + id, + name, + domElementId, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'DOM Element (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(domElementId)) { + domElementId = ''; + } + this.domElementId = domElementId; + + R3.API.Component.call( + this, + R3.Component.DOM_ELEMENT, + parentEntity + ); +}; + +R3.API.DomElement.prototype = Object.create(R3.API.Component.prototype); +R3.API.DomElement.prototype.constructor = R3.API.DomElement; + +/** + * Returns an API domElement from an Object domElement + * @param objectDomElement + * @constructor + */ +R3.API.DomElement.FromObject = function (objectDomElement) { + return new R3.API.DomElement( + objectDomElement.id, + objectDomElement.name, + objectDomElement.domElementId, + objectDomElement.parentEntity + ) +}; diff --git a/src/r3-api-draw-range.js b/src/r3-api-draw-range.js new file mode 100644 index 0000000..70516bf --- /dev/null +++ b/src/r3-api-draw-range.js @@ -0,0 +1,45 @@ +/** + * R3.API.Box3 + * @constructor + * @param id + * @param name + * @param parentEntity + * @param start + * @param count + */ +R3.API.DrawRange = function ( + id, + name, + parentEntity, + start, + count +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'DrawRange (' + id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(start)) { + start = 0; + } + this.start = start; + + if (R3.Utils.UndefinedOrNull(count)) { + count = Infinity; + } + this.count = count; + + R3.API.Component.call( + this, + R3.Component.DRAW_RANGE, + parentEntity + ) +}; + +R3.API.DrawRange.prototype = Object.create(R3.API.Component.prototype); +R3.API.DrawRange.prototype.constructor = R3.API.DrawRange; diff --git a/src/r3-api-entity-manager.js b/src/r3-api-entity-manager.js new file mode 100644 index 0000000..9398d21 --- /dev/null +++ b/src/r3-api-entity-manager.js @@ -0,0 +1,67 @@ +/** + * Entity API Object (for storing / loading entities to and from API) + * @constructor + * @param id + * @param name + * @param entities R3.API.Entity[] + * @param defaultEntity + * @param parentEntity + */ +R3.API.EntityManager = function( + id, + name, + entities, + defaultEntity, + parentEntity +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Entity Manager (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(entities)) { + entities = []; + } + this.entities = entities; + + if (R3.Utils.UndefinedOrNull(defaultEntity)) { + defaultEntity = null; + } + this.defaultEntity = defaultEntity; + + R3.API.Component.call( + this, + R3.Component.ENTITY_MANAGER, + parentEntity + ); +}; + +R3.API.EntityManager.prototype = Object.create(R3.API.Component.prototype); +R3.API.EntityManager.prototype.constructor = R3.API.EntityManager; + +/** + * Creates an API entity manager from an Object entity manager + * @param objectEntityManager + * @constructor + */ +R3.API.EntityManager.FromObject = function(objectEntityManager) { + + var apiEntities = objectEntityManager.entities.map( + function (objectEntity) { + return R3.API.Entity.FromObject(objectEntity); + } + ); + + return new R3.API.EntityManager( + objectEntityManager.id, + objectEntityManager.name, + apiEntities, + objectEntityManager.defaultEntity, + objectEntityManager.parentEntity + ); +}; diff --git a/src/r3-api-entity.js b/src/r3-api-entity.js new file mode 100644 index 0000000..8c33190 --- /dev/null +++ b/src/r3-api-entity.js @@ -0,0 +1,52 @@ +/** + * Entity API Object (for storing / loading entities to and from API) + * @param id + * @param name + * @param components R3.Component[] + * @param parentEntity R3.Entity + * @constructor + */ +R3.API.Entity = function( + id, + name, + components, + parentEntity +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Entity (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(components)) { + components = []; + } + this.components = components; + + R3.API.Component.call( + this, + R3.Component.ENTITY, + parentEntity + ); +}; + +R3.API.Entity.prototype = Object.create(R3.API.Component.prototype); +R3.API.Entity.prototype.constructor = R3.API.Entity; + +/** + * Returns an API entity from an Object entity + * @param objectEntity + * @constructor + */ +R3.API.Entity.FromObject = function(objectEntity) { + return new R3.API.Entity( + objectEntity.id, + objectEntity.name, + objectEntity.components, + objectEntity.parentEntity + ) +}; diff --git a/src/r3-api-graphics-runtime-a.js b/src/r3-api-graphics-runtime-a.js new file mode 100644 index 0000000..769621c --- /dev/null +++ b/src/r3-api-graphics-runtime-a.js @@ -0,0 +1,64 @@ +/** + * R3.API.GraphicsRuntime + * @param id + * @param name + * @param graphicsType + * @param parentEntity + * @constructor + */ +R3.API.GraphicsRuntime = function( + id, + name, + graphicsType, + parentEntity +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Graphics Runtime (' + id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(graphicsType)) { + graphicsType = null; + } + this.graphicsType = graphicsType; + + R3.API.Component.call( + this, + R3.API.GraphicsRuntime.GetComponentType(this.graphicsType), + parentEntity + ); +}; + +R3.API.GraphicsRuntime.prototype = Object.create(R3.API.Component.prototype); +R3.API.GraphicsRuntime.prototype.constructor = R3.API.GraphicsRuntime; + +R3.API.GraphicsRuntime.GetComponentType = function(graphicsType) { + + var componentType = null; + + switch (graphicsType) { + case R3.API.GraphicsRuntime.GRAPHICS_TYPE_NONE : + componentType = R3.Component.GRAPHICS; + break; + case R3.API.GraphicsRuntime.GRAPHICS_TYPE_THREE_JS : + componentType = R3.Component.GRAPHICS_THREE; + break; + case R3.API.GraphicsRuntime.GRAPHICS_TYPE_IMPACT_JS : + componentType = R3.Component.GRAPHICS_IMPACT; + break; + default: + throw new Error('Invalid graphics type'); + + } + + return componentType; +}; + +R3.API.GraphicsRuntime.GRAPHICS_TYPE_NONE = 0x0; +R3.API.GraphicsRuntime.GRAPHICS_TYPE_THREE_JS = 0x1; +R3.API.GraphicsRuntime.GRAPHICS_TYPE_IMPACT_JS = 0x2; diff --git a/src/r3-api-graphics-runtime-impact.js b/src/r3-api-graphics-runtime-impact.js new file mode 100644 index 0000000..ec62464 --- /dev/null +++ b/src/r3-api-graphics-runtime-impact.js @@ -0,0 +1,30 @@ +/** + * R3.API.GraphicsRuntime.Impact + * @constructor + * @param apiGraphicsRuntime + */ +R3.API.GraphicsRuntime.Impact = function( + apiGraphicsRuntime +) { + if (R3.Utils.UndefinedOrNull(apiGraphicsRuntime)) { + apiGraphicsRuntime = { + graphicsType : R3.API.GraphicsRuntime.GRAPHICS_TYPE_IMPACT_JS + }; + } + + if (R3.Utils.UndefinedOrNull(apiGraphicsRuntime.graphicsType)) { + apiGraphicsRuntime.graphicsType = R3.API.GraphicsRuntime.GRAPHICS_TYPE_IMPACT_JS; + } + + R3.API.GraphicsRuntime.call( + this, + apiGraphicsRuntime.id, + apiGraphicsRuntime.name, + apiGraphicsRuntime.graphicsType, + apiGraphicsRuntime.parentEntity + ); + +}; + +R3.API.GraphicsRuntime.Impact.prototype = Object.create(R3.API.GraphicsRuntime.prototype); +R3.API.GraphicsRuntime.Impact.prototype.constructor = R3.API.GraphicsRuntime.Impact; diff --git a/src/r3-api-graphics-runtime-three.js b/src/r3-api-graphics-runtime-three.js new file mode 100644 index 0000000..a91d5ea --- /dev/null +++ b/src/r3-api-graphics-runtime-three.js @@ -0,0 +1,30 @@ +/** + * R3.API.GraphicsRuntime.Three + * @constructor + * @param apiGraphicsRuntime + */ +R3.API.GraphicsRuntime.Three = function( + apiGraphicsRuntime +) { + if (R3.Utils.UndefinedOrNull(apiGraphicsRuntime)) { + apiGraphicsRuntime = { + graphicsType : R3.API.GraphicsRuntime.GRAPHICS_TYPE_THREE_JS + }; + } + + if (R3.Utils.UndefinedOrNull(apiGraphicsRuntime.graphicsType)) { + apiGraphicsRuntime.graphicsType = R3.API.GraphicsRuntime.GRAPHICS_TYPE_THREE_JS; + } + + R3.API.GraphicsRuntime.call( + this, + apiGraphicsRuntime.id, + apiGraphicsRuntime.name, + apiGraphicsRuntime.graphicsType, + apiGraphicsRuntime.parentEntity + ); + +}; + +R3.API.GraphicsRuntime.Three.prototype = Object.create(R3.API.GraphicsRuntime.prototype); +R3.API.GraphicsRuntime.Three.prototype.constructor = R3.API.GraphicsRuntime.Three; diff --git a/src/r3-api-group.js b/src/r3-api-group.js new file mode 100644 index 0000000..6d0dd7e --- /dev/null +++ b/src/r3-api-group.js @@ -0,0 +1,52 @@ +/** + * R3.API.Group + * @constructor + * @param id + * @param name + * @param parentEntity + * @param start + * @param count + * @param materialIndex + */ +R3.API.Group = function ( + id, + name, + parentEntity, + start, + count, + materialIndex +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Group (' + id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(start)) { + start = 0; + } + this.start = start; + + if (R3.Utils.UndefinedOrNull(count)) { + count = 0; + } + this.count = count; + + if (R3.Utils.UndefinedOrNull(materialIndex)) { + materialIndex = 0; + } + this.materialIndex = materialIndex; + + R3.API.Component.call( + this, + R3.Component.GROUP, + parentEntity + ) +}; + +R3.API.Group.prototype = Object.create(R3.API.Component.prototype); +R3.API.Group.prototype.constructor = R3.API.Group; diff --git a/src/r3-api-gui.js b/src/r3-api-gui.js new file mode 100644 index 0000000..2e6277f --- /dev/null +++ b/src/r3-api-gui.js @@ -0,0 +1,64 @@ +/** + * Raw GUI API object - should always correspond with the GUI Schema + * @param id + * @param name + * @param domElement + * @param parentEntity + * @constructor + */ +R3.API.GUI = function( + id, + name, + domElement, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'GUI (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(domElement)) { + domElement = null; + } + this.domElement = domElement; + + R3.API.Component.call( + this, + R3.Component.GUI, + parentEntity + ); +}; + +R3.API.GUI.prototype = Object.create(R3.API.Component.prototype); +R3.API.GUI.prototype.constructor = R3.API.GUI; + +/** + * Creates an API GUI from an Object GUI + * @param objectGUI + * @constructor + */ +R3.API.GUI.FromObject = function(objectGUI) { + + var apiDomElement = null; + if (objectGUI.domElement) { + if (objectGUI.domElement instanceof Object) { + apiDomElement = R3.API.DomElement.FromObject(objectGUI.domElement); + } else { + apiDomElement = objectGUI.domElement; + } + } + + return new R3.API.GUI( + objectGUI.id, + objectGUI.name, + apiDomElement, + objectGUI.parentEntity + ); + +}; diff --git a/src/r3-api-image.js b/src/r3-api-image.js new file mode 100644 index 0000000..87a6a9e --- /dev/null +++ b/src/r3-api-image.js @@ -0,0 +1,100 @@ +/** + * R3.API.Image + * @param id + * @param name + * @param parentEntity + * @param parentTexture + * @param fileName + * @param extension + * @param path + * @param contentType + * @param size + * @param width + * @param height + * @constructor + */ +R3.API.Image = function( + id, + name, + parentEntity, + parentTexture, + fileName, + extension, + path, + contentType, + size, + width, + height +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Image ' + id; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(parentTexture)) { + parentTexture = null; + } + this.parentTexture = parentTexture; + + if (R3.Utils.UndefinedOrNull(fileName)) { + fileName = R3.Utils.LowerUnderscore(name); + } + this.fileName = fileName; + + if (R3.Utils.UndefinedOrNull(extension)) { + extension = '.unknown'; + } + this.extension = extension; + + if (R3.Utils.UndefinedOrNull(path)) { + path = '/'; + } + this.path = path; + + if (R3.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 (R3.Utils.UndefinedOrNull(size)) { + size = 0; + } + this.size = size; + + if (R3.Utils.UndefinedOrNull(width)) { + width = 0; + } + this.width = width; + + if (R3.Utils.UndefinedOrNull(height)) { + height = 0; + } + this.height = height; + + R3.API.Component.call( + this, + R3.Component.IMAGE, + parentEntity + ); +}; + +R3.API.Image.prototype = Object.create(R3.API.Component.prototype); +R3.API.Image.prototype.constructor = R3.API.Image; diff --git a/src/r3-api-matrix4.js b/src/r3-api-matrix4.js new file mode 100644 index 0000000..a7db1d5 --- /dev/null +++ b/src/r3-api-matrix4.js @@ -0,0 +1,159 @@ +/** + * Api Matrix 4 + * @param row0 R3.API.Vector4 + * @param row1 R3.API.Vector4 + * @param row2 R3.API.Vector4 + * @param row3 R3.API.Vector4 + * @constructor + */ +R3.API.Matrix4 = function ApiMatrix4( + row0, + row1, + row2, + row3 +) { + this.rows = []; + + if (R3.Utils.UndefinedOrNull(row0)) { + row0 = new R3.API.Vector4(1, 0, 0, 0); + } + this.rows[0] = row0; + + if (R3.Utils.UndefinedOrNull(row1)) { + row1 = new R3.API.Vector4(0, 1, 0, 0); + } + this.rows[1] = row1; + + if (R3.Utils.UndefinedOrNull(row2)) { + row2 = new R3.API.Vector4(0, 0, 1, 0); + } + this.rows[2] = row2; + + if (R3.Utils.UndefinedOrNull(row3)) { + row3 = new R3.API.Vector4(0, 0, 0, 1); + } + this.rows[3] = row3; + + this.temp = []; + this.temp.push( + new R3.API.Vector4() + ); + + this.temp.push( + new R3.API.Vector4() + ); + + this.temp.push( + new R3.API.Vector4() + ); + + this.temp.push( + new R3.API.Vector4() + ); + + this.forward = new R3.API.Vector4(); + this.left = new R3.API.Vector4(); + this.up = new R3.API.Vector4(); +}; + +/** + * Returns an API matrix from an Object matrix + * @param objectMatrix + * @constructor + */ +R3.API.Matrix4.FromObject = function(objectMatrix) { + + if (objectMatrix.rows) { + return new R3.API.Matrix4( + R3.API.Vector4.FromObject(objectMatrix.rows[0]), + R3.API.Vector4.FromObject(objectMatrix.rows[1]), + R3.API.Vector4.FromObject(objectMatrix.rows[2]), + R3.API.Vector4.FromObject(objectMatrix.rows[3]) + ); + } else if (objectMatrix instanceof Array) { + return new R3.API.Matrix4( + R3.API.Vector4.FromObject(objectMatrix[0]), + R3.API.Vector4.FromObject(objectMatrix[1]), + R3.API.Vector4.FromObject(objectMatrix[2]), + R3.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?'); + } +}; + +R3.API.Matrix4.prototype.rotationMatrixX = function (radians) { + this.identity(); + this.rows[1] = new R3.API.Vector4(0, Math.cos(radians), -1 * Math.sin(radians), 0); + this.rows[2] = new R3.API.Vector4(0, Math.sin(radians), Math.cos(radians), 0); + return this; +}; + +R3.API.Matrix4.prototype.rotationMatrixY = function (radians) { + this.identity(); + this.rows[0] = new R3.API.Vector4( + Math.cos(radians), + 0, + Math.sin(radians), + 0 + ); + this.rows[2] = new R3.API.Vector4( + -1 * Math.sin(radians), + 0, + Math.cos(radians), + 0 + ); + return this; +}; + +R3.API.Matrix4.prototype.rotationMatrixZ = function (radians) { + this.identity(); + this.rows[0] = new R3.API.Vector4(Math.cos(radians), -1 * Math.sin(radians), 0, 0); + this.rows[1] = new R3.API.Vector4(Math.sin(radians), Math.cos(radians), 0, 0); + return this; +}; + +R3.API.Matrix4.prototype.rotateX = function (radians, point) { + this.identity(); + this.rotationMatrixX(radians); + return this.multiply(point); +}; + +R3.API.Matrix4.prototype.rotateY = function (radians, point) { + this.identity(); + this.rotationMatrixY(radians); + return this.multiply(point); +}; + +R3.API.Matrix4.prototype.rotateZ = function (radians, point) { + this.identity(); + this.rotationMatrixZ(radians); + return this.multiply(point); +}; + +R3.API.Matrix4.prototype.multiply = function (mvp) { + if (mvp instanceof R3.API.Quaternion || mvp instanceof R3.API.Vector4) { + return new R3.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 R3.API.Vector3) { + return new R3.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 + ); + } +}; + +R3.API.Matrix4.prototype.identity = function () { + this.rows = [ + new R3.API.Vector4(1, 0, 0, 0), + new R3.API.Vector4(0, 1, 0, 0), + new R3.API.Vector4(0, 0, 1, 0), + new R3.API.Vector4(0, 0, 0, 1) + ]; +}; diff --git a/src/r3-api-mouse.js b/src/r3-api-mouse.js new file mode 100644 index 0000000..ebe6f49 --- /dev/null +++ b/src/r3-api-mouse.js @@ -0,0 +1,45 @@ +/** + * API Mouse + * @param id + * @param name + * @param parentEntity + * @param x + * @param y + * @constructor + */ +R3.API.Mouse = function( + id, + name, + parentEntity, + x, + y +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Mouse (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(x)) { + x = 0; + } + this.x = x; + + if (R3.Utils.UndefinedOrNull(y)) { + y = 0; + } + this.y = y; + + R3.API.Component.call( + this, + R3.Component.MOUSE, + parentEntity + ); +}; + +R3.API.Mouse.prototype = Object.create(R3.API.Component.prototype); +R3.API.Mouse.prototype.constructor = R3.API.Mouse; diff --git a/src/r3-api-number.js b/src/r3-api-number.js new file mode 100644 index 0000000..a22e60f --- /dev/null +++ b/src/r3-api-number.js @@ -0,0 +1,34 @@ +/** + * R3.API.Number + * @constructor + * @param value + * @param grain + * @param min + * @param max + */ +R3.API.Number = function ( + value, + grain, + min, + max +) { + if (R3.Utils.UndefinedOrNull(value)) { + value = 0; + } + this.value = value; + + if (R3.Utils.UndefinedOrNull(grain)) { + grain = 0.1; + } + this.grain = grain; + + if (R3.Utils.UndefinedOrNull(min)) { + min = 0; + } + this.min = min; + + if (R3.Utils.UndefinedOrNull(max)) { + max = 100; + } + this.max = max; +}; \ No newline at end of file diff --git a/src/r3-api-plane.js b/src/r3-api-plane.js new file mode 100644 index 0000000..d6257a1 --- /dev/null +++ b/src/r3-api-plane.js @@ -0,0 +1,53 @@ +R3.API.Plane = function ( + id, + name, + normal, + constant, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Plane (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(normal)) { + normal = new R3.API.Vector3(1,0,0); + } + this.normal = normal; + + if (R3.Utils.UndefinedOrNull(constant)) { + constant = 0; + } + this.constant = constant; + + R3.API.Component.call( + this, + R3.Component.PLANE, + parentEntity + ); +}; + + +R3.API.Plane.prototype = Object.create(R3.API.Component.prototype); +R3.API.Plane.prototype.constructor = R3.API.Plane; + +/** + * Returns an API vector from an Object vector + * @param objectPlane + * @constructor + */ +R3.API.Plane.FromObject = function (objectPlane) { + return new R3.API.Plane( + objectPlane.id, + objectPlane.name, + R3.API.Vector3.FromObject(objectPlane.normal), + objectPlane.constant, + objectPlane.parentEntity + ); +}; diff --git a/src/r3-api-quaternion-a.js b/src/r3-api-quaternion-a.js new file mode 100644 index 0000000..5a35d23 --- /dev/null +++ b/src/r3-api-quaternion-a.js @@ -0,0 +1,237 @@ +/** + * Quaternion + * @param x + * @param y + * @param z + * @param w + * @param axis + * @param angle + * @constructor + */ +R3.API.Quaternion = function ( + x, + y, + z, + w, + axis, + angle +) { + + if (R3.Utils.UndefinedOrNull(x)) { + x = 0; + } + this.x = x; + + if (R3.Utils.UndefinedOrNull(y)) { + y = 0; + } + this.y = y; + + if (R3.Utils.UndefinedOrNull(z)) { + z = 0; + } + this.z = z; + + if (R3.Utils.UndefinedOrNull(w)) { + w = 1; + } + this.w = w; + + if (R3.Utils.UndefinedOrNull(axis)) { + axis = new R3.API.Vector3(); + } + this.axis = axis; + + if (R3.Utils.UndefinedOrNull(angle)) { + angle = 0; + } + this.angle = angle; +}; + +R3.API.Quaternion.prototype.translate = function (v) { + this.x += v.x; + this.y += v.y; + this.z += v.z; + return this; +}; + +R3.API.Quaternion.prototype.copy = function () { + return new R3.API.Quaternion( + this.x, + this.y, + this.z, + this.w + ); +}; + +/** + * Note, this normalize function leaves 'w' component untouched + */ +R3.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; +}; + +R3.API.Quaternion.prototype.multiply = function (q) { + + var x, y, z, w; + var a = q; + var b = this; + + if (q instanceof R3.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 R3.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"); + } +}; + +R3.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; +}; + +R3.API.Quaternion.prototype.subtract = function (v) { + + if (v instanceof R3.API.Vector3) { + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + } + + if (v instanceof R3.API.Quaternion) { + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + this.w -= v.w; + } + + return this; +}; + +R3.API.Quaternion.prototype.magnitude = function () { + return Math.sqrt( + (this.x * this.x) + + (this.y * this.y) + + (this.z * this.z) + + (this.w * this.w) + ); +}; + +R3.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 R3.Matrix4 + */ +R3.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 R3.Quaternion + * @param t + * @returns {R3.Quaternion} + */ +R3.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 + */ +R3.API.Quaternion.FromObject = function (objectQuaternion) { + + var apiAxis = null; + + if (objectQuaternion.axis) { + apiAxis = R3.API.Vector3.FromObject(objectQuaternion.axis); + } + + return new R3.API.Quaternion( + objectQuaternion.x, + objectQuaternion.y, + objectQuaternion.z, + objectQuaternion.w, + apiAxis, + objectQuaternion.angle + ) +}; \ No newline at end of file diff --git a/src/r3-api-quaternion-points.js b/src/r3-api-quaternion-points.js new file mode 100644 index 0000000..5dd94bb --- /dev/null +++ b/src/r3-api-quaternion-points.js @@ -0,0 +1,224 @@ +R3.API.Quaternion.Points = function () { + this.vectors = []; +}; + +R3.API.Quaternion.Points.prototype.add = function (vector) { + + if (vector instanceof R3.API.Vector3) { + vector = new R3.API.Quaternion( + vector.x, + vector.y, + vector.z, + 1 + ) + } + + if (!vector instanceof R3.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; +}; + +R3.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; +}; + +R3.API.Quaternion.Points.prototype.maximizeXDistance = function (grain) { + +// console.log("vectors (before): " + JSON.stringify(this.vectors, null, 2)); + + var multiplier = 0; + + var rotationMatrixY = new R3.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 R3.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)); + +}; + +R3.API.Quaternion.Points.prototype.maximizeYDistance = function (grain) { + +// console.log("vectors (before): " + JSON.stringify(this.vectors, null, 2)); + + var multiplier = 0; + + var rotationMatrixX = new R3.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 R3.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)); + +}; + + +R3.API.Quaternion.Points.prototype.lookAt = function (at, up) { + + var polyCenter = this.average(); + + console.log("poly center : " + JSON.stringify(polyCenter)); + + var lookAtMatrix = new R3.API.Matrix4().lookAt(polyCenter, at, up); + + lookAtMatrix.rows[0] = new R3.API.Quaternion(1, 0, 0, 0); + lookAtMatrix.rows[1] = new R3.API.Quaternion(0, 0, 1, 0); + lookAtMatrix.rows[2] = new R3.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])); + } +}; + +R3.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 R3.API.Vector3( + Math.abs(maxX - minX), + Math.abs(maxY - minY), + Math.abs(maxY - minZ) + ) +}; + +R3.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 R3.API.Vector3( + averageX / this.vectors.length, + averageY / this.vectors.length, + averageZ / this.vectors.length + ); +}; + +R3.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; +}; + + +R3.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); + } +}; \ No newline at end of file diff --git a/src/r3-api-render-configuration.js b/src/r3-api-render-configuration.js new file mode 100644 index 0000000..1585690 --- /dev/null +++ b/src/r3-api-render-configuration.js @@ -0,0 +1,117 @@ +/** + * R3.API.RenderConfiguration + * @param id + * @param name + * @param parentEntity + * @param logicalSize + * @param aspectRatio + * @param scaleMode + * @param activeCamera + * @param activeScenes + * @param activeComposer + * @param activeEffect + * @param activeRenderer + * @param enableComposer + * @param enableEffect + * @constructor + */ +R3.API.RenderConfiguration = function ( + id, + name, + parentEntity, + logicalSize, + aspectRatio, + scaleMode, + activeCamera, + activeScenes, + activeRenderer, + activeComposer, + activeEffect, + enableComposer, + enableEffect +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = "RenderConfiguration (" + this.id + ")"; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(logicalSize)) { + logicalSize = new R3.API.Vector2( + 480, + 320 + ); + } + this.logicalSize = logicalSize; + + if (R3.Utils.UndefinedOrNull(aspectRatio)) { + aspectRatio = R3.API.Renderer.ASPECT_RATIO_3_2; + } + this.aspectRatio = aspectRatio; + + if (R3.Utils.UndefinedOrNull(scaleMode)) { + scaleMode = R3.API.Renderer.SCALE_MODE_LETTERBOX; + } + this.scaleMode = scaleMode; + + if (R3.Utils.UndefinedOrNull(activeCamera)) { + activeCamera = null; + } + this.activeCamera = activeCamera; + + if (R3.Utils.UndefinedOrNull(activeScenes)) { + activeScenes = []; + } + this.activeScenes = activeScenes; + + if (R3.Utils.UndefinedOrNull(activeRenderer)) { + activeRenderer = null; + } + this.activeRenderer = activeRenderer; + + if (R3.Utils.UndefinedOrNull(activeComposer)) { + activeComposer = null; + } + this.activeComposer = activeComposer; + + if (R3.Utils.UndefinedOrNull(activeEffect)) { + activeEffect = null; + } + this.activeEffect = activeEffect; + + if (R3.Utils.UndefinedOrNull(enableComposer)) { + enableComposer = false; + } + this.enableComposer = enableComposer; + + if (R3.Utils.UndefinedOrNull(enableEffect)) { + enableEffect = false; + } + this.enableEffect = enableEffect; + + R3.API.Component.call( + this, + R3.Component.RENDER_CONFIGURATION, + parentEntity + ); + +}; + +R3.API.RenderConfiguration.prototype = Object.create(R3.API.Component.prototype); +R3.API.RenderConfiguration.prototype.constructor = R3.API.RenderConfiguration; + +R3.API.RenderConfiguration.ASPECT_RATIO_NONE = 0x1; +R3.API.RenderConfiguration.ASPECT_RATIO_4_3 = 0x2; +R3.API.RenderConfiguration.ASPECT_RATIO_3_2 = 0x3; +R3.API.RenderConfiguration.ASPECT_RATIO_16_10 = 0x4; +R3.API.RenderConfiguration.ASPECT_RATIO_17_10 = 0x5; +R3.API.RenderConfiguration.ASPECT_RATIO_16_9 = 0x6; + +R3.API.RenderConfiguration.SCALE_MODE_NONE = 0x1; +R3.API.RenderConfiguration.SCALE_MODE_LETTERBOX = 0x2; +R3.API.RenderConfiguration.SCALE_MODE_ZOOM_TO_BIGGER = 0x3; +R3.API.RenderConfiguration.SCALE_MODE_NON_UNIFORM = 0x4; diff --git a/src/r3-api-renderer-a.js b/src/r3-api-renderer-a.js new file mode 100644 index 0000000..95dbda3 --- /dev/null +++ b/src/r3-api-renderer-a.js @@ -0,0 +1,122 @@ +/** + * R3.API.Renderer + * @param id + * @param name + * @param rendererType + * @param parentEntity + * @param width + * @param height + * @param offset + * @param canvas + * @constructor + */ +R3.API.Renderer = function ( + id, + name, + rendererType, + parentEntity, + width, + height, + offset, + canvas +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(rendererType)) { + rendererType = R3.API.Renderer.RENDERER_TYPE_NONE; + } + this.rendererType = rendererType; + + if (R3.Utils.UndefinedOrNull(name)) { + + switch (this.rendererType) { + case R3.API.Renderer.RENDERER_TYPE_NONE : + name = "Renderer"; + break; + case R3.API.Renderer.RENDERER_TYPE_2D : + name = "Renderer 2D"; + break; + case R3.API.Renderer.RENDERER_TYPE_3D : + name = "Renderer 3D"; + break; + default : + console.warn('no nice name for renderer'); + break; + } + + name += " (" + this.id + ")"; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(width)) { + width = 1; + } + this.width = width; + + if (R3.Utils.UndefinedOrNull(height)) { + height = 1; + } + this.height = height; + + if (R3.Utils.UndefinedOrNull(offset)) { + offset = new R3.API.Vector2(0,0); + } + this.offset = offset; + + if (R3.Utils.UndefinedOrNull(canvas)) { + canvas = new R3.API.Canvas(); + } + this.canvas = canvas; + + R3.API.Component.call( + this, + R3.API.Renderer.GetComponentType(this.rendererType), + parentEntity + ); + +}; + +R3.API.Renderer.prototype = Object.create(R3.API.Component.prototype); +R3.API.Renderer.prototype.constructor = R3.API.Renderer; + +R3.API.Renderer.GetComponentType = function(rendererType) { + + var componentType = null; + + switch (rendererType) { + case R3.API.Renderer.RENDERER_TYPE_NONE : + componentType = R3.Component.RENDERER; + break; + case R3.API.Renderer.RENDERER_TYPE_2D : + componentType = R3.Component.RENDERER_D2; + break; + case R3.API.Renderer.RENDERER_TYPE_3D : + componentType = R3.Component.RENDERER_D3; + break; + default : + console.warn('could not determine component type'); + break; + } + + return componentType; +}; + +R3.API.Renderer.RENDERER_TYPE_NONE = 0x0; +R3.API.Renderer.RENDERER_TYPE_2D = 0x1; +R3.API.Renderer.RENDERER_TYPE_3D = 0x2; + +R3.API.Renderer.MODE_CANVAS = 0x1; +R3.API.Renderer.MODE_TARGET = 0x2; +R3.API.Renderer.MODE_CANVAS_AND_TARGET = 0x3; + +R3.API.Renderer.SHADOW_MAP_TYPE_BASIC = 0; +R3.API.Renderer.SHADOW_MAP_TYPE_PCF = 1; +R3.API.Renderer.SHADOW_MAP_TYPE_PCF_SOFT = 2; + +R3.API.Renderer.TONE_MAPPING_LINEAR = 1; +R3.API.Renderer.TONE_MAPPING_REINHARD = 2; +R3.API.Renderer.TONE_MAPPING_UNCHARTED_2 = 3; +R3.API.Renderer.TONE_MAPPING_CINEON = 4; diff --git a/src/r3-api-renderer-d2.js b/src/r3-api-renderer-d2.js new file mode 100644 index 0000000..d207dcf --- /dev/null +++ b/src/r3-api-renderer-d2.js @@ -0,0 +1,35 @@ +/** + * R3.API.Renderer.D2 + * @constructor + * @param apiRenderer + */ +R3.API.Renderer.D2 = function ( + apiRenderer +) { + + if (R3.Utils.UndefinedOrNull(apiRenderer)) { + apiRenderer = { + rendererType : R3.API.Renderer.RENDERER_TYPE_2D + }; + } + + if (R3.Utils.UndefinedOrNull(apiRenderer.rendererType)) { + apiRenderer.rendererType = R3.API.Renderer.RENDERER_TYPE_2D; + } + + R3.API.Renderer.call( + this, + apiRenderer.id, + apiRenderer.name, + apiRenderer.rendererType, + apiRenderer.parentEntity, + apiRenderer.width, + apiRenderer.height, + apiRenderer.offset, + apiRenderer.canvas + ); + +}; + +R3.API.Renderer.D2.prototype = Object.create(R3.API.Renderer.prototype); +R3.API.Renderer.D2.prototype.constructor = R3.API.Renderer.D2; \ No newline at end of file diff --git a/src/r3-api-renderer-d3.js b/src/r3-api-renderer-d3.js new file mode 100644 index 0000000..9de21bf --- /dev/null +++ b/src/r3-api-renderer-d3.js @@ -0,0 +1,266 @@ +/** + * R3.API.Renderer.D3 + * @param apiRenderer + * @param renderMode + * @param autoClear + * @param autoClearColor + * @param autoClearDepth + * @param autoClearStencil + * @param gammaFactor + * @param gammaInput + * @param gammaOutput + * @param maxMorphTargets + * @param maxMorphNormals + * @param physicallyCorrectLights + * @param shadowMapEnabled + * @param shadowMapAutoUpdate + * @param shadowMapNeedsUpdate + * @param shadowMapType + * @param shadowMapRenderReverseSided + * @param shadowMapRenderSingleSided + * @param sortObjects + * @param toneMapping + * @param toneMappingExposure + * @param toneMappingWhitePoint + * @param premultipliedAlpha + * @param antialias + * @param stencil + * @param preserveDrawingBuffer + * @param depth + * @param logarithmicDepthBuffer + * @param localClippingEnabled + * @param renderTarget + * @param clippingPlanes + * @param clearColor + * @param viewports + * @constructor + */ +R3.API.Renderer.D3 = function ( + apiRenderer, + renderMode, + autoClear, + autoClearColor, + autoClearDepth, + autoClearStencil, + gammaFactor, + gammaInput, + gammaOutput, + maxMorphTargets, + maxMorphNormals, + physicallyCorrectLights, + shadowMapEnabled, + shadowMapAutoUpdate, + shadowMapNeedsUpdate, + shadowMapType, + shadowMapRenderReverseSided, + shadowMapRenderSingleSided, + sortObjects, + toneMapping, + toneMappingExposure, + toneMappingWhitePoint, + premultipliedAlpha, + antialias, + stencil, + preserveDrawingBuffer, + depth, + logarithmicDepthBuffer, + localClippingEnabled, + renderTarget, + clippingPlanes, + clearColor, + viewports +) { + + if (R3.Utils.UndefinedOrNull(apiRenderer)) { + apiRenderer = { + rendererType : R3.API.Renderer.RENDERER_TYPE_3D + }; + } + + if (R3.Utils.UndefinedOrNull(apiRenderer.rendererType)) { + apiRenderer.rendererType = R3.API.Renderer.RENDERER_TYPE_3D; + } + + if (R3.Utils.UndefinedOrNull(renderMode)) { + renderMode = R3.API.Renderer.MODE_CANVAS; + } + this.renderMode = renderMode; + + if (R3.Utils.UndefinedOrNull(autoClear)) { + autoClear = true; + } + this.autoClear = autoClear; + + if (R3.Utils.UndefinedOrNull(autoClearColor)) { + autoClearColor = true; + } + this.autoClearColor = autoClearColor; + + if (R3.Utils.UndefinedOrNull(autoClearDepth)) { + autoClearDepth = true; + } + this.autoClearDepth = autoClearDepth; + + if (R3.Utils.UndefinedOrNull(autoClearStencil)) { + autoClearStencil = true; + } + this.autoClearStencil = autoClearStencil; + + if (R3.Utils.UndefinedOrNull(gammaFactor)) { + gammaFactor = 2; + } + this.gammaFactor = gammaFactor; + + if (R3.Utils.UndefinedOrNull(gammaInput)) { + gammaInput = false; + } + this.gammaInput = gammaInput; + + if (R3.Utils.UndefinedOrNull(gammaOutput)) { + gammaOutput = false; + } + this.gammaOutput = gammaOutput; + + if (R3.Utils.UndefinedOrNull(maxMorphTargets)) { + maxMorphTargets = 8; + } + this.maxMorphTargets = maxMorphTargets; + + if (R3.Utils.UndefinedOrNull(maxMorphNormals)) { + maxMorphNormals = 4; + } + this.maxMorphNormals = maxMorphNormals; + + if (R3.Utils.UndefinedOrNull(physicallyCorrectLights)) { + physicallyCorrectLights = false; + } + this.physicallyCorrectLights = physicallyCorrectLights; + + if (R3.Utils.UndefinedOrNull(shadowMapEnabled)) { + shadowMapEnabled = false; + } + this.shadowMapEnabled = shadowMapEnabled; + + if (R3.Utils.UndefinedOrNull(shadowMapAutoUpdate)) { + shadowMapAutoUpdate = true; + } + this.shadowMapAutoUpdate = shadowMapAutoUpdate; + + if (R3.Utils.UndefinedOrNull(shadowMapNeedsUpdate)) { + shadowMapNeedsUpdate = false; + } + this.shadowMapNeedsUpdate = shadowMapNeedsUpdate; + + if (R3.Utils.UndefinedOrNull(shadowMapType)) { + shadowMapType = R3.API.Renderer.SHADOW_MAP_TYPE_BASIC; + } + this.shadowMapType = shadowMapType; + + if (R3.Utils.UndefinedOrNull(shadowMapRenderReverseSided)) { + shadowMapRenderReverseSided = true; + } + this.shadowMapRenderReverseSided = shadowMapRenderReverseSided; + + if (R3.Utils.UndefinedOrNull(shadowMapRenderSingleSided)) { + shadowMapRenderSingleSided = true; + } + this.shadowMapRenderSingleSided = shadowMapRenderSingleSided; + + if (R3.Utils.UndefinedOrNull(sortObjects)) { + sortObjects = true; + } + this.sortObjects = sortObjects; + + if (R3.Utils.UndefinedOrNull(toneMapping)) { + toneMapping = R3.API.Renderer.TONE_MAPPING_LINEAR; + } + this.toneMapping = toneMapping; + + if (R3.Utils.UndefinedOrNull(toneMappingExposure)) { + toneMappingExposure = 1; + } + this.toneMappingExposure = toneMappingExposure; + + if (R3.Utils.UndefinedOrNull(toneMappingWhitePoint)) { + toneMappingWhitePoint = 1; + } + this.toneMappingWhitePoint = toneMappingWhitePoint; + + if (R3.Utils.UndefinedOrNull(premultipliedAlpha)) { + premultipliedAlpha = true; + } + this.premultipliedAlpha = premultipliedAlpha; + + if (R3.Utils.UndefinedOrNull(antialias)) { + antialias = false; + } + this.antialias = antialias; + + if (R3.Utils.UndefinedOrNull(stencil)) { + stencil = true; + } + this.stencil = stencil; + + if (R3.Utils.UndefinedOrNull(preserveDrawingBuffer)) { + preserveDrawingBuffer = false; + } + this.preserveDrawingBuffer = preserveDrawingBuffer; + + if (R3.Utils.UndefinedOrNull(depth)) { + depth = true; + } + this.depth = depth; + + if (R3.Utils.UndefinedOrNull(logarithmicDepthBuffer)) { + logarithmicDepthBuffer = false; + } + this.logarithmicDepthBuffer = logarithmicDepthBuffer; + + if (R3.Utils.UndefinedOrNull(localClippingEnabled)) { + localClippingEnabled = false; + } + this.localClippingEnabled = localClippingEnabled; + + if (R3.Utils.UndefinedOrNull(renderTarget)) { + renderTarget = null; + } + this.renderTarget = renderTarget; + + if (R3.Utils.UndefinedOrNull(clippingPlanes)) { + clippingPlanes = []; + } + this.clippingPlanes = clippingPlanes; + + if (R3.Utils.UndefinedOrNull(clearColor)) { + clearColor = new R3.API.Color(0.11, 0.11, 0.11); + } + this.clearColor = clearColor; + + if (R3.Utils.UndefinedOrNull(viewports)) { + viewports = [new R3.D3.API.Viewport( + null, + null, + 1, + 1, + 0, + 0 + )]; + } + this.viewports = viewports; + + R3.API.Renderer.call( + this, + apiRenderer.id, + apiRenderer.name, + apiRenderer.rendererType, + apiRenderer.parentEntity, + apiRenderer.width, + apiRenderer.height, + apiRenderer.offset, + apiRenderer.canvas + ); + +}; + +R3.API.Renderer.D3.prototype = Object.create(R3.API.Renderer.prototype); +R3.API.Renderer.D3.prototype.constructor = R3.API.Renderer.D3; \ No newline at end of file diff --git a/src/r3-api-server.js b/src/r3-api-server.js new file mode 100644 index 0000000..427a5e8 --- /dev/null +++ b/src/r3-api-server.js @@ -0,0 +1,79 @@ +/** + * Raw Server API object - should always correspond with the Server Schema + * @param id + * @param name + * @param protocol + * @param ip + * @param port + * @param protocols + * @param parentEntity + * @constructor + */ +R3.API.Server = function( + id, + name, + protocol, + ip, + port, + protocols, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Server (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(protocol)) { + protocol = 'http'; + } + this.protocol = protocol; + + if (R3.Utils.UndefinedOrNull(ip)) { + ip = '127.0.0.1'; + } + this.ip = ip; + + if (R3.Utils.UndefinedOrNull(port)) { + port = 80; + } + this.port = port; + + if (R3.Utils.UndefinedOrNull(protocols)) { + protocols = []; + } + this.protocols = protocols; + + R3.API.Component.call( + this, + R3.Component.SERVER, + parentEntity + ); +}; + +R3.API.Server.prototype = Object.create(R3.API.Component.prototype); +R3.API.Server.prototype.constructor = R3.API.Server; + +/** + * Creates an API Server from an Object Server + * @param objectServer + * @constructor + */ +R3.API.Server.FromObject = function(objectServer) { + + return new R3.API.Server( + objectServer.id, + objectServer.name, + objectServer.protocol, + objectServer.ip, + objectServer.port, + objectServer.protocols, + objectServer.parentEntity + ); + +}; diff --git a/src/r3-api-socket-0.js b/src/r3-api-socket-0.js new file mode 100644 index 0000000..fdfa3a0 --- /dev/null +++ b/src/r3-api-socket-0.js @@ -0,0 +1,93 @@ +/** + * Raw Socket API object - should always correspond with the Socket Schema + * @param id + * @param name + * @param socketType + * @param roomId + * @param peerId + * @param server R3.Server + * @param parentEntity + * @constructor + */ +R3.API.Socket = function( + id, + name, + socketType, + roomId, + peerId, + server, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Socket (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(socketType)) { + socketType = R3.API.Socket.TYPE_NONE; + } + this.socketType = socketType; + + if (R3.Utils.UndefinedOrNull(roomId)) { + roomId = 'room_' + R3.Utils.RandomId(); + } + this.roomId = roomId; + + if (R3.Utils.UndefinedOrNull(peerId)) { + peerId = null; + } + this.peerId = peerId; + + if (R3.Utils.UndefinedOrNull(server)) { + server = null; + } + this.server = server; + + var componentType = R3.Component.SOCKET; + + if (this.socketType === R3.API.Socket.TYPE_CAST) { + componentType = R3.Component.SOCKET_CAST; + } + + if (this.socketType === R3.API.Socket.TYPE_RECEIVE) { + componentType = R3.Component.SOCKET_RECEIVE; + } + + R3.API.Component.call( + this, + componentType, + parentEntity + ); +}; + +R3.API.Socket.prototype = Object.create(R3.API.Component.prototype); +R3.API.Socket.prototype.constructor = R3.API.Socket; + +R3.API.Socket.TYPE_NONE = 0x1; +R3.API.Socket.TYPE_CAST = 0x2; +R3.API.Socket.TYPE_RECEIVE = 0x3; + +/** + * Creates an API Socket from an Object Socket + * @param objectSocket + * @constructor + */ +R3.API.Socket.FromObject = function(objectSocket) { + + return new R3.API.Socket( + objectSocket.id, + objectSocket.name, + objectSocket.socketType, + objectSocket.roomId, + objectSocket.peerId, + objectSocket.server, + objectSocket.parentEntity + ); + +}; diff --git a/src/r3-api-socket-cast.js b/src/r3-api-socket-cast.js new file mode 100644 index 0000000..cf3f1e0 --- /dev/null +++ b/src/r3-api-socket-cast.js @@ -0,0 +1,78 @@ +/** + * Raw Cast API object - should always correspond with the Cast Schema + * @param apiSocket + * @param castType + * @param source + * @param sourceProperties + * @constructor + */ +R3.API.Socket.Cast = function( + apiSocket, + castType, + source, + sourceProperties +) { + + if (R3.Utils.UndefinedOrNull(apiSocket)) { + apiSocket = { + socketType : R3.API.Socket.SOCKET_CAST + }; + } + + R3.API.Socket.call( + this, + apiSocket.id, + apiSocket.name, + apiSocket.socketType, + apiSocket.roomId, + apiSocket.peerId, + apiSocket.server, + apiSocket.parentEntity + ); + + if (R3.Utils.UndefinedOrNull(castType)) { + castType = R3.API.Socket.Cast.CAST_TYPE_ROOM; + } + this.castType = castType; + + if (R3.Utils.UndefinedOrNull(source)) { + source = null; + } + this.source = source; + + if (R3.Utils.UndefinedOrNull(sourceProperties)) { + sourceProperties = null; + } + this.sourceProperties = sourceProperties; + + R3.API.Component.call( + this, + R3.Component.SOCKET_CAST + ); +}; + +R3.API.Socket.Cast.prototype = Object.create(R3.API.Socket.prototype); +R3.API.Socket.Cast.prototype.constructor = R3.API.Socket.Cast.Receive; + +R3.API.Socket.Cast.CAST_TYPE_ROOM = 0x1; +R3.API.Socket.Cast.CAST_TYPE_PEER = 0x2; +R3.API.Socket.Cast.CAST_TYPE_ALL = 0x3; +R3.API.Socket.Cast.CAST_TYPE_ALL_BUT_PEER = 0x4; + + +/** + * Creates an API.Socket.Cast from an Object Cast + * @param objectSocketCast + * @constructor + */ +R3.API.Socket.Cast.FromObject = function(objectSocketCast) { + + var apiSocket = R3.API.Socket.FromObject(objectSocketCast); + + return new R3.API.Socket.Cast( + apiSocket, + objectSocketCast.castType, + objectSocketCast.source, + objectSocketCast.sourceProperties + ); +}; diff --git a/src/r3-api-socket-receive.js b/src/r3-api-socket-receive.js new file mode 100644 index 0000000..3723a96 --- /dev/null +++ b/src/r3-api-socket-receive.js @@ -0,0 +1,77 @@ +/** + * Raw Socket.Receive API object - should always correspond with the Socket.Receive Schema + * @param apiSocket + * @param receiveType + * @param destination + * @param destinationProperties + * @constructor + */ +R3.API.Socket.Receive = function( + apiSocket, + receiveType, + destination, + destinationProperties +) { + + if (R3.Utils.UndefinedOrNull(apiSocket)) { + apiSocket = { + socketType : R3.API.Socket.SOCKET_RECEIVE + }; + } + + R3.API.Socket.call( + this, + apiSocket.id, + apiSocket.name, + apiSocket.socketType, + apiSocket.roomId, + apiSocket.peerId, + apiSocket.server, + apiSocket.parentEntity + ); + + if (R3.Utils.UndefinedOrNull(receiveType)) { + receiveType = R3.API.Socket.Receive.RECEIVE_TYPE_ROOM; + } + this.receiveType = receiveType; + + if (R3.Utils.UndefinedOrNull(destination)) { + destination = null; + } + this.destination = destination; + + if (R3.Utils.UndefinedOrNull(destinationProperties)) { + destinationProperties = null; + } + this.destinationProperties = destinationProperties; + + R3.API.Component.call( + this, + R3.Component.SOCKET_RECEIVE + ); +}; + +R3.API.Socket.Receive.prototype = Object.create(R3.API.Socket.prototype); +R3.API.Socket.Receive.prototype.constructor = R3.API.Socket.Receive; + +R3.API.Socket.Receive.RECEIVE_TYPE_ROOM = 0x1; +R3.API.Socket.Receive.RECEIVE_TYPE_PEER = 0x2; + +/** + * Creates an API Socket.Receive from an Object Socket.Receive + * @param socket R3.SocketsRuntime + * @param objectSocketReceive + * @constructor + */ +R3.API.Socket.Receive.FromObject = function(socket, objectSocketReceive) { + + var apiSocket = R3.API.Socket.FromObject(objectSocketReceive); + + return new R3.API.Socket.Receive( + apiSocket, + objectSocketReceive.receiveType, + objectSocketReceive.destination, + objectSocketReceive.destinationProperties + ); + +}; diff --git a/src/r3-api-sphere.js b/src/r3-api-sphere.js new file mode 100644 index 0000000..c8901e8 --- /dev/null +++ b/src/r3-api-sphere.js @@ -0,0 +1,20 @@ +/** + * R3.API.Sphere + * @constructor + * @param center + * @param radius + */ +R3.API.Sphere = function ( + center, + radius +) { + if (R3.Utils.UndefinedOrNull(center)) { + center = new R3.API.Vector3(0,0,0); + } + this.center = center; + + if (R3.Utils.UndefinedOrNull(radius)) { + radius = 1; + } + this.radius = radius; +}; diff --git a/src/r3-api-stats.js b/src/r3-api-stats.js new file mode 100644 index 0000000..ccc1dc2 --- /dev/null +++ b/src/r3-api-stats.js @@ -0,0 +1,64 @@ +/** + * Raw Stats API object - should always correspond with the Stats Schema + * @param id + * @param name + * @param domElement + * @param parentEntity + * @constructor + */ +R3.API.Stats = function( + id, + name, + domElement, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Stats (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(domElement)) { + domElement = null; + } + this.domElement = domElement; + + R3.API.Component.call( + this, + R3.Component.STATS, + parentEntity + ); +}; + +R3.API.Stats.prototype = Object.create(R3.API.Component.prototype); +R3.API.Stats.prototype.constructor = R3.API.Stats; + +/** + * Creates an API Stats from an Object Stats + * @param objectStats + * @constructor + */ +R3.API.Stats.FromObject = function(objectStats) { + + var apiDomElement = null; + if (objectStats.domElement) { + if (objectStats.domElement instanceof Object) { + apiDomElement = R3.API.DomElement.FromObject(objectStats.domElement); + } else { + apiDomElement = objectStats.domElement; + } + } + + return new R3.API.Stats( + objectStats.id, + objectStats.name, + apiDomElement, + objectStats.parentEntity + ); + +}; diff --git a/src/r3-api-system.js b/src/r3-api-system.js new file mode 100644 index 0000000..508902c --- /dev/null +++ b/src/r3-api-system.js @@ -0,0 +1,104 @@ +/** + * This component renders a scene + * @param id String + * @param name String + * @param systemType + * @param parentEntity + * @constructor + */ +R3.API.System = function ( + id, + name, + systemType, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = "System (" + this.id + ")"; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(systemType)) { + systemType = R3.System.SYSTEM_TYPE_NONE; + } + this.systemType = systemType; + + var componentType = R3.Component.SYSTEM; + + if (this.systemType === R3.System.SYSTEM_TYPE_NONE) { + componentType = R3.Component.SYSTEM; + } + + if (this.systemType === R3.System.SYSTEM_TYPE_ANIMATION) { + componentType = R3.Component.SYSTEM_ANIMATION; + } + + if (this.systemType === R3.System.SYSTEM_TYPE_CUSTOM) { + componentType = R3.Component.SYSTEM_CUSTOM_CODE; + } + + if (this.systemType === R3.System.SYSTEM_TYPE_GUI) { + componentType = R3.Component.SYSTEM_GUI; + } + + if (this.systemType === R3.System.SYSTEM_TYPE_INPUT) { + componentType = R3.Component.SYSTEM_INPUT; + } + + if (this.systemType === R3.System.SYSTEM_TYPE_LINKING) { + componentType = R3.Component.SYSTEM_LINKING; + } + + if (this.systemType === R3.System.SYSTEM_TYPE_PHYSICS) { + componentType = R3.Component.SYSTEM_PHYSICS; + } + + if (this.systemType === R3.System.SYSTEM_TYPE_RENDER) { + componentType = R3.Component.SYSTEM_RENDER; + } + + if (this.systemType === R3.System.SYSTEM_TYPE_STORAGE) { + componentType = R3.Component.SYSTEM_STORAGE; + } + + if (this.systemType === R3.System.SYSTEM_TYPE_VISUALIZATION) { + componentType = R3.Component.SYSTEM_VISUALIZATION; + } + + if (this.systemType === R3.System.SYSTEM_TYPE_PARTICLE) { + componentType = R3.Component.SYSTEM_PARTICLE; + } + + if (this.systemType === R3.System.SYSTEM_TYPE_AUDIO) { + componentType = R3.Component.SYSTEM_AUDIO; + } + + R3.API.Component.call( + this, + componentType, + parentEntity + ); + +}; + +R3.API.System.prototype = Object.create(R3.API.Component.prototype); +R3.API.System.prototype.constructor = R3.API.System; + +/** + * Object to R3.D3.API.System + * @param objectComponent + * @constructor + */ +R3.API.System.FromObject = function(objectComponent) { + return new R3.API.System( + objectComponent.id, + objectComponent.name, + objectComponent.systemType, + objectComponent.parentEntity + ); +}; diff --git a/src/r3-api-vector2.js b/src/r3-api-vector2.js new file mode 100644 index 0000000..f9a7c36 --- /dev/null +++ b/src/r3-api-vector2.js @@ -0,0 +1,42 @@ +R3.API.Vector2 = function (x, y) { + + if (R3.Utils.UndefinedOrNull(x)) { + x = 0; + } + this.x = x; + + if (R3.Utils.UndefinedOrNull(y)) { + y = 0; + } + this.y = y; + +}; + +R3.API.Vector2.prototype.copy = function () { + return new R3.API.Vector2( + this.x, + this.y + ); +}; + +R3.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 + */ +R3.API.Vector2.FromObject = function (objectVector) { + + if (R3.Utils.UndefinedOrNull(objectVector)) { + console.warn('vector from db undefined - stale version in db'); + objectVector = {}; + } + + return new R3.API.Vector2( + objectVector.x, + objectVector.y + ) +}; diff --git a/src/r3-api-vector3.js b/src/r3-api-vector3.js new file mode 100644 index 0000000..923b136 --- /dev/null +++ b/src/r3-api-vector3.js @@ -0,0 +1,277 @@ +R3.API.Vector3 = function (x, y, z) { + + if (R3.Utils.UndefinedOrNull(x)) { + x = 0; + } + this.x = x; + + if (R3.Utils.UndefinedOrNull(y)) { + y = 0; + } + this.y = y; + + if (R3.Utils.UndefinedOrNull(z)) { + z = 0; + } + this.z = z; + +}; + +R3.API.Vector3.prototype.negate = function() { + this.x = -this.x; + this.y = -this.y; + this.z = -this.z; + return this; +}; + +R3.API.Vector3.prototype.subtract = function (v) { + return new R3.API.Vector3( + this.x - v.x, + this.y - v.y, + this.z - v.z + ); +}; + +R3.API.Vector3.prototype.sub = function (v) { + return new R3.API.Vector3( + this.x - v.x, + this.y - v.y, + this.z - v.z + ); +}; + +R3.API.Vector3.prototype.equals = function (v) { + return this.x === v.x && this.y === v.y && this.z === v.z; +}; + +R3.API.Vector3.prototype.cross = function (v) { + return new R3.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 + ); +}; + +R3.API.Vector3.clockwise = function (u, v, w, viewPoint) { + var normal = R3.API.Vector3.normal(u, v, w); + var uv = u.copy(); + var winding = normal.dot(uv.subtract(viewPoint)); + return (winding > 0); +}; + +R3.API.Vector3.normal = function (u, v, w) { + var vv = v.copy(); + var wv = w.copy(); + return vv.subtract(u).cross(wv.subtract(u)); +}; + +R3.API.Vector3.prototype.lookAt = function (at, up) { + var lookAtMatrix = R3.API.Matrix4.lookAt(this, at, up); + return this.multiply(lookAtMatrix); +}; + +R3.API.Vector3.prototype.translate = function (v) { + this.x += v.x; + this.y += v.y; + this.z += v.z; + return this; +}; + +R3.API.Vector3.prototype.add = function (v) { + this.x += v.x; + this.y += v.y; + this.z += v.z; + return this; +}; + +R3.API.Vector3.prototype.squared = function () { + return this.x * this.x + this.y * this.y + this.z * this.z; +}; + +R3.API.Vector3.prototype.copy = function () { + return new R3.API.Vector3( + this.x, + this.y, + this.z + ); +}; + +R3.API.Vector3.prototype.set = function (x, y, z) { + this.x = x; + this.y = y; + this.z = z; +}; + +R3.API.Vector3.prototype.lerp = function ( v, alpha ) { + return new R3.API.Vector3( + this.x + ( v.x - this.x ) * alpha, + this.y + ( v.y - this.y ) * alpha, + this.z + ( v.z - this.z ) * alpha + ); +}; + +R3.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} + */ +R3.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 | R3.API.Vector3 | R3.API.Vector4 | R3.API.Matrix3 | R3.API.Matrix4} + * @param cross boolean true if you want the cross product, otherwise returns the scalar (dot or inner) product + * @returns {R3.API.Vector3 | Number} + */ +R3.API.Vector3.prototype.multiply = function (object, cross) { + + var x, y, z; + + var a = object; + var b = this; + + if (R3.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 R3.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"); + } +}; + + +R3.API.Vector3.prototype.dot = function (v) { + return (this.x * v.x) + (this.y * v.y) + (this.z * v.z); +}; + +R3.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 R3.API.Vector3( + this.x * invLength, + this.y * invLength, + this.z * invLength + ); +}; + +R3.API.Vector3.prototype.clone = function () { + return new R3.API.Vector3( + this.x, + this.y, + this.z + ); +}; + +R3.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; +}; + +R3.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; +}; + +R3.API.Vector3.prototype.length = function() { + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); +}; + +R3.API.Vector3.prototype.reflect = function(normal) { + return this.sub( v1.copy( normal ).multiply( 2 * this.dot( normal ) ) ); +}; + +R3.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 + */ +R3.API.Vector3.FromObject = function (objectVector) { + + if (R3.Utils.UndefinedOrNull(objectVector)) { + console.warn('vector from db undefined - stale version in db'); + objectVector = {}; + } + + return new R3.API.Vector3( + objectVector.x, + objectVector.y, + objectVector.z + ) +}; diff --git a/src/r3-api-vector4.js b/src/r3-api-vector4.js new file mode 100644 index 0000000..442bd2a --- /dev/null +++ b/src/r3-api-vector4.js @@ -0,0 +1,46 @@ +R3.API.Vector4 = function (x, y, z, w) { + + if (R3.Utils.UndefinedOrNull(x)) { + x = 0; + } + this.x = x; + + if (R3.Utils.UndefinedOrNull(y)) { + y = 0; + } + this.y = y; + + if (R3.Utils.UndefinedOrNull(z)) { + z = 0; + } + this.z = z; + + if (R3.Utils.UndefinedOrNull(w)) { + w = 1; + } + this.w = w; +}; + +R3.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 + */ +R3.API.Vector4.FromObject = function (objectVector) { + + if (R3.Utils.UndefinedOrNull(objectVector)) { + console.warn('vector from db undefined - stale version in db'); + objectVector = {}; + } + + return new R3.API.Vector4( + objectVector.x, + objectVector.y, + objectVector.z, + objectVector.w + ) +}; diff --git a/src/r3-box3.js b/src/r3-box3.js new file mode 100644 index 0000000..a2f8524 --- /dev/null +++ b/src/r3-box3.js @@ -0,0 +1,97 @@ +/** + * R3.Box3 + * @param implementation + * @param apiBox3 + * @param parentObject + * @constructor + */ +R3.Box3 = function ( + implementation, + apiBox3, + parentObject +) { + + this.implementation = implementation; + this.implementation.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(parentObject)) { + parentObject = null; + } + this.parentObject = parentObject; + + if (R3.Utils.UndefinedOrNull(apiBox3)) { + apiBox3 = {}; + } + + R3.API.Box3.call( + this, + apiBox3.id, + apiBox3.name, + apiBox3.parentEntity, + apiBox3.min, + apiBox3.max + ); + + this.min = new R3.Vector3( + this.implementation, + this.min, + this + ); + + this.max = new R3.Vector3( + this.implementation, + this.max, + this + ); + + this.createInstance(); +}; + +R3.Box3.prototype = Object.create(R3.Component.prototype); +R3.Box3.prototype.constructor = R3.Box3; + +/** + * Creates an instance R3.Box3 + * @returns {*} + */ +R3.Box3.prototype.createInstance = function() { + + this.instance = new THREE.Box3( + this.min.instance, + this.max.instance + ); + +}; + +/** + * Updates R3.Box3 instance + * @param property + */ +R3.Box3.prototype.updateInstance = function(property) { + + if (property === 'min') { + this.instance.min.x = this.min.x; + this.instance.min.y = this.min.y; + this.instance.min.z = this.min.z; + } + + if (property === 'max') { + this.instance.max.x = this.max.x; + this.instance.max.y = this.max.y; + this.instance.max.z = this.max.z; + } +}; + +/** + * R3.Box3 to R3.API.Box3 + * @returns {R3.API.Box3} + */ +R3.Box3.prototype.toApiObject = function() { + return new R3.API.Box3( + this.id, + this.name, + R3.Utils.IdOrNull(this.parentEntity), + this.min.toApiObject(), + this.max.toApiObject() + ); +}; diff --git a/src/r3-canvas.js b/src/r3-canvas.js new file mode 100644 index 0000000..f766141 --- /dev/null +++ b/src/r3-canvas.js @@ -0,0 +1,335 @@ +/** + * Canvas object + * @param graphics + * @param apiCanvas + * @returns {R3.Canvas} + * @constructor + */ +R3.Canvas = function( + graphics, + apiCanvas +) { + this.graphics = graphics; + + if (R3.Utils.UndefinedOrNull(apiCanvas)) { + apiCanvas = {}; + } + + R3.API.Canvas.call( + this, + apiCanvas.id, + apiCanvas.name, + apiCanvas.parentEntity, + apiCanvas.parentTexture, + apiCanvas.autoUpdateSize, + apiCanvas.width, + apiCanvas.height, + apiCanvas.offset, + apiCanvas.tabIndex, + apiCanvas.texts, + apiCanvas.textBaseline + ); + + this.offset = new R3.Vector2( + this.graphics, + this.offset, + this + ); + + R3.Component.call( + this, + { + 'parentTexture' : R3.D3.Texture, + 'texts' : [R3.D3.Text] + } + ); + + this.context = null; +}; + +R3.Canvas.prototype = Object.create(R3.Component.prototype); +R3.Canvas.prototype.constructor = R3.Canvas; + +/** + * Creates a light instance + * @returns {*} + */ +R3.Canvas.prototype.createInstance = function() { + + this.instance = document.createElement('canvas'); + + this.instance.setAttribute('id', this.id); + + this.instance.setAttribute('tabindex', this.tabIndex); + + this.instance.setAttribute('style', 'left: ' + this.offset.x + 'px;top: ' + this.offset.y + 'px'); + + if (this.autoUpdateSize) { + /** + * Update our size from the instance size + */ + this.width = this.instance.width; + this.height = this.instance.height; + } else { + /** + * Update our instance with our size + */ + this.instance.width = this.width; + this.instance.height = this.height; + } + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.Canvas.prototype.updateInstance = function(property) { + + if (R3.Utils.UndefinedOrNull(property)) { + console.warn('unknown property update for Canvas: ' + property); + } + + if (property === 'id') { + this.instance.setAttribute('id', this.id); + return; + } + + if (property === 'offset') { + this.instance.style.left = this.offset.x + 'px'; + this.instance.style.top = this.offset.y + 'px'; + return; + } + + if (property === 'tabIndex') { + this.instance.setAttribute('tabIndex', this.tabIndex); + return; + } + + if ( + property === 'autoUpdateSize' || + property === 'width' || + property === 'height' + ) { + /** + * We cannot control everything about the canvas - this is dependent on where the canvas lives and its + * dimensions can also be controlled via CSS - + * + * This means - autoUpdateSize works a little different for this component - instead of getting our size and + * applying it, it gets our canvas size and applies it, or applies our size to the canvas - of course + * the user settings override this. + */ + if (this.autoUpdateSize) { + + /** + * Update from our canvas size + */ + this.width = this.instance.width; + this.height = this.instance.height; + + } else { + + /** + * Command our canvas to take a size - this is not guaranteed however - CSS wins + */ + this.instance.width = this.width; + this.instance.height = this.height; + } + return; + } + + if (property === 'texts') { + this.writeText(); + return; + } + + if (property === 'textBaseLine') { + if (!this.context) { + this.context = this.instance.getContext('2d'); + } + this.context.textBaseline = this.textBaseline; + return; + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.Canvas to a R3.API.Canvas + * @returns {R3.API.Canvas} + */ +R3.Canvas.prototype.toApiObject = function() { + + return new R3.API.Canvas( + this.id, + this.name, + R3.Utils.IdOrNull(this.parentEntity), + R3.Utils.IdOrNull(this.parentTexture), + this.autoUpdateSize, + this.width, + this.height, + this.offset.toApiObject(), + this.tabIndex, + this.texts.map(function(text){ + return R3.Utils.IdOrNull(text) + }), + this.textBaseline + ); +}; + +R3.Canvas.prototype.writeText = function() { + + this.clear(); + + this.texts.map( + + function(text){ + + if (!this.context) { + this.context = this.instance.getContext('2d'); + } + + text.parentCanvas = this; + + this.context.fillStyle = text.fillStyle; + this.context.font = text.font; + this.context.fillText(text.value, text.offset.x, text.offset.y); + + if (this.parentTexture && this.parentTexture.instance) { + this.parentTexture.instance.needsUpdate = true; + } + + }.bind(this) + ); +}; + +R3.Canvas.prototype.clear = function() { + + if (!this.context) { + this.context = this.instance.getContext('2d'); + } + + this.context.clearRect(0, 0, this.width, this.height); +}; + +R3.Canvas.prototype.filledRectangle = function( + x, + y, + width, + height, + fillStyle +) { + + if (!this.context) { + this.context = this.instance.getContext('2d'); + } + + if (fillStyle) { + this.context.fillStyle = fillStyle; + } + + this.context.fillRect(x, y, width, height); +}; + +R3.Canvas.prototype.outlineRectangle = function( + x, + y, + width, + height, + lineWidth, + strokeStyle +) { + + if (!this.context) { + this.context = this.instance.getContext('2d'); + } + + if (lineWidth) { + this.context.lineWidth = lineWidth; + } + + if (strokeStyle) { + this.context.strokeStyle = strokeStyle; + } + + this.context.fillRect(x, y, width, height); +}; + +R3.Canvas.prototype.line = function( + x, + y, + endX, + endY, + lineWidth, + strokeStyle +) { + + if (!this.context) { + this.context = this.instance.getContext('2d'); + } + + if (lineWidth) { + this.context.lineWidth = lineWidth; + } + + if (strokeStyle) { + this.context.strokeStyle = strokeStyle; + } + + this.context.beginPath(); + this.context.moveTo(x, y); + this.context.lineTo(endX, endY); + this.context.stroke(); +}; + +R3.Canvas.prototype.text = function( + text, + x, + y, + font, + fillStyle +) { + + if (!this.context) { + this.context = this.instance.getContext('2d'); + } + + if (font) { + this.context.font = font; + } + + if (fillStyle) { + this.context.fillStyle = fillStyle; + } + + this.context.fillText(text, x, y); +}; + +R3.Canvas.prototype.image = function( + image, + x, + y, + width, + height, + sx, + sy, + swidth, + sheight +) { + + if (!this.context) { + this.context = this.instance.getContext('2d'); + } + + if (sx && sy && swidth && sheight) { + this.context.drawImage(image, sx, sy, swidth, sheight, x, y, width, height); + return; + } + + if (width && height) { + this.context.drawImage(image, x, y, width, height); + return; + } + + this.context.drawImage(image, x, y); +}; diff --git a/src/r3-clock.js b/src/r3-clock.js new file mode 100644 index 0000000..e04fe0c --- /dev/null +++ b/src/r3-clock.js @@ -0,0 +1,96 @@ +/** + * Creates a Clock object + * @param graphics + * @param apiClock R3.API.Clock + * @constructor + */ +R3.Clock = function( + graphics, + apiClock +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiClock)) { + apiClock = {}; + } + + R3.API.Clock.call( + this, + apiClock.id, + apiClock.name, + apiClock.parentEntity + ); + + R3.Component.call(this); +} ; + +R3.Clock.prototype = Object.create(R3.Component.prototype); +R3.Clock.prototype.constructor = R3.Clock; + +/** + * Creates a camera instance of 'graphics' type (only THREE for now) + * @returns {THREE.Clock} + */ +R3.Clock.prototype.createInstance = function() { + + this.instance = new THREE.Clock(); + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.Clock.prototype.updateInstance = function() { + +}; + +R3.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 R3.Clock to a new R3.API.Clock + * @returns {R3.API.Clock} + */ +R3.Clock.prototype.toApiObject = function() { + + return new R3.API.Clock( + this.id, + this.name, + R3.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Converts from an Object camera to a R3.Clock + * @param graphics R3.Graphics + * @param objectClock Object + * @returns {R3.Clock} + * @constructor + */ +R3.Clock.FromObject = function(graphics, objectClock) { + + var apiClock = R3.API.Clock.FromObject(objectClock); + + return new R3.Clock( + graphics, + apiClock + ); + +}; diff --git a/src/r3-coder-runtime.js b/src/r3-coder-runtime.js new file mode 100644 index 0000000..ae1ef1b --- /dev/null +++ b/src/r3-coder-runtime.js @@ -0,0 +1,60 @@ +/** + * Coder + * @param id + * @param name + * @param coderType + * @constructor + */ +R3.CoderRuntime = function( + id, + name, + coderType +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Coder (' + id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(coderType)) { + coderType = R3.CoderRuntime.TYPE_CODE_MIRROR; + } + this.coderType = coderType; + + this.createInstance(); +}; + +/** + * R3.CoderRuntime Types + * @type {number} + */ +R3.CoderRuntime.TYPE_CODE_MIRROR = 0x1; + +R3.CoderRuntime.prototype.createInstance = function() { + if (this.coderType === R3.CoderRuntime.TYPE_CODE_MIRROR) { + this.instance = CodeMirror; + } else { + this.instance = null; + } +}; + +R3.CoderRuntime.prototype.updateInstance = function(property) { + if (property === 'coderType') { + this.createInstance(); + } +}; + +/** + * Logs a warning and throws an error if not cannon + */ +R3.CoderRuntime.prototype.isNotCodeMirrorThrow = function() { + if (this.instance !== CodeMirror) { + console.error('Only CodeMirror supported'); + throw new Error('Only CodeMirror supported'); + } +}; + \ No newline at end of file diff --git a/src/r3-color.js b/src/r3-color.js new file mode 100644 index 0000000..a7a5683 --- /dev/null +++ b/src/r3-color.js @@ -0,0 +1,152 @@ +/** + * Runtime color for updating instance objects + * @param graphics R3.GraphicsRuntime + * @param parentObject R3.D3.* + * @param apiColor R3.API.Color + * @param grain Number + * @constructor + */ +R3.Color = function ( + graphics, + apiColor, + parentObject, + grain +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiColor)) { + apiColor = {}; + } + + R3.API.Color.call( + this, + apiColor.r, + apiColor.g, + apiColor.b, + apiColor.a + ); + + if (R3.Utils.UndefinedOrNull(parentObject)) { + parentObject = null; + } + this.parentObject = parentObject; + + if (R3.Utils.UndefinedOrNull(grain)) { + grain = 0.001; + } + this.grain = grain; + + this.createInstance(); +}; + +R3.Color.prototype = Object.create(R3.API.Color.prototype); +R3.Color.prototype.constructor = R3.Color; + +/** + * Creates an instance color + * @returns {*} + */ +R3.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 + */ +R3.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 {R3.API.Color} + */ +R3.Color.prototype.toApiObject = function() { + return new R3.API.Color( + this.r, + this.g, + this.b, + this.a + ); +}; + +/** + * Converts the current color to HTML hex format (ex. #ffffff) + * @returns {string} + */ +R3.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} + */ +R3.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; + + this.instance.r = this.r; + this.instance.g = this.g; + this.instance.b = this.b; +}; \ No newline at end of file diff --git a/src/r3-controls-0.js b/src/r3-controls-0.js new file mode 100644 index 0000000..0fbaee7 --- /dev/null +++ b/src/r3-controls-0.js @@ -0,0 +1,100 @@ +/** + * R3.Controls + * @param apiControls + * @property controlsType + * @constructor + */ +R3.Controls = function ( + apiControls +) { + + if (R3.Utils.UndefinedOrNull(apiControls)) { + apiControls = {}; + } + + R3.API.Controls.call( + this, + apiControls.id, + apiControls.name, + apiControls.controlsType, + apiControls.canvas, + apiControls.parentEntity + ); + + var linkedObjects = { + canvas : R3.Canvas + }; + + var delayed = false; + + switch (this.controlsType) { + case (R3.API.Controls.CONTROLS_TYPE_EDITOR) : + linkedObjects.raycaster = R3.D3.Raycaster; + linkedObjects.camera = R3.D3.Camera; + delayed = true; + break; + case (R3.API.Controls.CONTROLS_TYPE_FIRST_PERSON) : + linkedObjects.camera = R3.D3.Camera; + delayed = true; + break; + case (R3.API.Controls.CONTROLS_TYPE_ORBIT) : + linkedObjects.camera = R3.D3.Camera; + linkedObjects.target = R3.Component; + delayed = true; + break; + } + + R3.Component.call( + this, + linkedObjects, + delayed + ); +}; + +R3.Controls.prototype = Object.create(R3.Component.prototype); +R3.Controls.prototype.constructor = R3.Controls; + +R3.Controls.D3 = function() {}; +R3.Controls.D3.prototype = Object.create(R3.Controls.prototype); +R3.Controls.D3.prototype.constructor = R3.Controls.D3; + +/** + * Creates a mesh instance or updates it + */ +R3.Controls.prototype.createInstance = function() { + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the mesh instance + */ +R3.Controls.prototype.updateInstance = function(property) { + + if (property === 'canvas') { + R3.Event.Emit( + R3.Event.CANVAS_CHANGE, + { + component: this + } + ); + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.Controls to a R3.API.Controls + * @returns {R3.API.Controls} + */ +R3.Controls.prototype.toApiObject = function() { + + var apiControls = new R3.API.Controls( + this.id, + this.name, + this.controlsType, + R3.Utils.IdOrNull(this.canvas), + R3.Utils.IdOrNull(this.parentEntity) + ); + + return apiControls; +}; diff --git a/src/r3-controls-d3-editor.js b/src/r3-controls-d3-editor.js new file mode 100644 index 0000000..344be21 --- /dev/null +++ b/src/r3-controls-d3-editor.js @@ -0,0 +1,116 @@ +/** + * Controls Superset - The apiControls properties get moved into the Controls object itself, and then the instance is created + * @param graphics R3.GraphicsRuntime + * @param apiEditorControls + * @constructor + */ +R3.Controls.D3.Editor = function ( + graphics, + apiEditorControls +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiEditorControls)) { + apiEditorControls = { + controlsType : R3.API.Controls.CONTROLS_TYPE_EDITOR + }; + } + + if (R3.Utils.UndefinedOrNull()) { + apiEditorControls.controlsType = R3.API.Controls.CONTROLS_TYPE_EDITOR; + } + + R3.API.Controls.D3.Editor.call( + this, + apiEditorControls, + apiEditorControls.raycaster, + apiEditorControls.camera + ); + + if (this.raycaster instanceof R3.D3.API.Raycaster) { + this.raycaster = new R3.D3.Raycaster( + this.graphics, + this.raycaster + ); + } + + R3.Controls.call( + this, + apiEditorControls + ); + +}; + +/** + * Inheritance + * @type {R3.Controls} + */ +R3.Controls.D3.Editor.prototype = Object.create(R3.Controls.D3.prototype); +R3.Controls.D3.Editor.prototype.constructor = R3.Controls.D3.Editor; + +/** + * Create Instance + */ +R3.Controls.D3.Editor.prototype.createInstance = function() { + + if ( + R3.Utils.UndefinedOrNull(this.camera) || + R3.Utils.UndefinedOrNull(this.camera.instance) + ) { + console.warn('no camera at time of editor-controls create instance'); + return; + } + + if ( + R3.Utils.UndefinedOrNull(this.canvas) || + R3.Utils.UndefinedOrNull(this.canvas.instance) + ) { + console.warn('no canvas at time of editor-controls create instance'); + return; + } + + this.instance = new THREE.EditorControls( + this.camera.instance, + this.canvas.instance + ); + + R3.Controls.prototype.createInstance.call(this); +}; + +/** + * Update Instance + */ +R3.Controls.D3.Editor.prototype.updateInstance = function(property) { + + if ( + property === 'canvas' || + property === 'camera' + ) { + if (R3.Utils.UndefinedOrNull(this.instance)) { + this.createInstance(); + } else { + this.instance.dispose(); + this.createInstance(); + } + } + + 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'); + + R3.Controls.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.Controls.D3.Editor to a R3.D3.API.Mesh + * @returns {R3.API.Controls} + */ +R3.Controls.D3.Editor.prototype.toApiObject = function() { + + var apiControls = R3.Controls.prototype.toApiObject.call(this); + + apiControls.raycaster = R3.Utils.IdOrNull(this.raycaster); + apiControls.camera = R3.Utils.IdOrNull(this.camera); + + return apiControls; +}; diff --git a/src/r3-controls-d3-first-person.js b/src/r3-controls-d3-first-person.js new file mode 100644 index 0000000..2f4ecfa --- /dev/null +++ b/src/r3-controls-d3-first-person.js @@ -0,0 +1,220 @@ +/** + * Controls Superset - The apiControls properties get moved into the Controls object itself, and then the instance is created + * @param graphics R3.GraphicsRuntime + * @param apiFirstPersonControls + * @constructor + */ +R3.Controls.D3.FirstPerson = function ( + graphics, + apiFirstPersonControls +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiFirstPersonControls)) { + apiFirstPersonControls = { + controlsType : R3.API.Controls.CONTROLS_TYPE_FIRST_PERSON + }; + } + + if (R3.Utils.UndefinedOrNull()) { + apiFirstPersonControls.controlsType = R3.API.Controls.CONTROLS_TYPE_FIRST_PERSON; + } + + R3.API.Controls.D3.FirstPerson.call( + this, + apiFirstPersonControls, + apiFirstPersonControls.camera, + apiFirstPersonControls.enabled, + apiFirstPersonControls.movementSpeed, + apiFirstPersonControls.lookSpeed, + apiFirstPersonControls.lookVertical, + apiFirstPersonControls.autoForward, + apiFirstPersonControls.activeLook, + apiFirstPersonControls.heightSpeed, + apiFirstPersonControls.heightCoef, + apiFirstPersonControls.heightMin, + apiFirstPersonControls.heightMax, + apiFirstPersonControls.constrainVertical, + apiFirstPersonControls.verticalMin, + apiFirstPersonControls.verticalMax, + apiFirstPersonControls.autoSpeedFactor + ); + + R3.Controls.call( + this, + apiFirstPersonControls + ); + +}; + +/** + * Inheritance + * @type {R3.Controls} + */ +R3.Controls.D3.FirstPerson.prototype = Object.create(R3.Controls.D3.prototype); +R3.Controls.D3.FirstPerson.prototype.constructor = R3.Controls.D3.FirstPerson; + +/** + * Create Instance + */ +R3.Controls.D3.FirstPerson.prototype.createInstance = function() { + + if ( + R3.Utils.UndefinedOrNull(this.camera) || + R3.Utils.UndefinedOrNull(this.camera.instance) + ) { + console.warn('no camera at time of editor-controls create instance'); + return; + } + + if ( + R3.Utils.UndefinedOrNull(this.canvas) || + R3.Utils.UndefinedOrNull(this.canvas.instance) + ) { + console.warn('no canvas at time of editor-controls create instance'); + return; + } + + this.instance = new THREE.FirstPersonControls( + this.camera.instance, + this.canvas.instance + ); + + this.instance.enabled = this.enabled; + this.instance.movementSpeed = this.movementSpeed; + this.instance.lookSpeed = this.lookSpeed; + this.instance.lookVertical = this.lookVertical; + this.instance.autoForward = this.autoForward; + this.instance.activeLook = this.activeLook; + this.instance.heightSpeed = this.heightSpeed; + this.instance.heightCoef = this.heightCoef; + this.instance.heightMin = this.heightMin; + this.instance.heightMax = this.heightMax; + this.instance.constrainVertical = this.constrainVertical; + this.instance.verticalMin = this.verticalMin; + this.instance.verticalMax = this.verticalMax; + this.instance.autoSpeedFactor = this.autoSpeedFactor; + + R3.Controls.prototype.createInstance.call(this); +}; + +/** + * Update Instance + */ +R3.Controls.D3.FirstPerson.prototype.updateInstance = function(property) { + + if ( + property === 'canvas' || + property === 'camera' + ) { + if (R3.Utils.UndefinedOrNull(this.instance)) { + this.createInstance(); + } else { + this.instance.dispose(); + this.createInstance(); + } + } + + if (property === 'enabled') { + this.instance.enabled = this.enabled; + return; + } + + if (property === 'movementSpeed') { + this.instance.movementSpeed = this.movementSpeed; + return; + } + + if (property === 'lookSpeed') { + this.instance.lookSpeed = this.lookSpeed; + return; + } + + if (property === 'lookVertical') { + this.instance.lookVertical = this.lookVertical; + return; + } + + if (property === 'autoForward') { + this.instance.autoForward = this.autoForward; + return; + } + + if (property === 'activeLook') { + this.instance.activeLook = this.activeLook; + return; + } + + if (property === 'heightSpeed') { + this.instance.heightSpeed = this.heightSpeed; + return; + } + + if (property === 'heightCoef') { + this.instance.heightCoef = this.heightCoef; + return; + } + + if (property === 'heightMin') { + this.instance.heightMin = this.heightMin; + return; + } + + if (property === 'heightMax') { + this.instance.heightMax = this.heightMax; + return; + } + + if (property === 'constrainVertical') { + this.instance.constrainVertical = this.constrainVertical; + return; + } + + if (property === 'verticalMin') { + this.instance.verticalMin = this.verticalMin; + return; + } + + if (property === 'verticalMax') { + this.instance.verticalMax = this.verticalMax; + return; + } + + if (property === 'autoSpeedFactor') { + this.instance.autoSpeedFactor = this.autoSpeedFactor; + return; + } + + + R3.Controls.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.Controls.D3.FirstPerson to a R3.D3.API.Mesh + * @returns {R3.API.Controls} + */ +R3.Controls.D3.FirstPerson.prototype.toApiObject = function() { + + var apiControls = R3.Controls.prototype.toApiObject.call(this); + + return new R3.API.Controls.D3.FirstPerson( + apiControls, + R3.Utils.IdOrNull(this.camera), + this.enabled, + this.movementSpeed, + this.lookSpeed, + this.lookVertical, + this.autoForward, + this.activeLook, + this.heightSpeed, + this.heightCoef, + this.heightMin, + this.heightMax, + this.constrainVertical, + this.verticalMin, + this.verticalMax, + this.autoSpeedFactor + ); +}; diff --git a/src/r3-controls-d3-orbit.js b/src/r3-controls-d3-orbit.js new file mode 100644 index 0000000..52b6454 --- /dev/null +++ b/src/r3-controls-d3-orbit.js @@ -0,0 +1,235 @@ +/** + * Controls Superset - The apiControls properties get moved into the Controls object itself, and then the instance is created + * @param graphics R3.GraphicsRuntime + * @param apiOrbitControls + * @constructor + */ +R3.Controls.D3.Orbit = function ( + graphics, + apiOrbitControls +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiOrbitControls)) { + apiOrbitControls = { + controlsType : R3.API.Controls.CONTROLS_TYPE_ORBIT + }; + } + + if (R3.Utils.UndefinedOrNull()) { + apiOrbitControls.controlsType = R3.API.Controls.CONTROLS_TYPE_ORBIT; + } + + R3.API.Controls.D3.Orbit.call( + this, + apiOrbitControls, + apiOrbitControls.camera, + apiOrbitControls.target, + apiOrbitControls.enabled, + apiOrbitControls.minPolarAngle, + apiOrbitControls.maxPolarAngle, + apiOrbitControls.enableDamping, + apiOrbitControls.dampingFactor, + apiOrbitControls.enableZoom, + apiOrbitControls.zoomSpeed, + apiOrbitControls.enableRotate, + apiOrbitControls.rotateSpeed, + apiOrbitControls.enablePan, + apiOrbitControls.keyPanSpeed, + apiOrbitControls.autoRotate, + apiOrbitControls.autoRotateSpeed, + apiOrbitControls.enableKeys + ); + + R3.Controls.call( + this, + apiOrbitControls + ); + +}; + +/** + * Inheritance + * @type {R3.Controls} + */ +R3.Controls.D3.Orbit.prototype = Object.create(R3.Controls.D3.prototype); +R3.Controls.D3.Orbit.prototype.constructor = R3.Controls.D3.Orbit; + +/** + * Create Instance + */ +R3.Controls.D3.Orbit.prototype.createInstance = function() { + + if ( + R3.Utils.UndefinedOrNull(this.camera) || + R3.Utils.UndefinedOrNull(this.camera.instance) + ) { + console.warn('no camera at time of editor-controls create instance'); + return; + } + + if ( + R3.Utils.UndefinedOrNull(this.canvas) || + R3.Utils.UndefinedOrNull(this.canvas.instance) + ) { + console.warn('no canvas at time of editor-controls create instance'); + return; + } + + this.instance = new THREE.OrbitControls( + this.camera.instance, + this.canvas.instance + ); + + if (this.target && this.target.instance) { + this.instance.target = this.target.instance.position; + } + + this.instance.enabled = this.enabled; + this.instance.minPolarAngle = this.minPolarAngle; + this.instance.maxPolarAngle = this.maxPolarAngle; + this.instance.enableDamping = this.enableDamping; + this.instance.dampingFactor = this.dampingFactor; + this.instance.enableZoom = this.enableZoom; + this.instance.zoomSpeed = this.zoomSpeed; + this.instance.enableRotate = this.enableRotate; + this.instance.rotateSpeed = this.rotateSpeed; + this.instance.enablePan = this.enablePan; + this.instance.keyPanSpeed = this.keyPanSpeed; + this.instance.autoRotate = this.autoRotate; + this.instance.autoRotateSpeed = this.autoRotateSpeed; + this.instance.enableKeys = this.enableKeys; + + R3.Controls.prototype.createInstance.call(this); +}; + +/** + * Update Instance + */ +R3.Controls.D3.Orbit.prototype.updateInstance = function(property) { + + if ( + property === 'canvas' || + property === 'camera' + ) { + if (R3.Utils.UndefinedOrNull(this.instance)) { + this.createInstance(); + } else { + this.instance.dispose(); + this.createInstance(); + } + } + + if (property === 'target') { + + if (this.target && this.target.instance) { + this.instance.target = this.target.instance.position; + } else { + this.instance.target = new THREE.Vector3(); + } + return; + } + + if (property === 'enabled') { + this.instance.enabled = this.enabled; + return; + } + + if (property === 'minPolarAngle') { + this.instance.minPolarAngle = this.minPolarAngle; + return; + } + + if (property === 'maxPolarAngle') { + this.instance.maxPolarAngle = this.maxPolarAngle; + return; + } + + if (property === 'enableDamping') { + this.instance.enableDamping = this.enableDamping; + return; + } + + if (property === 'dampingFactor') { + this.instance.dampingFactor = this.dampingFactor; + return; + } + + if (property === 'enableZoom') { + this.instance.enableZoom = this.enableZoom; + return; + } + + if (property === 'zoomSpeed') { + this.instance.zoomSpeed = this.zoomSpeed; + return; + } + + if (property === 'enableRotate') { + this.instance.enableRotate = this.enableRotate; + return; + } + + if (property === 'rotateSpeed') { + this.instance.rotateSpeed = this.rotateSpeed; + return; + } + + if (property === 'enablePan') { + this.instance.enablePan = this.enablePan; + return; + } + + if (property === 'keyPanSpeed') { + this.instance.keyPanSpeed = this.keyPanSpeed; + return; + } + + if (property === 'autoRotate') { + this.instance.autoRotate = this.autoRotate; + return; + } + + if (property === 'autoRotateSpeed') { + this.instance.autoRotateSpeed = this.autoRotateSpeed; + return; + } + + if (property === 'enableKeys') { + this.instance.enableKeys = this.enableKeys; + return; + } + + R3.Controls.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.Controls.D3.Orbit to a R3.D3.API.Mesh + * @returns {R3.API.Controls} + */ +R3.Controls.D3.Orbit.prototype.toApiObject = function() { + + var apiControls = R3.Controls.prototype.toApiObject.call(this); + + return new R3.API.Controls.D3.Orbit( + apiControls, + R3.Utils.IdOrNull(this.camera), + R3.Utils.IdOrNull(this.target), + this.enabled, + this.minPolarAngle, + this.maxPolarAngle, + this.enableDamping, + this.dampingFactor, + this.enableZoom, + this.zoomSpeed, + this.enableRotate, + this.rotateSpeed, + this.enablePan, + this.keyPanSpeed, + this.autoRotate, + this.autoRotateSpeed, + this.enableKeys + ); +}; diff --git a/src/r3-controls-keyboard.js b/src/r3-controls-keyboard.js new file mode 100644 index 0000000..3c4630e --- /dev/null +++ b/src/r3-controls-keyboard.js @@ -0,0 +1,79 @@ +/** + * Keyboard Controls + * @param apiKeyboardControls R3.API.Controls + * @constructor + */ +R3.Controls.Keyboard = function ( + apiKeyboardControls +) { + + if (R3.Utils.UndefinedOrNull(apiKeyboardControls)) { + apiKeyboardControls = { + controlsType : R3.API.Controls.CONTROLS_TYPE_KEYBOARD + }; + } + + R3.API.Controls.Keyboard.call( + this, + apiKeyboardControls + ); + + R3.Controls.call( + this, + apiKeyboardControls + ); +}; + +/** + * Inheritance + * @type {R3.Controls} + */ +R3.Controls.Keyboard.prototype = Object.create(R3.Controls.prototype); +R3.Controls.Keyboard.prototype.constructor = R3.Controls.Keyboard; + +/** + * Create Instance + * @returns + */ +R3.Controls.Keyboard.prototype.createInstance = function() { + /** + * Set instance to true to indicate no dependencies to other components + */ + this.instance = true; + R3.Controls.prototype.createInstance.call(this); +}; + +/** + * Update Instance + */ +R3.Controls.Keyboard.prototype.updateInstance = function(property) { + R3.Controls.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.Controls.Keyboard to a R3.API.Controls + * @returns {R3.API.Controls} + */ +R3.Controls.Keyboard.prototype.toApiObject = function() { + var apiControls = R3.Controls.prototype.toApiObject.call(this); + /** + * add other properties here as this component develops... + */ + return apiControls; +}; + +/** + * Construct an Keyboard Controls object from data + * @param objectControls + * @returns {R3.Controls.Keyboard} + * @constructor + */ +R3.Controls.Keyboard.FromObject = function(objectControls) { + + var apiKeyboardControls = R3.API.Controls.Keyboard.FromObject(objectControls); + + return new R3.Controls.Keyboard( + apiKeyboardControls + ); + +}; \ No newline at end of file diff --git a/src/r3-controls-mouse.js b/src/r3-controls-mouse.js new file mode 100644 index 0000000..c8fa81d --- /dev/null +++ b/src/r3-controls-mouse.js @@ -0,0 +1,79 @@ +/** + * Mouse Controls + * @param apiMouseControls R3.API.Controls + * @constructor + */ +R3.Controls.Mouse = function ( + apiMouseControls +) { + + if (R3.Utils.UndefinedOrNull(apiMouseControls)) { + apiMouseControls = { + controlsType : R3.API.Controls.CONTROLS_TYPE_MOUSE + }; + } + + R3.API.Controls.Mouse.call( + this, + apiMouseControls + ); + + R3.Controls.call( + this, + apiMouseControls + ); +}; + +/** + * Inheritance + * @type {R3.Controls} + */ +R3.Controls.Mouse.prototype = Object.create(R3.Controls.prototype); +R3.Controls.Mouse.prototype.constructor = R3.Controls.Mouse; + +/** + * Create Instance + * @returns + */ +R3.Controls.Mouse.prototype.createInstance = function() { + /** + * Set instance to true to indicate no dependencies to other components + */ + this.instance = true; + R3.Controls.prototype.createInstance.call(this); +}; + +/** + * Update Instance + */ +R3.Controls.Mouse.prototype.updateInstance = function(property) { + R3.Controls.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.Controls.Mouse to a R3.API.Controls + * @returns {R3.API.Controls} + */ +R3.Controls.Mouse.prototype.toApiObject = function() { + var apiControls = R3.Controls.prototype.toApiObject.call(this); + /** + * add other properties here as this component develops... + */ + return apiControls; +}; + +/** + * Construct an Mouse Controls object from data + * @param objectControls + * @returns {R3.Controls.Mouse} + * @constructor + */ +R3.Controls.Mouse.FromObject = function(objectControls) { + + var apiMouseControls = R3.API.Controls.Mouse.FromObject(objectControls); + + return new R3.Controls.Mouse( + apiMouseControls + ); + +}; \ No newline at end of file diff --git a/src/r3-controls-touch.js b/src/r3-controls-touch.js new file mode 100644 index 0000000..4fe08f0 --- /dev/null +++ b/src/r3-controls-touch.js @@ -0,0 +1,82 @@ +/** + * Touch Controls + * @constructor + * @param apiTouchControls + */ +R3.Controls.Touch = function ( + apiTouchControls +) { + + if (R3.Utils.UndefinedOrNull(apiTouchControls)) { + apiTouchControls = { + controlsType : R3.API.Controls.CONTROLS_TYPE_TOUCH + }; + } + + R3.API.Controls.Touch.call( + this, + apiTouchControls, + apiTouchControls.sensitivity + ); + + R3.Controls.call( + this, + apiTouchControls + ); +}; + +/** + * Inheritance + * @type {R3.Controls} + */ +R3.Controls.Touch.prototype = Object.create(R3.Controls.prototype); +R3.Controls.Touch.prototype.constructor = R3.Controls.Touch; + +/** + * Create Instance + * @returns + */ +R3.Controls.Touch.prototype.createInstance = function() { + /** + * Set instance to true to indicate no dependencies to other components + */ + this.instance = true; + R3.Controls.prototype.createInstance.call(this); +}; + +/** + * Update Instance + */ +R3.Controls.Touch.prototype.updateInstance = function(property) { + R3.Controls.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.Controls.Touch to a R3.API.Controls + * @returns {R3.API.Controls} + */ +R3.Controls.Touch.prototype.toApiObject = function() { + + var apiControls = R3.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 objectControls + * @returns {R3.Controls.Touch} + * @constructor + */ +R3.Controls.Touch.FromObject = function(objectControls) { + + var apiTouchControls = R3.API.Controls.Touch.FromObject(objectControls); + + return new R3.Controls.Touch(apiTouchControls); + +}; \ No newline at end of file diff --git a/src/r3-curve-a.js b/src/r3-curve-a.js new file mode 100644 index 0000000..c9e4a7c --- /dev/null +++ b/src/r3-curve-a.js @@ -0,0 +1,87 @@ +/** + * R3.Curve + * @param graphics R3.GraphicsRuntime + * @param apiCurve R3.API.Curve + * @property curveType + * @constructor + */ +R3.Curve = function( + graphics, + apiCurve +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiCurve)) { + apiCurve = {}; + } + + R3.API.Curve.call( + this, + apiCurve.id, + apiCurve.name, + apiCurve.curveType, + apiCurve.parentEntity, + apiCurve.arcLenghDivisions + ); + + var linkedObjects = {}; + + switch (this.curveType) { + case R3.API.Curve.CURVE_TYPE_PATH : + linkedObjects.curves = [R3.Curve]; + break; + } + + R3.Component.call( + this, + linkedObjects + ); +}; + +R3.Curve.prototype = Object.create(R3.Component.prototype); +R3.Curve.prototype.constructor = R3.Curve; + +/** + * Create Instance + */ +R3.Curve.prototype.createInstance = function() { + + if (R3.Utils.UndefinedOrNull(this.instance)) { + console.warn('you should not instantiate this curve object directly'); + this.instance = new THREE.Curve(); + } + + this.instance.arcLenghDivisions = this.arcLenghDivisions; + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.Curve.prototype.updateInstance = function(property) { + + if (property === 'arcLenghDivisions') { + this.instance.arcLenghDivisions = this.arcLenghDivisions; + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.Curve to a new R3.API.Curve + * @returns {R3.API.Curve} + */ +R3.Curve.prototype.toApiObject = function() { + + return new R3.API.Curve( + this.id, + this.name, + this.curveType, + R3.Utils.IdOrNull(this.parentEntity), + this.arcLenghDivisions + ); + +}; diff --git a/src/r3-curve-path-a.js b/src/r3-curve-path-a.js new file mode 100644 index 0000000..a6a74df --- /dev/null +++ b/src/r3-curve-path-a.js @@ -0,0 +1,109 @@ +/** + * R3.Curve.Path + * @param graphics R3.GraphicsRuntime + * @param apiCurvePath + * @constructor + */ +R3.Curve.Path = function( + graphics, + apiCurvePath +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiCurvePath)) { + apiCurvePath = { + curveType : R3.API.Curve.CURVE_TYPE_PATH + }; + } + + R3.API.Curve.Path.call( + this, + apiCurvePath, + apiCurvePath.curves, + apiCurvePath.autoClose + ); + + this.curves = this.curves.map( + function(curve) { + if (curve instanceof R3.API.Curve) { + return new R3.Curve( + this.graphics, + curve + ); + } + }.bind(this) + ); + + R3.Curve.call( + this, + this.graphics, + this + ); + +}; + +R3.Curve.Path.prototype = Object.create(R3.Curve.prototype); +R3.Curve.Path.prototype.constructor = R3.Curve.Path; + +/** + * Creates a camera instance + * @returns {*} + */ +R3.Curve.Path.prototype.createInstance = function() { + + if (R3.Utils.UndefinedOrNull(this.instance)) { + console.warn('you should not instantiate this curve object directly'); + this.instance = new THREE.CurvePath(); + } + + this.instance.curves = this.curves.map( + function(curve) { + return curve.instance; + } + ); + + this.instance.autoClose = this.autoClose; + + R3.Curve.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.Curve.Path.prototype.updateInstance = function(property) { + + if (property === 'curves') { + console.warn('todo: update curves'); + return; + } + + if (property === 'autoClose') { + this.instance.autoClose = this.autoClose; + return; + } + + R3.Curve.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.Curve to a R3.API.Curve + * @returns {R3.API.Curve} + */ +R3.Curve.Path.prototype.toApiObject = function() { + + var apiCurve = R3.Curve.prototype.toApiObject.call(this); + + var apiCurvePath = new R3.API.Curve.Path( + apiCurve, + this.curves.map( + function(curve) { + return R3.Utils.IdOrNull(curve); + } + ), + this.autoClose + ); + + return apiCurvePath; +}; diff --git a/src/r3-curve-path-d2-a.js b/src/r3-curve-path-d2-a.js new file mode 100644 index 0000000..12c1b2b --- /dev/null +++ b/src/r3-curve-path-d2-a.js @@ -0,0 +1,101 @@ +/** + * R3.Curve.Path.D2 + * @param graphics R3.GraphicsRuntime + * @param apiCurvePath + * @constructor + */ +R3.Curve.Path.D2 = function( + graphics, + apiCurvePath +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiCurvePath)) { + apiCurvePath = { + curveType : R3.API.Curve.CURVE_TYPE_PATH_2D + }; + } + + R3.API.Curve.Path.D2.call( + this, + apiCurvePath, + apiCurvePath.points + ); + + this.points = this.points.map( + function(point) { + return new R3.Vector2( + this.graphics, + point + ); + }.bind(this) + ); + + R3.Curve.Path.call( + this, + this.graphics, + this + ); + +}; + +R3.Curve.Path.D2.prototype = Object.create(R3.Curve.Path.prototype); +R3.Curve.Path.D2.prototype.constructor = R3.Curve.Path.D2; + +/** + * Creates a camera instance + * @returns {*} + */ +R3.Curve.Path.D2.prototype.createInstance = function() { + + if (R3.Utils.UndefinedOrNull(this.instance)) { + this.instance = new THREE.Path( + this.points.map( + function(point) { + return point.instance; + } + ) + ); + } + + R3.Curve.Path.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.Curve.Path.D2.prototype.updateInstance = function(property) { + + if (property === 'points') { + console.warn('todo: update points (and test it)'); + this.instance.points = this.points.map( + function(point) { + return point.instance; + } + ); + return; + } + + R3.Curve.Path.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.Curve to a R3.API.Curve + * @returns {R3.API.Curve} + */ +R3.Curve.Path.D2.prototype.toApiObject = function() { + + var apiCurvePath = R3.Curve.Path.prototype.toApiObject.call(this); + + return new R3.API.Curve.Path.D2( + apiCurvePath, + this.points.map( + function(point) { + return point.toApiObject(); + } + ) + ); + +}; diff --git a/src/r3-curve-path-d2-shape.js b/src/r3-curve-path-d2-shape.js new file mode 100644 index 0000000..0249956 --- /dev/null +++ b/src/r3-curve-path-d2-shape.js @@ -0,0 +1,74 @@ +/** + * R3.Curve.Path.D2 + * @param graphics R3.GraphicsRuntime + * @param apiCurvePathD2 + * @constructor + */ +R3.Curve.Path.D2.Shape = function( + graphics, + apiCurvePathD2 +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiCurvePathD2)) { + apiCurvePathD2 = { + curveType : R3.API.Curve.CURVE_TYPE_PATH_2D_SHAPE + }; + } + + R3.API.Curve.Path.D2.call( + this, + apiCurvePathD2, + apiCurvePathD2.points + ); + + R3.Curve.Path.D2.call( + this, + this.graphics, + this + ); + +}; + +R3.Curve.Path.D2.Shape.prototype = Object.create(R3.Curve.Path.D2.prototype); +R3.Curve.Path.D2.Shape.prototype.constructor = R3.Curve.Path.D2.Shape; + +/** + * Creates a camera instance + * @returns {*} + */ +R3.Curve.Path.D2.Shape.prototype.createInstance = function() { + + this.instance = new THREE.Shape( + this.points.map( + function(point) { + return point.instance; + } + ) + ); + + R3.Curve.Path.D2.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.Curve.Path.D2.Shape.prototype.updateInstance = function(property) { + R3.Curve.Path.D2.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.Curve to a R3.API.Curve + * @returns {R3.API.Curve} + */ +R3.Curve.Path.D2.Shape.prototype.toApiObject = function() { + + var apiCurvePathD2 = R3.Curve.Path.D2.prototype.toApiObject.call(this); + + return new R3.API.Curve.Path.D2.Shape( + apiCurvePathD2 + ); + +}; diff --git a/src/r3-custom-code.js b/src/r3-custom-code.js new file mode 100644 index 0000000..147e85c --- /dev/null +++ b/src/r3-custom-code.js @@ -0,0 +1,173 @@ +/** + * Creates a CustomCode object + * @param apiCustomCode R3.API.CustomCode + * @constructor + */ +R3.CustomCode = function( + apiCustomCode +) { + + if (R3.Utils.UndefinedOrNull(apiCustomCode)) { + apiCustomCode = {}; + } + + R3.API.CustomCode.call( + this, + apiCustomCode.id, + apiCustomCode.name, + apiCustomCode.eventId, + apiCustomCode.code, + apiCustomCode.parentEntity + ); + + this.editor = null; + + R3.Component.call(this); +}; + +R3.CustomCode.prototype = Object.create(R3.Component.prototype); +R3.CustomCode.prototype.constructor = R3.CustomCode; + +R3.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); + } + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.CustomCode.prototype.updateInstance = function(property) { + + if (property === 'name') { + R3.Event.Emit( + R3.Event.NAME_UPDATE, + { + component : this + } + ); + return; + } + + if (property === 'code') { + + try { + this.instance = new Function('data', this.code).bind(this); + this.publish( + R3.Event.COMPILE_SUCCESS, + { + component: this + } + ) + } catch (error) { + this.instance = new Function('data', "console.log('compilation update failed for : " + this.name + "');").bind(this); + this.publish( + R3.Event.COMPILE_FAILED, + { + component: this + } + ) + } + + return; + } + + if (property === 'eventId') { + this.publish( + R3.Event.EVENT_ID_UPDATE, + { + component : this + } + ) + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.CustomCode to a new R3.API.CustomCode + * @returns {R3.API.CustomCode} + */ +R3.CustomCode.prototype.toApiObject = function() { + + return new R3.API.CustomCode( + this.id, + this.name, + this.eventId, + this.code, + R3.Utils.IdOrNull(this.parentEntity) + ); + +}; + +R3.CustomCode.prototype.launchEditor = function(){ + + R3.Event.Emit( + R3.Event.GET_RUNTIME, + null, + function(runtime) { + this.coder = runtime.coder; + this.coder.isNotCodeMirrorThrow(); + }.bind(this) + ); + + if (this instanceof R3.D3.Shader.Vertex) { + this.editor = this.coder.instance( + document.body, + { + value: this.code, + mode: 'x-shader/x-vertex', + lineNumbers: true, + scrollbarStyle: 'overlay', + indentWithTabs: true, + indentUnit: 4 + } + ); + } else if (this instanceof R3.D3.Shader.Fragment) { + this.editor = this.coder.instance( + document.body, + { + value: this.code, + mode: 'x-shader/x-fragment', + lineNumbers: true, + scrollbarStyle: 'overlay', + indentWithTabs: true, + indentUnit: 4 + } + ); + } else { + 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('code'); + + }.bind(this)) +}; + +R3.CustomCode.prototype.closeEditor = function(){ + var dom = this.editor.getWrapperElement(); + dom.parentElement.removeChild(dom); +}; \ No newline at end of file diff --git a/src/r3-d3-api-a-object.js b/src/r3-d3-api-a-object.js new file mode 100644 index 0000000..54e6125 --- /dev/null +++ b/src/r3-d3-api-a-object.js @@ -0,0 +1,173 @@ +/** + * R3.D3.API.Object + * @param id + * @param name + * @param objectType + * @param parentEntity + * @param useQuaternion + * @param position + * @param quaternion + * @param rotation + * @param scale + * @param up + * @param lookAt + * @constructor + */ +R3.D3.API.Object = function( + id, + name, + objectType, + parentEntity, + useQuaternion, + position, + quaternion, + rotation, + scale, + up, + lookAt +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(objectType)) { + objectType = 0; + } + this.objectType = objectType; + + if (R3.Utils.UndefinedOrNull(name)) { + switch (this.objectType) { + case R3.D3.API.Object.OBJECT_TYPE_NONE : + name = 'Object'; + break; + /** + * Cameras + */ + case R3.D3.API.Object.OBJECT_TYPE_CAMERA : + name = 'Camera'; + break; + case R3.D3.API.Object.OBJECT_TYPE_CAMERA_ORTHOGRAPHIC : + name = 'Camera Orthographic'; + break; + case R3.D3.API.Object.OBJECT_TYPE_CAMERA_PERSPECTIVE : + name = 'Camera Perspective'; + break; + case R3.D3.API.Object.OBJECT_TYPE_CAMERA_CUBE : + name = 'Camera Cube'; + break; + case R3.D3.API.Object.OBJECT_TYPE_CAMERA_STEREO : + name = 'Camera Stereo'; + break; + /** + * Meshes + */ + case R3.D3.API.Object.OBJECT_TYPE_MESH : + name = 'Mesh'; + break; + } + name += ' (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(useQuaternion)) { + useQuaternion = true; + } + this.useQuaternion = useQuaternion; + + if (R3.Utils.UndefinedOrNull(position)) { + position = new R3.API.Vector3(); + } + this.position = position; + + if (R3.Utils.UndefinedOrNull(quaternion)) { + quaternion = new R3.API.Quaternion(); + } + this.quaternion = quaternion; + + if (R3.Utils.UndefinedOrNull(rotation)) { + rotation = new R3.API.Vector3(); + } + this.rotation = rotation; + + if (R3.Utils.UndefinedOrNull(scale)) { + scale = new R3.API.Vector3(1,1,1); + } + this.scale = scale; + + if (R3.Utils.UndefinedOrNull(up)) { + up = new R3.API.Vector3(0,1,0); + } + this.up = up; + + if (R3.Utils.UndefinedOrNull(lookAt)) { + lookAt = new R3.API.Vector3(); + } + this.lookAt = lookAt; + + R3.API.Component.call( + this, + R3.D3.API.Object.GetComponentType(this.objectType), + parentEntity + ); +}; + +R3.D3.API.Object.prototype = Object.create(R3.API.Component.prototype); +R3.D3.API.Object.prototype.constructor = R3.D3.API.Object; + +R3.D3.API.Object.GetComponentType = function(objectType) { + + var componentType = null; + + switch (objectType) { + case R3.D3.API.Object.OBJECT_TYPE_NONE : + componentType = R3.Component.OBJECT; + break; + /** + * Cameras + */ + case R3.D3.API.Object.OBJECT_TYPE_CAMERA : + componentType = R3.Component.CAMERA; + break; + case R3.D3.API.Object.OBJECT_TYPE_CAMERA_PERSPECTIVE : + componentType = R3.Component.CAMERA_PERSPECTIVE; + break; + case R3.D3.API.Object.OBJECT_TYPE_CAMERA_ORTHOGRAPHIC : + componentType = R3.Component.CAMERA_ORTHOGRAPHIC; + break; + case R3.D3.API.Object.OBJECT_TYPE_CAMERA_STEREO : + componentType = R3.Component.CAMERA_STEREO; + break; + case R3.D3.API.Object.OBJECT_TYPE_CAMERA_CUBE : + componentType = R3.Component.CAMERA_CUBE; + break; + /** + * Meshes + */ + case R3.D3.API.Object.OBJECT_TYPE_MESH : + componentType = R3.Component.MESH; + break; + default: + throw new Error('unsupported camera type: ' + objectType); + } + + return componentType; +}; + +R3.D3.API.Object.OBJECT_TYPE_NONE = 0x0; + +/** + * Cameras + * @type {number} + */ +R3.D3.API.Object.OBJECT_TYPE_CAMERA = 0x11; +R3.D3.API.Object.OBJECT_TYPE_CAMERA_PERSPECTIVE = 0x12;//0x1; +R3.D3.API.Object.OBJECT_TYPE_CAMERA_ORTHOGRAPHIC = 0x13;//0x2; +R3.D3.API.Object.OBJECT_TYPE_CAMERA_STEREO = 0x14;//0x3; +R3.D3.API.Object.OBJECT_TYPE_CAMERA_CUBE = 0x15;//0x4; + +/** + * Meshes + * @type {number} + */ +R3.D3.API.Object.OBJECT_TYPE_MESH = 0x21; diff --git a/src/r3-d3-api-animation.js b/src/r3-d3-api-animation.js new file mode 100644 index 0000000..4c7979f --- /dev/null +++ b/src/r3-d3-api-animation.js @@ -0,0 +1,121 @@ +/** + * 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 + */ +R3.D3.API.Animation = function ( + id, + name, + rotationSpeed, + translationSpeed, + scaleSpeed, + rotationFn, + translationFn, + scaleFn, + blocking, + applyToMeshWhenDone, + meshes, + parentEntity +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Animation (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(rotationSpeed)) { + rotationSpeed = 0; + } + this.rotationSpeed = rotationSpeed; + + if (R3.Utils.UndefinedOrNull(translationSpeed)) { + translationSpeed = 0; + } + this.translationSpeed = translationSpeed; + + if (R3.Utils.UndefinedOrNull(scaleSpeed)) { + scaleSpeed = 0; + } + this.scaleSpeed = scaleSpeed; + + if (R3.Utils.UndefinedOrNull(rotationFn)) { + rotationFn = null; + } + this.rotationFn = rotationFn; + + if (R3.Utils.UndefinedOrNull(translationFn)) { + translationFn = null; + } + this.translationFn = translationFn; + + if (R3.Utils.UndefinedOrNull(scaleFn)) { + scaleFn = null; + } + this.scaleFn = scaleFn; + + if (R3.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 (R3.Utils.UndefinedOrNull(applyToMeshWhenDone)) { + applyToMeshWhenDone = true; + } + this.applyToMeshWhenDone = applyToMeshWhenDone; + + if (R3.Utils.UndefinedOrNull(meshes)) { + meshes = []; + } + this.meshes = meshes; + + R3.API.Component.call( + this, + R3.Component.ANIMATION, + parentEntity + ); +}; + +R3.D3.API.Animation.prototype = Object.create(R3.API.Component.prototype); +R3.D3.API.Animation.prototype.constructor = R3.D3.API.Animation; + +/** + * Object to R3.D3.API.Animation + * @param objectComponent + * @returns {R3.D3.API.Animation} + * @constructor + */ +R3.D3.API.Animation.FromObject = function(objectComponent) { + return new R3.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 + ); +}; diff --git a/src/r3-d3-api-audio.js b/src/r3-d3-api-audio.js new file mode 100644 index 0000000..eb193d1 --- /dev/null +++ b/src/r3-d3-api-audio.js @@ -0,0 +1,104 @@ +/** + * 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 paused + * @param parentEntity + * @constructor + */ +R3.D3.API.Audio = function( + id, + name, + path, + loop, + volume, + camera, + overplay, + paused, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Audio (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(path)) { + path = ''; + } + this.path = path; + + if (R3.Utils.UndefinedOrNull(loop)) { + loop = false; + } + this.loop = loop; + + if (R3.Utils.UndefinedOrNull(volume)) { + volume = 0.5; + } + this.volume = volume; + + if (R3.Utils.UndefinedOrNull(camera)) { + camera = null; + } + this.camera = camera; + + if (R3.Utils.UndefinedOrNull(overplay)) { + overplay = false; + } + this.overplay = overplay; + + if (R3.Utils.UndefinedOrNull(paused)) { + paused = false; + } + this.paused = paused; + + R3.API.Component.call( + this, + R3.Component.AUDIO, + parentEntity + ); +}; + +R3.D3.API.Audio.prototype = Object.create(R3.API.Component.prototype); +R3.D3.API.Audio.prototype.constructor = R3.D3.API.Audio; + +/** + * Creates an API Audio from an Object Audio + * @param objectAudio + * @constructor + */ +R3.D3.API.Audio.FromObject = function(objectAudio) { + + var apiCamera = null; + if (objectAudio.camera) { + if (objectAudio.camera instanceof Object) { + apiCamera = R3.D3.API.Camera.FromObject(objectAudio.camera); + } else { + apiCamera = objectAudio.camera; + } + } + + return new R3.D3.API.Audio( + objectAudio.id, + objectAudio.name, + objectAudio.path, + objectAudio.loop, + objectAudio.volume, + apiCamera, + objectAudio.overplay, + objectAudio.paused, + objectAudio.parentEntity + ); + +}; diff --git a/src/r3-d3-api-bone-weight.js b/src/r3-d3-api-bone-weight.js new file mode 100644 index 0000000..26e139f --- /dev/null +++ b/src/r3-d3-api-bone-weight.js @@ -0,0 +1,26 @@ +/** + * BoneWeight object - associates a vertex to a bone with some weight + * @param boneIndex int + * @param weight float + * @constructor + */ +R3.D3.API.BoneWeight = function ( + boneIndex, + weight +) { + this.boneIndex = boneIndex; + this.weight = weight; +}; + +/** + * Object to R3.D3.API.BoneWeight + * @param objectBoneWeight + * @returns {R3.D3.API.BoneWeight} + * @constructor + */ +R3.D3.API.BoneWeight.FromObject = function(objectBoneWeight) { + return new R3.D3.API.BoneWeight( + objectBoneWeight.boneIndex, + objectBoneWeight.weight + ) +}; diff --git a/src/r3-d3-api-bone.js b/src/r3-d3-api-bone.js new file mode 100644 index 0000000..de34c70 --- /dev/null +++ b/src/r3-d3-api-bone.js @@ -0,0 +1,93 @@ +/** + * Bone Superset + * @param id + * @param name string + * @param childBoneIds + * @param parentBoneIds + * @param quaternion R3.API.Quaternion + * @param position R3.API.Vector3 + * @param scale R3.API.Vector3 + * @param up R3.API.Vector3 + * @param parentEntity + * @constructor + */ +R3.D3.API.Bone = function ( + id, + name, + childBoneIds, + parentBoneIds, + position, + quaternion, + scale, + up, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Bone (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(childBoneIds)) { + childBoneIds = []; + } + this.childBoneIds = childBoneIds; + + if (R3.Utils.UndefinedOrNull(parentBoneIds)) { + parentBoneIds = []; + } + this.parentBoneIds = parentBoneIds; + + if (R3.Utils.UndefinedOrNull(position)) { + position = new R3.API.Vector3(); + } + this.position = position; + + if (R3.Utils.UndefinedOrNull(quaternion)) { + quaternion = new R3.API.Quaternion(); + } + this.quaternion = quaternion; + + if (R3.Utils.UndefinedOrNull(scale)) { + scale = new R3.API.Vector3(1,1,1); + } + this.scale = scale; + + if (R3.Utils.UndefinedOrNull(up)) { + up = new R3.API.Vector3(0,1,0); + } + this.up = up; + + R3.API.Component.call( + this, + R3.Component.BONE, + parentEntity + ); +}; + +R3.D3.API.Bone.prototype = Object.create(R3.API.Component.prototype); +R3.D3.API.Bone.prototype.constructor = R3.D3.API.Bone; + +/** + * Returns an API bone from an Object bone + * @param objectBone + * @constructor + */ +R3.D3.API.Bone.FromObject = function(objectBone) { + return new R3.D3.API.Bone( + objectBone.id, + objectBone.name, + objectBone.childBoneIds, + objectBone.parentBoneIds, + R3.API.Vector3.FromObject(objectBone.position), + R3.API.Quaternion.FromObject(objectBone.quaternion), + R3.API.Vector3.FromObject(objectBone.scale), + R3.API.Vector3.FromObject(objectBone.up), + objectBone.parentEntity + ); +}; diff --git a/src/r3-d3-api-broadphase.js b/src/r3-d3-api-broadphase.js new file mode 100644 index 0000000..70bdab0 --- /dev/null +++ b/src/r3-d3-api-broadphase.js @@ -0,0 +1,54 @@ +/** + * Raw Broadphase API object - should always correspond with the Broadphase Schema + * @param id + * @param name + * @param broadphaseType + * @param parentEntity + * @constructor + */ +R3.D3.API.Broadphase = function( + id, + name, + broadphaseType, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Broadphase (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(broadphaseType)) { + broadphaseType = R3.D3.Broadphase.BROADPHASE_TYPE_NAIVE; + } + this.broadphaseType = broadphaseType; + + R3.API.Component.call( + this, + R3.Component.BROADPHASE, + parentEntity + ); +}; + +R3.D3.API.Broadphase.prototype = Object.create(R3.API.Component.prototype); +R3.D3.API.Broadphase.prototype.constructor = R3.D3.API.Broadphase; + +/** + * Creates an API Broadphase from an Object Broadphase + * @param objectBroadphase + * @constructor + */ +R3.D3.API.Broadphase.FromObject = function(objectBroadphase) { + return new R3.D3.API.Broadphase( + objectBroadphase.id, + objectBroadphase.name, + objectBroadphase.broadphaseType, + objectBroadphase.parentEntity + ); +}; + diff --git a/src/r3-d3-api-camera-a.js b/src/r3-d3-api-camera-a.js new file mode 100644 index 0000000..54ca09a --- /dev/null +++ b/src/r3-d3-api-camera-a.js @@ -0,0 +1,52 @@ +/** + * R3.D3.API.Camera + * @param apiD3Object + * @param aspect + * @constructor + */ +R3.D3.API.Camera = function( + apiD3Object, + aspect +) { + + if (R3.Utils.UndefinedOrNull(apiD3Object)) { + apiD3Object = { + objectType : R3.D3.API.Object.OBJECT_TYPE_CAMERA + }; + } + + if (R3.Utils.UndefinedOrNull(apiD3Object.objectType)) { + apiD3Object.objectType = R3.D3.API.Object.OBJECT_TYPE_CAMERA; + } + + if (R3.Utils.UndefinedOrNull(aspect)) { + aspect = 1; + } + this.aspect = aspect; + + if (R3.Utils.UndefinedOrNull(apiD3Object.position)) { + apiD3Object.position = new R3.API.Vector3( + 15, + 15, + 15 + ); + } + + R3.D3.API.Object.call( + this, + apiD3Object.id, + apiD3Object.name, + apiD3Object.objectType, + apiD3Object.parentEntity, + apiD3Object.useQuaternion, + apiD3Object.position, + apiD3Object.quaternion, + apiD3Object.rotation, + apiD3Object.scale, + apiD3Object.up, + apiD3Object.lookAt + ); +}; + +R3.D3.API.Camera.prototype = Object.create(R3.D3.API.Object.prototype); +R3.D3.API.Camera.prototype.constructor = R3.D3.API.Camera; diff --git a/src/r3-d3-api-camera-cube.js b/src/r3-d3-api-camera-cube.js new file mode 100644 index 0000000..48a7c85 --- /dev/null +++ b/src/r3-d3-api-camera-cube.js @@ -0,0 +1,59 @@ +/** + * R3.D3.API.Camera.Cube + * @constructor + * @param apiD3ObjectCamera + * @param near + * @param far + * @param cubeResolution + * @param renderTarget + */ +R3.D3.API.Camera.Cube = function( + apiD3ObjectCamera, + near, + far, + cubeResolution, + renderTarget +) { + + if (R3.Utils.UndefinedOrNull(apiD3ObjectCamera)) { + apiD3ObjectCamera = { + objectType : R3.D3.API.Object.OBJECT_TYPE_CAMERA_CUBE + }; + } + + if (R3.Utils.UndefinedOrNull(apiD3ObjectCamera.objectType)) { + apiD3ObjectCamera.objectType = R3.D3.API.Object.OBJECT_TYPE_CAMERA_CUBE; + } + + if (R3.Utils.UndefinedOrNull(near)) { + near = 0.1; + } + this.near = near; + + if (R3.Utils.UndefinedOrNull(far)) { + far = 2000; + } + this.far = far; + + if (R3.Utils.UndefinedOrNull(cubeResolution)) { + cubeResolution = 128; + } + this.cubeResolution = cubeResolution; + + if (R3.Utils.UndefinedOrNull(renderTarget)) { + renderTarget = null; + } + this.renderTarget = renderTarget; + + /** + * CubeCamera's have hardcoded fov=90 and aspect=1 + */ + R3.D3.API.Camera.call( + this, + apiD3ObjectCamera, + apiD3ObjectCamera.aspect + ); +}; + +R3.D3.API.Camera.Cube.prototype = Object.create(R3.D3.API.Camera.prototype); +R3.D3.API.Camera.Cube.prototype.constructor = R3.D3.API.Camera.Cube; diff --git a/src/r3-d3-api-camera-orthographic.js b/src/r3-d3-api-camera-orthographic.js new file mode 100644 index 0000000..b8611d1 --- /dev/null +++ b/src/r3-d3-api-camera-orthographic.js @@ -0,0 +1,144 @@ +/** + * R3.D3.API.Camera.Orthographic + * + * OK - since the introduction of fixed aspect ratio's for our canvases, we only need to know + * the aspect ratio and width - then we calculate the left, right, up and down coords - + * + * for the Z space - we simply use the values in near and far - you should know what you are doing when you + * create an orthographic camera + * + * There are two ways to update the camera - one is by affecting the aspect ratio - the other is modifying the left, + * right, top and bottom values - this also affects the aspect ratio. + * + * In both modes - the camera is assumed to be at position 0,0,10 and facing direction 0,0,-1 (in the positive Z facing + * the negative Z direction seeing what happens around the origin) + * + * Also - the offset is always respected + * + * @constructor + * @param apiD3ObjectCamera + * @param aspectRatioMode + * @param minWidth + * @param minHeight + * @param width + * @param height + * @param near + * @param far + * @param left + * @param right + * @param top + * @param bottom + * @param zoom + */ +R3.D3.API.Camera.Orthographic = function( + apiD3ObjectCamera, + aspectRatioMode, + minWidth, + minHeight, + width, + height, + near, + far, + left, + right, + top, + bottom, + zoom +) { + + if (R3.Utils.UndefinedOrNull(apiD3ObjectCamera)) { + apiD3ObjectCamera = { + objectType : R3.D3.API.Object.OBJECT_TYPE_CAMERA_ORTHOGRAPHIC + }; + } + + if (R3.Utils.UndefinedOrNull(apiD3ObjectCamera.objectType)) { + apiD3ObjectCamera.objectType = R3.D3.API.Object.OBJECT_TYPE_CAMERA_ORTHOGRAPHIC; + } + + if (R3.Utils.UndefinedOrNull(apiD3ObjectCamera.position)) { + apiD3ObjectCamera.position = new R3.API.Vector3(0,0,10); + } + + if (R3.Utils.UndefinedOrNull(apiD3ObjectCamera.lookAt)) { + apiD3ObjectCamera.lookAt = new R3.API.Vector3(0,0,-10); + } + + if (R3.Utils.UndefinedOrNull(aspectRatioMode)) { + aspectRatioMode = R3.D3.API.Camera.Orthographic.ASPECT_RATIO_MODE_BASED_ON_CURRENT; + } + this.aspectRatioMode = aspectRatioMode; + + if (R3.Utils.UndefinedOrNull(minWidth)) { + minWidth = 10; + } + this.minWidth = minWidth; + + if (R3.Utils.UndefinedOrNull(minHeight)) { + minHeight = 10; + } + this.minHeight = minHeight; + + if (R3.Utils.UndefinedOrNull(height)) { + height = 10; + } + this.height = height; + + if (R3.Utils.UndefinedOrNull(width)) { + width = 10; + } + this.width = width; + + if (R3.Utils.UndefinedOrNull(height)) { + height = 10; + } + this.height = height; + + if (R3.Utils.UndefinedOrNull(near)) { + near = 0.1; + } + this.near = near; + + if (R3.Utils.UndefinedOrNull(far)) { + far = 2000; + } + this.far = far; + + if (R3.Utils.UndefinedOrNull(left)) { + left = -5; + } + this.left = left; + + if (R3.Utils.UndefinedOrNull(right)) { + right = 5; + } + this.right = right; + + if (R3.Utils.UndefinedOrNull(top)) { + top = 5; + } + this.top = top; + + if (R3.Utils.UndefinedOrNull(bottom)) { + bottom = -5; + } + this.bottom = bottom; + + if (R3.Utils.UndefinedOrNull(zoom)) { + zoom = 1; + } + this.zoom = zoom; + + R3.D3.API.Camera.call( + this, + apiD3ObjectCamera, + apiD3ObjectCamera.aspect + ); +}; + +R3.D3.API.Camera.Orthographic.prototype = Object.create(R3.D3.API.Camera.prototype); +R3.D3.API.Camera.Orthographic.prototype.constructor = R3.D3.API.Camera.Orthographic; + +R3.D3.API.Camera.Orthographic.ASPECT_RATIO_MODE_NONE = 0x0; +R3.D3.API.Camera.Orthographic.ASPECT_RATIO_MODE_FIXED = 0x1; +R3.D3.API.Camera.Orthographic.ASPECT_RATIO_MODE_BASED_ON_CURRENT = 0x2; diff --git a/src/r3-d3-api-camera-perspective.js b/src/r3-d3-api-camera-perspective.js new file mode 100644 index 0000000..ad79bfc --- /dev/null +++ b/src/r3-d3-api-camera-perspective.js @@ -0,0 +1,84 @@ +/** + * R3.D3.API.Camera.Perspective + * @constructor + * @param apiD3ObjectCamera + * @param fov + * @param near + * @param far + * @param filmGauge + * @param filmOffset + * @param focus + * @param zoom + */ +R3.D3.API.Camera.Perspective = function( + apiD3ObjectCamera, + near, + far, + fov, + filmGauge, + filmOffset, + focus, + zoom +) { + + if (R3.Utils.UndefinedOrNull(apiD3ObjectCamera)) { + apiD3ObjectCamera = { + objectType : R3.D3.API.Object.OBJECT_TYPE_CAMERA_PERSPECTIVE + }; + } + + if (R3.Utils.UndefinedOrNull(apiD3ObjectCamera.objectType)) { + apiD3ObjectCamera.objectType = R3.D3.API.Object.OBJECT_TYPE_CAMERA_PERSPECTIVE; + } + + if (R3.Utils.UndefinedOrNull(near)) { + // near = new R3.API.Number(0.1, 0.001, 0.001, 2000); + near = 0.1; + } + this.near = near; + + if (R3.Utils.UndefinedOrNull(far)) { + // far = new R3.API.Number(2000, 1, 1, 4000); + far = 2000; + } + this.far = far; + + if (R3.Utils.UndefinedOrNull(fov)) { + // fov = new R3.API.Number(50, 1, 0, 180); + fov = 50; + } + this.fov = fov; + + if (R3.Utils.UndefinedOrNull(filmGauge)) { + // filmGauge = new R3.API.Number(35, 1, 0, 200); + filmGauge = 35; + } + this.filmGauge = filmGauge; + + if (R3.Utils.UndefinedOrNull(filmOffset)) { + // filmOffset = new R3.API.Number(0, 1, 0, 200); + filmOffset = 0; + } + this.filmOffset = filmOffset; + + if (R3.Utils.UndefinedOrNull(focus)) { + // focus = new R3.API.Number(10, 0.1, 0, 200); + focus = 10; + } + this.focus = focus; + + if (R3.Utils.UndefinedOrNull(zoom)) { + // zoom = new R3.API.Number(1, 0.01, 0, 10); + zoom = 1; + } + this.zoom = zoom; + + R3.D3.API.Camera.call( + this, + apiD3ObjectCamera, + apiD3ObjectCamera.aspect + ); +}; + +R3.D3.API.Camera.Perspective.prototype = Object.create(R3.D3.API.Camera.prototype); +R3.D3.API.Camera.Perspective.prototype.constructor = R3.D3.API.Camera.Perspective; \ No newline at end of file diff --git a/src/r3-d3-api-camera-stereo-a.js b/src/r3-d3-api-camera-stereo-a.js new file mode 100644 index 0000000..dad747a --- /dev/null +++ b/src/r3-d3-api-camera-stereo-a.js @@ -0,0 +1,40 @@ +/** + * R3.D3.API.Camera.Stereo + * @constructor + * @param apiD3ObjectCamera + * @param stereoMode + */ +R3.D3.API.Camera.Stereo = function( + apiD3ObjectCamera, + stereoMode +) { + + if (R3.Utils.UndefinedOrNull(apiD3ObjectCamera)) { + apiD3ObjectCamera = { + objectType : R3.D3.API.Object.OBJECT_TYPE_CAMERA_STEREO + }; + } + + if (R3.Utils.UndefinedOrNull(apiD3ObjectCamera.objectType)) { + apiD3ObjectCamera.objectType = R3.D3.API.Object.OBJECT_TYPE_CAMERA_STEREO; + } + + + if (R3.Utils.UndefinedOrNull(stereoMode)) { + stereoMode = R3.D3.API.Camera.Stereo.STEREO_MODE_STEREO; + } + this.stereoMode = stereoMode; + + R3.D3.API.Camera.call( + this, + apiD3ObjectCamera, + apiD3ObjectCamera.aspect + ); +}; + +R3.D3.API.Camera.Stereo.prototype = Object.create(R3.D3.API.Camera.prototype); +R3.D3.API.Camera.Stereo.prototype.constructor = R3.D3.API.Camera.Stereo; + +R3.D3.API.Camera.Stereo.STEREO_MODE_STEREO = 0x1; +R3.D3.API.Camera.Stereo.STEREO_MODE_ANAGLYPH = 0x2; +R3.D3.API.Camera.Stereo.STEREO_MODE_PARALLAX = 0x3; diff --git a/src/r3-d3-api-composer.js b/src/r3-d3-api-composer.js new file mode 100644 index 0000000..8852e0d --- /dev/null +++ b/src/r3-d3-api-composer.js @@ -0,0 +1,73 @@ +/** + * R3.D3.API.Composer + * @param id + * @param name + * @param parentEntity + * @param autoUpdateSize + * @param width + * @param height + * @param renderer + * @param renderTarget + * @param passes + * @constructor + */ +R3.D3.API.Composer = function ( + id, + name, + parentEntity, + autoUpdateSize, + width, + height, + renderer, + renderTarget, + passes +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Composer (' + id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(autoUpdateSize)) { + autoUpdateSize = true; + } + this.autoUpdateSize = autoUpdateSize; + + if (R3.Utils.UndefinedOrNull(width)) { + width = 512; + } + this.width = width; + + if (R3.Utils.UndefinedOrNull(height)) { + height = 512; + } + this.height = height; + + if (R3.Utils.UndefinedOrNull(renderer)) { + renderer = null; + } + this.renderer = renderer; + + if (R3.Utils.UndefinedOrNull(renderTarget)) { + renderTarget = null; + } + this.renderTarget = renderTarget; + + if (R3.Utils.UndefinedOrNull(passes)) { + passes = []; + } + this.passes = passes; + + R3.API.Component.call( + this, + R3.Component.COMPOSER, + parentEntity + ); +}; + +R3.D3.API.Composer.prototype = Object.create(R3.API.Component.prototype); +R3.D3.API.Composer.prototype.constructor = R3.D3.API.Composer; diff --git a/src/r3-d3-api-effect-a.js b/src/r3-d3-api-effect-a.js new file mode 100644 index 0000000..151219e --- /dev/null +++ b/src/r3-d3-api-effect-a.js @@ -0,0 +1,100 @@ +/** + * R3.D3.API.Effect + * @param id + * @param name + * @param effectType + * @param parentEntity + * @param renderer + * @param width + * @param height + * + * @property effectType + * + * @constructor + */ +R3.D3.API.Effect = function( + id, + name, + effectType, + parentEntity, + renderer, + width, + height +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(effectType)) { + effectType = R3.D3.API.Effect.EFFECT_TYPE_NONE; + } + this.effectType = effectType; + + if (R3.Utils.UndefinedOrNull(name)) { + + switch (this.effectType) { + case R3.D3.API.Effect.EFFECT_TYPE_ANAGLYPH : + name = 'Effect Anaglyph'; + break; + case R3.D3.API.Effect.EFFECT_TYPE_PARALLAX : + name = 'Effect Parallax'; + break; + case R3.D3.API.Effect.EFFECT_TYPE_STEREO : + name = 'Effect Stereo'; + break; + default : + console.warn('no nice name for effect'); + name = 'Effect'; + } + + name += ' (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(renderer)) { + renderer = null; + } + this.renderer = renderer; + + if (R3.Utils.UndefinedOrNull(width)) { + width = 512; + } + this.width = width; + + if (R3.Utils.UndefinedOrNull(height)) { + height = 512; + } + this.height = height; + + var componentType = null; + + switch (this.effectType) { + case R3.D3.API.Effect.EFFECT_TYPE_STEREO : + componentType = R3.Component.EFFECT_STEREO; + break; + case R3.D3.API.Effect.EFFECT_TYPE_ANAGLYPH : + componentType = R3.Component.EFFECT_ANAGLYPH; + break; + case R3.D3.API.Effect.EFFECT_TYPE_PARALLAX : + componentType = R3.Component.EFFECT_PARALLAX; + break; + default: + throw new Error('unsupported effect type: ' + this.effectType); + } + + R3.API.Component.call( + this, + componentType, + parentEntity + ); +}; + +R3.D3.API.Effect.prototype = Object.create(R3.API.Component.prototype); +R3.D3.API.Effect.prototype.constructor = R3.D3.API.Effect; + +R3.D3.API.Effect.EFFECT_TYPE_NONE = 0x0; +R3.D3.API.Effect.EFFECT_TYPE_STEREO = 0x1; +R3.D3.API.Effect.EFFECT_TYPE_ANAGLYPH = 0x2; +R3.D3.API.Effect.EFFECT_TYPE_PARALLAX = 0x3; diff --git a/src/r3-d3-api-effect-anaglyph.js b/src/r3-d3-api-effect-anaglyph.js new file mode 100644 index 0000000..1d3288d --- /dev/null +++ b/src/r3-d3-api-effect-anaglyph.js @@ -0,0 +1,34 @@ +/** + * R3.D3.API.Effect.Anaglyph + * @constructor + * @param apiEffect + */ +R3.D3.API.Effect.Anaglyph = function( + apiEffect +) { + + if (R3.Utils.UndefinedOrNull(apiEffect)) { + apiEffect = { + effectType : R3.D3.API.Effect.EFFECT_TYPE_ANAGLYPH + }; + } + + if (R3.Utils.UndefinedOrNull(apiEffect.cameraType)) { + apiEffect.effectType = R3.D3.API.Effect.EFFECT_TYPE_ANAGLYPH; + } + + R3.D3.API.Effect.call( + this, + apiEffect.id, + apiEffect.name, + apiEffect.effectType, + apiEffect.parentEntity, + apiEffect.renderer, + apiEffect.width, + apiEffect.height + ); + +}; + +R3.D3.API.Effect.Anaglyph.prototype = Object.create(R3.D3.API.Effect.prototype); +R3.D3.API.Effect.Anaglyph.prototype.constructor = R3.D3.API.Effect.Anaglyph; \ No newline at end of file diff --git a/src/r3-d3-api-effect-parallax.js b/src/r3-d3-api-effect-parallax.js new file mode 100644 index 0000000..7725d57 --- /dev/null +++ b/src/r3-d3-api-effect-parallax.js @@ -0,0 +1,34 @@ +/** + * R3.D3.API.Effect.Parallax + * @constructor + * @param apiEffect + */ +R3.D3.API.Effect.Parallax = function( + apiEffect +) { + + if (R3.Utils.UndefinedOrNull(apiEffect)) { + apiEffect = { + effectType : R3.D3.API.Effect.EFFECT_TYPE_PARALLAX + }; + } + + if (R3.Utils.UndefinedOrNull(apiEffect.cameraType)) { + apiEffect.effectType = R3.D3.API.Effect.EFFECT_TYPE_PARALLAX; + } + + R3.D3.API.Effect.call( + this, + apiEffect.id, + apiEffect.name, + apiEffect.effectType, + apiEffect.parentEntity, + apiEffect.renderer, + apiEffect.width, + apiEffect.height + ); + +}; + +R3.D3.API.Effect.Parallax.prototype = Object.create(R3.D3.API.Effect.prototype); +R3.D3.API.Effect.Parallax.prototype.constructor = R3.D3.API.Effect.Parallax; \ No newline at end of file diff --git a/src/r3-d3-api-effect-stereo.js b/src/r3-d3-api-effect-stereo.js new file mode 100644 index 0000000..ab37ecb --- /dev/null +++ b/src/r3-d3-api-effect-stereo.js @@ -0,0 +1,41 @@ +/** + * R3.D3.API.Effect.Stereo + * @constructor + * @param apiEffect + * @param eyeSeperation + */ +R3.D3.API.Effect.Stereo = function( + apiEffect, + eyeSeperation +) { + + if (R3.Utils.UndefinedOrNull(apiEffect)) { + apiEffect = { + effectType : R3.D3.API.Effect.EFFECT_TYPE_STEREO + }; + } + + if (R3.Utils.UndefinedOrNull(apiEffect.cameraType)) { + apiEffect.effectType = R3.D3.API.Effect.EFFECT_TYPE_STEREO; + } + + if (R3.Utils.UndefinedOrNull(eyeSeperation)) { + eyeSeperation = 0.064; + } + this.eyeSeperation = eyeSeperation; + + R3.D3.API.Effect.call( + this, + apiEffect.id, + apiEffect.name, + apiEffect.effectType, + apiEffect.parentEntity, + apiEffect.renderer, + apiEffect.width, + apiEffect.height + ); + +}; + +R3.D3.API.Effect.Stereo.prototype = Object.create(R3.D3.API.Effect.prototype); +R3.D3.API.Effect.Stereo.prototype.constructor = R3.D3.API.Effect.Stereo; \ No newline at end of file diff --git a/src/r3-d3-api-face.js b/src/r3-d3-api-face.js new file mode 100644 index 0000000..1c7deed --- /dev/null +++ b/src/r3-d3-api-face.js @@ -0,0 +1,243 @@ +/** + * Face + * @param id + * @param name + * @param v0index + * @param v1index + * @param v2index + * @param materialIndex + * @param uvs [[v0uv (R3.Vector2), v1uv(R3.Vector2), v2uv(R3.Vector2)]] + * @param color + * @param vertexColors + * @param vertexNormals + * @param normal + * @param selected + * @param parentGeometry + * @param parentEntity + * @constructor + */ +R3.D3.API.Face = function( + id, + name, + v0index, + v1index, + v2index, + materialIndex, + uvs, + color, + vertexColors, + vertexNormals, + normal, + selected, + parentGeometry, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Face ' + id; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(v0index)) { + v0index = -1; + } + this.v0index = v0index; + + if (R3.Utils.UndefinedOrNull(v1index)) { + v1index = -1; + } + this.v1index = v1index; + + if (R3.Utils.UndefinedOrNull(v2index)) { + v2index = -1; + } + this.v2index = v2index; + + if (R3.Utils.UndefinedOrNull(materialIndex)) { + materialIndex = -1; + } + this.materialIndex = materialIndex; + + if (R3.Utils.UndefinedOrNull(uvs)) { + uvs = [[]]; + } + this.uvs = uvs; + + if (R3.Utils.UndefinedOrNull(color)) { + color = new R3.API.Color(); + } + this.color = color; + + if (R3.Utils.UndefinedOrNull(vertexColors)) { + vertexColors = [ + new R3.API.Color(), + new R3.API.Color(), + new R3.API.Color() + ]; + } + this.vertexColors = vertexColors; + + if (R3.Utils.UndefinedOrNull(vertexNormals)) { + vertexNormals = []; + } + this.vertexNormals = vertexNormals; + + if (R3.Utils.UndefinedOrNull(normal)) { + normal = null; + } + this.normal = normal; + + if (R3.Utils.UndefinedOrNull(selected)) { + selected = false; + } + this.selected = selected; + + if (R3.Utils.UndefinedOrNull(parentGeometry)) { + parentGeometry = null; + } + this.parentGeometry = parentGeometry; + + R3.API.Component.call( + this, + R3.Component.FACE, + parentEntity + ); +}; + +/** + * We don't inherit from component - it makes the entitymanager too heavy - all faces end up in the register etc.. + */ + +R3.D3.API.Face.prototype = Object.create(R3.API.Component.prototype); +R3.D3.API.Face.prototype.constructor = R3.D3.API.Face; + +/** + * Returns an API Face from a data object + * @constructor + * @param objectFace + */ +// R3.D3.API.Face.FromObject = function(objectFace) { +// +// var apiUvs = objectFace.uvs.reduce( +// +// function(result, uvArray, index) { +// +// result[index] = uvArray.reduce( +// function(uvResult, uv) { +// uvResult.push(R3.API.Vector2.FromObject(uv)); +// return uvResult; +// }, +// [] +// ); +// +// return result; +// }, +// [] +// ); +// +// var apiVertexColors = objectFace.vertexColors.map( +// function(vertexColor) { +// return R3.API.Color.FromObject(vertexColor); +// } +// ); +// +// var apiColor = null; +// if (objectFace.color) { +// apiColor = R3.API.Color.FromObject(objectFace.color); +// } +// +// var apiVertexNormals = objectFace.vertexNormals.map( +// function(vertexNormal) { +// return R3.API.Vector3.FromObject(vertexNormal); +// } +// ); +// +// var apiNormal = null; +// if (objectFace.normal) { +// apiNormal = R3.API.Vector3.FromObject(objectFace.normal); +// } +// +// return new R3.D3.API.Face( +// objectFace.id, +// objectFace.name, +// objectFace.v0index, +// objectFace.v1index, +// objectFace.v2index, +// objectFace.materialIndex, +// apiUvs, +// apiColor, +// apiVertexColors, +// apiVertexNormals, +// apiNormal +// ); +// }; +// +/** + * Clone a Face + * @returns {R3.D3.API.Face} + */ +R3.D3.API.Face.prototype.clone = function(){ + return new R3.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} + */ +R3.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) + ) + ); +}; diff --git a/src/r3-d3-api-fog.js b/src/r3-d3-api-fog.js new file mode 100644 index 0000000..34e0df4 --- /dev/null +++ b/src/r3-d3-api-fog.js @@ -0,0 +1,67 @@ +/** + * 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 + */ +R3.D3.API.Fog = function( + id, + name, + exponential, + color, + near, + far, + density, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Fog (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(exponential)) { + exponential = false; + } + this.exponential = exponential; + + if (R3.Utils.UndefinedOrNull(color)) { + color = new R3.API.Color(1, 1, 1, 1) + } + this.color = color; + + if (R3.Utils.UndefinedOrNull(near)) { + near = 1; + } + this.near = near; + + if (R3.Utils.UndefinedOrNull(far)) { + far = 1000; + } + this.far = far; + + if (R3.Utils.UndefinedOrNull(density)) { + density = 0.00025; + } + this.density = density; + + R3.API.Component.call( + this, + R3.Component.FOG, + parentEntity + ); +}; + +R3.D3.API.Fog.prototype = Object.create(R3.API.Component.prototype); +R3.D3.API.Fog.prototype.constructor = R3.D3.API.Fog; diff --git a/src/r3-d3-api-font.js b/src/r3-d3-api-font.js new file mode 100644 index 0000000..aeca15c --- /dev/null +++ b/src/r3-d3-api-font.js @@ -0,0 +1,52 @@ +/** + * Raw Font API object - should always correspond with the Font Schema + * @param id + * @param name + * @param url + * @param parentEntity + * @constructor + */ +R3.D3.API.Font = function( + id, + name, + url, + parentEntity +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Font (' + id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(url)) { + url = '/apiRelative/path/to/font'; + } + this.url = url; + + R3.API.Component.call( + this, + R3.Component.FONT, + parentEntity + ); +}; + +R3.D3.API.Font.prototype = Object.create(R3.API.Component.prototype); +R3.D3.API.Font.prototype.constructor = R3.D3.API.Font; + +/** + * Returns an API light from an Object light + * @param objectFont + * @constructor + */ +R3.D3.API.Font.FromObject = function(objectFont) { + return new R3.D3.API.Font( + objectFont.id, + objectFont.name, + objectFont.url, + objectFont.parentEntity + ); +}; diff --git a/src/r3-d3-api-friction-contact-material.js b/src/r3-d3-api-friction-contact-material.js new file mode 100644 index 0000000..6259c77 --- /dev/null +++ b/src/r3-d3-api-friction-contact-material.js @@ -0,0 +1,102 @@ +/** + * Raw FrictionContactMaterial API object - should always correspond with the FrictionContactMaterial Schema + * @param id + * @param name + * @param materials + * @param friction + * @param restitution + * @param contactEquationStiffness + * @param contactEquationRelaxation + * @param frictionEquationStiffness + * @param frictionEquationRelaxation + * @param parentEntity + * @constructor + */ +R3.D3.API.FrictionContactMaterial = function( + id, + name, + materials, + friction, + restitution, + contactEquationStiffness, + contactEquationRelaxation, + frictionEquationStiffness, + frictionEquationRelaxation, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Friction Material (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(materials)) { + materials = []; + } + this.materials = materials; + + if (R3.Utils.UndefinedOrNull(friction)) { + friction = 0.3; + } + this.friction = friction; + + if (R3.Utils.UndefinedOrNull(restitution)) { + restitution = 0.3; + } + this.restitution = restitution; + + if (R3.Utils.UndefinedOrNull(contactEquationStiffness)) { + contactEquationStiffness = 1e7; + } + this.contactEquationStiffness = contactEquationStiffness; + + if (R3.Utils.UndefinedOrNull(contactEquationRelaxation)) { + contactEquationRelaxation = 3; + } + this.contactEquationRelaxation = contactEquationRelaxation; + + if (R3.Utils.UndefinedOrNull(frictionEquationStiffness)) { + frictionEquationStiffness = 1e7; + } + this.frictionEquationStiffness = frictionEquationStiffness; + + if (R3.Utils.UndefinedOrNull(frictionEquationRelaxation)) { + frictionEquationRelaxation = 3; + } + this.frictionEquationRelaxation = frictionEquationRelaxation; + + R3.API.Component.call( + this, + R3.Component.FRICTION_CONTACT_MATERIAL, + parentEntity + ); +}; + +R3.D3.API.FrictionContactMaterial.prototype = Object.create(R3.API.Component.prototype); +R3.D3.API.FrictionContactMaterial.prototype.constructor = R3.D3.API.FrictionContactMaterial; + +/** + * Creates an API FrictionContactMaterial from an Object FrictionContactMaterial + * @param objectFrictionContactMaterial + * @constructor + */ +R3.D3.API.FrictionContactMaterial.FromObject = function(objectFrictionContactMaterial) { + return new R3.D3.API.FrictionContactMaterial( + objectFrictionContactMaterial.id, + objectFrictionContactMaterial.name, + objectFrictionContactMaterial.materials, + objectFrictionContactMaterial.friction, + objectFrictionContactMaterial.restitution, + objectFrictionContactMaterial.contactEquationStiffness, + objectFrictionContactMaterial.contactEquationRelaxation, + objectFrictionContactMaterial.frictionEquationStiffness, + objectFrictionContactMaterial.frictionEquationRelaxation, + objectFrictionContactMaterial.parentEntity + ); +}; + diff --git a/src/r3-d3-api-friction-material.js b/src/r3-d3-api-friction-material.js new file mode 100644 index 0000000..17f6193 --- /dev/null +++ b/src/r3-d3-api-friction-material.js @@ -0,0 +1,62 @@ +/** + * Raw FrictionMaterial API object - should always correspond with the FrictionMaterial Schema + * @param id + * @param name + * @param friction + * @param restitution + * @param parentEntity + * @constructor + */ +R3.D3.API.FrictionMaterial = function( + id, + name, + friction, + restitution, + parentEntity +) { + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Friction Material (' + this.id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(friction)) { + friction = -1; + } + this.friction = friction; + + if (R3.Utils.UndefinedOrNull(restitution)) { + restitution = -1; + } + this.restitution = restitution; + + R3.API.Component.call( + this, + R3.Component.FRICTION_MATERIAL, + parentEntity + ); +}; + +R3.D3.API.FrictionMaterial.prototype = Object.create(R3.API.Component.prototype); +R3.D3.API.FrictionMaterial.prototype.constructor = R3.D3.API.FrictionMaterial; + +/** + * Creates an API FrictionMaterial from an Object FrictionMaterial + * @param objectFrictionMaterial + * @constructor + */ +R3.D3.API.FrictionMaterial.FromObject = function(objectFrictionMaterial) { + return new R3.D3.API.FrictionMaterial( + objectFrictionMaterial.id, + objectFrictionMaterial.name, + objectFrictionMaterial.friction, + objectFrictionMaterial.restitution, + objectFrictionMaterial.parentEntity + ); +}; + diff --git a/src/r3-d3-api-geometry-a.js b/src/r3-d3-api-geometry-a.js new file mode 100644 index 0000000..8f31a6e --- /dev/null +++ b/src/r3-d3-api-geometry-a.js @@ -0,0 +1,413 @@ +/** + * R3.D3.API.Geometry + * @param id + * @param name + * @param geometryType + * @param parentEntity + * @param parentMesh + * @param boundingBox + * @param boundingSphere + * @param faces + * @param vertices + * @constructor + */ +R3.D3.API.Geometry = function( + id, + name, + geometryType, + parentEntity, + parentMesh, + boundingBox, + boundingSphere, + faces, + vertices +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(geometryType)) { + geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_NONE; + } + this.geometryType = geometryType; + + if (R3.Utils.UndefinedOrNull(name)) { + + switch (this.geometryType) { + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL : + name = 'Geometry'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_BOX : + name = 'Geometry Normal Box'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_CIRCLE : + name = 'Geometry Normal Circle'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_CONE : + name = 'Geometry Normal Cone'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_CYLINDER : + name = 'Geometry Normal Cylinder'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_DODECAHEDRON : + name = 'Geometry Normal Dodecahedron'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_EDGES : + name = 'Geometry Normal Edges'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_EXTRUDE : + name = 'Geometry Normal Extrude'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_ICOSAHEDRON : + name = 'Geometry Normal Icosahedron'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_LATHE : + name = 'Geometry Normal Lathe'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_OCTAHEDRON : + name = 'Geometry Normal Octahedron'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_PARAMETRIC : + name = 'Geometry Normal Parametric'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_PLANE : + name = 'Geometry Normal Plane'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_POLYHEDRON : + name = 'Geometry Normal Polyhedron'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_RING : + name = 'Geometry Normal Ring'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_SHAPE : + name = 'Geometry Normal Shape'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_SPHERE : + name = 'Geometry Normal Sphere'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TETRAHEDRON : + name = 'Geometry Normal Tetrahedron'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TEXT : + name = 'Geometry Normal Text'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TORUS : + name = 'Geometry Normal Torus'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TORUS_KNOT : + name = 'Geometry Normal Torus Knot'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TUBE : + name = 'Geometry Normal Tube'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_WIREFRAME : + name = 'Geometry Normal Wireframe'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER : + name = 'Geometry Buffer'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_BOX : + name = 'Geometry Buffer Box'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CIRCLE : + name = 'Geometry Buffer Circle'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CONE : + name = 'Geometry Buffer Cone'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CYLINDER : + name = 'Geometry Buffer Cylinder'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_DODECAHEDRON : + name = 'Geometry Buffer Dodecahedron'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_EXTRUDE : + name = 'Geometry Buffer Extrude'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_ICOSAHEDRON : + name = 'Geometry Buffer Icosahedron'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_LATHE : + name = 'Geometry Buffer Lathe'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_OCTAHEDRON : + name = 'Geometry Buffer Octahedron'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_PARAMETRIC : + name = 'Geometry Buffer Parametric'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_PLANE : + name = 'Geometry Buffer Plane'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_POLYHEDRON : + name = 'Geometry Buffer Polyhedron'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_RING : + name = 'Geometry Buffer Ring'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_SHAPE : + name = 'Geometry Buffer Shape'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_SPHERE : + name = 'Geometry Buffer Sphere'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TETRAHEDRON : + name = 'Geometry Buffer Tetrahedron'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TEXT : + name = 'Geometry Buffer Text'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TORUS : + name = 'Geometry Buffer Torus'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TORUS_KNOT : + name = 'Geometry Buffer Torus Knot'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TUBE : + name = 'Geometry Buffer Tube'; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_INSTANCED : + name = 'Geometry Buffer Instanced'; + break; + default : + console.warn('no nice name for geometry'); + name = 'Geometry'; + } + + name += ' (' + id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(parentMesh)) { + parentMesh = null; + } + this.parentMesh = parentMesh; + + if (R3.Utils.UndefinedOrNull(boundingBox)) { + boundingBox = new R3.API.Box3(); + } + this.boundingBox = boundingBox; + + if (R3.Utils.UndefinedOrNull(boundingSphere)) { + boundingSphere = new R3.API.Sphere(); + } + this.boundingSphere = boundingSphere; + + if (R3.Utils.UndefinedOrNull(faces)) { + faces = []; + } + this.faces = faces; + + if (R3.Utils.UndefinedOrNull(vertices)) { + vertices = []; + } + this.vertices = vertices; + + R3.API.Component.call( + this, + R3.D3.API.Geometry.GetComponentType(this.geometryType), + parentEntity + ); +}; + +R3.D3.API.Geometry.prototype = Object.create(R3.API.Component.prototype); +R3.D3.API.Geometry.prototype.constructor = R3.D3.API.Geometry; + +R3.D3.API.Geometry.GetComponentType = function(geometryType) { + + var componentType = null; + + switch (geometryType) { + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL : + componentType = R3.Component.GEOMETRY_NORMAL; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_BOX : + componentType = R3.Component.GEOMETRY_NORMAL_BOX; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_CIRCLE : + componentType = R3.Component.GEOMETRY_NORMAL_CIRCLE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_CONE : + componentType = R3.Component.GEOMETRY_NORMAL_CONE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_CYLINDER : + componentType = R3.Component.GEOMETRY_NORMAL_CYLINDER; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_DODECAHEDRON : + componentType = R3.Component.GEOMETRY_NORMAL_DODECAHEDRON; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_EDGES : + componentType = R3.Component.GEOMETRY_NORMAL_EDGES; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_EXTRUDE : + componentType = R3.Component.GEOMETRY_NORMAL_EXTRUDE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_ICOSAHEDRON : + componentType = R3.Component.GEOMETRY_NORMAL_ICOSAHEDRON; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_LATHE : + componentType = R3.Component.GEOMETRY_NORMAL_LATHE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_OCTAHEDRON : + componentType = R3.Component.GEOMETRY_NORMAL_OCTAHEDRON; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_PARAMETRIC : + componentType = R3.Component.GEOMETRY_NORMAL_PARAMETRIC; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_PLANE : + componentType = R3.Component.GEOMETRY_NORMAL_PLANE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_POLYHEDRON : + componentType = R3.Component.GEOMETRY_NORMAL_POLYHEDRON; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_RING : + componentType = R3.Component.GEOMETRY_NORMAL_RING; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_SHAPE : + componentType = R3.Component.GEOMETRY_NORMAL_SHAPE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_SPHERE : + componentType = R3.Component.GEOMETRY_NORMAL_SPHERE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TETRAHEDRON : + componentType = R3.Component.GEOMETRY_NORMAL_TETRAHEDRON; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TEXT : + componentType = R3.Component.GEOMETRY_NORMAL_TEXT; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TORUS : + componentType = R3.Component.GEOMETRY_NORMAL_TORUS; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TORUS_KNOT : + componentType = R3.Component.GEOMETRY_NORMAL_TORUS_KNOT; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TUBE : + componentType = R3.Component.GEOMETRY_NORMAL_TUBE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_WIREFRAME : + componentType = R3.Component.GEOMETRY_NORMAL_WIREFRAME; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER : + componentType = R3.Component.GEOMETRY_BUFFER; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_BOX : + componentType = R3.Component.GEOMETRY_BUFFER_BOX; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CIRCLE : + componentType = R3.Component.GEOMETRY_BUFFER_CIRCLE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CONE : + componentType = R3.Component.GEOMETRY_BUFFER_CONE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CYLINDER : + componentType = R3.Component.GEOMETRY_BUFFER_CYLINDER; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_DODECAHEDRON : + componentType = R3.Component.GEOMETRY_BUFFER_DODECAHEDRON; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_EXTRUDE : + componentType = R3.Component.GEOMETRY_BUFFER_EXTRUDE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_ICOSAHEDRON : + componentType = R3.Component.GEOMETRY_BUFFER_ICOSAHEDRON; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_LATHE : + componentType = R3.Component.GEOMETRY_BUFFER_LATHE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_OCTAHEDRON : + componentType = R3.Component.GEOMETRY_BUFFER_OCTAHEDRON; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_PARAMETRIC: + componentType = R3.Component.GEOMETRY_BUFFER_PARAMETRIC; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_PLANE : + componentType = R3.Component.GEOMETRY_BUFFER_PLANE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_POLYHEDRON : + componentType = R3.Component.GEOMETRY_BUFFER_POLYHEDRON; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_RING: + componentType = R3.Component.GEOMETRY_BUFFER_RING; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_SHAPE : + componentType = R3.Component.GEOMETRY_BUFFER_SHAPE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_SPHERE : + componentType = R3.Component.GEOMETRY_BUFFER_SPHERE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TETRAHEDRON : + componentType = R3.Component.GEOMETRY_BUFFER_TETRAHEDRON; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TEXT : + componentType = R3.Component.GEOMETRY_BUFFER_TEXT; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TORUS : + componentType = R3.Component.GEOMETRY_BUFFER_TORUS; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TORUS_KNOT : + componentType = R3.Component.GEOMETRY_BUFFER_TORUS_KNOT; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TUBE : + componentType = R3.Component.GEOMETRY_BUFFER_TUBE; + break; + case R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_INSTANCED : + componentType = R3.Component.GEOMETRY_BUFFER_INSTANCED; + break; + default: + throw new Error('unhandled geometry type: ' + geometryType); + } + + return componentType; +}; + +/** + * Geometry Type + * @type {number} + */ +R3.D3.API.Geometry.GEOMETRY_TYPE_NONE = 0x0; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL = 0x1; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_BOX = 0x2; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_CIRCLE = 0x3; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_CONE = 0x4; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_CYLINDER = 0x5; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_DODECAHEDRON = 0x6; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_EDGES = 0x7; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_EXTRUDE = 0x8; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_ICOSAHEDRON = 0x9; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_LATHE = 0xa; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_OCTAHEDRON = 0xb; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_PARAMETRIC = 0xc; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_PLANE = 0xd; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_POLYHEDRON = 0xe; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_RING = 0xf; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_SHAPE = 0x10; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_SPHERE = 0x11; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TETRAHEDRON = 0x12; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TEXT = 0x13; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TORUS = 0x14; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TORUS_KNOT = 0x15; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TUBE = 0x16; +R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_WIREFRAME = 0x17; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER = 0x18; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_BOX = 0x19; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CIRCLE = 0x1a; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CONE = 0x1b; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CYLINDER = 0x1c; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_DODECAHEDRON = 0x1d; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_EXTRUDE = 0x1e; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_ICOSAHEDRON = 0x1f; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_LATHE = 0x20; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_OCTAHEDRON = 0x21; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_PARAMETRIC = 0x22; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_PLANE = 0x23; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_POLYHEDRON = 0x24; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_RING = 0x25; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_SHAPE = 0x26; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_SPHERE = 0x27; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TETRAHEDRON = 0x28; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TEXT = 0x29; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TORUS = 0x2a; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TORUS_KNOT = 0x2b; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TUBE = 0x2c; +R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_INSTANCED = 0x2d; diff --git a/src/r3-d3-api-geometry-buffer-a.js b/src/r3-d3-api-geometry-buffer-a.js new file mode 100644 index 0000000..7d03872 --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-a.js @@ -0,0 +1,69 @@ +/** + * R3.D3.API.Geometry.Buffer + * @param apiGeometry + * @param attributes + * @param drawRange + * @param groups + * @param index + * @param morphAttributes + * @constructor + */ +R3.D3.API.Geometry.Buffer = function( + apiGeometry, + attributes, + drawRange, + groups, + index, + morphAttributes +) { + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER; + } + + if (R3.Utils.UndefinedOrNull(attributes)) { + attributes = []; + } + this.attributes = attributes; + + if (R3.Utils.UndefinedOrNull(groups)) { + groups = []; + } + this.groups = groups; + + if (R3.Utils.UndefinedOrNull(drawRange)) { + drawRange = new R3.API.DrawRange() + } + this.drawRange = drawRange; + + if (R3.Utils.UndefinedOrNull(index)) { + index = null; + } + this.index = index; + + if (R3.Utils.UndefinedOrNull(morphAttributes)) { + morphAttributes = null; + } + this.morphAttributes = morphAttributes; + + R3.D3.API.Geometry.call( + this, + apiGeometry.id, + apiGeometry.name, + apiGeometry.geometryType, + apiGeometry.parentEntity, + apiGeometry.parentMesh, + apiGeometry.boundingBox, + apiGeometry.boundingSphere, + apiGeometry.faces, + apiGeometry.vertices + ); +}; + +R3.D3.API.Geometry.Buffer.prototype = Object.create(R3.D3.API.Geometry.prototype); +R3.D3.API.Geometry.Buffer.prototype.constructor = R3.D3.API.Geometry.Buffer; diff --git a/src/r3-d3-api-geometry-buffer-box.js b/src/r3-d3-api-geometry-buffer-box.js new file mode 100644 index 0000000..a61e41c --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-box.js @@ -0,0 +1,74 @@ +/** + * R3.D3.API.Geometry.Buffer.Box + * @param apiGeometry + * @param width + * @param height + * @param depth + * @param widthSegments + * @param heightSegments + * @param depthSegments + * @constructor + */ +R3.D3.API.Geometry.Buffer.Box = function( + apiGeometry, + width, + height, + depth, + widthSegments, + heightSegments, + depthSegments +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_BOX + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_BOX; + } + + if (R3.Utils.UndefinedOrNull(width)) { + width = 1; + } + this.width = width; + + if (R3.Utils.UndefinedOrNull(height)) { + height = 1; + } + this.height = height; + + if (R3.Utils.UndefinedOrNull(depth)) { + depth = 1; + } + this.depth = depth; + + if (R3.Utils.UndefinedOrNull(widthSegments)) { + widthSegments = 1; + } + this.widthSegments = widthSegments; + + if (R3.Utils.UndefinedOrNull(heightSegments)) { + heightSegments = 1; + } + this.heightSegments = heightSegments; + + if (R3.Utils.UndefinedOrNull(depthSegments)) { + depthSegments = 1; + } + this.depthSegments = depthSegments; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Box.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Box.prototype.constructor = R3.D3.API.Geometry.Buffer.Box; diff --git a/src/r3-d3-api-geometry-buffer-circle.js b/src/r3-d3-api-geometry-buffer-circle.js new file mode 100644 index 0000000..f831fb6 --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-circle.js @@ -0,0 +1,60 @@ +/** + * R3.D3.API.Geometry.Buffer.Circle + * @param apiGeometry + * @param radius + * @param segments + * @param thetaStart + * @param thetaLength + * @constructor + */ +R3.D3.API.Geometry.Buffer.Circle = function( + apiGeometry, + radius, + segments, + thetaStart, + thetaLength +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CIRCLE + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CIRCLE; + } + + if (R3.Utils.UndefinedOrNull(radius)) { + radius = 1; + } + this.radius = radius; + + if (R3.Utils.UndefinedOrNull(segments)) { + segments = 8; + } + this.segments = segments; + + if (R3.Utils.UndefinedOrNull(thetaStart)) { + thetaStart = 0; + } + this.thetaStart = thetaStart; + + if (R3.Utils.UndefinedOrNull(thetaLength)) { + thetaLength = Math.PI * 2; + } + this.thetaLength = thetaLength; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Circle.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Circle.prototype.constructor = R3.D3.API.Geometry.Buffer.Circle; diff --git a/src/r3-d3-api-geometry-buffer-cone.js b/src/r3-d3-api-geometry-buffer-cone.js new file mode 100644 index 0000000..89bc745 --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-cone.js @@ -0,0 +1,81 @@ +/** + * R3.D3.API.Geometry.Buffer.Cone + * @param apiGeometry + * @param radius + * @param height + * @param radialSegments + * @param heightSegments + * @param openEnded + * @param thetaStart + * @param thetaLength + * @constructor + */ +R3.D3.API.Geometry.Buffer.Cone = function( + apiGeometry, + radius, + height, + radialSegments, + heightSegments, + openEnded, + thetaStart, + thetaLength +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CONE + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CONE; + } + + if (R3.Utils.UndefinedOrNull(radius)) { + radius = 1; + } + this.radius = radius; + + if (R3.Utils.UndefinedOrNull(height)) { + height = 100; + } + this.height = height; + + if (R3.Utils.UndefinedOrNull(radialSegments)) { + radialSegments = 8; + } + this.radialSegments = radialSegments; + + if (R3.Utils.UndefinedOrNull(heightSegments)) { + heightSegments = 1; + } + this.heightSegments = heightSegments; + + if (R3.Utils.UndefinedOrNull(openEnded)) { + openEnded = false; + } + this.openEnded = openEnded; + + if (R3.Utils.UndefinedOrNull(thetaStart)) { + thetaStart = 0; + } + this.thetaStart = thetaStart; + + if (R3.Utils.UndefinedOrNull(thetaLength)) { + thetaLength = Math.PI * 2; + } + this.thetaLength = thetaLength; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Cone.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Cone.prototype.constructor = R3.D3.API.Geometry.Buffer.Cone; diff --git a/src/r3-d3-api-geometry-buffer-cylinder.js b/src/r3-d3-api-geometry-buffer-cylinder.js new file mode 100644 index 0000000..565c757 --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-cylinder.js @@ -0,0 +1,88 @@ +/** + * R3.D3.API.Geometry.Buffer.Cylinder + * @param apiGeometry + * @param radiusTop + * @param radiusBottom + * @param height + * @param radialSegments + * @param heightSegments + * @param openEnded + * @param thetaStart + * @param thetaLength + * @constructor + */ +R3.D3.API.Geometry.Buffer.Cylinder = function( + apiGeometry, + radiusTop, + radiusBottom, + height, + radialSegments, + heightSegments, + openEnded, + thetaStart, + thetaLength +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CYLINDER + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CYLINDER; + } + + if (R3.Utils.UndefinedOrNull(radiusTop)) { + radiusTop = 1; + } + this.radiusTop = radiusTop; + + if (R3.Utils.UndefinedOrNull(radiusBottom)) { + radiusBottom = 1; + } + this.radiusBottom = radiusBottom; + + if (R3.Utils.UndefinedOrNull(height)) { + height = 100; + } + this.height = height; + + if (R3.Utils.UndefinedOrNull(radialSegments)) { + radialSegments = 8; + } + this.radialSegments = radialSegments; + + if (R3.Utils.UndefinedOrNull(heightSegments)) { + heightSegments = 1; + } + this.heightSegments = heightSegments; + + if (R3.Utils.UndefinedOrNull(openEnded)) { + openEnded = false; + } + this.openEnded = openEnded; + + if (R3.Utils.UndefinedOrNull(thetaStart)) { + thetaStart = 0; + } + this.thetaStart = thetaStart; + + if (R3.Utils.UndefinedOrNull(thetaLength)) { + thetaLength = Math.PI * 2; + } + this.thetaLength = thetaLength; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Cylinder.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Cylinder.prototype.constructor = R3.D3.API.Geometry.Buffer.Cylinder; diff --git a/src/r3-d3-api-geometry-buffer-dodecahedron.js b/src/r3-d3-api-geometry-buffer-dodecahedron.js new file mode 100644 index 0000000..fd63e60 --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-dodecahedron.js @@ -0,0 +1,46 @@ +/** + * R3.D3.API.Geometry.Buffer.Dodecahedron + * @param apiGeometry + * @param radius + * @param detail + * @constructor + */ +R3.D3.API.Geometry.Buffer.Dodecahedron = function( + apiGeometry, + radius, + detail +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_DODECAHEDRON + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_DODECAHEDRON; + } + + if (R3.Utils.UndefinedOrNull(radius)) { + radius = 1; + } + this.radius = radius; + + if (R3.Utils.UndefinedOrNull(detail)) { + detail = 0; + } + this.detail = detail; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Dodecahedron.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Dodecahedron.prototype.constructor = R3.D3.API.Geometry.Buffer.Dodecahedron; diff --git a/src/r3-d3-api-geometry-buffer-extrude.js b/src/r3-d3-api-geometry-buffer-extrude.js new file mode 100644 index 0000000..078e189 --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-extrude.js @@ -0,0 +1,104 @@ +/** + * R3.D3.API.Geometry.Buffer.Extrude + * @param apiGeometry + * @param shapes + * @param curveSegments + * @param steps + * @param amount + * @param bevelEnabled + * @param bevelThickness + * @param bevelSize + * @param bevelSegments + * @param extrudePath + * @param frames + * @param UVGenerator + * @constructor + */ +R3.D3.API.Geometry.Buffer.Extrude = function( + apiGeometry, + shapes, + curveSegments, + steps, + amount, + bevelEnabled, + bevelThickness, + bevelSize, + bevelSegments, + extrudePath, + frames, + UVGenerator +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_EXTRUDE + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_EXTRUDE; + } + + if (R3.Utils.UndefinedOrNull(shapes)) { + shapes = []; + } + this.shapes = shapes; + + if (R3.Utils.UndefinedOrNull(curveSegments)) { + curveSegments = 12; + } + this.curveSegments = curveSegments; + + if (R3.Utils.UndefinedOrNull(steps)) { + steps = 1; + } + this.steps = steps; + + if (R3.Utils.UndefinedOrNull(amount)) { + amount = 100; + } + this.amount = amount; + + if (R3.Utils.UndefinedOrNull(bevelEnabled)) { + bevelEnabled = true; + } + this.bevelEnabled = bevelEnabled; + + if (R3.Utils.UndefinedOrNull(bevelThickness)) { + bevelThickness = 6; + } + this.bevelThickness = bevelThickness; + + if (R3.Utils.UndefinedOrNull(bevelSegments)) { + bevelSegments = 3; + } + this.bevelSegments = bevelSegments; + + if (R3.Utils.UndefinedOrNull(extrudePath)) { + extrudePath = null; + } + this.extrudePath = extrudePath; + + if (R3.Utils.UndefinedOrNull(frames)) { + frames = null; + } + this.frames = frames; + + if (R3.Utils.UndefinedOrNull(UVGenerator)) { + UVGenerator = null; + } + this.UVGenerator = UVGenerator; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Extrude.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Extrude.prototype.constructor = R3.D3.API.Geometry.Buffer.Extrude; diff --git a/src/r3-d3-api-geometry-buffer-icosahedron.js b/src/r3-d3-api-geometry-buffer-icosahedron.js new file mode 100644 index 0000000..60e2d70 --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-icosahedron.js @@ -0,0 +1,46 @@ +/** + * R3.D3.API.Geometry.Buffer.Icosahedron + * @param apiGeometry + * @param radius + * @param detail + * @constructor + */ +R3.D3.API.Geometry.Buffer.Icosahedron = function( + apiGeometry, + radius, + detail +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_ICOSAHEDRON + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_ICOSAHEDRON; + } + + if (R3.Utils.UndefinedOrNull(radius)) { + radius = 1; + } + this.radius = radius; + + if (R3.Utils.UndefinedOrNull(detail)) { + detail = 0; + } + this.detail = detail; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Icosahedron.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Icosahedron.prototype.constructor = R3.D3.API.Geometry.Buffer.Icosahedron; diff --git a/src/r3-d3-api-geometry-buffer-instanced.js b/src/r3-d3-api-geometry-buffer-instanced.js new file mode 100644 index 0000000..420397f --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-instanced.js @@ -0,0 +1,39 @@ +/** + * R3.D3.API.Geometry.Buffer.Instanced + * @param apiGeometry + * @param maxInstancedCount + * @constructor + */ +R3.D3.API.Geometry.Buffer.Instanced = function( + apiGeometry, + maxInstancedCount +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_INSTANCED + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_INSTANCED; + } + + if (R3.Utils.UndefinedOrNull(maxInstancedCount)) { + maxInstancedCount = null; + } + this.maxInstancedCount = maxInstancedCount; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Instanced.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Instanced.prototype.constructor = R3.D3.API.Geometry.Buffer.Instanced; diff --git a/src/r3-d3-api-geometry-buffer-lathe.js b/src/r3-d3-api-geometry-buffer-lathe.js new file mode 100644 index 0000000..2c541d4 --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-lathe.js @@ -0,0 +1,60 @@ +/** + * R3.D3.API.Geometry.Buffer.Lathe + * @param apiGeometry + * @param points [R3.Vector2] (x must be larger than 0) + * @param segments + * @param phiStart + * @param phiLength + * @constructor + */ +R3.D3.API.Geometry.Buffer.Lathe = function( + apiGeometry, + points, + segments, + phiStart, + phiLength +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_LATHE + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_LATHE; + } + + if (R3.Utils.UndefinedOrNull(points)) { + points = []; + } + this.points = points; + + if (R3.Utils.UndefinedOrNull(segments)) { + segments = 12; + } + this.segments = segments; + + if (R3.Utils.UndefinedOrNull(phiStart)) { + phiStart = 0; + } + this.phiStart = phiStart; + + if (R3.Utils.UndefinedOrNull(phiLength)) { + phiLength = Math.PI * 2; + } + this.phiLength = phiLength; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Lathe.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Lathe.prototype.constructor = R3.D3.API.Geometry.Buffer.Lathe; diff --git a/src/r3-d3-api-geometry-buffer-octahedron.js b/src/r3-d3-api-geometry-buffer-octahedron.js new file mode 100644 index 0000000..191655f --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-octahedron.js @@ -0,0 +1,46 @@ +/** + * R3.D3.API.Geometry.Buffer.Octahedron + * @param apiGeometry + * @param radius + * @param detail + * @constructor + */ +R3.D3.API.Geometry.Buffer.Octahedron = function( + apiGeometry, + radius, + detail +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_OCTAHEDRON + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_OCTAHEDRON; + } + + if (R3.Utils.UndefinedOrNull(radius)) { + radius = 1; + } + this.radius = radius; + + if (R3.Utils.UndefinedOrNull(detail)) { + detail = 0; + } + this.detail = detail; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Octahedron.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Octahedron.prototype.constructor = R3.D3.API.Geometry.Buffer.Octahedron; diff --git a/src/r3-d3-api-geometry-buffer-parametric.js b/src/r3-d3-api-geometry-buffer-parametric.js new file mode 100644 index 0000000..15bf883 --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-parametric.js @@ -0,0 +1,53 @@ +/** + * R3.D3.API.Geometry.Buffer.Parametric + * @param apiGeometry + * @param generatorFn(u,v) => returns Vector3, u and v is values between 0 and 1 + * @param slices + * @param stacks + * @constructor + */ +R3.D3.API.Geometry.Buffer.Parametric = function( + apiGeometry, + generatorFn, + slices, + stacks +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_PARAMETRIC + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_PARAMETRIC; + } + + if (R3.Utils.UndefinedOrNull(generatorFn)) { + generatorFn = ''; + } + this.generatorFn = generatorFn; + + if (R3.Utils.UndefinedOrNull(slices)) { + slices = 20; + } + this.slices = slices; + + if (R3.Utils.UndefinedOrNull(stacks)) { + stacks = 20; + } + this.stacks = stacks; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Parametric.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Parametric.prototype.constructor = R3.D3.API.Geometry.Buffer.Parametric; diff --git a/src/r3-d3-api-geometry-buffer-plane.js b/src/r3-d3-api-geometry-buffer-plane.js new file mode 100644 index 0000000..506cbd2 --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-plane.js @@ -0,0 +1,60 @@ +/** + * R3.D3.API.Geometry.Buffer.Plane + * @param apiGeometry + * @param width + * @param height + * @param widthSegments + * @param heightSegments + * @constructor + */ +R3.D3.API.Geometry.Buffer.Plane = function( + apiGeometry, + width, + height, + widthSegments, + heightSegments +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_PLANE + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_PLANE; + } + + if (R3.Utils.UndefinedOrNull(width)) { + width = 1; + } + this.width = width; + + if (R3.Utils.UndefinedOrNull(height)) { + height = 1; + } + this.height = height; + + if (R3.Utils.UndefinedOrNull(widthSegments)) { + widthSegments = 1; + } + this.widthSegments = widthSegments; + + if (R3.Utils.UndefinedOrNull(heightSegments)) { + heightSegments = 1; + } + this.heightSegments = heightSegments; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Plane.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Plane.prototype.constructor = R3.D3.API.Geometry.Buffer.Plane; diff --git a/src/r3-d3-api-geometry-buffer-polyhedron.js b/src/r3-d3-api-geometry-buffer-polyhedron.js new file mode 100644 index 0000000..ddbcb6c --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-polyhedron.js @@ -0,0 +1,60 @@ +/** + * R3.D3.API.Geometry.Buffer.Polyhedron + * @param apiGeometry + * @param vertices + * @param indices + * @param radius + * @param detail + * @constructor + */ +R3.D3.API.Geometry.Buffer.Polyhedron = function( + apiGeometry, + vertices, + indices, + radius, + detail +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_POLYHEDRON + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_POLYHEDRON; + } + + if (R3.Utils.UndefinedOrNull(vertices)) { + vertices = []; + } + this.vertices = vertices; + + if (R3.Utils.UndefinedOrNull(indices)) { + indices = 1; + } + this.indices = indices; + + if (R3.Utils.UndefinedOrNull(radius)) { + radius = 5; + } + this.radius = radius; + + if (R3.Utils.UndefinedOrNull(detail)) { + detail = 0; + } + this.detail = detail; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Polyhedron.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Polyhedron.prototype.constructor = R3.D3.API.Geometry.Buffer.Polyhedron; diff --git a/src/r3-d3-api-geometry-buffer-ring.js b/src/r3-d3-api-geometry-buffer-ring.js new file mode 100644 index 0000000..88a3805 --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-ring.js @@ -0,0 +1,74 @@ +/** + * R3.D3.API.Geometry.Buffer.Ring + * @param apiGeometry + * @param innerRadius + * @param outerRadius + * @param thetaSegments + * @param phiSegments + * @param thetaStart + * @param thetaLength + * @constructor + */ +R3.D3.API.Geometry.Buffer.Ring = function( + apiGeometry, + innerRadius, + outerRadius, + thetaSegments, + phiSegments, + thetaStart, + thetaLength +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_RING + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_RING; + } + + if (R3.Utils.UndefinedOrNull(innerRadius)) { + innerRadius = 0.5; + } + this.innerRadius = innerRadius; + + if (R3.Utils.UndefinedOrNull(outerRadius)) { + outerRadius = 1; + } + this.outerRadius = outerRadius; + + if (R3.Utils.UndefinedOrNull(thetaSegments)) { + thetaSegments = 8; + } + this.thetaSegments = thetaSegments; + + if (R3.Utils.UndefinedOrNull(phiSegments)) { + phiSegments = 8; + } + this.phiSegments = phiSegments; + + if (R3.Utils.UndefinedOrNull(thetaStart)) { + thetaStart = 0; + } + this.thetaStart = thetaStart; + + if (R3.Utils.UndefinedOrNull(thetaLength)) { + thetaLength = Math.PI * 2; + } + this.thetaLength = thetaLength; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Ring.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Ring.prototype.constructor = R3.D3.API.Geometry.Buffer.Ring; diff --git a/src/r3-d3-api-geometry-buffer-shape.js b/src/r3-d3-api-geometry-buffer-shape.js new file mode 100644 index 0000000..062d309 --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-shape.js @@ -0,0 +1,46 @@ +/** + * R3.D3.API.Geometry.Buffer.Shape + * @param apiGeometry + * @param shapes + * @param curveSegments + * @constructor + */ +R3.D3.API.Geometry.Buffer.Shape = function( + apiGeometry, + shapes, + curveSegments +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_SHAPE + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_SHAPE; + } + + if (R3.Utils.UndefinedOrNull(shapes)) { + shapes = []; + } + this.shapes = shapes; + + if (R3.Utils.UndefinedOrNull(curveSegments)) { + curveSegments = 12; + } + this.curveSegments = curveSegments; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Shape.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Shape.prototype.constructor = R3.D3.API.Geometry.Buffer.Shape; diff --git a/src/r3-d3-api-geometry-buffer-sphere.js b/src/r3-d3-api-geometry-buffer-sphere.js new file mode 100644 index 0000000..f7651de --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-sphere.js @@ -0,0 +1,81 @@ +/** + * R3.D3.API.Geometry.Buffer.Sphere + * @param apiGeometry + * @param radius + * @param widthSegments + * @param heightSegments + * @param phiStart + * @param phiLength + * @param thetaStart + * @param thetaLength + * @constructor + */ +R3.D3.API.Geometry.Buffer.Sphere = function( + apiGeometry, + radius, + widthSegments, + heightSegments, + phiStart, + phiLength, + thetaStart, + thetaLength +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_SPHERE + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_SPHERE; + } + + if (R3.Utils.UndefinedOrNull(radius)) { + radius = 1; + } + this.radius = radius; + + if (R3.Utils.UndefinedOrNull(widthSegments)) { + widthSegments = 8; + } + this.widthSegments = widthSegments; + + if (R3.Utils.UndefinedOrNull(heightSegments)) { + heightSegments = 6; + } + this.heightSegments = heightSegments; + + if (R3.Utils.UndefinedOrNull(phiStart)) { + phiStart = 0; + } + this.phiStart = phiStart; + + if (R3.Utils.UndefinedOrNull(phiLength)) { + phiLength = Math.PI * 2; + } + this.phiLength = phiLength; + + if (R3.Utils.UndefinedOrNull(thetaStart)) { + thetaStart = 0; + } + this.thetaStart = thetaStart; + + if (R3.Utils.UndefinedOrNull(thetaLength)) { + thetaLength = Math.PI; + } + this.thetaLength = thetaLength; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Sphere.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Sphere.prototype.constructor = R3.D3.API.Geometry.Buffer.Sphere; diff --git a/src/r3-d3-api-geometry-buffer-tetrahedron.js b/src/r3-d3-api-geometry-buffer-tetrahedron.js new file mode 100644 index 0000000..734e0f9 --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-tetrahedron.js @@ -0,0 +1,46 @@ +/** + * R3.D3.API.Geometry.Buffer.Tetrahedron + * @param apiGeometry + * @param radius + * @param detail + * @constructor + */ +R3.D3.API.Geometry.Buffer.Tetrahedron = function( + apiGeometry, + radius, + detail +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TETRAHEDRON + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TETRAHEDRON; + } + + if (R3.Utils.UndefinedOrNull(radius)) { + radius = 1; + } + this.radius = radius; + + if (R3.Utils.UndefinedOrNull(detail)) { + detail = 0; + } + this.detail = detail; + + R3.D3.API.Geometry.Buffer.call( + this, + apiGeometry, + apiGeometry.attributes, + apiGeometry.drawRange, + apiGeometry.groups, + apiGeometry.index, + apiGeometry.morphAttributes + ); +}; + +R3.D3.API.Geometry.Buffer.Tetrahedron.prototype = Object.create(R3.D3.API.Geometry.Buffer.prototype); +R3.D3.API.Geometry.Buffer.Tetrahedron.prototype.constructor = R3.D3.API.Geometry.Buffer.Tetrahedron; diff --git a/src/r3-d3-api-geometry-buffer-text.js b/src/r3-d3-api-geometry-buffer-text.js new file mode 100644 index 0000000..2b6d5de --- /dev/null +++ b/src/r3-d3-api-geometry-buffer-text.js @@ -0,0 +1,95 @@ +/** + * R3.D3.API.Geometry.Buffer.Text + * @param apiGeometry + * @param text + * @param font + * @param size + * @param height + * @param curveSegments + * @param bevelEnabled + * @param bevelThickness + * @param bevelSize + * @param bevelSegments + * @constructor + */ +R3.D3.API.Geometry.Buffer.Text = function( + apiGeometry, + text, + font, + size, + height, + curveSegments, + bevelEnabled, + bevelThickness, + bevelSize, + bevelSegments +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TEXT + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TEXT; + } + + if (R3.Utils.UndefinedOrNull(text)) { + text = '-= returns Vector3, u and v is values between 0 and 1 + * @param slices + * @param stacks + * @constructor + */ +R3.D3.API.Geometry.Normal.Parametric = function( + apiGeometry, + generatorFn, + slices, + stacks +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_PARAMETRIC + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_PARAMETRIC; + } + + if (R3.Utils.UndefinedOrNull(generatorFn)) { + generatorFn = ''; + } + this.generatorFn = generatorFn; + + if (R3.Utils.UndefinedOrNull(slices)) { + slices = 20; + } + this.slices = slices; + + if (R3.Utils.UndefinedOrNull(stacks)) { + stacks = 20; + } + this.stacks = stacks; + + R3.D3.API.Geometry.Normal.call( + this, + apiGeometry, + apiGeometry.colors, + apiGeometry.lineDistances, + apiGeometry.morphTargets, + apiGeometry.morphNormals, + apiGeometry.skinWeights, + apiGeometry.skinIndices, + apiGeometry.verticesNeedsUpdate, + apiGeometry.elementsNeedUpdate, + apiGeometry.uvsNeedUpdate, + apiGeometry.normalsNeedUpdate, + apiGeometry.colorsNeedUpdate, + apiGeometry.groupsNeedUpdate, + apiGeometry.lineDistancesNeedUpdate + ); +}; + +R3.D3.API.Geometry.Normal.Parametric.prototype = Object.create(R3.D3.API.Geometry.Normal.prototype); +R3.D3.API.Geometry.Normal.Parametric.prototype.constructor = R3.D3.API.Geometry.Normal.Parametric; diff --git a/src/r3-d3-api-geometry-normal-plane.js b/src/r3-d3-api-geometry-normal-plane.js new file mode 100644 index 0000000..ec54326 --- /dev/null +++ b/src/r3-d3-api-geometry-normal-plane.js @@ -0,0 +1,68 @@ +/** + * R3.D3.API.Geometry.Normal.Plane + * @param apiGeometry + * @param width + * @param height + * @param widthSegments + * @param heightSegments + * @constructor + */ +R3.D3.API.Geometry.Normal.Plane = function( + apiGeometry, + width, + height, + widthSegments, + heightSegments +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_PLANE + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_PLANE; + } + + if (R3.Utils.UndefinedOrNull(width)) { + width = 1; + } + this.width = width; + + if (R3.Utils.UndefinedOrNull(height)) { + height = 1; + } + this.height = height; + + if (R3.Utils.UndefinedOrNull(widthSegments)) { + widthSegments = 1; + } + this.widthSegments = widthSegments; + + if (R3.Utils.UndefinedOrNull(heightSegments)) { + heightSegments = 1; + } + this.heightSegments = heightSegments; + + R3.D3.API.Geometry.Normal.call( + this, + apiGeometry, + apiGeometry.colors, + apiGeometry.lineDistances, + apiGeometry.morphTargets, + apiGeometry.morphNormals, + apiGeometry.skinWeights, + apiGeometry.skinIndices, + apiGeometry.verticesNeedsUpdate, + apiGeometry.elementsNeedUpdate, + apiGeometry.uvsNeedUpdate, + apiGeometry.normalsNeedUpdate, + apiGeometry.colorsNeedUpdate, + apiGeometry.groupsNeedUpdate, + apiGeometry.lineDistancesNeedUpdate + ); +}; + +R3.D3.API.Geometry.Normal.Plane.prototype = Object.create(R3.D3.API.Geometry.Normal.prototype); +R3.D3.API.Geometry.Normal.Plane.prototype.constructor = R3.D3.API.Geometry.Normal.Plane; diff --git a/src/r3-d3-api-geometry-normal-polyhedron.js b/src/r3-d3-api-geometry-normal-polyhedron.js new file mode 100644 index 0000000..652531f --- /dev/null +++ b/src/r3-d3-api-geometry-normal-polyhedron.js @@ -0,0 +1,68 @@ +/** + * R3.D3.API.Geometry.Normal.Polyhedron + * @param apiGeometry + * @param vertices + * @param indices + * @param radius + * @param detail + * @constructor + */ +R3.D3.API.Geometry.Normal.Polyhedron = function( + apiGeometry, + vertices, + indices, + radius, + detail +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_POLYHEDRON + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_POLYHEDRON; + } + + if (R3.Utils.UndefinedOrNull(vertices)) { + vertices = []; + } + this.vertices = vertices; + + if (R3.Utils.UndefinedOrNull(indices)) { + indices = 1; + } + this.indices = indices; + + if (R3.Utils.UndefinedOrNull(radius)) { + radius = 5; + } + this.radius = radius; + + if (R3.Utils.UndefinedOrNull(detail)) { + detail = 0; + } + this.detail = detail; + + R3.D3.API.Geometry.Normal.call( + this, + apiGeometry, + apiGeometry.colors, + apiGeometry.lineDistances, + apiGeometry.morphTargets, + apiGeometry.morphNormals, + apiGeometry.skinWeights, + apiGeometry.skinIndices, + apiGeometry.verticesNeedsUpdate, + apiGeometry.elementsNeedUpdate, + apiGeometry.uvsNeedUpdate, + apiGeometry.normalsNeedUpdate, + apiGeometry.colorsNeedUpdate, + apiGeometry.groupsNeedUpdate, + apiGeometry.lineDistancesNeedUpdate + ); +}; + +R3.D3.API.Geometry.Normal.Polyhedron.prototype = Object.create(R3.D3.API.Geometry.Normal.prototype); +R3.D3.API.Geometry.Normal.Polyhedron.prototype.constructor = R3.D3.API.Geometry.Normal.Polyhedron; diff --git a/src/r3-d3-api-geometry-normal-ring.js b/src/r3-d3-api-geometry-normal-ring.js new file mode 100644 index 0000000..0873d80 --- /dev/null +++ b/src/r3-d3-api-geometry-normal-ring.js @@ -0,0 +1,82 @@ +/** + * R3.D3.API.Geometry.Normal.Ring + * @param apiGeometry + * @param innerRadius + * @param outerRadius + * @param thetaSegments + * @param phiSegments + * @param thetaStart + * @param thetaLength + * @constructor + */ +R3.D3.API.Geometry.Normal.Ring = function( + apiGeometry, + innerRadius, + outerRadius, + thetaSegments, + phiSegments, + thetaStart, + thetaLength +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_RING + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_RING; + } + + if (R3.Utils.UndefinedOrNull(innerRadius)) { + innerRadius = 0.5; + } + this.innerRadius = innerRadius; + + if (R3.Utils.UndefinedOrNull(outerRadius)) { + outerRadius = 1; + } + this.outerRadius = outerRadius; + + if (R3.Utils.UndefinedOrNull(thetaSegments)) { + thetaSegments = 8; + } + this.thetaSegments = thetaSegments; + + if (R3.Utils.UndefinedOrNull(phiSegments)) { + phiSegments = 8; + } + this.phiSegments = phiSegments; + + if (R3.Utils.UndefinedOrNull(thetaStart)) { + thetaStart = 0; + } + this.thetaStart = thetaStart; + + if (R3.Utils.UndefinedOrNull(thetaLength)) { + thetaLength = Math.PI * 2; + } + this.thetaLength = thetaLength; + + R3.D3.API.Geometry.Normal.call( + this, + apiGeometry, + apiGeometry.colors, + apiGeometry.lineDistances, + apiGeometry.morphTargets, + apiGeometry.morphNormals, + apiGeometry.skinWeights, + apiGeometry.skinIndices, + apiGeometry.verticesNeedsUpdate, + apiGeometry.elementsNeedUpdate, + apiGeometry.uvsNeedUpdate, + apiGeometry.normalsNeedUpdate, + apiGeometry.colorsNeedUpdate, + apiGeometry.groupsNeedUpdate, + apiGeometry.lineDistancesNeedUpdate + ); +}; + +R3.D3.API.Geometry.Normal.Ring.prototype = Object.create(R3.D3.API.Geometry.Normal.prototype); +R3.D3.API.Geometry.Normal.Ring.prototype.constructor = R3.D3.API.Geometry.Normal.Ring; diff --git a/src/r3-d3-api-geometry-normal-shape.js b/src/r3-d3-api-geometry-normal-shape.js new file mode 100644 index 0000000..1730c0e --- /dev/null +++ b/src/r3-d3-api-geometry-normal-shape.js @@ -0,0 +1,54 @@ +/** + * R3.D3.API.Geometry.Normal.Shape + * @param apiGeometry + * @param shapes + * @param curveSegments + * @constructor + */ +R3.D3.API.Geometry.Normal.Shape = function( + apiGeometry, + shapes, + curveSegments +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_SHAPE + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_SHAPE; + } + + if (R3.Utils.UndefinedOrNull(shapes)) { + shapes = []; + } + this.shapes = shapes; + + if (R3.Utils.UndefinedOrNull(curveSegments)) { + curveSegments = 12; + } + this.curveSegments = curveSegments; + + R3.D3.API.Geometry.Normal.call( + this, + apiGeometry, + apiGeometry.colors, + apiGeometry.lineDistances, + apiGeometry.morphTargets, + apiGeometry.morphNormals, + apiGeometry.skinWeights, + apiGeometry.skinIndices, + apiGeometry.verticesNeedsUpdate, + apiGeometry.elementsNeedUpdate, + apiGeometry.uvsNeedUpdate, + apiGeometry.normalsNeedUpdate, + apiGeometry.colorsNeedUpdate, + apiGeometry.groupsNeedUpdate, + apiGeometry.lineDistancesNeedUpdate + ); +}; + +R3.D3.API.Geometry.Normal.Shape.prototype = Object.create(R3.D3.API.Geometry.Normal.prototype); +R3.D3.API.Geometry.Normal.Shape.prototype.constructor = R3.D3.API.Geometry.Normal.Shape; diff --git a/src/r3-d3-api-geometry-normal-sphere.js b/src/r3-d3-api-geometry-normal-sphere.js new file mode 100644 index 0000000..2da46a7 --- /dev/null +++ b/src/r3-d3-api-geometry-normal-sphere.js @@ -0,0 +1,89 @@ +/** + * R3.D3.API.Geometry.Normal.Sphere + * @param apiGeometry + * @param radius + * @param widthSegments + * @param heightSegments + * @param phiStart + * @param phiLength + * @param thetaStart + * @param thetaLength + * @constructor + */ +R3.D3.API.Geometry.Normal.Sphere = function( + apiGeometry, + radius, + widthSegments, + heightSegments, + phiStart, + phiLength, + thetaStart, + thetaLength +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_SPHERE + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_SPHERE; + } + + if (R3.Utils.UndefinedOrNull(radius)) { + radius = 1; + } + this.radius = radius; + + if (R3.Utils.UndefinedOrNull(widthSegments)) { + widthSegments = 8; + } + this.widthSegments = widthSegments; + + if (R3.Utils.UndefinedOrNull(heightSegments)) { + heightSegments = 6; + } + this.heightSegments = heightSegments; + + if (R3.Utils.UndefinedOrNull(phiStart)) { + phiStart = 0; + } + this.phiStart = phiStart; + + if (R3.Utils.UndefinedOrNull(phiLength)) { + phiLength = Math.PI * 2; + } + this.phiLength = phiLength; + + if (R3.Utils.UndefinedOrNull(thetaStart)) { + thetaStart = 0; + } + this.thetaStart = thetaStart; + + if (R3.Utils.UndefinedOrNull(thetaLength)) { + thetaLength = Math.PI; + } + this.thetaLength = thetaLength; + + R3.D3.API.Geometry.Normal.call( + this, + apiGeometry, + apiGeometry.colors, + apiGeometry.lineDistances, + apiGeometry.morphTargets, + apiGeometry.morphNormals, + apiGeometry.skinWeights, + apiGeometry.skinIndices, + apiGeometry.verticesNeedsUpdate, + apiGeometry.elementsNeedUpdate, + apiGeometry.uvsNeedUpdate, + apiGeometry.normalsNeedUpdate, + apiGeometry.colorsNeedUpdate, + apiGeometry.groupsNeedUpdate, + apiGeometry.lineDistancesNeedUpdate + ); +}; + +R3.D3.API.Geometry.Normal.Sphere.prototype = Object.create(R3.D3.API.Geometry.Normal.prototype); +R3.D3.API.Geometry.Normal.Sphere.prototype.constructor = R3.D3.API.Geometry.Normal.Sphere; diff --git a/src/r3-d3-api-geometry-normal-tetrahedron.js b/src/r3-d3-api-geometry-normal-tetrahedron.js new file mode 100644 index 0000000..43dade8 --- /dev/null +++ b/src/r3-d3-api-geometry-normal-tetrahedron.js @@ -0,0 +1,54 @@ +/** + * R3.D3.API.Geometry.Normal.Tetrahedron + * @param apiGeometry + * @param radius + * @param detail + * @constructor + */ +R3.D3.API.Geometry.Normal.Tetrahedron = function( + apiGeometry, + radius, + detail +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TETRAHEDRON + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TETRAHEDRON; + } + + if (R3.Utils.UndefinedOrNull(radius)) { + radius = 1; + } + this.radius = radius; + + if (R3.Utils.UndefinedOrNull(detail)) { + detail = 0; + } + this.detail = detail; + + R3.D3.API.Geometry.Normal.call( + this, + apiGeometry, + apiGeometry.colors, + apiGeometry.lineDistances, + apiGeometry.morphTargets, + apiGeometry.morphNormals, + apiGeometry.skinWeights, + apiGeometry.skinIndices, + apiGeometry.verticesNeedsUpdate, + apiGeometry.elementsNeedUpdate, + apiGeometry.uvsNeedUpdate, + apiGeometry.normalsNeedUpdate, + apiGeometry.colorsNeedUpdate, + apiGeometry.groupsNeedUpdate, + apiGeometry.lineDistancesNeedUpdate + ); +}; + +R3.D3.API.Geometry.Normal.Tetrahedron.prototype = Object.create(R3.D3.API.Geometry.Normal.prototype); +R3.D3.API.Geometry.Normal.Tetrahedron.prototype.constructor = R3.D3.API.Geometry.Normal.Tetrahedron; diff --git a/src/r3-d3-api-geometry-normal-text.js b/src/r3-d3-api-geometry-normal-text.js new file mode 100644 index 0000000..b9f06ba --- /dev/null +++ b/src/r3-d3-api-geometry-normal-text.js @@ -0,0 +1,103 @@ +/** + * R3.D3.API.Geometry.Normal.Text + * @param apiGeometry + * @param text + * @param font + * @param size + * @param height + * @param curveSegments + * @param bevelEnabled + * @param bevelThickness + * @param bevelSize + * @param bevelSegments + * @constructor + */ +R3.D3.API.Geometry.Normal.Text = function( + apiGeometry, + text, + font, + size, + height, + curveSegments, + bevelEnabled, + bevelThickness, + bevelSize, + bevelSegments +) { + + if (R3.Utils.UndefinedOrNull(apiGeometry)) { + apiGeometry = { + geometryType: R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TEXT + }; + } + + if (R3.Utils.UndefinedOrNull(apiGeometry.geometryType)) { + apiGeometry.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TEXT; + } + + if (R3.Utils.UndefinedOrNull(text)) { + text = '-= 0) { + this.instance.addAttribute('color', new THREE.BufferAttribute(colors, 3, true)); + } + + /** + * Setup face UVs + */ + var uvs = new Float32Array( + this.faces.reduce( + function(result, face) { + + face.uvs[0].map( + function(uv) { + result.push(uv.x); + result.push(uv.y); + } + ); + + return result; + }, + [] + ) + ); + this.instance.addAttribute('uv', new THREE.BufferAttribute(uvs, 2)); + + /** + * Normals + * @type {Float32Array} + */ + var normals = new Float32Array( + this.faces.reduce( + function(result, face) { + + result.push( + face.normal.x, + face.normal.y, + face.normal.z + ); + result.push( + face.normal.x, + face.normal.y, + face.normal.z + ); + result.push( + face.normal.x, + face.normal.y, + face.normal.z + ); + return result; + }, + [] + ) + ); + this.instance.addAttribute('normal', new THREE.BufferAttribute(normals, 3 )); + + //TODO: check below i don't do this - i used to but i don't think i should + this.instance.normalizeNormals(); + this.instance.computeVertexNormals(); + + /** + * Do faces setup + */ + this.faces = R3.Utils.SortFacesByMaterialIndex(this.faces); + + /** + * 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) { + this.instance.addGroup(start, group.count, group.index); + return start + group.count; + }.bind(this), + 0 + ); + + R3.D3.Geometry.prototype.createInstance.call(this); + +}; + +R3.D3.Geometry.Buffer.prototype.updateInstance = function(property) { + + if (R3.Utils.UndefinedOrNull(this.instance)) { + console.warn('no buffer geometry instance'); + return; + } + + if (property === 'faces') { + console.warn('todo: faces setup - just re-creating the instance for now'); + this.instance = null; + this.createInstance(); + return; + } + + if (property === 'vertices') { + console.warn('todo: vertices setup - just re-creating the instance for now'); + this.instance = null; + this.createInstance(); + return; + } + + if (property === 'attributes') { + console.warn('todo: attributes setup'); + return; + } + + if (property === 'drawRange') { + this.instance.setDrawRange( + this.drawRange.start, + this.drawRange.count + ); + return; + } + + if (property === 'groups') { + + this.instance.clearGroups(); + + this.groups.map( + function(group) { + this.instance.addGroup( + group.start, + group.count, + group.materialIndex + ) + }.bind(this) + ); + + return; + } + + if (property === 'index') { + console.warn('index is read only atm'); + return; + } + + if (property === 'morphAttributes') { + console.warn('morphAttributes is read only atm'); + return; + } + + R3.D3.Geometry.prototype.updateInstance.call(this, property); + +}; + +/** + * Converts a R3.D3.Geometry.Buffer to a R3.D3.API.Geometry.Buffer + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.prototype.toApiObject = function() { + + var apiGeometry = R3.D3.Geometry.prototype.toApiObject.call(this); + + /** + * Right now we don't store attributes and index, also we don't use morphAttributes yet. + * @type {R3.D3.API.Geometry.Buffer} + */ + + var apiBufferGeometry = new R3.D3.API.Geometry.Buffer( + + apiGeometry, + null, //attributes, + this.drawRange.toApiObject(), + this.groups.map( + function(group){ + if (group instanceof R3.Group) { + return group.toApiObject(); + } else { + return group; + } + } + ), + null, //index, + null //morphAttributes + ); + + return apiBufferGeometry; + +}; + +/** + * Update R3.D3.Geometry.Buffer from instance + */ +R3.D3.Geometry.Buffer.prototype.updateFromInstance = function() { + + this.faces = []; + this.vertices = []; + + var normalGeometry = new R3.D3.Geometry.Normal(this.graphics); + normalGeometry.instance.fromBufferGeometry(this.instance); + normalGeometry.updateFromInstance(); + + this.faces = normalGeometry.faces.map( + function(face) { + return face; + } + ); + + this.vertices = normalGeometry.vertices.map( + function(vertex) { + return vertex; + } + ); + + /** + * Now - we have to ensure our geometry is 'downgraded' to a normal buffer geometry + */ + this.geometryType = R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER; + + var componentType = R3.D3.API.Geometry.GetComponentType(R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER); + + this.replace(componentType); + + normalGeometry.remove(); + + // TODO: ok - after some testing - this code below doesn't work + // + // var vertices = this.instance.getAttribute('position').array; + // + // var uvs = this.instance.getAttribute('uv').array; + // + // this.instance.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 R3.D3.Vertex( + // this.graphics, + // new R3.D3.API.Vertex( + // new R3.Vector3( + // this.graphics, + // new R3.API.Vector3( + // vertices[i*3], + // vertices[i*3 + 1], + // vertices[i*3 + 2] + // ) + // ) + // ) + // ); + // + // var uv = new R3.Vector2( + // this.graphics, + // new R3.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 R3.D3.Face( + // this.graphics, + // new R3.D3.API.Face( + // null, + // null, + // faceIndexes[0], + // faceIndexes[1], + // faceIndexes[2], + // materialIndex, + // [[indexedUvs[0], indexedUvs[1], indexedUvs[2]]] + // ) + // ) + // ); + // + // indexedUvs = []; + // faceIndexes = []; + // } + // } + // + // }.bind(this)); + +}; + +/** + * Clears all groups + */ +R3.D3.Geometry.Buffer.prototype.clearGroups = function() { + this.instance.clearGroups(); + this.groups = this.instance.groups; +}; + +/** + * Clears all material groups and makes the geometry use a single material only + */ +R3.D3.Geometry.Buffer.prototype.toSingleMaterial = function() { + + if (this.instance && this.instance.index) { + + this.instance.clearGroups(); + + this.instance.addGroup( + 0, + this.instance.index.count, + 0 + ); + + this.groups = this.instance.groups.map( + function(group) { + return new R3.Group( + this.graphics, + group, + this + ) + }.bind(this) + ) + + } else { + console.warn('this is not an indexed buffer geometry or geometry not loaded'); + } + +}; + + +/** + * To non-index buffer geometry + */ +R3.D3.Geometry.Buffer.prototype.toNonIndexed = function() { + console.warn('not yet tested fully'); + + this.instance = this.instance.toNonIndexed(); + + this.parentMesh.instance.geometry = this.instance; + +// this.updateFromInstance(); +}; + +R3.D3.Geometry.Buffer.prototype.applyPositionRotationScale = function() { + + console.warn('todo and test'); + /** + * + You want to get the world position of a mesh's geometry, taking into consideration the mesh's transform matrix, mesh.matrix. + Also, your mesh geometry is THREE.BufferGeometry. + + Here is the pattern to follow: + + mesh = new THREE.Mesh( geometry, material ); + mesh.position.set( 10, 10, 10 ); + mesh.rotation.set( - Math.PI / 2, 0, 0 ); + mesh.scale.set( 1, 1, 1 ); + scene.add( mesh ); + + mesh.updateMatrix(); // make sure the mesh's matrix is updated + + var vec = new THREE.Vector3(); + var attribute = mesh.geometry.attributes.position; // we want the position data + var index = 1; // index is zero-based, so this the the 2nd vertex + + vec.fromAttribute( attribute, index ); // extract the x,y,z coordinates + + vec.applyMatrix4( mesh.matrix ); // apply the mesh's matrix transform + */ +}; + +/** + * Buffer geometry needs to do more work after updating vertex normals + */ +R3.D3.Geometry.Buffer.prototype.computeVertexNormals = function() { + this.instance.computeVertexNormals(); + // var attribute = this.instance.getAttribute('normal'); + // attribute.setDynamic(true); +}; + +R3.D3.Geometry.Buffer.prototype.normalizeNormals = function() { + this.instance.normalizeNormals(); + // var attribute = this.instance.getAttribute('normal'); + // attribute.setDynamic(true); +}; \ No newline at end of file diff --git a/src/r3-d3-geometry-buffer-box.js b/src/r3-d3-geometry-buffer-box.js new file mode 100644 index 0000000..9998b58 --- /dev/null +++ b/src/r3-d3-geometry-buffer-box.js @@ -0,0 +1,108 @@ +/** + * R3.D3.Geometry.Buffer.Box + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferBox + * @constructor + */ +R3.D3.Geometry.Buffer.Box = function( + graphics, + apiGeometryBufferBox +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferBox)) { + apiGeometryBufferBox = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_BOX + }; + } + + R3.D3.API.Geometry.Buffer.Box.call( + this, + apiGeometryBufferBox, + apiGeometryBufferBox.width, + apiGeometryBufferBox.height, + apiGeometryBufferBox.depth, + apiGeometryBufferBox.widthSegments, + apiGeometryBufferBox.heightSegments, + apiGeometryBufferBox.depthSegments + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferBox + ); + +}; + +R3.D3.Geometry.Buffer.Box.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Box.prototype.constructor = R3.D3.Geometry.Buffer.Box; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Box.prototype.createInstance = function() { + + this.instance = new THREE.BoxBufferGeometry( + this.width, + this.height, + this.depth, + this.widthSegments, + this.heightSegments, + this.depthSegments + ); + + this.instance.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Box.prototype.updateInstance = function(property) { + + if ( + property === 'width' || + property === 'height' || + property === 'depth' || + property === 'widthSegments' || + property === 'heightSegments' || + property === 'depthSegments' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Box to a R3.D3.API.Geometry.Buffer.Box + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Box.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferBox = new R3.D3.API.Geometry.Buffer.Box( + apiBufferGeometry, + this.width, + this.height, + this.depth, + this.widthSegments, + this.heightSegments, + this.depthSegments + ); + + return apiGeometryBufferBox; +}; diff --git a/src/r3-d3-geometry-buffer-circle.js b/src/r3-d3-geometry-buffer-circle.js new file mode 100644 index 0000000..070c0c1 --- /dev/null +++ b/src/r3-d3-geometry-buffer-circle.js @@ -0,0 +1,110 @@ +/** + * R3.D3.Geometry.Buffer.Circle + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferCircle + * @constructor + */ +R3.D3.Geometry.Buffer.Circle = function( + graphics, + apiGeometryBufferCircle +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferCircle)) { + apiGeometryBufferCircle = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CIRCLE + }; + } + + R3.D3.API.Geometry.Buffer.Circle.call( + this, + apiGeometryBufferCircle, + apiGeometryBufferCircle.radius, + apiGeometryBufferCircle.segments, + apiGeometryBufferCircle.thetaStart, + apiGeometryBufferCircle.thetaLength + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferCircle + ); + +}; + +R3.D3.Geometry.Buffer.Circle.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Circle.prototype.constructor = R3.D3.Geometry.Buffer.Circle; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Circle.prototype.createInstance = function() { + + this.instance = new THREE.CircleBufferGeometry( + this.radius, + this.segments, + this.thetaStart, + this.thetaLength + ); + + /** + * The instance doesn't have any groups associated with it - so I just create the default single material group + */ + this.toSingleMaterial(); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Circle.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'segments' || + property === 'thetaStart' || + property === 'thetaLength' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Circle to a R3.D3.API.Geometry.Buffer.Circle + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Circle.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferCircle = new R3.D3.API.Geometry.Buffer.Circle( + apiBufferGeometry, + this.radius, + this.segments, + this.thetaStart, + this.thetaLength + ); + + return apiGeometryBufferCircle; +}; diff --git a/src/r3-d3-geometry-buffer-cone.js b/src/r3-d3-geometry-buffer-cone.js new file mode 100644 index 0000000..a216a67 --- /dev/null +++ b/src/r3-d3-geometry-buffer-cone.js @@ -0,0 +1,117 @@ +/** + * R3.D3.Geometry.Buffer.Cone + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferCone + * @constructor + */ +R3.D3.Geometry.Buffer.Cone = function( + graphics, + apiGeometryBufferCone +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferCone)) { + apiGeometryBufferCone = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CONE + }; + } + + R3.D3.API.Geometry.Buffer.Cone.call( + this, + apiGeometryBufferCone, + apiGeometryBufferCone.radius, + apiGeometryBufferCone.height, + apiGeometryBufferCone.radialSegments, + apiGeometryBufferCone.heightSegments, + apiGeometryBufferCone.openEnded, + apiGeometryBufferCone.thetaStart, + apiGeometryBufferCone.thetaLength + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferCone + ); + +}; + +R3.D3.Geometry.Buffer.Cone.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Cone.prototype.constructor = R3.D3.Geometry.Buffer.Cone; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Cone.prototype.createInstance = function() { + + this.instance = new THREE.ConeBufferGeometry( + this.radius, + this.height, + this.radialSegments, + this.heightSegments, + this.openEnded, + this.thetaStart, + this.thetaLength + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Cone.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'height' || + property === 'radialSegments' || + property === 'heightSegments' || + property === 'openEnded' || + property === 'thetaStart' || + property === 'thetaLength' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Cone to a R3.D3.API.Geometry.Buffer.Cone + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Cone.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferCone = new R3.D3.API.Geometry.Buffer.Cone( + apiBufferGeometry, + this.radius, + this.height, + this.radialSegments, + this.heightSegments, + this.openEnded, + this.thetaStart, + this.thetaLength + ); + + return apiGeometryBufferCone; +}; diff --git a/src/r3-d3-geometry-buffer-cylinder.js b/src/r3-d3-geometry-buffer-cylinder.js new file mode 100644 index 0000000..0b6d42b --- /dev/null +++ b/src/r3-d3-geometry-buffer-cylinder.js @@ -0,0 +1,121 @@ +/** + * R3.D3.Geometry.Buffer.Cylinder + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferCylinder + * @constructor + */ +R3.D3.Geometry.Buffer.Cylinder = function( + graphics, + apiGeometryBufferCylinder +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferCylinder)) { + apiGeometryBufferCylinder = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_CYLINDER + }; + } + + R3.D3.API.Geometry.Buffer.Cylinder.call( + this, + apiGeometryBufferCylinder, + apiGeometryBufferCylinder.radiusTop, + apiGeometryBufferCylinder.radiusBottom, + apiGeometryBufferCylinder.height, + apiGeometryBufferCylinder.radialSegments, + apiGeometryBufferCylinder.heightSegments, + apiGeometryBufferCylinder.openEnded, + apiGeometryBufferCylinder.thetaStart, + apiGeometryBufferCylinder.thetaLength + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferCylinder + ); + +}; + +R3.D3.Geometry.Buffer.Cylinder.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Cylinder.prototype.constructor = R3.D3.Geometry.Buffer.Cylinder; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Cylinder.prototype.createInstance = function() { + + this.instance = new THREE.CylinderBufferGeometry( + this.radiusTop, + this.radiusBottom, + this.height, + this.radialSegments, + this.heightSegments, + this.openEnded, + this.thetaStart, + this.thetaLength + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Cylinder.prototype.updateInstance = function(property) { + + if ( + property === 'radiusTop' || + property === 'radiusBottom' || + property === 'height' || + property === 'radialSegments' || + property === 'heightSegments' || + property === 'openEnded' || + property === 'thetaStart' || + property === 'thetaLength' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Cylinder to a R3.D3.API.Geometry.Buffer.Cylinder + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Cylinder.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferCylinder = new R3.D3.API.Geometry.Buffer.Cylinder( + apiBufferGeometry, + this.radiusTop, + this.radiusBottom, + this.height, + this.radialSegments, + this.heightSegments, + this.openEnded, + this.thetaStart, + this.thetaLength + ); + + return apiGeometryBufferCylinder; +}; diff --git a/src/r3-d3-geometry-buffer-dodecahedron.js b/src/r3-d3-geometry-buffer-dodecahedron.js new file mode 100644 index 0000000..14bcb1b --- /dev/null +++ b/src/r3-d3-geometry-buffer-dodecahedron.js @@ -0,0 +1,103 @@ +/** + * R3.D3.Geometry.Buffer.Dodecahedron + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferDodecahedron + * @constructor + */ +R3.D3.Geometry.Buffer.Dodecahedron = function( + graphics, + apiGeometryBufferDodecahedron +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferDodecahedron)) { + apiGeometryBufferDodecahedron = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_DODECAHEDRON + }; + } + + R3.D3.API.Geometry.Buffer.Dodecahedron.call( + this, + apiGeometryBufferDodecahedron, + apiGeometryBufferDodecahedron.radius, + apiGeometryBufferDodecahedron.detail + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferDodecahedron + ); + +}; + +R3.D3.Geometry.Buffer.Dodecahedron.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Dodecahedron.prototype.constructor = R3.D3.Geometry.Buffer.Dodecahedron; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Dodecahedron.prototype.createInstance = function() { + + this.instance = new THREE.DodecahedronBufferGeometry( + this.radius, + this.detail + ); + + this.instance.addGroup( + 0, + this.instance.attributes.position.count, + 0 + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Dodecahedron.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'detail' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Dodecahedron to a R3.D3.API.Geometry.Buffer.Dodecahedron + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Dodecahedron.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferDodecahedron = new R3.D3.API.Geometry.Buffer.Dodecahedron( + apiBufferGeometry, + this.radius, + this.detail + ); + + return apiGeometryBufferDodecahedron; +}; diff --git a/src/r3-d3-geometry-buffer-extrude.js b/src/r3-d3-geometry-buffer-extrude.js new file mode 100644 index 0000000..82dcd61 --- /dev/null +++ b/src/r3-d3-geometry-buffer-extrude.js @@ -0,0 +1,146 @@ +/** + * R3.D3.Geometry.Buffer.Extrude + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferExtrude + * @constructor + */ +R3.D3.Geometry.Buffer.Extrude = function( + graphics, + apiGeometryBufferExtrude +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferExtrude)) { + apiGeometryBufferExtrude = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_EXTRUDE + }; + } + + R3.D3.API.Geometry.Buffer.Extrude.call( + this, + apiGeometryBufferExtrude, + apiGeometryBufferExtrude.shapes, + apiGeometryBufferExtrude.curveSegments, + apiGeometryBufferExtrude.steps, + apiGeometryBufferExtrude.amount, + apiGeometryBufferExtrude.bevelEnabled, + apiGeometryBufferExtrude.bevelThickness, + apiGeometryBufferExtrude.bevelSize, + apiGeometryBufferExtrude.bevelSegments, + apiGeometryBufferExtrude.extrudePath, + apiGeometryBufferExtrude.frames, + apiGeometryBufferExtrude.UVGenerator + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferExtrude + ); + +}; + +R3.D3.Geometry.Buffer.Extrude.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Extrude.prototype.constructor = R3.D3.Geometry.Buffer.Extrude; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Extrude.prototype.createInstance = function() { + + if (this.shapes.length === 0) { + console.warn('shapes are not ready for this instance'); + return; + } + + this.instance = new THREE.ExtrudeBufferGeometry( + this.shapes.map( + function(shape) { + return shape.instance; + } + ), + { + curveSegments : this.curveSegments, + steps : this.steps, + amount : this.amount, + bevelEnabled : this.bevelEnabled, + bevelThickness : this.bevelThickness, + bevelSize : this.bevelSize, + bevelSegments : this.bevelSegments + } + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Extrude.prototype.updateInstance = function(property) { + + if ( + property === 'shapes' || + property === 'curveSegments' || + property === 'steps' || + property === 'amount' || + property === 'bevelEnabled' || + property === 'bevelThickness' || + property === 'bevelSize' || + property === 'bevelSegments' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + console.warn('do other properties here'); + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Extrude to a R3.D3.API.Geometry.Buffer.Extrude + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Extrude.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferExtrude = new R3.D3.API.Geometry.Buffer.Extrude( + apiBufferGeometry, + this.shapes.map( + function(shape) { + return R3.Utils.IdOrNull(shape); + } + ), + this.curveSegments, + this.steps, + this.amount, + this.bevelEnabled, + this.bevelThickness, + this.bevelSize, + this.bevelSegments, + R3.Utils.IdOrNull(this.extrudePath), + this.frames.map(function(frame){ + return R3.Utils.IdOrNull(frame); + }), + R3.Utils.IdOrNull(this.UVGenerator) + ); + + return apiGeometryBufferExtrude; +}; diff --git a/src/r3-d3-geometry-buffer-icosahedron.js b/src/r3-d3-geometry-buffer-icosahedron.js new file mode 100644 index 0000000..593b980 --- /dev/null +++ b/src/r3-d3-geometry-buffer-icosahedron.js @@ -0,0 +1,103 @@ +/** + * R3.D3.Geometry.Buffer.Icosahedron + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferIcosahedron + * @constructor + */ +R3.D3.Geometry.Buffer.Icosahedron = function( + graphics, + apiGeometryBufferIcosahedron +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferIcosahedron)) { + apiGeometryBufferIcosahedron = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_ICOSAHEDRON + }; + } + + R3.D3.API.Geometry.Buffer.Icosahedron.call( + this, + apiGeometryBufferIcosahedron, + apiGeometryBufferIcosahedron.radius, + apiGeometryBufferIcosahedron.detail + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferIcosahedron + ); + +}; + +R3.D3.Geometry.Buffer.Icosahedron.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Icosahedron.prototype.constructor = R3.D3.Geometry.Buffer.Icosahedron; + +/** + * Create Instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Icosahedron.prototype.createInstance = function() { + + this.instance = new THREE.IcosahedronBufferGeometry( + this.radius, + this.detail + ); + + this.instance.addGroup( + 0, + this.instance.attributes.position.count, + 0 + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Icosahedron.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'detail' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Icosahedron to a R3.D3.API.Geometry.Buffer.Icosahedron + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Icosahedron.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferIcosahedron = new R3.D3.API.Geometry.Buffer.Icosahedron( + apiBufferGeometry, + this.radius, + this.detail + ); + + return apiGeometryBufferIcosahedron; +}; diff --git a/src/r3-d3-geometry-buffer-instanced.js b/src/r3-d3-geometry-buffer-instanced.js new file mode 100644 index 0000000..630243f --- /dev/null +++ b/src/r3-d3-geometry-buffer-instanced.js @@ -0,0 +1,82 @@ +/** + * R3.D3.Geometry.Buffer.Instanced + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferInstanced + * @constructor + */ +R3.D3.Geometry.Buffer.Instanced = function( + graphics, + apiGeometryBufferInstanced +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferInstanced)) { + apiGeometryBufferInstanced = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_INSTANCED + }; + } + + R3.D3.API.Geometry.Buffer.Instanced.call( + this, + apiGeometryBufferInstanced, + apiGeometryBufferInstanced.maxInstancedCount + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferInstanced + ); + +}; + +R3.D3.Geometry.Buffer.Instanced.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Instanced.prototype.constructor = R3.D3.Geometry.Buffer.Instanced; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Instanced.prototype.createInstance = function() { + + this.instance = new THREE.InstancedBufferGeometry(); + + if (R3.Utils.Defined(this.maxInstancedCount)) { + this.instance.maxInstancedCount = this.maxInstancedCount; + } + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Instanced.prototype.updateInstance = function(property) { + + if ( + property === 'maxInstancedCount' + ) { + this.instance.maxInstancedCount = this.maxInstancedCount; + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Instanced to a R3.D3.API.Geometry.Buffer.Instanced + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Instanced.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferInstanced = new R3.D3.API.Geometry.Buffer.Instanced( + apiBufferGeometry, + this.maxInstancedCount + ); + + return apiGeometryBufferInstanced; +}; diff --git a/src/r3-d3-geometry-buffer-lathe.js b/src/r3-d3-geometry-buffer-lathe.js new file mode 100644 index 0000000..e06f30c --- /dev/null +++ b/src/r3-d3-geometry-buffer-lathe.js @@ -0,0 +1,118 @@ +/** + * R3.D3.Geometry.Buffer.Lathe + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferLathe + * @constructor + */ +R3.D3.Geometry.Buffer.Lathe = function( + graphics, + apiGeometryBufferLathe +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferLathe)) { + apiGeometryBufferLathe = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_LATHE + }; + } + + R3.D3.API.Geometry.Buffer.Lathe.call( + this, + apiGeometryBufferLathe, + apiGeometryBufferLathe.points, + apiGeometryBufferLathe.segments, + apiGeometryBufferLathe.phiStart, + apiGeometryBufferLathe.phiLength + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferLathe + ); + +}; + +R3.D3.Geometry.Buffer.Lathe.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Lathe.prototype.constructor = R3.D3.Geometry.Buffer.Lathe; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Lathe.prototype.createInstance = function() { + + this.instance = new THREE.LatheBufferGeometry( + this.points.map( + function(point) { + return point.instance; + } + ), + this.segments, + this.phiStart, + this.phiLength + ); + + /** + * The instance doesn't have any groups associated with it - so I just create the default single material group + */ + this.toSingleMaterial(); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Lathe.prototype.updateInstance = function(property) { + + if ( + property === 'points' || + property === 'segments' || + property === 'phiStart' || + property === 'phiLength' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Lathe to a R3.D3.API.Geometry.Buffer.Lathe + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Lathe.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferLathe = new R3.D3.API.Geometry.Buffer.Lathe( + apiBufferGeometry, + this.points.map( + function(point) { + return point.toApiObject(); + } + ), + this.segments, + this.phiStart, + this.phiLength + ); + + return apiGeometryBufferLathe; +}; diff --git a/src/r3-d3-geometry-buffer-octahedron.js b/src/r3-d3-geometry-buffer-octahedron.js new file mode 100644 index 0000000..b051347 --- /dev/null +++ b/src/r3-d3-geometry-buffer-octahedron.js @@ -0,0 +1,103 @@ +/** + * R3.D3.Geometry.Buffer.Octahedron + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferOctahedron + * @constructor + */ +R3.D3.Geometry.Buffer.Octahedron = function( + graphics, + apiGeometryBufferOctahedron +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferOctahedron)) { + apiGeometryBufferOctahedron = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_OCTAHEDRON + }; + } + + R3.D3.API.Geometry.Buffer.Octahedron.call( + this, + apiGeometryBufferOctahedron, + apiGeometryBufferOctahedron.radius, + apiGeometryBufferOctahedron.detail + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferOctahedron + ); + +}; + +R3.D3.Geometry.Buffer.Octahedron.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Octahedron.prototype.constructor = R3.D3.Geometry.Buffer.Octahedron; + +/** + * Create Instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Octahedron.prototype.createInstance = function() { + + this.instance = new THREE.OctahedronBufferGeometry( + this.radius, + this.detail + ); + + this.instance.addGroup( + 0, + this.instance.attributes.position.count, + 0 + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Octahedron.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'detail' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Octahedron to a R3.D3.API.Geometry.Buffer.Octahedron + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Octahedron.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferOctahedron = new R3.D3.API.Geometry.Buffer.Octahedron( + apiBufferGeometry, + this.radius, + this.detail + ); + + return apiGeometryBufferOctahedron; +}; diff --git a/src/r3-d3-geometry-buffer-parametric.js b/src/r3-d3-geometry-buffer-parametric.js new file mode 100644 index 0000000..fbbe45a --- /dev/null +++ b/src/r3-d3-geometry-buffer-parametric.js @@ -0,0 +1,107 @@ +/** + * R3.D3.Geometry.Buffer.Parametric + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferParametric + * @constructor + */ +R3.D3.Geometry.Buffer.Parametric = function( + graphics, + apiGeometryBufferParametric +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferParametric)) { + apiGeometryBufferParametric = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_PARAMETRIC + }; + } + + R3.D3.API.Geometry.Buffer.Parametric.call( + this, + apiGeometryBufferParametric, + apiGeometryBufferParametric.generatorFn, + apiGeometryBufferParametric.slices, + apiGeometryBufferParametric.stacks + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferParametric + ); + +}; + +R3.D3.Geometry.Buffer.Parametric.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Parametric.prototype.constructor = R3.D3.Geometry.Buffer.Parametric; + +/** + * Create Instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Parametric.prototype.createInstance = function() { + + this.instance = new THREE.ParametricBufferGeometry( + new Function('u', 'v', this.generatorFn).bind(this), + this.slices, + this.stacks + ); + + this.instance.addGroup( + 0, + this.instance.attributes.position.count, + 0 + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Parametric.prototype.updateInstance = function(property) { + + if ( + property === 'generatorFn' || + property === 'slices' || + property === 'stacks' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Parametric to a R3.D3.API.Geometry.Buffer.Parametric + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Parametric.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferParametric = new R3.D3.API.Geometry.Buffer.Parametric( + apiBufferGeometry, + this.generatorFn, + this.slices, + this.stacks + ); + + return apiGeometryBufferParametric; +}; diff --git a/src/r3-d3-geometry-buffer-plane.js b/src/r3-d3-geometry-buffer-plane.js new file mode 100644 index 0000000..a8efcfc --- /dev/null +++ b/src/r3-d3-geometry-buffer-plane.js @@ -0,0 +1,100 @@ +/** + * R3.D3.Geometry.Buffer.Plane + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferPlane + * @constructor + */ +R3.D3.Geometry.Buffer.Plane = function( + graphics, + apiGeometryBufferPlane +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferPlane)) { + apiGeometryBufferPlane = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_PLANE + }; + } + + R3.D3.API.Geometry.Buffer.Plane.call( + this, + apiGeometryBufferPlane, + apiGeometryBufferPlane.width, + apiGeometryBufferPlane.height, + apiGeometryBufferPlane.widthSegments, + apiGeometryBufferPlane.heightSegments + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferPlane + ); + +}; + +R3.D3.Geometry.Buffer.Plane.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Plane.prototype.constructor = R3.D3.Geometry.Buffer.Plane; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Plane.prototype.createInstance = function() { + + this.instance = new THREE.PlaneBufferGeometry( + this.width, + this.height, + this.widthSegments, + this.heightSegments + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Plane.prototype.updateInstance = function(property) { + + if ( + property === 'width' || + property === 'height' || + property === 'widthSegments' || + property === 'heightSegments' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Plane to a R3.D3.API.Geometry.Buffer.Plane + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Plane.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferPlane = new R3.D3.API.Geometry.Buffer.Plane( + apiBufferGeometry, + this.width, + this.height, + this.widthSegments, + this.heightSegments + ); + + return apiGeometryBufferPlane; +}; diff --git a/src/r3-d3-geometry-buffer-polyhedron.js b/src/r3-d3-geometry-buffer-polyhedron.js new file mode 100644 index 0000000..ccb2fa4 --- /dev/null +++ b/src/r3-d3-geometry-buffer-polyhedron.js @@ -0,0 +1,116 @@ +/** + * R3.D3.Geometry.Buffer.Polyhedron + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferPolyhedron + * @constructor + */ +R3.D3.Geometry.Buffer.Polyhedron = function( + graphics, + apiGeometryBufferPolyhedron +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferPolyhedron)) { + apiGeometryBufferPolyhedron = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_POLYHEDRON + }; + } + + R3.D3.API.Geometry.Buffer.Polyhedron.call( + this, + apiGeometryBufferPolyhedron, + apiGeometryBufferPolyhedron.vertices, + apiGeometryBufferPolyhedron.indices, + apiGeometryBufferPolyhedron.radius, + apiGeometryBufferPolyhedron.detail + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferPolyhedron + ); + +}; + +R3.D3.Geometry.Buffer.Polyhedron.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Polyhedron.prototype.constructor = R3.D3.Geometry.Buffer.Polyhedron; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Polyhedron.prototype.createInstance = function() { + + this.instance = new THREE.PolyhedronBufferGeometry( + this.vertices.map( + function(vertex) { + return vertex.position.instance; + } + ), + this.indices.map( + function(index) { + return index.instance; + } + ), + this.radius, + this.detail + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Polyhedron.prototype.updateInstance = function(property) { + + if ( + property === 'vertices' || + property === 'indices' || + property === 'radius' || + property === 'detail' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Polyhedron to a R3.D3.API.Geometry.Buffer.Polyhedron + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Polyhedron.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferPolyhedron = new R3.D3.API.Geometry.Buffer.Polyhedron( + apiBufferGeometry, + this.vertices.map( + function(vertex){ + return vertex.toApiObject(); + } + ), + this.indices.map( + function(index){ + return index.toApiObject(); + } + ), + this.radius, + this.detail + ); + + return apiGeometryBufferPolyhedron; +}; diff --git a/src/r3-d3-geometry-buffer-ring.js b/src/r3-d3-geometry-buffer-ring.js new file mode 100644 index 0000000..bea537c --- /dev/null +++ b/src/r3-d3-geometry-buffer-ring.js @@ -0,0 +1,113 @@ +/** + * R3.D3.Geometry.Buffer.Ring + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferRing + * @constructor + */ +R3.D3.Geometry.Buffer.Ring = function( + graphics, + apiGeometryBufferRing +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferRing)) { + apiGeometryBufferRing = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_RING + }; + } + + R3.D3.API.Geometry.Buffer.Ring.call( + this, + apiGeometryBufferRing, + apiGeometryBufferRing.innerRadius, + apiGeometryBufferRing.outerRadius, + apiGeometryBufferRing.thetaSegments, + apiGeometryBufferRing.phiSegments, + apiGeometryBufferRing.thetaStart, + apiGeometryBufferRing.thetaLength + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferRing + ); + +}; + +R3.D3.Geometry.Buffer.Ring.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Ring.prototype.constructor = R3.D3.Geometry.Buffer.Ring; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Ring.prototype.createInstance = function() { + + this.instance = new THREE.RingBufferGeometry( + this.innerRadius, + this.outerRadius, + this.thetaSegments, + this.phiSegments, + this.thetaStart, + this.thetaLength + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Ring.prototype.updateInstance = function(property) { + + if ( + property === 'innerRadius' || + property === 'outerRadius' || + property === 'thetaSegments' || + property === 'phiSegments' || + property === 'thetaStart' || + property === 'thetaLength' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Ring to a R3.D3.API.Geometry.Buffer.Ring + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Ring.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferRing = new R3.D3.API.Geometry.Buffer.Ring( + apiBufferGeometry, + this.innerRadius, + this.outerRadius, + this.thetaSegments, + this.phiSegments, + this.thetaStart, + this.thetaLength + ); + + return apiGeometryBufferRing; +}; diff --git a/src/r3-d3-geometry-buffer-shape.js b/src/r3-d3-geometry-buffer-shape.js new file mode 100644 index 0000000..7ea8295 --- /dev/null +++ b/src/r3-d3-geometry-buffer-shape.js @@ -0,0 +1,112 @@ +/** + * R3.D3.Geometry.Buffer.Shape + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferShape + * @constructor + */ +R3.D3.Geometry.Buffer.Shape = function( + graphics, + apiGeometryBufferShape +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferShape)) { + apiGeometryBufferShape = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_SHAPE + }; + } + + R3.D3.API.Geometry.Buffer.Shape.call( + this, + apiGeometryBufferShape, + apiGeometryBufferShape.shapes, + apiGeometryBufferShape.curveSegments + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferShape + ); + +}; + +R3.D3.Geometry.Buffer.Shape.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Shape.prototype.constructor = R3.D3.Geometry.Buffer.Shape; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Shape.prototype.createInstance = function() { + + if (this.shapes.length === 0) { + console.warn('shapes are not ready for this instance'); + return; + } + + this.instance = new THREE.ShapeBufferGeometry( + this.shapes.map( + function(shape) { + return shape.instance; + } + ), + this.curveSegments + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Shape.prototype.updateInstance = function(property) { + + if ( + property === 'shapes' || + property === 'curveSegments' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + console.warn('do other properties here'); + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Shape to a R3.D3.API.Geometry.Buffer.Shape + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Shape.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferShape = new R3.D3.API.Geometry.Buffer.Shape( + apiBufferGeometry, + this.shapes.map( + function(shape) { + return R3.Utils.IdOrNull(shape); + } + ), + this.curveSegments + ); + + return apiGeometryBufferShape; +}; diff --git a/src/r3-d3-geometry-buffer-sphere.js b/src/r3-d3-geometry-buffer-sphere.js new file mode 100644 index 0000000..052d9a0 --- /dev/null +++ b/src/r3-d3-geometry-buffer-sphere.js @@ -0,0 +1,117 @@ +/** + * R3.D3.Geometry.Buffer.Sphere + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferSphere + * @constructor + */ +R3.D3.Geometry.Buffer.Sphere = function( + graphics, + apiGeometryBufferSphere +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferSphere)) { + apiGeometryBufferSphere = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_SPHERE + }; + } + + R3.D3.API.Geometry.Buffer.Sphere.call( + this, + apiGeometryBufferSphere, + apiGeometryBufferSphere.radius, + apiGeometryBufferSphere.widthSegments, + apiGeometryBufferSphere.heightSegments, + apiGeometryBufferSphere.phiStart, + apiGeometryBufferSphere.phiLength, + apiGeometryBufferSphere.thetaStart, + apiGeometryBufferSphere.thetaLength + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferSphere + ); + +}; + +R3.D3.Geometry.Buffer.Sphere.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Sphere.prototype.constructor = R3.D3.Geometry.Buffer.Sphere; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Sphere.prototype.createInstance = function() { + + this.instance = new THREE.SphereBufferGeometry( + this.radius, + this.widthSegments, + this.heightSegments, + this.phiStart, + this.phiLength, + this.thetaStart, + this.thetaLength + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Sphere.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'widthSegments' || + property === 'heightSegments' || + property === 'phiStart' || + property === 'phiLength' || + property === 'thetaStart' || + property === 'thetaLength' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Sphere to a R3.D3.API.Geometry.Buffer.Sphere + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Sphere.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferSphere = new R3.D3.API.Geometry.Buffer.Sphere( + apiBufferGeometry, + this.radius, + this.widthSegments, + this.heightSegments, + this.phiStart, + this.phiLength, + this.thetaStart, + this.thetaLength + ); + + return apiGeometryBufferSphere; +}; diff --git a/src/r3-d3-geometry-buffer-tetrahedron.js b/src/r3-d3-geometry-buffer-tetrahedron.js new file mode 100644 index 0000000..ec5b004 --- /dev/null +++ b/src/r3-d3-geometry-buffer-tetrahedron.js @@ -0,0 +1,103 @@ +/** + * R3.D3.Geometry.Buffer.Tetrahedron + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferTetrahedron + * @constructor + */ +R3.D3.Geometry.Buffer.Tetrahedron = function( + graphics, + apiGeometryBufferTetrahedron +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferTetrahedron)) { + apiGeometryBufferTetrahedron = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TETRAHEDRON + }; + } + + R3.D3.API.Geometry.Buffer.Tetrahedron.call( + this, + apiGeometryBufferTetrahedron, + apiGeometryBufferTetrahedron.radius, + apiGeometryBufferTetrahedron.detail + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferTetrahedron + ); + +}; + +R3.D3.Geometry.Buffer.Tetrahedron.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Tetrahedron.prototype.constructor = R3.D3.Geometry.Buffer.Tetrahedron; + +/** + * Create Instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Tetrahedron.prototype.createInstance = function() { + + this.instance = new THREE.TetrahedronBufferGeometry( + this.radius, + this.detail + ); + + this.instance.addGroup( + 0, + this.instance.attributes.position.count, + 0 + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Tetrahedron.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'detail' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Tetrahedron to a R3.D3.API.Geometry.Buffer.Tetrahedron + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Tetrahedron.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferTetrahedron = new R3.D3.API.Geometry.Buffer.Tetrahedron( + apiBufferGeometry, + this.radius, + this.detail + ); + + return apiGeometryBufferTetrahedron; +}; diff --git a/src/r3-d3-geometry-buffer-text.js b/src/r3-d3-geometry-buffer-text.js new file mode 100644 index 0000000..280491e --- /dev/null +++ b/src/r3-d3-geometry-buffer-text.js @@ -0,0 +1,142 @@ +/** + * R3.D3.Geometry.Buffer.Text + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferText + * @constructor + */ +R3.D3.Geometry.Buffer.Text = function( + graphics, + apiGeometryBufferText +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferText)) { + apiGeometryBufferText = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TEXT + }; + } + + R3.D3.API.Geometry.Buffer.Text.call( + this, + apiGeometryBufferText, + apiGeometryBufferText.text, + apiGeometryBufferText.font, + apiGeometryBufferText.size, + apiGeometryBufferText.height, + apiGeometryBufferText.curveSegments, + apiGeometryBufferText.bevelEnabled, + apiGeometryBufferText.bevelThickness, + apiGeometryBufferText.bevelSize, + apiGeometryBufferText.bevelSegments + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferText + ); + +}; + +R3.D3.Geometry.Buffer.Text.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Text.prototype.constructor = R3.D3.Geometry.Buffer.Text; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Text.prototype.createInstance = function() { + + if (!this.font || !this.font.instance) { + console.warn('font not ready for this instance'); + return; + } + + this.instance = new THREE.TextBufferGeometry( + this.text, + { + font : this.font.instance, + size : this.size, + curveSegments : this.curveSegments, + steps : this.steps, + amount : this.amount, + bevelEnabled : this.bevelEnabled, + bevelThickness : this.bevelThickness, + bevelSize : this.bevelSize, + bevelSegments : this.bevelSegments + } + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Text.prototype.updateInstance = function(property) { + + if ( + property === 'text' || + property === 'font' || + property === 'size' || + property === 'height' || + property === 'curveSegments' || + property === 'bevelEnabled' || + property === 'bevelThickness' || + property === 'bevelSize' || + property === 'bevelSegments' + ) { + + /** + * Could be that the instance does not exist - because font was not ready + */ + if (this.instance) { + this.instance.dispose(); + } + + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + console.warn('do other properties here'); + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Text to a R3.D3.API.Geometry.Buffer.Text + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Text.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferText = new R3.D3.API.Geometry.Buffer.Text( + apiBufferGeometry, + this.text, + R3.Utils.IdOrNull(this.font), + this.size, + this.height, + this.curveSegments, + this.bevelEnabled, + this.bevelThickness, + this.bevelSize, + this.bevelSegments + ); + + return apiGeometryBufferText; +}; diff --git a/src/r3-d3-geometry-buffer-torus-knot.js b/src/r3-d3-geometry-buffer-torus-knot.js new file mode 100644 index 0000000..89d244d --- /dev/null +++ b/src/r3-d3-geometry-buffer-torus-knot.js @@ -0,0 +1,113 @@ +/** + * R3.D3.Geometry.Buffer.TorusKnot + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferTorusKnot + * @constructor + */ +R3.D3.Geometry.Buffer.TorusKnot = function( + graphics, + apiGeometryBufferTorusKnot +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferTorusKnot)) { + apiGeometryBufferTorusKnot = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TORUS_KNOT + }; + } + + R3.D3.API.Geometry.Buffer.TorusKnot.call( + this, + apiGeometryBufferTorusKnot, + apiGeometryBufferTorusKnot.radius, + apiGeometryBufferTorusKnot.tube, + apiGeometryBufferTorusKnot.radialSegments, + apiGeometryBufferTorusKnot.tubularSegments, + apiGeometryBufferTorusKnot.p, + apiGeometryBufferTorusKnot.q + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferTorusKnot + ); + +}; + +R3.D3.Geometry.Buffer.TorusKnot.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.TorusKnot.prototype.constructor = R3.D3.Geometry.Buffer.TorusKnot; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.TorusKnot.prototype.createInstance = function() { + + this.instance = new THREE.TorusKnotBufferGeometry( + this.radius, + this.tube, + this.radialSegments, + this.tubularSegments, + this.p, + this.q + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.TorusKnot.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'tube' || + property === 'radialSegments' || + property === 'tubularSegments' || + property === 'p' || + property === 'q' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.TorusKnot to a R3.D3.API.Geometry.Buffer.TorusKnot + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.TorusKnot.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferTorusKnot = new R3.D3.API.Geometry.Buffer.TorusKnot( + apiBufferGeometry, + this.radius, + this.tube, + this.radialSegments, + this.tubularSegments, + this.p, + this.q + ); + + return apiGeometryBufferTorusKnot; +}; diff --git a/src/r3-d3-geometry-buffer-torus.js b/src/r3-d3-geometry-buffer-torus.js new file mode 100644 index 0000000..64f36f1 --- /dev/null +++ b/src/r3-d3-geometry-buffer-torus.js @@ -0,0 +1,109 @@ +/** + * R3.D3.Geometry.Buffer.Torus + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferTorus + * @constructor + */ +R3.D3.Geometry.Buffer.Torus = function( + graphics, + apiGeometryBufferTorus +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferTorus)) { + apiGeometryBufferTorus = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TORUS + }; + } + + R3.D3.API.Geometry.Buffer.Torus.call( + this, + apiGeometryBufferTorus, + apiGeometryBufferTorus.radius, + apiGeometryBufferTorus.tube, + apiGeometryBufferTorus.radialSegments, + apiGeometryBufferTorus.tubularSegments, + apiGeometryBufferTorus.arc + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferTorus + ); + +}; + +R3.D3.Geometry.Buffer.Torus.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Torus.prototype.constructor = R3.D3.Geometry.Buffer.Torus; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Torus.prototype.createInstance = function() { + + this.instance = new THREE.TorusBufferGeometry( + this.radius, + this.tube, + this.radialSegments, + this.tubularSegments, + this.arc + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Torus.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'tube' || + property === 'radialSegments' || + property === 'tubularSegments' || + property === 'arc' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Torus to a R3.D3.API.Geometry.Buffer.Torus + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Torus.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferTorus = new R3.D3.API.Geometry.Buffer.Torus( + apiBufferGeometry, + this.radius, + this.tube, + this.radialSegments, + this.tubularSegments, + this.arc + ); + + return apiGeometryBufferTorus; +}; diff --git a/src/r3-d3-geometry-buffer-tube.js b/src/r3-d3-geometry-buffer-tube.js new file mode 100644 index 0000000..930a7a3 --- /dev/null +++ b/src/r3-d3-geometry-buffer-tube.js @@ -0,0 +1,109 @@ +/** + * R3.D3.Geometry.Buffer.Tube + * @param graphics R3.GraphicsRuntime + * @param apiGeometryBufferTube + * @constructor + */ +R3.D3.Geometry.Buffer.Tube = function( + graphics, + apiGeometryBufferTube +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryBufferTube)) { + apiGeometryBufferTube = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_BUFFER_TUBE + }; + } + + R3.D3.API.Geometry.Buffer.Tube.call( + this, + apiGeometryBufferTube, + apiGeometryBufferTube.path, + apiGeometryBufferTube.tubularSegments, + apiGeometryBufferTube.radius, + apiGeometryBufferTube.radialSegments, + apiGeometryBufferTube.closed + ); + + R3.D3.Geometry.Buffer.call( + this, + this.graphics, + apiGeometryBufferTube + ); + +}; + +R3.D3.Geometry.Buffer.Tube.prototype = Object.create(R3.D3.Geometry.Buffer.prototype); +R3.D3.Geometry.Buffer.Tube.prototype.constructor = R3.D3.Geometry.Buffer.Tube; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Buffer.Tube.prototype.createInstance = function() { + + this.instance = new THREE.TubeBufferGeometry( + this.path.instance, + this.tubularSegments, + this.radius, + this.radialSegments, + this.closed + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Buffer.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Buffer.Tube.prototype.updateInstance = function(property) { + + if ( + property === 'path' || + property === 'tubularSegments' || + property === 'radius' || + property === 'radialSegments' || + property === 'closed' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Buffer.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Buffer.Tube to a R3.D3.API.Geometry.Buffer.Tube + * @returns {R3.D3.API.Geometry.Buffer} + */ +R3.D3.Geometry.Buffer.Tube.prototype.toApiObject = function() { + + var apiBufferGeometry = R3.D3.Geometry.Buffer.prototype.toApiObject.call(this); + + var apiGeometryBufferTube = new R3.D3.API.Geometry.Buffer.Tube( + apiBufferGeometry, + R3.Utils.IdOrNull(this.path), + this.tubularSegments, + this.radius, + this.radialSegments, + this.closed + ); + + return apiGeometryBufferTube; +}; diff --git a/src/r3-d3-geometry-normal-a.js b/src/r3-d3-geometry-normal-a.js new file mode 100644 index 0000000..76aece3 --- /dev/null +++ b/src/r3-d3-geometry-normal-a.js @@ -0,0 +1,511 @@ +/** + * R3.D3.Geometry.Normal + * @param graphics + * @param apiNormalGeometry + * @property geometryType + * @constructor + */ +R3.D3.Geometry.Normal = function( + graphics, + apiNormalGeometry +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiNormalGeometry)) { + apiNormalGeometry = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL + }; + } + + R3.D3.API.Geometry.Normal.call( + this, + apiNormalGeometry, + apiNormalGeometry.colors, + apiNormalGeometry.lineDistances, + apiNormalGeometry.morphTargets, + apiNormalGeometry.morphNormals, + apiNormalGeometry.skinWeights, + apiNormalGeometry.skinIndices, + apiNormalGeometry.verticesNeedsUpdate, + apiNormalGeometry.elementsNeedUpdate, + apiNormalGeometry.uvsNeedUpdate, + apiNormalGeometry.normalsNeedUpdate, + apiNormalGeometry.colorsNeedUpdate, + apiNormalGeometry.groupsNeedUpdate, + apiNormalGeometry.lineDistancesNeedUpdate + ); + + this.colors = this.colors.map( + function(color) { + return new R3.Color( + this.graphics, + color + ) + }.bind(this) + ); + + this.skinWeights = this.skinWeights.map( + function(skinWeight) { + return new R3.Vector4( + this.graphics, + skinWeight, + this + ) + }.bind(this) + ); + + this.skinIndices = this.skinIndices.map( + function(skinIndex) { + return new R3.Vector4( + this.graphics, + skinIndex, + this + ) + }.bind(this) + ); + + R3.D3.Geometry.call( + this, + this.graphics, + this + ); +}; + +R3.D3.Geometry.Normal.prototype = Object.create(R3.D3.Geometry.prototype); +R3.D3.Geometry.Normal.prototype.constructor = R3.D3.Geometry.Normal; + +R3.D3.Geometry.Normal.prototype.createInstance = function() { + + if (R3.Utils.Defined(this.instance)) { + + /** + * We already have our object - just call our parent and return + */ + R3.D3.Geometry.prototype.createInstance.call(this); + + return; + } + + this.instance = new THREE.Geometry(); + + /** + * Setup colors + */ + this.instance.colors = this.colors.map( + function(color) { + return color.instance; + } + ); + + /** + * Setup faces + */ + this.applyToInstance('faces'); + + /** + * Setup line distances - we let three calculate it and then update our information + */ + this.instance.computeLineDistances(); + this.lineDistances = this.instance.lineDistances; + + /** + * Some more stuff + */ + if (this.morphTargets && this.morphTargets.length > 0) { + this.instance.morphTargets = this.morphTargets; + } + + if (this.morphNormals && this.morphNormals.length > 0) { + this.instance.morphNormals = this.morphNormals; + } + + if (this.skinWeights && this.skinWeights.length > 0) { + this.instance.skinWeights = this.skinWeights.map( + function(skinWeight) { + return skinWeight.instance; + } + ); + } + + if (this.skinIndices && this.skinIndices.length > 0) { + this.instance.skinIndices = this.skinIndices.map( + function(skinIndex) { + return skinIndex.instance; + } + ); + } + + /** + * Setup vertices + */ + this.applyToInstance('vertices'); + + //TODO: Below is actually for blender data - fix this server side and then remove this eventually + this.invertWindingOrder(); + this.computeFaceNormals(); + this.computeVertexNormals(); + + R3.D3.Geometry.prototype.createInstance.call(this); +}; + +R3.D3.Geometry.Normal.prototype.updateInstance = function(property) { + + if (R3.Utils.UndefinedOrNull(this.instance)) { + console.warn('no geometry instance'); + return; + } + + if (property === 'colors') { + this.instance.colors = this.colors.map( + function(color) { + return color.instance; + } + ); + this.instance.colorsNeedUpdate = true; + return; + } + + if (property === 'faces') { + this.applyToInstance(property); + this.instance.elementsNeedUpdate = true; + this.instance.groupsNeedUpdate = true; + return; + } + + if (property === 'lineDistances') { + this.instance.lineDistances = this.lineDistances; + this.instance.lineDistancesNeedUpdate = true; + return; + } + + if (property === 'morphTargets') { + this.instance.morphTargets = this.morphTargets; + return; + } + + if (property === 'morphNormals') { + this.instance.morphNormals = this.morphNormals; + return; + } + + if (property === 'skinWeights') { + + if (this.skinWeights) { + this.instance.skinWeights = this.skinWeights.map( + function(skinWeight) { + return skinWeight.instance; + } + ) + } else { + console.warn('todo : check deleting skinweights'); + delete this.instance.skinWeights; + } + + return; + } + + if (property === 'skinIndices') { + + if (this.skinIndices) { + this.instance.skinIndices = this.skinIndices.map( + function(skinIndex) { + return skinIndex.instance; + } + ) + } else { + console.warn('todo : check deleting skinIndices'); + delete this.instance.skinIndices; + } + + return; + } + + if (property === 'vertices') { + this.applyToInstance(property); + this.instance.verticesNeedUpdate = true; + return; + } + + /** + * Manually trigger updates (and ignore our setting) + */ + if (property === 'verticesNeedsUpdate') { + this.instance.verticesNeedsUpdate = true; + this.verticesNeedUpdate = false; + } + + if (property === 'elementsNeedUpdate') { + this.instance.elementsNeedUpdate = true; + this.elementsNeedUpdate = false; + } + + if (property === 'uvsNeedUpdate') { + this.instance.uvsNeedUpdate = true; + this.uvsNeedUpdate = false; + } + + if (property === 'normalsNeedUpdate') { + this.instance.normalsNeedUpdate = true; + this.normalsNeedUpdate = false; + } + + if (property === 'colorsNeedUpdate') { + this.instance.colorsNeedUpdate = true; + this.colorsNeedUpdate = false; + } + + if (property === 'groupsNeedUpdate') { + this.instance.groupsNeedUpdate = true; + this.groupsNeedUpdate = false; + } + + if (property === 'lineDistancesNeedUpdate') { + this.instance.lineDistancesNeedUpdate = true; + this.lineDistancesNeedUpdate = false; + } + + R3.D3.Geometry.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal to a R3.D3.API.Geometry.Normal + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.prototype.toApiObject = function() { + + var apiGeometry = R3.D3.Geometry.prototype.toApiObject.call(this); + + var apiNormalGeometry = new R3.D3.API.Geometry.Normal( + apiGeometry, + this.colors.map( + function(color) { + return color.toApiObject(); + } + ), + this.lineDistances, + this.morphTargets, + this.morphNormals, + this.skinWeights.map( + function(skinWeight) { + return skinWeight.toApiObject(); + } + ), + this.skinIndices.map( + function(skinIndex) { + return skinIndex.toApiObject(); + } + ) + ); + + return apiNormalGeometry; +}; + +/** + * Update R3.D3.Geometry.Normal from instance + */ +R3.D3.Geometry.Normal.prototype.updateFromInstance = function() { + + var processed = 0; + + this.faces = []; + this.vertices = []; + + this.instance.faces.map(function(face, faceIndex){ + + processed++; + + if (processed % 100 === 0) { + console.log('processed ' + processed + ' faces'); + } + + this.faces.push( + new R3.D3.Face( + this.graphics, + new R3.D3.API.Face( + null, + null, + face.a, + face.b, + face.c, + face.materialIndex, + [[ + new R3.API.Vector2( + this.instance.faceVertexUvs[0][faceIndex][0].x, + this.instance.faceVertexUvs[0][faceIndex][0].y + ), + new R3.API.Vector2( + this.instance.faceVertexUvs[0][faceIndex][1].x, + this.instance.faceVertexUvs[0][faceIndex][1].y + ), + new R3.API.Vector2( + this.instance.faceVertexUvs[0][faceIndex][2].x, + this.instance.faceVertexUvs[0][faceIndex][2].y + ) + ]], + new R3.Color( + this.graphics, + new R3.API.Color( + face.color.r, + face.color.g, + face.color.b + ) + ), + face.vertexColors.map(function(vertexColor){ + return new R3.Color( + this.graphics, + new R3.API.Color( + vertexColor.r, + vertexColor.g, + vertexColor.b + ) + ) + }.bind(this)), + face.vertexNormals.map(function(vertexNormal){ + return new R3.Vector3( + this.graphics, + new R3.API.Vector3( + vertexNormal.x, + vertexNormal.y, + vertexNormal.z + ) + ) + }.bind(this)), + new R3.Vector3( + this.graphics, + new R3.API.Vector3( + face.normal.x, + face.normal.y, + face.normal.z + ) + ) + ) + ) + ) + }.bind(this)); + + processed = 0; + + this.instance.vertices.map(function(vertex){ + + processed++; + + if (processed % 100 === 0) { + console.log('processed ' + processed + ' vertices'); + } + + this.vertices.push( + new R3.D3.Vertex( + this.graphics, + new R3.D3.API.Vertex( + new R3.Vector3( + this.graphics, + new R3.API.Vector3( + vertex.x, + vertex.y, + vertex.z + ) + ) + ) + ) + ) + + }.bind(this)); + +}; + +R3.D3.Geometry.Normal.prototype.applyToInstance = function(property) { + + if (property === 'faces') { + + this.faces = R3.Utils.SortFacesByMaterialIndex(this.faces); + + var standardUvs = []; + + /** + * Now setup each face and collect UV information during this process + */ + this.instance.faces = this.faces.map( + function (face) { + + if (face.uvs[0].length > 0) { + standardUvs.push( + face.uvs[0].map( + function (uv) { + return uv.instance; + } + ) + ); + } + + if (!face.instance) { + face.createInstance(this); + } + + return face.instance; + }.bind(this) + ); + + /** + * UV data - but only if it exists + */ + if (standardUvs.length > 0) { + this.instance.faceVertexUvs = [standardUvs]; + } + + return; + } + + if (property === 'vertices') { + this.instance.vertices = this.vertices.map( + function (vertex) { + return vertex.position.instance; + } + ); + } +}; + +/** + * Re-compute vertex normals + */ +R3.D3.Geometry.Normal.prototype.computeVertexNormals = function() { + console.log('re-computing vertex normals'); + this.instance.computeVertexNormals(); +}; + +/** + * Re-compute vertex normals + */ +R3.D3.Geometry.Normal.prototype.computeFaceNormals = function() { + console.log('re-computing face normals'); + this.instance.computeFaceNormals(); +}; + +/** + * Invert winding order + */ +R3.D3.Geometry.Normal.prototype.invertWindingOrder = function() { + + this.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; + + } + ); + + if (this.instance) { + this.instance.computeVertexNormals(); + this.instance.computeFaceNormals(); + this.instance.elementsNeedUpdate = true; + this.instance.normalsNeedUpdate = true; + } + +}; \ No newline at end of file diff --git a/src/r3-d3-geometry-normal-box.js b/src/r3-d3-geometry-normal-box.js new file mode 100644 index 0000000..bfa27f7 --- /dev/null +++ b/src/r3-d3-geometry-normal-box.js @@ -0,0 +1,97 @@ +/** + * R3.D3.Geometry.Normal.Box + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalBox + * @constructor + */ +R3.D3.Geometry.Normal.Box = function( + graphics, + apiGeometryNormalBox +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalBox)) { + apiGeometryNormalBox = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_BOX + }; + } + + R3.D3.API.Geometry.Normal.Box.call( + this, + apiGeometryNormalBox, + apiGeometryNormalBox.width, + apiGeometryNormalBox.height, + apiGeometryNormalBox.depth, + apiGeometryNormalBox.widthSegments, + apiGeometryNormalBox.heightSegments, + apiGeometryNormalBox.depthSegments + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalBox + ); + +}; + +R3.D3.Geometry.Normal.Box.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Box.prototype.constructor = R3.D3.Geometry.Normal.Box; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Box.prototype.createInstance = function() { + + this.instance = new THREE.BoxGeometry( + this.width, + this.height, + this.depth, + this.widthSegments, + this.heightSegments, + this.depthSegments + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Box.prototype.updateInstance = function(property) { + + if ( + property === 'width' + ) { + this.createInstance(); + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Box to a R3.D3.API.Geometry.Normal.Box + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Box.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalBox = new R3.D3.API.Geometry.Normal.Box( + apiNormalGeometry, + this.width, + this.height, + this.depth, + this.widthSegments, + this.heightSegments, + this.depthSegments + ); + + return apiGeometryNormalBox; +}; diff --git a/src/r3-d3-geometry-normal-circle.js b/src/r3-d3-geometry-normal-circle.js new file mode 100644 index 0000000..0f8eed0 --- /dev/null +++ b/src/r3-d3-geometry-normal-circle.js @@ -0,0 +1,105 @@ +/** + * R3.D3.Geometry.Normal.Circle + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalCircle + * @constructor + */ +R3.D3.Geometry.Normal.Circle = function( + graphics, + apiGeometryNormalCircle +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalCircle)) { + apiGeometryNormalCircle = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_CIRCLE + }; + } + + R3.D3.API.Geometry.Normal.Circle.call( + this, + apiGeometryNormalCircle, + apiGeometryNormalCircle.radius, + apiGeometryNormalCircle.segments, + apiGeometryNormalCircle.thetaStart, + apiGeometryNormalCircle.thetaLength + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalCircle + ); + +}; + +R3.D3.Geometry.Normal.Circle.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Circle.prototype.constructor = R3.D3.Geometry.Normal.Circle; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Circle.prototype.createInstance = function() { + + this.instance = new THREE.CircleGeometry( + this.radius, + this.segments, + this.thetaStart, + this.thetaLength + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Circle.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'segments' || + property === 'thetaStart' || + property === 'thetaLength' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Circle to a R3.D3.API.Geometry.Normal.Circle + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Circle.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalCircle = new R3.D3.API.Geometry.Normal.Circle( + apiNormalGeometry, + this.radius, + this.segments, + this.thetaStart, + this.thetaLength + ); + + return apiGeometryNormalCircle; +}; diff --git a/src/r3-d3-geometry-normal-cone.js b/src/r3-d3-geometry-normal-cone.js new file mode 100644 index 0000000..930f787 --- /dev/null +++ b/src/r3-d3-geometry-normal-cone.js @@ -0,0 +1,117 @@ +/** + * R3.D3.Geometry.Normal.Cone + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalCone + * @constructor + */ +R3.D3.Geometry.Normal.Cone = function( + graphics, + apiGeometryNormalCone +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalCone)) { + apiGeometryNormalCone = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_CONE + }; + } + + R3.D3.API.Geometry.Normal.Cone.call( + this, + apiGeometryNormalCone, + apiGeometryNormalCone.radius, + apiGeometryNormalCone.height, + apiGeometryNormalCone.radialSegments, + apiGeometryNormalCone.heightSegments, + apiGeometryNormalCone.openEnded, + apiGeometryNormalCone.thetaStart, + apiGeometryNormalCone.thetaLength + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalCone + ); + +}; + +R3.D3.Geometry.Normal.Cone.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Cone.prototype.constructor = R3.D3.Geometry.Normal.Cone; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Cone.prototype.createInstance = function() { + + this.instance = new THREE.ConeGeometry( + this.radius, + this.height, + this.radialSegments, + this.heightSegments, + this.openEnded, + this.thetaStart, + this.thetaLength + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Cone.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'height' || + property === 'radialSegments' || + property === 'heightSegments' || + property === 'openEnded' || + property === 'thetaStart' || + property === 'thetaLength' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Cone to a R3.D3.API.Geometry.Normal.Cone + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Cone.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalCone = new R3.D3.API.Geometry.Normal.Cone( + apiNormalGeometry, + this.radius, + this.height, + this.radialSegments, + this.heightSegments, + this.openEnded, + this.thetaStart, + this.thetaLength + ); + + return apiGeometryNormalCone; +}; diff --git a/src/r3-d3-geometry-normal-cylinder.js b/src/r3-d3-geometry-normal-cylinder.js new file mode 100644 index 0000000..cd1cf88 --- /dev/null +++ b/src/r3-d3-geometry-normal-cylinder.js @@ -0,0 +1,121 @@ +/** + * R3.D3.Geometry.Normal.Cylinder + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalCylinder + * @constructor + */ +R3.D3.Geometry.Normal.Cylinder = function( + graphics, + apiGeometryNormalCylinder +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalCylinder)) { + apiGeometryNormalCylinder = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_CYLINDER + }; + } + + R3.D3.API.Geometry.Normal.Cylinder.call( + this, + apiGeometryNormalCylinder, + apiGeometryNormalCylinder.radiusTop, + apiGeometryNormalCylinder.radiusBottom, + apiGeometryNormalCylinder.height, + apiGeometryNormalCylinder.radialSegments, + apiGeometryNormalCylinder.heightSegments, + apiGeometryNormalCylinder.openEnded, + apiGeometryNormalCylinder.thetaStart, + apiGeometryNormalCylinder.thetaLength + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalCylinder + ); + +}; + +R3.D3.Geometry.Normal.Cylinder.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Cylinder.prototype.constructor = R3.D3.Geometry.Normal.Cylinder; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Cylinder.prototype.createInstance = function() { + + this.instance = new THREE.CylinderGeometry( + this.radiusTop, + this.radiusBottom, + this.height, + this.radialSegments, + this.heightSegments, + this.openEnded, + this.thetaStart, + this.thetaLength + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Cylinder.prototype.updateInstance = function(property) { + + if ( + property === 'radiusTop' || + property === 'radiusBottom' || + property === 'height' || + property === 'radialSegments' || + property === 'heightSegments' || + property === 'openEnded' || + property === 'thetaStart' || + property === 'thetaLength' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Cylinder to a R3.D3.API.Geometry.Normal.Cylinder + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Cylinder.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalCylinder = new R3.D3.API.Geometry.Normal.Cylinder( + apiNormalGeometry, + this.radiusTop, + this.radiusBottom, + this.height, + this.radialSegments, + this.heightSegments, + this.openEnded, + this.thetaStart, + this.thetaLength + ); + + return apiGeometryNormalCylinder; +}; diff --git a/src/r3-d3-geometry-normal-dodecahedron.js b/src/r3-d3-geometry-normal-dodecahedron.js new file mode 100644 index 0000000..f33b499 --- /dev/null +++ b/src/r3-d3-geometry-normal-dodecahedron.js @@ -0,0 +1,97 @@ +/** + * R3.D3.Geometry.Normal.Dodecahedron + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalDodecahedron + * @constructor + */ +R3.D3.Geometry.Normal.Dodecahedron = function( + graphics, + apiGeometryNormalDodecahedron +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalDodecahedron)) { + apiGeometryNormalDodecahedron = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_DODECAHEDRON + }; + } + + R3.D3.API.Geometry.Normal.Dodecahedron.call( + this, + apiGeometryNormalDodecahedron, + apiGeometryNormalDodecahedron.radius, + apiGeometryNormalDodecahedron.detail + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalDodecahedron + ); + +}; + +R3.D3.Geometry.Normal.Dodecahedron.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Dodecahedron.prototype.constructor = R3.D3.Geometry.Normal.Dodecahedron; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Dodecahedron.prototype.createInstance = function() { + + this.instance = new THREE.DodecahedronGeometry( + this.radius, + this.detail + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Dodecahedron.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'detail' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Dodecahedron to a R3.D3.API.Geometry.Normal.Dodecahedron + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Dodecahedron.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalDodecahedron = new R3.D3.API.Geometry.Normal.Dodecahedron( + apiNormalGeometry, + this.radius, + this.detail + ); + + return apiGeometryNormalDodecahedron; +}; diff --git a/src/r3-d3-geometry-normal-edges.js b/src/r3-d3-geometry-normal-edges.js new file mode 100644 index 0000000..993a6c8 --- /dev/null +++ b/src/r3-d3-geometry-normal-edges.js @@ -0,0 +1,108 @@ +/** + * R3.D3.Geometry.Normal.Edges + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalEdges + * @constructor + */ +R3.D3.Geometry.Normal.Edges = function( + graphics, + apiGeometryNormalEdges +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalEdges)) { + apiGeometryNormalEdges = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_EDGES + }; + } + + R3.D3.API.Geometry.Normal.Edges.call( + this, + apiGeometryNormalEdges, + apiGeometryNormalEdges.geometry, + apiGeometryNormalEdges.thresholdAngle + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalEdges + ); + +}; + +R3.D3.Geometry.Normal.Edges.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Edges.prototype.constructor = R3.D3.Geometry.Normal.Edges; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Edges.prototype.createInstance = function() { + + if (!this.geometry || !this.geometry.instance) { + console.warn('geometry not ready'); + return; + } + + this.instance = new THREE.EdgesGeometry( + this.geometry.instance, + this.thresholdAngle + ); + + console.log('edges instance created'); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Edges.prototype.updateInstance = function(property) { + + if ( + property === 'geometry' || + property === 'thresholdAngle' + ) { + /** + * Could be that geometry was not ready + */ + if (this.instance) { + this.instance.dispose(); + } + + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Edges to a R3.D3.API.Geometry.Normal.Edges + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Edges.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalEdges = new R3.D3.API.Geometry.Normal.Edges( + apiNormalGeometry, + R3.Utils.IdOrNull(this.geometry), + this.thresholdAngle + ); + + return apiGeometryNormalEdges; +}; diff --git a/src/r3-d3-geometry-normal-extrude.js b/src/r3-d3-geometry-normal-extrude.js new file mode 100644 index 0000000..09288f4 --- /dev/null +++ b/src/r3-d3-geometry-normal-extrude.js @@ -0,0 +1,141 @@ +/** + * R3.D3.Geometry.Normal.Extrude + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalExtrude + * @constructor + */ +R3.D3.Geometry.Normal.Extrude = function( + graphics, + apiGeometryNormalExtrude +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalExtrude)) { + apiGeometryNormalExtrude = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_EXTRUDE + }; + } + + R3.D3.API.Geometry.Normal.Extrude.call( + this, + apiGeometryNormalExtrude, + apiGeometryNormalExtrude.shapes, + apiGeometryNormalExtrude.curveSegments, + apiGeometryNormalExtrude.steps, + apiGeometryNormalExtrude.amount, + apiGeometryNormalExtrude.bevelEnabled, + apiGeometryNormalExtrude.bevelThickness, + apiGeometryNormalExtrude.bevelSize, + apiGeometryNormalExtrude.bevelSegments, + apiGeometryNormalExtrude.extrudePath, + apiGeometryNormalExtrude.frames, + apiGeometryNormalExtrude.UVGenerator + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalExtrude + ); + +}; + +R3.D3.Geometry.Normal.Extrude.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Extrude.prototype.constructor = R3.D3.Geometry.Normal.Extrude; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Extrude.prototype.createInstance = function() { + + this.instance = new THREE.ExtrudeGeometry( + this.shapes.map( + function(shape) { + return shape.instance; + } + ), + { + curveSegments : this.curveSegments, + steps : this.steps, + amount : this.amount, + bevelEnabled : this.bevelEnabled, + bevelThickness : this.bevelThickness, + bevelSize : this.bevelSize, + bevelSegments : this.bevelSegments + } + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Extrude.prototype.updateInstance = function(property) { + + if ( + property === 'shapes' || + property === 'curveSegments' || + property === 'steps' || + property === 'amount' || + property === 'bevelEnabled' || + property === 'bevelThickness' || + property === 'bevelSize' || + property === 'bevelSegments' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + console.warn('do other properties here'); + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Extrude to a R3.D3.API.Geometry.Normal.Extrude + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Extrude.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalExtrude = new R3.D3.API.Geometry.Normal.Extrude( + apiNormalGeometry, + this.shapes.map( + function(shape) { + return R3.Utils.IdOrNull(shape); + } + ), + this.curveSegments, + this.steps, + this.amount, + this.bevelEnabled, + this.bevelThickness, + this.bevelSize, + this.bevelSegments, + R3.Utils.IdOrNull(this.extrudePath), + this.frames.map(function(frame){ + return R3.Utils.IdOrNull(frame); + }), + R3.Utils.IdOrNull(this.UVGenerator) + ); + + return apiGeometryNormalExtrude; +}; diff --git a/src/r3-d3-geometry-normal-icosahedron.js b/src/r3-d3-geometry-normal-icosahedron.js new file mode 100644 index 0000000..e707152 --- /dev/null +++ b/src/r3-d3-geometry-normal-icosahedron.js @@ -0,0 +1,97 @@ +/** + * R3.D3.Geometry.Normal.Icosahedron + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalIcosahedron + * @constructor + */ +R3.D3.Geometry.Normal.Icosahedron = function( + graphics, + apiGeometryNormalIcosahedron +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalIcosahedron)) { + apiGeometryNormalIcosahedron = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_ICOSAHEDRON + }; + } + + R3.D3.API.Geometry.Normal.Icosahedron.call( + this, + apiGeometryNormalIcosahedron, + apiGeometryNormalIcosahedron.radius, + apiGeometryNormalIcosahedron.detail + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalIcosahedron + ); + +}; + +R3.D3.Geometry.Normal.Icosahedron.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Icosahedron.prototype.constructor = R3.D3.Geometry.Normal.Icosahedron; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Icosahedron.prototype.createInstance = function() { + + this.instance = new THREE.IcosahedronGeometry( + this.radius, + this.detail + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Icosahedron.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'detail' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Icosahedron to a R3.D3.API.Geometry.Normal.Icosahedron + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Icosahedron.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalIcosahedron = new R3.D3.API.Geometry.Normal.Icosahedron( + apiNormalGeometry, + this.radius, + this.detail + ); + + return apiGeometryNormalIcosahedron; +}; diff --git a/src/r3-d3-geometry-normal-lathe.js b/src/r3-d3-geometry-normal-lathe.js new file mode 100644 index 0000000..668dc86 --- /dev/null +++ b/src/r3-d3-geometry-normal-lathe.js @@ -0,0 +1,113 @@ +/** + * R3.D3.Geometry.Normal.Lathe + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalLathe + * @constructor + */ +R3.D3.Geometry.Normal.Lathe = function( + graphics, + apiGeometryNormalLathe +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalLathe)) { + apiGeometryNormalLathe = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_LATHE + }; + } + + R3.D3.API.Geometry.Normal.Lathe.call( + this, + apiGeometryNormalLathe, + apiGeometryNormalLathe.points, + apiGeometryNormalLathe.segments, + apiGeometryNormalLathe.phiStart, + apiGeometryNormalLathe.phiLength + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalLathe + ); + +}; + +R3.D3.Geometry.Normal.Lathe.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Lathe.prototype.constructor = R3.D3.Geometry.Normal.Lathe; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Lathe.prototype.createInstance = function() { + + this.instance = new THREE.LatheGeometry( + this.points.map( + function(point) { + return point.instance; + } + ), + this.segments, + this.phiStart, + this.phiLength + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Lathe.prototype.updateInstance = function(property) { + + if ( + property === 'points' || + property === 'segments' || + property === 'phiStart' || + property === 'phiLength' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Lathe to a R3.D3.API.Geometry.Normal.Lathe + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Lathe.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalLathe = new R3.D3.API.Geometry.Normal.Lathe( + apiNormalGeometry, + this.points.map( + function(point) { + return point.toApiObject(); + } + ), + this.segments, + this.phiStart, + this.phiLength + ); + + return apiGeometryNormalLathe; +}; diff --git a/src/r3-d3-geometry-normal-octahedron.js b/src/r3-d3-geometry-normal-octahedron.js new file mode 100644 index 0000000..1156927 --- /dev/null +++ b/src/r3-d3-geometry-normal-octahedron.js @@ -0,0 +1,97 @@ +/** + * R3.D3.Geometry.Normal.Octahedron + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalOctahedron + * @constructor + */ +R3.D3.Geometry.Normal.Octahedron = function( + graphics, + apiGeometryNormalOctahedron +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalOctahedron)) { + apiGeometryNormalOctahedron = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_OCTAHEDRON + }; + } + + R3.D3.API.Geometry.Normal.Octahedron.call( + this, + apiGeometryNormalOctahedron, + apiGeometryNormalOctahedron.radius, + apiGeometryNormalOctahedron.detail + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalOctahedron + ); + +}; + +R3.D3.Geometry.Normal.Octahedron.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Octahedron.prototype.constructor = R3.D3.Geometry.Normal.Octahedron; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Octahedron.prototype.createInstance = function() { + + this.instance = new THREE.OctahedronGeometry( + this.radius, + this.detail + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Octahedron.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'detail' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Octahedron to a R3.D3.API.Geometry.Normal.Octahedron + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Octahedron.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalOctahedron = new R3.D3.API.Geometry.Normal.Octahedron( + apiNormalGeometry, + this.radius, + this.detail + ); + + return apiGeometryNormalOctahedron; +}; diff --git a/src/r3-d3-geometry-normal-parametric.js b/src/r3-d3-geometry-normal-parametric.js new file mode 100644 index 0000000..0744768 --- /dev/null +++ b/src/r3-d3-geometry-normal-parametric.js @@ -0,0 +1,101 @@ +/** + * R3.D3.Geometry.Normal.Parametric + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalParametric + * @constructor + */ +R3.D3.Geometry.Normal.Parametric = function( + graphics, + apiGeometryNormalParametric +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalParametric)) { + apiGeometryNormalParametric = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_PARAMETRIC + }; + } + + R3.D3.API.Geometry.Normal.Parametric.call( + this, + apiGeometryNormalParametric, + apiGeometryNormalParametric.generatorFn, + apiGeometryNormalParametric.slices, + apiGeometryNormalParametric.stacks + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalParametric + ); + +}; + +R3.D3.Geometry.Normal.Parametric.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Parametric.prototype.constructor = R3.D3.Geometry.Normal.Parametric; + +/** + * Create Instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Parametric.prototype.createInstance = function() { + + this.instance = new THREE.ParametricGeometry( + new Function('u', 'v', this.generatorFn).bind(this), + this.slices, + this.stacks + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Parametric.prototype.updateInstance = function(property) { + + if ( + property === 'generatorFn' || + property === 'slices' || + property === 'stacks' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Parametric to a R3.D3.API.Geometry.Normal.Parametric + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Parametric.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalParametric = new R3.D3.API.Geometry.Normal.Parametric( + apiNormalGeometry, + this.generatorFn, + this.slices, + this.stacks + ); + + return apiGeometryNormalParametric; +}; diff --git a/src/r3-d3-geometry-normal-plane.js b/src/r3-d3-geometry-normal-plane.js new file mode 100644 index 0000000..386201d --- /dev/null +++ b/src/r3-d3-geometry-normal-plane.js @@ -0,0 +1,100 @@ +/** + * R3.D3.Geometry.Normal.Plane + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalPlane + * @constructor + */ +R3.D3.Geometry.Normal.Plane = function( + graphics, + apiGeometryNormalPlane +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalPlane)) { + apiGeometryNormalPlane = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_PLANE + }; + } + + R3.D3.API.Geometry.Normal.Plane.call( + this, + apiGeometryNormalPlane, + apiGeometryNormalPlane.width, + apiGeometryNormalPlane.height, + apiGeometryNormalPlane.widthSegments, + apiGeometryNormalPlane.heightSegments + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalPlane + ); + +}; + +R3.D3.Geometry.Normal.Plane.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Plane.prototype.constructor = R3.D3.Geometry.Normal.Plane; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Plane.prototype.createInstance = function() { + + this.instance = new THREE.PlaneGeometry( + this.width, + this.height, + this.widthSegments, + this.heightSegments + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Plane.prototype.updateInstance = function(property) { + + if ( + property === 'width' || + property === 'height' || + property === 'widthSegments' || + property === 'heightSegments' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Plane to a R3.D3.API.Geometry.Normal.Plane + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Plane.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalPlane = new R3.D3.API.Geometry.Normal.Plane( + apiNormalGeometry, + this.width, + this.height, + this.widthSegments, + this.heightSegments + ); + + return apiGeometryNormalPlane; +}; diff --git a/src/r3-d3-geometry-normal-polyhedron.js b/src/r3-d3-geometry-normal-polyhedron.js new file mode 100644 index 0000000..baa1c86 --- /dev/null +++ b/src/r3-d3-geometry-normal-polyhedron.js @@ -0,0 +1,116 @@ +/** + * R3.D3.Geometry.Normal.Polyhedron + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalPolyhedron + * @constructor + */ +R3.D3.Geometry.Normal.Polyhedron = function( + graphics, + apiGeometryNormalPolyhedron +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalPolyhedron)) { + apiGeometryNormalPolyhedron = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_POLYHEDRON + }; + } + + R3.D3.API.Geometry.Normal.Polyhedron.call( + this, + apiGeometryNormalPolyhedron, + apiGeometryNormalPolyhedron.vertices, + apiGeometryNormalPolyhedron.indices, + apiGeometryNormalPolyhedron.radius, + apiGeometryNormalPolyhedron.detail + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalPolyhedron + ); + +}; + +R3.D3.Geometry.Normal.Polyhedron.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Polyhedron.prototype.constructor = R3.D3.Geometry.Normal.Polyhedron; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Polyhedron.prototype.createInstance = function() { + + this.instance = new THREE.PolyhedronGeometry( + this.vertices.map( + function(vertex) { + return vertex.position.instance; + } + ), + this.indices.map( + function(index) { + return index.instance; + } + ), + this.radius, + this.detail + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Polyhedron.prototype.updateInstance = function(property) { + + if ( + property === 'vertices' || + property === 'indices' || + property === 'radius' || + property === 'detail' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Polyhedron to a R3.D3.API.Geometry.Normal.Polyhedron + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Polyhedron.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalPolyhedron = new R3.D3.API.Geometry.Normal.Polyhedron( + apiNormalGeometry, + this.vertices.map( + function(vertex){ + return vertex.toApiObject(); + } + ), + this.indices.map( + function(index){ + return index.toApiObject(); + } + ), + this.radius, + this.detail + ); + + return apiGeometryNormalPolyhedron; +}; diff --git a/src/r3-d3-geometry-normal-ring.js b/src/r3-d3-geometry-normal-ring.js new file mode 100644 index 0000000..7104b6a --- /dev/null +++ b/src/r3-d3-geometry-normal-ring.js @@ -0,0 +1,113 @@ +/** + * R3.D3.Geometry.Normal.Ring + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalRing + * @constructor + */ +R3.D3.Geometry.Normal.Ring = function( + graphics, + apiGeometryNormalRing +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalRing)) { + apiGeometryNormalRing = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_RING + }; + } + + R3.D3.API.Geometry.Normal.Ring.call( + this, + apiGeometryNormalRing, + apiGeometryNormalRing.innerRadius, + apiGeometryNormalRing.outerRadius, + apiGeometryNormalRing.thetaSegments, + apiGeometryNormalRing.phiSegments, + apiGeometryNormalRing.thetaStart, + apiGeometryNormalRing.thetaLength + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalRing + ); + +}; + +R3.D3.Geometry.Normal.Ring.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Ring.prototype.constructor = R3.D3.Geometry.Normal.Ring; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Ring.prototype.createInstance = function() { + + this.instance = new THREE.RingGeometry( + this.innerRadius, + this.outerRadius, + this.thetaSegments, + this.phiSegments, + this.thetaStart, + this.thetaLength + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Ring.prototype.updateInstance = function(property) { + + if ( + property === 'innerRadius' || + property === 'outerRadius' || + property === 'thetaSegments' || + property === 'phiSegments' || + property === 'thetaStart' || + property === 'thetaLength' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Ring to a R3.D3.API.Geometry.Normal.Ring + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Ring.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalRing = new R3.D3.API.Geometry.Normal.Ring( + apiNormalGeometry, + this.innerRadius, + this.outerRadius, + this.thetaSegments, + this.phiSegments, + this.thetaStart, + this.thetaLength + ); + + return apiGeometryNormalRing; +}; diff --git a/src/r3-d3-geometry-normal-shape.js b/src/r3-d3-geometry-normal-shape.js new file mode 100644 index 0000000..dcaa368 --- /dev/null +++ b/src/r3-d3-geometry-normal-shape.js @@ -0,0 +1,112 @@ +/** + * R3.D3.Geometry.Normal.Shape + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalShape + * @constructor + */ +R3.D3.Geometry.Normal.Shape = function( + graphics, + apiGeometryNormalShape +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalShape)) { + apiGeometryNormalShape = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_SHAPE + }; + } + + R3.D3.API.Geometry.Normal.Shape.call( + this, + apiGeometryNormalShape, + apiGeometryNormalShape.shapes, + apiGeometryNormalShape.curveSegments + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalShape + ); + +}; + +R3.D3.Geometry.Normal.Shape.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Shape.prototype.constructor = R3.D3.Geometry.Normal.Shape; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Shape.prototype.createInstance = function() { + + if (this.shapes.length === 0) { + console.warn('shapes are not ready for this instance'); + return; + } + + this.instance = new THREE.ShapeGeometry( + this.shapes.map( + function(shape) { + return shape.instance; + } + ), + this.curveSegments + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Shape.prototype.updateInstance = function(property) { + + if ( + property === 'shapes' || + property === 'curveSegments' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + console.warn('do other properties here'); + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Shape to a R3.D3.API.Geometry.Normal.Shape + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Shape.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalShape = new R3.D3.API.Geometry.Normal.Shape( + apiNormalGeometry, + this.shapes.map( + function(shape) { + return R3.Utils.IdOrNull(shape); + } + ), + this.curveSegments + ); + + return apiGeometryNormalShape; +}; diff --git a/src/r3-d3-geometry-normal-sphere.js b/src/r3-d3-geometry-normal-sphere.js new file mode 100644 index 0000000..4eaddf1 --- /dev/null +++ b/src/r3-d3-geometry-normal-sphere.js @@ -0,0 +1,117 @@ +/** + * R3.D3.Geometry.Normal.Sphere + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalSphere + * @constructor + */ +R3.D3.Geometry.Normal.Sphere = function( + graphics, + apiGeometryNormalSphere +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalSphere)) { + apiGeometryNormalSphere = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_SPHERE + }; + } + + R3.D3.API.Geometry.Normal.Sphere.call( + this, + apiGeometryNormalSphere, + apiGeometryNormalSphere.radius, + apiGeometryNormalSphere.widthSegments, + apiGeometryNormalSphere.heightSegments, + apiGeometryNormalSphere.phiStart, + apiGeometryNormalSphere.phiLength, + apiGeometryNormalSphere.thetaStart, + apiGeometryNormalSphere.thetaLength + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalSphere + ); + +}; + +R3.D3.Geometry.Normal.Sphere.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Sphere.prototype.constructor = R3.D3.Geometry.Normal.Sphere; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Sphere.prototype.createInstance = function() { + + this.instance = new THREE.SphereGeometry( + this.radius, + this.widthSegments, + this.heightSegments, + this.phiStart, + this.phiLength, + this.thetaStart, + this.thetaLength + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Sphere.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'widthSegments' || + property === 'heightSegments' || + property === 'phiStart' || + property === 'phiLength' || + property === 'thetaStart' || + property === 'thetaLength' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Sphere to a R3.D3.API.Geometry.Normal.Sphere + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Sphere.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalSphere = new R3.D3.API.Geometry.Normal.Sphere( + apiNormalGeometry, + this.radius, + this.widthSegments, + this.heightSegments, + this.phiStart, + this.phiLength, + this.thetaStart, + this.thetaLength + ); + + return apiGeometryNormalSphere; +}; diff --git a/src/r3-d3-geometry-normal-tetrahedron.js b/src/r3-d3-geometry-normal-tetrahedron.js new file mode 100644 index 0000000..87d135f --- /dev/null +++ b/src/r3-d3-geometry-normal-tetrahedron.js @@ -0,0 +1,97 @@ +/** + * R3.D3.Geometry.Normal.Tetrahedron + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalTetrahedron + * @constructor + */ +R3.D3.Geometry.Normal.Tetrahedron = function( + graphics, + apiGeometryNormalTetrahedron +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalTetrahedron)) { + apiGeometryNormalTetrahedron = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TETRAHEDRON + }; + } + + R3.D3.API.Geometry.Normal.Tetrahedron.call( + this, + apiGeometryNormalTetrahedron, + apiGeometryNormalTetrahedron.radius, + apiGeometryNormalTetrahedron.detail + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalTetrahedron + ); + +}; + +R3.D3.Geometry.Normal.Tetrahedron.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Tetrahedron.prototype.constructor = R3.D3.Geometry.Normal.Tetrahedron; + +/** + * Create Instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Tetrahedron.prototype.createInstance = function() { + + this.instance = new THREE.TetrahedronGeometry( + this.radius, + this.detail + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Tetrahedron.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'detail' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Tetrahedron to a R3.D3.API.Geometry.Normal.Tetrahedron + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Tetrahedron.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalTetrahedron = new R3.D3.API.Geometry.Normal.Tetrahedron( + apiNormalGeometry, + this.radius, + this.detail + ); + + return apiGeometryNormalTetrahedron; +}; diff --git a/src/r3-d3-geometry-normal-text.js b/src/r3-d3-geometry-normal-text.js new file mode 100644 index 0000000..3c358c2 --- /dev/null +++ b/src/r3-d3-geometry-normal-text.js @@ -0,0 +1,141 @@ +/** + * R3.D3.Geometry.Normal.Text + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalText + * @constructor + */ +R3.D3.Geometry.Normal.Text = function( + graphics, + apiGeometryNormalText +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalText)) { + apiGeometryNormalText = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TEXT + }; + } + + R3.D3.API.Geometry.Normal.Text.call( + this, + apiGeometryNormalText, + apiGeometryNormalText.text, + apiGeometryNormalText.font, + apiGeometryNormalText.size, + apiGeometryNormalText.height, + apiGeometryNormalText.curveSegments, + apiGeometryNormalText.bevelEnabled, + apiGeometryNormalText.bevelThickness, + apiGeometryNormalText.bevelSize, + apiGeometryNormalText.bevelSegments + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalText + ); + +}; + +R3.D3.Geometry.Normal.Text.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Text.prototype.constructor = R3.D3.Geometry.Normal.Text; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Text.prototype.createInstance = function() { + + if (!this.font || !this.font.instance) { + console.warn('font not ready for this instance'); + return; + } + + this.instance = new THREE.TextGeometry( + this.text, + { + font : this.font.instance, + size : this.size, + curveSegments : this.curveSegments, + steps : this.steps, + amount : this.amount, + bevelEnabled : this.bevelEnabled, + bevelThickness : this.bevelThickness, + bevelSize : this.bevelSize, + bevelSegments : this.bevelSegments + } + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Text.prototype.updateInstance = function(property) { + + if ( + property === 'text' || + property === 'font' || + property === 'size' || + property === 'height' || + property === 'curveSegments' || + property === 'bevelEnabled' || + property === 'bevelThickness' || + property === 'bevelSize' || + property === 'bevelSegments' + ) { + /** + * Could be that the instance does not exist - because font was not ready + */ + if (this.instance) { + this.instance.dispose(); + } + + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + console.warn('do other properties here'); + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Text to a R3.D3.API.Geometry.Normal.Text + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Text.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalText = new R3.D3.API.Geometry.Normal.Text( + apiNormalGeometry, + this.text, + R3.Utils.IdOrNull(this.font), + this.size, + this.height, + this.curveSegments, + this.bevelEnabled, + this.bevelThickness, + this.bevelSize, + this.bevelSegments + ); + + return apiGeometryNormalText; +}; diff --git a/src/r3-d3-geometry-normal-torus-knot.js b/src/r3-d3-geometry-normal-torus-knot.js new file mode 100644 index 0000000..f52a867 --- /dev/null +++ b/src/r3-d3-geometry-normal-torus-knot.js @@ -0,0 +1,113 @@ +/** + * R3.D3.Geometry.Normal.TorusKnot + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalTorusKnot + * @constructor + */ +R3.D3.Geometry.Normal.TorusKnot = function( + graphics, + apiGeometryNormalTorusKnot +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalTorusKnot)) { + apiGeometryNormalTorusKnot = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TORUS_KNOT + }; + } + + R3.D3.API.Geometry.Normal.TorusKnot.call( + this, + apiGeometryNormalTorusKnot, + apiGeometryNormalTorusKnot.radius, + apiGeometryNormalTorusKnot.tube, + apiGeometryNormalTorusKnot.radialSegments, + apiGeometryNormalTorusKnot.tubularSegments, + apiGeometryNormalTorusKnot.p, + apiGeometryNormalTorusKnot.q + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalTorusKnot + ); + +}; + +R3.D3.Geometry.Normal.TorusKnot.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.TorusKnot.prototype.constructor = R3.D3.Geometry.Normal.TorusKnot; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.TorusKnot.prototype.createInstance = function() { + + this.instance = new THREE.TorusKnotGeometry( + this.radius, + this.tube, + this.radialSegments, + this.tubularSegments, + this.p, + this.q + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.TorusKnot.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'tube' || + property === 'radialSegments' || + property === 'tubularSegments' || + property === 'p' || + property === 'q' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.TorusKnot to a R3.D3.API.Geometry.Normal.TorusKnot + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.TorusKnot.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalTorusKnot = new R3.D3.API.Geometry.Normal.TorusKnot( + apiNormalGeometry, + this.radius, + this.tube, + this.radialSegments, + this.tubularSegments, + this.p, + this.q + ); + + return apiGeometryNormalTorusKnot; +}; diff --git a/src/r3-d3-geometry-normal-torus.js b/src/r3-d3-geometry-normal-torus.js new file mode 100644 index 0000000..61182f2 --- /dev/null +++ b/src/r3-d3-geometry-normal-torus.js @@ -0,0 +1,109 @@ +/** + * R3.D3.Geometry.Normal.Torus + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalTorus + * @constructor + */ +R3.D3.Geometry.Normal.Torus = function( + graphics, + apiGeometryNormalTorus +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalTorus)) { + apiGeometryNormalTorus = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TORUS + }; + } + + R3.D3.API.Geometry.Normal.Torus.call( + this, + apiGeometryNormalTorus, + apiGeometryNormalTorus.radius, + apiGeometryNormalTorus.tube, + apiGeometryNormalTorus.radialSegments, + apiGeometryNormalTorus.tubularSegments, + apiGeometryNormalTorus.arc + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalTorus + ); + +}; + +R3.D3.Geometry.Normal.Torus.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Torus.prototype.constructor = R3.D3.Geometry.Normal.Torus; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Torus.prototype.createInstance = function() { + + this.instance = new THREE.TorusGeometry( + this.radius, + this.tube, + this.radialSegments, + this.tubularSegments, + this.arc + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Torus.prototype.updateInstance = function(property) { + + if ( + property === 'radius' || + property === 'tube' || + property === 'radialSegments' || + property === 'tubularSegments' || + property === 'arc' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Torus to a R3.D3.API.Geometry.Normal.Torus + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Torus.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalTorus = new R3.D3.API.Geometry.Normal.Torus( + apiNormalGeometry, + this.radius, + this.tube, + this.radialSegments, + this.tubularSegments, + this.arc + ); + + return apiGeometryNormalTorus; +}; diff --git a/src/r3-d3-geometry-normal-tube.js b/src/r3-d3-geometry-normal-tube.js new file mode 100644 index 0000000..46e78e0 --- /dev/null +++ b/src/r3-d3-geometry-normal-tube.js @@ -0,0 +1,109 @@ +/** + * R3.D3.Geometry.Normal.Tube + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalTube + * @constructor + */ +R3.D3.Geometry.Normal.Tube = function( + graphics, + apiGeometryNormalTube +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalTube)) { + apiGeometryNormalTube = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_TUBE + }; + } + + R3.D3.API.Geometry.Normal.Tube.call( + this, + apiGeometryNormalTube, + apiGeometryNormalTube.path, + apiGeometryNormalTube.tubularSegments, + apiGeometryNormalTube.radius, + apiGeometryNormalTube.radialSegments, + apiGeometryNormalTube.closed + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalTube + ); + +}; + +R3.D3.Geometry.Normal.Tube.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Tube.prototype.constructor = R3.D3.Geometry.Normal.Tube; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Tube.prototype.createInstance = function() { + + this.instance = new THREE.TubeGeometry( + this.path.instance, + this.tubularSegments, + this.radius, + this.radialSegments, + this.closed + ); + + this.computeVertexNormals(); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Tube.prototype.updateInstance = function(property) { + + if ( + property === 'path' || + property === 'tubularSegments' || + property === 'radius' || + property === 'radialSegments' || + property === 'closed' + ) { + this.instance.dispose(); + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Tube to a R3.D3.API.Geometry.Normal.Tube + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Tube.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalTube = new R3.D3.API.Geometry.Normal.Tube( + apiNormalGeometry, + R3.Utils.IdOrNull(this.path), + this.tubularSegments, + this.radius, + this.radialSegments, + this.closed + ); + + return apiGeometryNormalTube; +}; diff --git a/src/r3-d3-geometry-normal-wireframe.js b/src/r3-d3-geometry-normal-wireframe.js new file mode 100644 index 0000000..3198057 --- /dev/null +++ b/src/r3-d3-geometry-normal-wireframe.js @@ -0,0 +1,104 @@ +/** + * R3.D3.Geometry.Normal.Wireframe + * @param graphics R3.GraphicsRuntime + * @param apiGeometryNormalWireframe + * @constructor + */ +R3.D3.Geometry.Normal.Wireframe = function( + graphics, + apiGeometryNormalWireframe +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiGeometryNormalWireframe)) { + apiGeometryNormalWireframe = { + geometryType : R3.D3.API.Geometry.GEOMETRY_TYPE_NORMAL_WIREFRAME + }; + } + + R3.D3.API.Geometry.Normal.Wireframe.call( + this, + apiGeometryNormalWireframe, + apiGeometryNormalWireframe.geometry + ); + + R3.D3.Geometry.Normal.call( + this, + this.graphics, + apiGeometryNormalWireframe + ); + +}; + +R3.D3.Geometry.Normal.Wireframe.prototype = Object.create(R3.D3.Geometry.Normal.prototype); +R3.D3.Geometry.Normal.Wireframe.prototype.constructor = R3.D3.Geometry.Normal.Wireframe; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Geometry.Normal.Wireframe.prototype.createInstance = function() { + + if (!this.geometry || !this.geometry.instance) { + console.warn('geometry not ready'); + return; + } + + this.instance = new THREE.WireframeGeometry( + this.geometry.instance + ); + + console.log('wireframe instance created'); + + R3.D3.Geometry.Normal.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Geometry.Normal.Wireframe.prototype.updateInstance = function(property) { + + if ( + property === 'geometry' + ) { + /** + * Could be that geometry was not ready + */ + if (this.instance) { + this.instance.dispose(); + } + + this.createInstance(); + + if (this.parentMesh && this.parentMesh.instance) { + this.parentMesh.instance.geometry = this.instance; + + if (this.parentMesh.helper) { + this.parentMesh.removeHelper(); + this.parentMesh.createHelper(); + } + } + + return; + } + + R3.D3.Geometry.Normal.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Geometry.Normal.Wireframe to a R3.D3.API.Geometry.Normal.Wireframe + * @returns {R3.D3.API.Geometry.Normal} + */ +R3.D3.Geometry.Normal.Wireframe.prototype.toApiObject = function() { + + var apiNormalGeometry = R3.D3.Geometry.Normal.prototype.toApiObject.call(this); + + var apiGeometryNormalWireframe = new R3.D3.API.Geometry.Normal.Wireframe( + apiNormalGeometry, + R3.Utils.IdOrNull(this.geometry) + ); + + return apiGeometryNormalWireframe; +}; diff --git a/src/r3-d3-helper.js b/src/r3-d3-helper.js new file mode 100644 index 0000000..3ecef8d --- /dev/null +++ b/src/r3-d3-helper.js @@ -0,0 +1,159 @@ +/** + * Helpers for displaying outlines or making 'invisible' scene objects visible + * @param graphics R3.GraphicsRuntime + * @param id + * @param name + * @param object + * @param helperType + * @param parentEntity + * @constructor + */ +R3.D3.Helper = function( + graphics, + id, + name, + object, + helperType, + parentEntity +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Helper (' + id + ')'; + } + this.name = name; + + if (R3.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 (R3.Utils.UndefinedOrNull(helperType)) { + + helperType = R3.D3.Helper.HELPER_TYPE_NONE; + + if ( + object instanceof R3.D3.Mesh && + object.meshType !== R3.D3.API.Object.OBJECT_TYPE_MESH_CURVE + ) { + helperType = R3.D3.Helper.HELPER_TYPE_EDGES; + } + + if (object instanceof R3.D3.Light) { + if (object.lightType === R3.D3.API.Light.LIGHT_TYPE_DIRECTIONAL) { + helperType = R3.D3.Helper.HELPER_TYPE_DIRECTIONAL_LIGHT; + } + + if (object.lightType === R3.D3.API.Light.LIGHT_TYPE_POINT) { + helperType = R3.D3.Helper.HELPER_TYPE_POINT_LIGHT; + } + + if (object.lightType === R3.D3.API.Light.LIGHT_TYPE_SPOT) { + helperType = R3.D3.Helper.HELPER_TYPE_SPOT_LIGHT; + } + } + + if (object instanceof R3.D3.Skeleton) { + helperType = R3.D3.Helper.HELPER_TYPE_SKELETON; + } + } + this.helperType = helperType; + + if (R3.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; + + this.createInstance(); + /** + * A helper as a component - does this make sense at all? + */ + // R3.Component.call( + // this, + // R3.Component.HELPER + // ); +}; + +R3.D3.Helper.prototype = Object.create(R3.Component.prototype); +R3.D3.Helper.prototype.constructor = R3.D3.Helper; + +/** + * Helper types + * @type {string} + */ +R3.D3.Helper.HELPER_TYPE_NONE = 0x0; +R3.D3.Helper.HELPER_TYPE_EDGES = 0x1; +R3.D3.Helper.HELPER_TYPE_DIRECTIONAL_LIGHT = 0x2; +R3.D3.Helper.HELPER_TYPE_SPOT_LIGHT = 0x3; +R3.D3.Helper.HELPER_TYPE_POINT_LIGHT = 0x4; +R3.D3.Helper.HELPER_TYPE_WIREFRAME = 0x5; +R3.D3.Helper.HELPER_TYPE_SKELETON = 0x6; + +/** + * Creates a helper instance + */ +R3.D3.Helper.prototype.createInstance = function() { + + if (this.helperType === R3.D3.Helper.HELPER_TYPE_EDGES) { + this.instance = new THREE.LineSegments( + new THREE.EdgesGeometry( + this.object.instance.geometry + ), + new THREE.LineBasicMaterial( + { + color:0x00ff00, + linewidth:2 + } + ) + ); + + this.updateInstance(); + } + + if (this.helperType === R3.D3.Helper.HELPER_TYPE_DIRECTIONAL_LIGHT) { + this.instance = new THREE.DirectionalLightHelper(this.object.instance); + } + + if (this.helperType === R3.D3.Helper.HELPER_TYPE_POINT_LIGHT) { + this.instance = new THREE.PointLightHelper(this.object.instance, 1); + } + + if (this.helperType === R3.D3.Helper.HELPER_TYPE_SPOT_LIGHT) { + this.instance = new THREE.SpotLightHelper(this.object.instance); + } + + if (this.helperType === R3.D3.Helper.HELPER_TYPE_WIREFRAME) { + this.instance = new THREE.WireframeGeometry(this.object.instance, 0x00FF00); + } + + if (this.helperType === R3.D3.Helper.HELPER_TYPE_SKELETON) { + this.instance = new THREE.SkeletonHelper(this.object.instance); + } + +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Helper.prototype.updateInstance = function() { + + this.instance.position.copy(this.object.instance.position); + this.instance.scale.copy(this.object.instance.scale); + this.instance.quaternion.copy(this.object.instance.quaternion); + + if (this.object.parentMesh && this.object.parentMesh.instance) { + this.object.parentMesh.instance.add(this.instance); + + this.instance.applyMatrix(this.object.instance.matrix); + this.instance.updateMatrix(); + + this.instance.updateMatrixWorld(); + } +}; diff --git a/src/r3-d3-light-a.js b/src/r3-d3-light-a.js new file mode 100644 index 0000000..7a0a01d --- /dev/null +++ b/src/r3-d3-light-a.js @@ -0,0 +1,130 @@ +/** + * R3.D3.Light + * @param graphics R3.GraphicsRuntime + * @param apiLight R3.D3.API.Light + * @constructor + */ +R3.D3.Light = function( + graphics, + apiLight +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiLight)) { + apiLight = {}; + } + + R3.D3.API.Light.call( + this, + apiLight.id, + apiLight.name, + apiLight.lightType, + apiLight.color, + apiLight.intensity, + apiLight.parentScene, + apiLight.parentEntity + ); + + this.color = new R3.Color( + this.graphics, + this.color, + this + ); + + var linkedObjects = { + 'parentScene' : R3.D3.Scene + }; + + switch (apiLight.lightType) { + + case R3.D3.API.Light.LIGHT_TYPE_DIRECTIONAL : + case R3.D3.API.Light.LIGHT_TYPE_SPOT : + linkedObjects.shadow = R3.D3.Shadow; + linkedObjects.target = R3.Component; + break; + case R3.D3.API.Light.LIGHT_TYPE_POINT : + linkedObjects.shadow = R3.D3.Shadow; + break; + case R3.D3.API.Light.LIGHT_TYPE_RECT_AREA : + linkedObjects.target = R3.Component; + break; + default: + break; + } + + R3.Component.call( + this, + linkedObjects + ); + +}; + +R3.D3.Light.prototype = Object.create(R3.Component.prototype); +R3.D3.Light.prototype.constructor = R3.D3.Light; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Light.prototype.createInstance = function() { + + if (!this.instance) { + console.warn('call the specific light createInstance first before calling its parent'); + return; + } + + this.instance.color.set(this.color.toHex()); + + this.instance.intensity = this.intensity; + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Light.prototype.updateInstance = function(property) { + + if (R3.Utils.UndefinedOrNull(property)) { + console.warn('no property for light: ' + this.name); + } + + if (property === 'lightType') { + var componentType = R3.D3.API.Light.GetComponentType(this.lightType); + this.replace(componentType); + return; + } + + if (property === 'color') { + this.instance.color.set(this.color.toHex()); + } + + if (property === 'intensity') { + this.instance.intensity = this.intensity; + } + + if (property === 'parentScene') { + console.warn('todo: implement parentScene change for light') + } + + R3.Component.prototype.updateInstance.call(this, property); + +}; + +/** + * Converts a R3.D3.Light to a R3.D3.API.Light + * @returns {R3.D3.API.Light} + */ +R3.D3.Light.prototype.toApiObject = function() { + return new R3.D3.API.Light( + this.id, + this.name, + this.lightType, + this.color.toApiObject(), + this.intensity, + R3.Utils.IdOrNull(this.parentScene), + R3.Utils.IdOrNull(this.parentEntity) + ); +}; diff --git a/src/r3-d3-light-ambient.js b/src/r3-d3-light-ambient.js new file mode 100644 index 0000000..7d90149 --- /dev/null +++ b/src/r3-d3-light-ambient.js @@ -0,0 +1,64 @@ +/** + * R3.D3.Light.Ambient + * @param graphics R3.GraphicsRuntime + * @param apiAmbientLight + * @constructor + */ +R3.D3.Light.Ambient = function( + graphics, + apiAmbientLight +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiAmbientLight)) { + apiAmbientLight = { + lightType : R3.D3.API.Light.LIGHT_TYPE_AMBIENT + }; + } + + R3.D3.API.Light.Ambient.call( + this, + apiAmbientLight + ); + + R3.D3.Light.call( + this, + this.graphics, + apiAmbientLight + ); + +}; + +R3.D3.Light.Ambient.prototype = Object.create(R3.D3.Light.prototype); +R3.D3.Light.Ambient.prototype.constructor = R3.D3.Light.Ambient; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Light.Ambient.prototype.createInstance = function() { + + this.instance = new THREE.AmbientLight(); + + R3.D3.Light.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Light.Ambient.prototype.updateInstance = function(property) { + R3.D3.Light.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Light to a R3.D3.API.Light + * @returns {R3.D3.API.Light} + */ +R3.D3.Light.Ambient.prototype.toApiObject = function() { + + var apiLight = R3.D3.Light.prototype.toApiObject.call(this); + + return apiLight; +}; diff --git a/src/r3-d3-light-directional.js b/src/r3-d3-light-directional.js new file mode 100644 index 0000000..8648354 --- /dev/null +++ b/src/r3-d3-light-directional.js @@ -0,0 +1,177 @@ +/** + * R3.D3.Light.Directional + * @param graphics R3.GraphicsRuntime + * @param apiDirectionalLight + * @constructor + */ +R3.D3.Light.Directional = function( + graphics, + apiDirectionalLight +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiDirectionalLight)) { + apiDirectionalLight = { + lightType : R3.D3.API.Light.LIGHT_TYPE_DIRECTIONAL + }; + } + + R3.D3.API.Light.Directional.call( + this, + apiDirectionalLight, + apiDirectionalLight.castShadow, + apiDirectionalLight.position, + apiDirectionalLight.shadow, + apiDirectionalLight.target + ); + + this.position = new R3.Vector3( + this.graphics, + this.position, + this + ); + + if (this.shadow instanceof R3.D3.API.Shadow.Directional) { + this.shadow = new R3.D3.Shadow.Directional( + this.graphics, + this.shadow + ) + } + + R3.D3.Light.call( + this, + this.graphics, + apiDirectionalLight + ); + +}; + +R3.D3.Light.Directional.prototype = Object.create(R3.D3.Light.prototype); +R3.D3.Light.Directional.prototype.constructor = R3.D3.Light.Directional; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Light.Directional.prototype.createInstance = function() { + + this.instance = new THREE.DirectionalLight(); + + this.instance.castShadow = this.castShadow; + + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + + /** + * Shadows work a little different - they are created internally by + * threejs - so we do it the other way around - we create our shadow object, + * and assign its properties from the one provided by threejs. + * + * If we already have a shadow object - it was loaded from the API, so we assign + * to our new shadow object the values from it. + * + * If we don't, we create a new one, and update it with the defaults from threejs + */ + + if (this.shadow === null) { + + /** + * This component is created during runtime + */ + this.shadow = new R3.D3.Shadow.Directional(this.graphics); + + this.shadow.instance = this.instance.shadow; + + this.shadow.updateFromInstance(); + + } else { + /** + * This component loaded from the API - update the instance with our settings + */ + this.shadow.instance = this.instance.shadow; + + this.shadow.updateInstance('camera'); + this.shadow.updateInstance('bias'); + this.shadow.updateInstance('mapSize'); + this.shadow.updateInstance('radius'); + } + + /** + * The directional light points to target - target has to update its matrix world so needs to be added to the scene + */ + if (this.target && this.target.instance) { + + this.instance.target = this.target.instance; + + if (this.parentScene && this.parentScene.instance) { + this.parentScene.addObject(this.target); + } + } + + R3.D3.Light.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Light.Directional.prototype.updateInstance = function(property, oldTarget) { + + if (property === 'castShadow') { + this.instance.castShadow = this.castShadow; + return; + } + + if (property === 'position') { + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + return; + } + + if (property === 'shadow') { + console.warn('experimental shadow change'); + if (this.shadow && this.shadow.instance) { + this.instance.shadow = this.shadow.instance; + } + return; + } + + if (property === 'target') { + + console.warn('experimental target change'); + + if (typeof oldTarget === 'undefined') { + console.warn('oldTarget undefined'); + } + + if (oldTarget) { + if (this.parentScene) { + this.parentScene.removeObject(oldTarget); + this.parentScene.addObject(this.target); + } + } + + return; + } + + R3.D3.Light.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Light to a R3.D3.API.Light + * @returns {R3.D3.API.Light} + */ +R3.D3.Light.Directional.prototype.toApiObject = function() { + + var apiDirectionalLight = R3.D3.Light.prototype.toApiObject.call(this); + + apiDirectionalLight.castShadow = this.castShadow; + apiDirectionalLight.position = this.position.toApiObject(); + apiDirectionalLight.shadow = R3.Utils.IdOrNull(this.shadow); + apiDirectionalLight.target = R3.Utils.IdOrNull(this.target); + + return apiDirectionalLight; +}; diff --git a/src/r3-d3-light-hemisphere.js b/src/r3-d3-light-hemisphere.js new file mode 100644 index 0000000..add5070 --- /dev/null +++ b/src/r3-d3-light-hemisphere.js @@ -0,0 +1,100 @@ +/** + * R3.D3.Light.Directional + * @param graphics R3.GraphicsRuntime + * @param apiHemisphereLight + * @constructor + */ +R3.D3.Light.Hemisphere = function( + graphics, + apiHemisphereLight +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiHemisphereLight)) { + apiHemisphereLight = { + lightType : R3.D3.API.Light.LIGHT_TYPE_HEMISPHERE + }; + } + + R3.D3.API.Light.Hemisphere.call( + this, + apiHemisphereLight, + apiHemisphereLight.position, + apiHemisphereLight.groundColor + ); + + this.position = new R3.Vector3( + this.graphics, + this.position, + this + ); + + this.groundColor = new R3.Color( + this.graphics, + this.groundColor, + this + ); + + R3.D3.Light.call( + this, + this.graphics, + apiHemisphereLight + ); + +}; + +R3.D3.Light.Hemisphere.prototype = Object.create(R3.D3.Light.prototype); +R3.D3.Light.Hemisphere.prototype.constructor = R3.D3.Light.Hemisphere; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Light.Hemisphere.prototype.createInstance = function() { + + this.instance = new THREE.HemisphereLight(); + + this.instance.castShadow = this.castShadow; + + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + + R3.D3.Light.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Light.Hemisphere.prototype.updateInstance = function(property, oldTarget) { + + if (property === 'position') { + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + return; + } + + if (property === 'groundColor') { + this.instance.groundColor.set(this.color.toHex()); + return; + } + + R3.D3.Light.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Light to a R3.D3.API.Light + * @returns {R3.D3.API.Light} + */ +R3.D3.Light.Hemisphere.prototype.toApiObject = function() { + + var apiHemisphereLight = R3.D3.Light.prototype.toApiObject.call(this); + + apiHemisphereLight.position = this.position.toApiObject(); + apiHemisphereLight.groundColor = this.groundColor.toApiObject(); + + return apiHemisphereLight; +}; diff --git a/src/r3-d3-light-point.js b/src/r3-d3-light-point.js new file mode 100644 index 0000000..b25b747 --- /dev/null +++ b/src/r3-d3-light-point.js @@ -0,0 +1,151 @@ +/** + * R3.D3.Light.Point + * @param graphics R3.GraphicsRuntime + * @param apiPointLight + * @constructor + */ +R3.D3.Light.Point = function( + graphics, + apiPointLight +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiPointLight)) { + apiPointLight = { + lightType : R3.D3.API.Light.LIGHT_TYPE_POINT + }; + } + + R3.D3.API.Light.Point.call( + this, + apiPointLight, + apiPointLight.position, + apiPointLight.decay, + apiPointLight.distance, + apiPointLight.power, + apiPointLight.shadow + ); + + this.position = new R3.Vector3( + this.graphics, + this.position, + this + ); + + if (this.shadow instanceof R3.D3.API.Shadow) { + this.shadow = new R3.D3.Shadow( + this.graphics, + this.shadow + ) + } + + R3.D3.Light.call( + this, + this.graphics, + apiPointLight + ); + +}; + +R3.D3.Light.Point.prototype = Object.create(R3.D3.Light.prototype); +R3.D3.Light.Point.prototype.constructor = R3.D3.Light.Point; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Light.Point.prototype.createInstance = function() { + + this.instance = new THREE.PointLight(); + + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + + this.instance.decay = this.decay; + this.instance.distance = this.distance; + this.instance.power = this.power; + + if (this.shadow === null) { + + /** + * This component is created during runtime + */ + this.shadow = new R3.D3.Shadow(this.graphics); + + this.shadow.instance = this.instance.shadow; + + this.shadow.updateFromInstance(); + + } else { + /** + * This component loaded from the API - update the instance with our settings + */ + this.shadow.instance = this.instance.shadow; + + this.shadow.updateInstance('camera'); + this.shadow.updateInstance('bias'); + this.shadow.updateInstance('mapSize'); + this.shadow.updateInstance('radius'); + } + + + R3.D3.Light.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Light.Point.prototype.updateInstance = function(property) { + + if (property === 'position') { + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + return; + } + + if (property === 'decay') { + this.instance.decay = this.decay; + return; + } + + if (property === 'distance') { + this.instance.distance = this.distance; + return; + } + + if (property === 'power') { + this.instance.power = this.power; + return; + } + + if (property === 'shadow') { + console.warn('experimental shadow change'); + if (this.shadow && this.shadow.instance) { + this.instance.shadow = this.shadow.instance; + } + return; + } + + R3.D3.Light.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Light to a R3.D3.API.Light + * @returns {R3.D3.API.Light} + */ +R3.D3.Light.Point.prototype.toApiObject = function() { + + var apiPointLight = R3.D3.Light.prototype.toApiObject.call(this); + + apiPointLight.position = this.position.toApiObject(); + apiPointLight.decay = this.decay; + apiPointLight.distance = this.distance; + apiPointLight.power = this.power; + apiPointLight.shadow = R3.Utils.IdOrNull(this.shadow); + + return apiPointLight; +}; diff --git a/src/r3-d3-light-rect-area.js b/src/r3-d3-light-rect-area.js new file mode 100644 index 0000000..95ee199 --- /dev/null +++ b/src/r3-d3-light-rect-area.js @@ -0,0 +1,156 @@ +/** + * R3.D3.Light.RectArea + * @param graphics R3.GraphicsRuntime + * @param apiRectAreaLight + * @constructor + */ +R3.D3.Light.RectArea = function( + graphics, + apiRectAreaLight +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiRectAreaLight)) { + apiRectAreaLight = { + lightType : R3.D3.API.Light.LIGHT_TYPE_RECT_AREA + }; + } + + R3.D3.API.Light.RectArea.call( + this, + apiRectAreaLight, + apiRectAreaLight.position, + apiRectAreaLight.castShadow, + apiRectAreaLight.decay, + apiRectAreaLight.distance, + apiRectAreaLight.width, + apiRectAreaLight.height, + apiRectAreaLight.target + ); + + this.position = new R3.Vector3( + this.graphics, + this.position, + this + ); + + R3.D3.Light.call( + this, + this.graphics, + apiRectAreaLight + ); + +}; + +R3.D3.Light.RectArea.prototype = Object.create(R3.D3.Light.prototype); +R3.D3.Light.RectArea.prototype.constructor = R3.D3.Light.RectArea; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Light.RectArea.prototype.createInstance = function() { + + this.instance = new THREE.RectAreaLight(); + + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + + //TODO: not yet implemented + //this.instance.castShadow = this.castShadow; + //this.instance.decay = this.decay; + //this.instance.distance = this.distance; + + this.instance.width = this.width; + this.instance.height = this.height; + + if (this.target && this.target.instance) { + this.instance.target = this.target.instance; + + if (this.parentScene && this.parentScene.instance) { + this.parentScene.addObject(this.target); + } + } + R3.D3.Light.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Light.RectArea.prototype.updateInstance = function(property, oldTarget) { + + if (property === 'castShadow') { + console.warn('not yet implemented : castShadow'); + // this.instance.castShadow = this.castShadow; + return; + } + + if (property === 'position') { + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + return; + } + + if (property === 'decay') { + console.warn('not yet implemented : decay'); + // this.instance.decay = this.decay; + return; + } + + if (property === 'distance') { + console.warn('not yet implemented : distance'); + // this.instance.distance = this.distance; + return; + } + + if (property === 'width') { + this.instance.width = this.width; + return; + } + + if (property === 'height') { + this.instance.height = this.height; + return; + } + + if (property === 'target') { + + if (typeof oldTarget === 'undefined') { + console.warn('oldTarget undefined'); + } + + if (oldTarget) { + if (this.parentScene) { + this.parentScene.removeObject(oldTarget); + this.parentScene.addObject(this.target); + } + } + + return; + } + + R3.D3.Light.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Light to a R3.D3.API.Light + * @returns {R3.D3.API.Light} + */ +R3.D3.Light.RectArea.prototype.toApiObject = function() { + + var apiRectAreaLight = R3.D3.Light.prototype.toApiObject.call(this); + + apiRectAreaLight.position = this.position.toApiObject(); + apiRectAreaLight.castShadow = this.castShadow; + apiRectAreaLight.decay = this.decay; + apiRectAreaLight.distance = this.distance; + apiRectAreaLight.width = this.width; + apiRectAreaLight.height = this.height; + apiRectAreaLight.target = R3.Utils.IdOrNull(this.target); + + return apiRectAreaLight; +}; diff --git a/src/r3-d3-light-spot.js b/src/r3-d3-light-spot.js new file mode 100644 index 0000000..2a8bf81 --- /dev/null +++ b/src/r3-d3-light-spot.js @@ -0,0 +1,208 @@ +/** + * R3.D3.Light.Spot + * @param graphics R3.GraphicsRuntime + * @param apiSpotLight + * @constructor + */ +R3.D3.Light.Spot = function( + graphics, + apiSpotLight +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiSpotLight)) { + apiSpotLight = { + lightType : R3.D3.API.Light.LIGHT_TYPE_SPOT + }; + } + + R3.D3.API.Light.Spot.call( + this, + apiSpotLight, + apiSpotLight.position, + apiSpotLight.angle, + apiSpotLight.castShadow, + apiSpotLight.decay, + apiSpotLight.distance, + apiSpotLight.penumbra, + apiSpotLight.power, + apiSpotLight.shadow, + apiSpotLight.target + ); + + this.position = new R3.Vector3( + this.graphics, + this.position, + this + ); + + if (this.shadow instanceof R3.D3.API.Shadow.Spot) { + this.shadow = new R3.D3.Shadow.Spot( + this.graphics, + this.shadow + ) + } + + R3.D3.Light.call( + this, + this.graphics, + apiSpotLight + ); + +}; + +R3.D3.Light.Spot.prototype = Object.create(R3.D3.Light.prototype); +R3.D3.Light.Spot.prototype.constructor = R3.D3.Light.Spot; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Light.Spot.prototype.createInstance = function() { + + this.instance = new THREE.SpotLight(); + + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + + this.instance.angle = this.angle; + this.instance.castShadow = this.castShadow; + this.instance.decay = this.decay; + this.instance.distance = this.distance; + this.instance.penumbra = this.penumbra; + this.instance.power = this.power; + + if (this.shadow === null) { + + /** + * This component is created during runtime + */ + this.shadow = new R3.D3.Shadow.Spot(this.graphics); + + this.shadow.instance = this.instance.shadow; + + this.shadow.updateFromInstance(); + + } else { + /** + * This component loaded from the API - update the instance with our settings + */ + this.shadow.instance = this.instance.shadow; + + this.shadow.updateInstance('camera'); + this.shadow.updateInstance('bias'); + this.shadow.updateInstance('mapSize'); + this.shadow.updateInstance('radius'); + } + + if (this.target && this.target.instance) { + this.instance.target = this.target.instance; + + if (this.parentScene && this.parentScene.instance) { + this.parentScene.addObject(this.target); + } + } + + R3.D3.Light.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Light.Spot.prototype.updateInstance = function(property, oldTarget) { + + if (property === 'position') { + this.instance.position.x = this.position.x; + this.instance.position.y = this.position.y; + this.instance.position.z = this.position.z; + return; + } + + if (property === 'angle') { + this.instance.angle = this.angle; + return; + } + + if (property === 'castShadow') { + this.instance.castShadow = this.castShadow; + return; + } + + if (property === 'decay') { + this.instance.decay = this.decay; + return; + } + + if (property === 'distance') { + this.instance.distance = this.distance; + return; + } + + if (property === 'penumbra') { + this.instance.penumbra = this.penumbra; + return; + } + + if (property === 'power') { + this.instance.power = this.power; + return; + } + + if (property === 'shadow') { + console.warn('experimental shadow change'); + if (this.shadow && this.shadow.instance) { + this.instance.shadow = this.shadow.instance; + } + return; + } + + if (property === 'target') { + + if (typeof oldTarget === 'undefined') { + console.warn('oldTarget undefined'); + } + + if (oldTarget) { + if (this.parentScene) { + this.parentScene.removeObject(oldTarget); + } + } + + if (this.target.instance) { + this.instance.target = this.target.instance; + } + + this.parentScene.addObject(this.target); + + return; + } + + R3.D3.Light.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Light to a R3.D3.API.Light + * @returns {R3.D3.API.Light} + */ +R3.D3.Light.Spot.prototype.toApiObject = function() { + + var apiLight = R3.D3.Light.prototype.toApiObject.call(this); + + var apiSpotLight = new R3.D3.API.Light.Spot( + apiLight, + this.position.toApiObject(), + this.angle, + this.castShadow, + this.decay, + this.distance, + this.penumbra, + this.power, + R3.Utils.IdOrNull(this.shadow), + R3.Utils.IdOrNull(this.target) + ); + + return apiSpotLight; +}; diff --git a/src/r3-d3-material-a.js b/src/r3-d3-material-a.js new file mode 100644 index 0000000..ed59129 --- /dev/null +++ b/src/r3-d3-material-a.js @@ -0,0 +1,1068 @@ +/** + * Material Superset - The apiMaterial properties get moved into the Material object itself, and then the instance is + * created + * @param graphics R3.GraphicsRuntime + * @param apiMaterial R3.D3.API.Material + * @property materialType + * @constructor + * @returns {R3.D3.Material} + */ +R3.D3.Material = function( + graphics, + apiMaterial +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiMaterial)) { + apiMaterial = { + materialType : R3.D3.API.Material.MATERIAL_TYPE_NONE + }; + } + + R3.D3.API.Material.call( + this, + apiMaterial.id, + apiMaterial.name, + apiMaterial.materialType, + apiMaterial.parentEntity, + apiMaterial.parentMeshes, + apiMaterial.alphaTest, + apiMaterial.blendDst, + apiMaterial.blendDstAlpha, + apiMaterial.blendEquation, + apiMaterial.blendEquationAlpha, + apiMaterial.blending, + apiMaterial.blendSrc, + apiMaterial.blendSrcAlpha, + apiMaterial.clipIntersection, + apiMaterial.clippingPlanes, + apiMaterial.clipShadows, + apiMaterial.colorWrite, + apiMaterial.customDepthMaterial, + apiMaterial.customDistanceMaterial, + apiMaterial.defines, + apiMaterial.depthFunc, + apiMaterial.depthTest, + apiMaterial.depthWrite, + apiMaterial.fog, + apiMaterial.lights, + apiMaterial.opacity, + apiMaterial.overdraw, + apiMaterial.polygonOffset, + apiMaterial.polygonOffsetFactor, + apiMaterial.polygonOffsetUnits, + apiMaterial.precision, + apiMaterial.premultipliedAlpha, + apiMaterial.dithering, + apiMaterial.flatShading, + apiMaterial.side, + apiMaterial.transparent, + apiMaterial.vertexColors, + apiMaterial.visible + ); + + var linkedObjects = {}; + + switch (this.materialType) { + case R3.D3.API.Material.MATERIAL_TYPE_STANDARD : + linkedObjects.alphaMap = R3.D3.Texture; + linkedObjects.aoMap = R3.D3.Texture; + linkedObjects.bumpMap = R3.D3.Texture; + linkedObjects.diffuseMap = R3.D3.Texture; + linkedObjects.displacementMap = R3.D3.Texture; + linkedObjects.emissiveMap = R3.D3.Texture; + linkedObjects.envMap = R3.D3.Texture; + linkedObjects.lightMap = R3.D3.Texture; + linkedObjects.metalnessMap = R3.D3.Texture; + linkedObjects.normalMap = R3.D3.Texture; + linkedObjects.roughnessMap = R3.D3.Texture; + break; + case R3.D3.API.Material.MATERIAL_TYPE_BASIC : + linkedObjects.alphaMap = R3.D3.Texture; + linkedObjects.aoMap = R3.D3.Texture; + linkedObjects.diffuseMap = R3.D3.Texture; + linkedObjects.envMap = R3.D3.Texture; + linkedObjects.lightMap = R3.D3.Texture; + linkedObjects.specularMap = R3.D3.Texture; + break; + case R3.D3.API.Material.MATERIAL_TYPE_PHONG : + linkedObjects.alphaMap = R3.D3.Texture; + linkedObjects.aoMap = R3.D3.Texture; + linkedObjects.bumpMap = R3.D3.Texture; + linkedObjects.diffuseMap = R3.D3.Texture; + linkedObjects.displacementMap = R3.D3.Texture; + linkedObjects.emissiveMap = R3.D3.Texture; + linkedObjects.envMap = R3.D3.Texture; + linkedObjects.lightMap = R3.D3.Texture; + linkedObjects.normalMap = R3.D3.Texture; + linkedObjects.specularMap = R3.D3.Texture; + break; + case R3.D3.API.Material.MATERIAL_TYPE_SHADER : + case R3.D3.API.Material.MATERIAL_TYPE_SHADER_RAW : + linkedObjects.vertexShader = R3.D3.Shader.Vertex; + linkedObjects.fragmentShader = R3.D3.Shader.Fragment; + break; + case R3.D3.API.Material.MATERIAL_TYPE_POINTS : + linkedObjects.diffuseMap = R3.D3.Texture; + break; + default : + throw new Error('unhandled material type: ' + this.materialType); + + } + + R3.Component.call( + this, + linkedObjects + ); +}; + +R3.D3.Material.prototype = Object.create(R3.Component.prototype); +R3.D3.Material.prototype.constructor = R3.D3.Material; + +R3.D3.Material.prototype.createInstance = function() { + + if (R3.Utils.UndefinedOrNull(this.instance)) { + console.warn('the child createInstance has to be called first'); + return; + } + + this.instance.alphaTest = this.alphaTest; + this.instance.blendDst = this.blendDst; + this.instance.blendDstAlpha = this.blendDstAlpha; + this.instance.blendEquation = this.blendEquation; + this.instance.blendEquationAlpha = this.blendEquationAlpha; + this.instance.blending = this.blending; + this.instance.blendSrc = this.blendSrc; + this.instance.blendSrcAlpha = this.blendSrcAlpha; + this.instance.clipIntersection = this.clipIntersection; + this.instance.clippingPlanes = this.clippingPlanes; + this.instance.clipShadows = this.clipShadows; + this.instance.colorWrite = this.colorWrite; + this.instance.customDepthMaterial = this.customDepthMaterial; + this.instance.customDistanceMaterial = this.customDistanceMaterial; + this.instance.defines = this.defines; + this.instance.depthFunc = this.depthFunc; + this.instance.depthTest = this.depthTest; + this.instance.depthWrite = this.depthWrite; + this.instance.fog = this.fog; + this.instance.lights = this.lights; + this.instance.opacity = this.opacity; + this.instance.overdraw = this.overdraw; + this.instance.polygonOffset = this.polygonOffset; + this.instance.polygonOffsetFactor = this.polygonOffsetFactor; + this.instance.polygonOffsetUnits = this.polygonOffsetUnits; + this.instance.precision = this.precision; + this.instance.premultipliedAlpha = this.premultipliedAlpha; + this.instance.dithering = this.dithering; + this.instance.flatShading = this.flatShading; + this.instance.side = this.side; + this.instance.transparent = this.transparent; + this.instance.vertexColors = this.vertexColors; + this.instance.visible = this.visible; + + R3.Component.prototype.createInstance.call(this); + +}; + +R3.D3.Material.prototype.updateInstance = function(property) { + + if (R3.Utils.UndefinedOrNull(this.instance)) { + console.warn('no material instance'); + return; + } + + if (property === 'materialType') { + + var componentType = R3.D3.API.Material.GetComponentType(this.materialType); + + this.replace(componentType); + + return; + } + + if (property === 'parentMeshes') { + console.warn('parent meshes are read-only'); + return; + } + + if (property === 'alphaTest') { + this.instance.alphaTest = this.alphaTest; + this.instance.needsUpdate = true; + return; + } + + if (property === 'blendDst') { + this.instance.blendDst = this.blendDst; + return; + } + + if (property === 'blendDstAlpha') { + this.instance.blendDstAlpha = this.blendDstAlpha; + return; + } + + if (property === 'blendEquation') { + this.instance.blendEquation = this.blendEquation; + return; + } + + if (property === 'blendEquationAlpha') { + this.instance.blendEquationAlpha = this.blendEquationAlpha; + return; + } + + if (property === 'blending') { + this.instance.blending = this.blending; + return; + } + + if (property === 'blendSrc') { + this.instance.blendSrc = this.blendSrc; + return; + } + + if (property === 'blendSrcAlpha') { + this.instance.blendSrcAlpha = this.blendSrcAlpha; + return; + } + + if (property === 'clipIntersection') { + this.instance.clipIntersection = this.clipIntersection; + return; + } + + if (property === 'clippingPlanes') { + console.warn('todo: implement clipping planes update'); + return; + } + + if (property === 'clipShadows') { + this.instance.clipShadows = this.clipShadows; + return; + } + + if (property === 'colorWrite') { + this.instance.colorWrite = this.colorWrite; + return; + } + + if (property === 'customDepthMaterial') { + console.warn('todo: implement custom depth material update'); + return; + } + + if (property === 'customDistanceMaterial') { + console.warn('todo: implement custom distance material update'); + return; + } + + if (property === 'defines') { + this.instance.defines = this.defines; + this.instance.needsUpdate = true; + return; + } + + if (property === 'depthFunc') { + this.instance.depthFunc = this.depthFunc; + return; + } + + if (property === 'depthTest') { + this.instance.depthTest = this.depthTest; + return; + } + + if (property === 'depthWrite') { + this.instance.depthWrite = this.depthWrite; + return; + } + + if (property === 'fog') { + this.instance.fog = this.fog; + return; + } + + if (property === 'lights') { + this.instance.lights = this.lights; + } + + if (property === 'opacity') { + this.instance.opacity = this.opacity; + return; + } + + if (property === 'overdraw') { + this.instance.overdraw = this.overdraw; + return; + } + + if (property === 'polygonOffset') { + this.instance.polygonOffset = this.polygonOffset; + return; + } + + if (property === 'polygonOffsetFactor') { + this.instance.polygonOffsetFactor = this.polygonOffsetFactor; + return; + } + + if (property === 'polygonOffsetUnits') { + this.instance.polygonOffsetUnits = this.polygonOffsetUnits; + return; + } + + if (property === 'precision') { + this.instance.precision = this.precision; + return; + } + + if (property === 'premultipliedAlpha') { + this.instance.premultipliedAlpha = this.premultipliedAlpha; + return; + } + + if (property === 'dithering') { + this.instance.dithering = this.dithering; + console.log('not sure about needsupdate - cannot detect any changes until now'); + } + + if (property === 'flatShading') { + this.instance.flatShading = this.flatShading; + } + + if (property === 'side') { + this.instance.side = this.side; + return; + } + + if (property === 'transparent') { + this.instance.transparent = this.transparent; + return; + } + + if (property === 'vertexColors') { + this.instance.vertexColors = this.vertexColors; + return; + } + + if (property === 'visible') { + this.instance.visible = this.visible; + return; + } + + if (property === 'needsUpdate') { + /** + * update follows + */ + } + + this.instance.needsUpdate = true; + this.needsUpdate = false; + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Material to a R3.D3.API.Material + * @returns {R3.D3.API.Material} + */ +R3.D3.Material.prototype.toApiObject = function() { + + var apiMaterial = new R3.D3.API.Material( + this.id, + this.name, + this.materialType, + R3.Utils.IdOrNull(this.parentEntity), + this.parentMeshes.map( + function(mesh) { + return R3.Utils.IdOrNull(mesh); + } + ), + this.alphaTest, + this.blendDst, + this.blendDstAlpha, + this.blendEquation, + this.blendEquationAlpha, + this.blending, + this.blendSrc, + this.blendSrcAlpha, + this.clipIntersection, + this.clippingPlanes, + this.clipShadows, + this.colorWrite, + this.customDepthMaterial, + this.customDistanceMaterial, + this.defines, + this.depthFunc, + this.depthTest, + this.depthWrite, + this.fog, + this.lights, + this.opacity, + this.overdraw, + this.polygonOffset, + this.polygonOffsetFactor, + this.polygonOffsetUnits, + this.precision, + this.premultipliedAlpha, + this.dithering, + this.flatShading, + this.side, + this.transparent, + this.vertexColors, + this.visible + ); + + return apiMaterial; + +}; + +R3.D3.Material.prototype.assignTexture = function(instanceProperty, property) { + if (this[property] && this[property].instance) { + this.instance[instanceProperty] = this[property].instance; + } else { + this.instance[instanceProperty] = null; + } + this.instance.needsUpdate = true; +}; + +R3.D3.Material.prototype.getTextures = function() { + + var textures = []; + + Object.keys(this.linkedObjects).map( + function(property) { + if (this[property] instanceof R3.D3.Texture) { + textures.push( + { + property: property, + texture: this[property] + } + ); + } + }.bind(this) + ); + + return textures; +}; + + +// +// +// +// R3.D3.Material.prototype.createToonMaterialInstance = function() { +// return new THREE.MeshToonMaterial({ +// 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: this.vertexColors, +// skinning: this.skinning, +// morphTargets: this.morphTargets, +// morphNormals: this.morphNormals +// }); +// }; + + +// R3.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: this.vertexColors, +// skinning: this.skinning, +// morphTargets: this.morphTargets, +// morphNormals: this.morphNormals +// }); +// }; + +// R3.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: R3.D3.API.Material.TYPE_VERTEX_COLORS, +// // fog: this.fog +// }); +// }; +// +// R3.D3.Material.prototype.createLineBasicMaterialInstance = function() { +// +// var linecap = 'round'; +// +// if (this.lineCap === R3.D3.API.Material.LINE_CAP_BUTT) { +// linecap = 'butt'; +// } +// +// if (this.lineCap === R3.D3.API.Material.LINE_CAP_SQUARE) { +// linecap = 'square'; +// } +// +// var linejoin = 'round'; +// +// if (this.lineJoin === R3.D3.API.Material.LINE_JOIN_BEVEL) { +// linejoin = 'bevel'; +// } +// +// if (this.lineJoin === R3.D3.API.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: R3.D3.API.Material.TYPE_VERTEX_COLORS, +// // fog: this.fog +// }); +// }; +// +// R3.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: this.vertexColors, +// skinning: this.skinning, +// morphTargets: this.morphTargets, +// morphNormals: this.morphNormals +// }); +// }; +// +// R3.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: this.vertexColors, +// fog: this.fog +// }); +// }; + +// R3.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 +// */ +// R3.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( +// R3.Event.MATERIAL_TEXTURES_UPDATED, +// { +// material : this +// } +// ); +// } +// +// return textureChanged; +// }; +// +// +// R3.D3.Material.prototype.updateToonMaterialInstance = 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 = this.vertexColors; +// this.instance.skinning = this.skinning; +// this.instance.morphTargets = this.morphTargets; +// this.instance.morphNormals = this.morphNormals; +// }; +// +// R3.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 = this.vertexColors; +// this.instance.skinning = this.skinning; +// this.instance.morphTargets = this.morphTargets; +// this.instance.morphNormals = this.morphNormals; +// }; +// +// R3.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 = this.vertexColors; +// //this.instance.fog = this.fog; +// }; +// +// R3.D3.Material.prototype.updateLineBasicMaterialInstance = function(property) { +// +// var linecap = 'round'; +// +// if (this.lineCap === R3.D3.API.Material.LINE_CAP_BUTT) { +// linecap = 'butt'; +// } +// +// if (this.lineCap === R3.D3.API.Material.LINE_CAP_SQUARE) { +// linecap = 'square'; +// } +// +// var linejoin = 'round'; +// +// if (this.lineJoin === R3.D3.API.Material.LINE_JOIN_BEVEL) { +// linejoin = 'bevel'; +// } +// +// if (this.lineJoin === R3.D3.API.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 = this.vertexColors; +// //this.instance.fog = this.fog; +// }; +// +// +// R3.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 = this.vertexColors; +// this.instance.skinning = this.skinning; +// this.instance.morphTargets = this.morphTargets; +// this.instance.morphNormals = this.morphNormals; +// }; +// +// R3.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 = this.vertexColors; +// this.instance.fog = this.fog; +// }; +// +// /** +// * Material instance +// * @returns {*} +// */ +// R3.D3.Material.prototype.createInstance = function() { +// +// if (this.materialType === R3.D3.API.Material.MATERIAL_TYPE_STANDARD) { +// +// this.instance = this.createStandardMaterialInstance(); +// +// } else if (this.materialType === R3.D3.API.Material.MATERIAL_TYPE_POINTS) { +// +// this.instance = this.createPointsMaterialInstance(); +// +// } else if (this.materialType === R3.D3.API.Material.MATERIAL_TYPE_PHONG) { +// +// this.instance = this.createPhongMaterialInstance(); +// +// } else if (this.materialType === R3.D3.API.Material.MATERIAL_TYPE_BASIC) { +// +// this.instance = this.createMeshBasicMaterialInstance(); +// +// } else if (this.materialType === R3.D3.API.Material.MATERIAL_TYPE_LINE_BASIC) { +// +// this.instance = this.createLineBasicMaterialInstance(); +// +// } else if (this.materialType === R3.D3.API.Material.MATERIAL_TYPE_TOON) { +// +// this.instance = this.createToonMaterialInstance(); +// +// } else { +// console.warn("material type is not implemented yet: " + this.materialType); +// } +// +// this.instance.needsUpdate = true; +// +// this.updateTextures(); +// +// R3.Component.prototype.createInstance.call(this); +// }; + +/** + * Updates the instance with the current state + */ + + diff --git a/src/r3-d3-material-basic.js b/src/r3-d3-material-basic.js new file mode 100644 index 0000000..e6dcc96 --- /dev/null +++ b/src/r3-d3-material-basic.js @@ -0,0 +1,245 @@ +/** + * R3.D3.Material.Basic + * @param graphics + * @param apiMaterialBasic + * @constructor + */ +R3.D3.Material.Basic = function( + graphics, + apiMaterialBasic +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiMaterialBasic)) { + apiMaterialBasic = { + materialType : R3.D3.API.Material.MATERIAL_TYPE_BASIC + }; + } + + R3.D3.API.Material.Basic.call( + this, + apiMaterialBasic, + apiMaterialBasic.alphaMap, + apiMaterialBasic.aoMap, + apiMaterialBasic.aoMapIntensity, + apiMaterialBasic.color, + apiMaterialBasic.combine, + apiMaterialBasic.envMap, + apiMaterialBasic.lightMap, + apiMaterialBasic.lightMapIntensity, + apiMaterialBasic.diffuseMap, + apiMaterialBasic.morphTargets, + apiMaterialBasic.reflectivity, + apiMaterialBasic.refractionRatio, + apiMaterialBasic.skinning, + apiMaterialBasic.specularMap, + apiMaterialBasic.wireframe, + apiMaterialBasic.wireframeLinecap, + apiMaterialBasic.wireframeLinejoin, + apiMaterialBasic.wireframeLinewidth + ); + + if (this.alphaMap instanceof R3.D3.API.Texture) { + this.alphaMap = R3.Component.ConstructFromObject(this.alphaMap); + } + + if (this.aoMap instanceof R3.D3.API.Texture) { + this.aoMap = R3.Component.ConstructFromObject(this.aoMap); + } + + this.color = new R3.Color( + this.graphics, + this.color, + this + ); + + if (this.envMap instanceof R3.D3.API.Texture) { + this.envMap = R3.Component.ConstructFromObject(this.envMap); + } + + if (this.lightMap instanceof R3.D3.API.Texture) { + this.lightMap = R3.Component.ConstructFromObject(this.lightMap); + } + + if (this.diffuseMap instanceof R3.D3.API.Texture) { + this.diffuseMap = R3.Component.ConstructFromObject(this.diffuseMap); + } + + if (this.specularMap instanceof R3.D3.API.Texture) { + this.specularMap = R3.Component.ConstructFromObject(this.specularMap); + } + + R3.D3.Material.call( + this, + this.graphics, + this + ); + +}; + +R3.D3.Material.Basic.prototype = Object.create(R3.D3.Material.prototype); +R3.D3.Material.Basic.prototype.constructor = R3.D3.Material.Basic; + +/** + * Creates an instance of our texture object + * @returns {*} + */ +R3.D3.Material.Basic.prototype.createInstance = function() { + + this.instance = new THREE.MeshBasicMaterial( + { + alphaMap : this.alphaMap ? this.alphaMap.instance : null, + aoMap : this.aoMap ? this.aoMap.instance : null, + aoMapIntensity : this.aoMapIntensity, + color : this.color.instance, + envMap : this.envMap ? this.envMap.instance : null, + lightMap : this.lightMap ? this.lightMap.instance : null, + lightMapIntensity : this.lightMapIntensity, + map : this.diffuseMap ? this.diffuseMap.instance : null, + morphTargets : this.morphTargets, + reflectivity : this.reflectivity, + refractionRatio : this.refractionRatio, + skinning : this.skinning, + specularMap : this.specularMap ? this.specularMap.instance : null, + wireframe : this.wireframe, + wireframeLinecap : this.wireframeLinecap, + wireframeLinejoin : this.wireframeLinejoin, + wireframeLinewidth : this.wireframeLinewidth + } + ); + + R3.D3.Material.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Material.Basic.prototype.updateInstance = function(property) { + + if (property === 'alphaMap') { + this.assignTexture('alphaMap', property); + return; + } + + if (property === 'aoMap') { + this.assignTexture('aoMap', property); + return; + } + + if (property === 'aoMapIntensity') { + this.instance.aoMapIntensity = this.aoMapIntensity; + return; + } + + if (property === 'color') { + this.instance.color = this.color.instance; + return; + } + + if (property === 'combine') { + this.instance.combine = this.combine; + this.instance.needsUpdate = true; + return; + } + + if (property === 'envMap') { + this.assignTexture('envMap', property); + return; + } + + if (property === 'lightMap') { + this.assignTexture('lightMap', property); + return; + } + + if (property === 'lightMapIntensity') { + this.instance.lightMapIntensity = this.lightMapIntensity; + return; + } + + if (property === 'diffuseMap') { + this.assignTexture('map', property); + return; + } + + if (property === 'morphTargets') { + this.instance.morphTargets = this.morphTargets; + return; + } + + if (property === 'reflectivity') { + this.instance.reflectivity = this.reflectivity; + return; + } + + if (property === 'refractionRatio') { + this.instance.refractionRatio = this.refractionRatio; + return; + } + + if (property === 'skinning') { + this.instance.skinning = this.skinning; + return; + } + + if (property === 'specularMap') { + this.assignTexture('specularMap', property); + return; + } + + if (property === 'wireframe') { + this.instance.wireframe = this.wireframe; + return; + } + + if (property === 'wireframeLinecap') { + this.instance.wireframeLinecap = this.wireframeLinecap; + return; + } + + if (property === 'wireframeLinejoin') { + this.instance.wireframeLinejoin = this.wireframeLinejoin; + return; + } + + if (property === 'wireframeLinewidth') { + this.instance.wireframeLinewidth = this.wireframeLinewidth; + return; + } + + R3.D3.Material.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Material.Basic to a R3.D3.API.Material.Basic + * @returns {R3.D3.API.Material.Basic} + */ +R3.D3.Material.Basic.prototype.toApiObject = function() { + + var apiMaterial = R3.D3.Material.prototype.toApiObject.call(this); + + var apiMaterialBasic = new R3.D3.API.Material.Basic( + apiMaterial, + R3.Utils.IdOrNull(this.alphaMap), + R3.Utils.IdOrNull(this.aoMap), + this.aoMapIntensity, + this.color.toApiObject(), + this.combine, + R3.Utils.IdOrNull(this.envMap), + R3.Utils.IdOrNull(this.lightMap), + this.lightMapIntensity, + R3.Utils.IdOrNull(this.diffuseMap), + this.morphTargets, + this.reflectivity, + this.refractionRatio, + this.skinning, + R3.Utils.IdOrNull(this.specularMap), + this.wireframe, + this.wireframeLinecap, + this.wireframeLinejoin, + this.wireframeLinewidth + ); + + return apiMaterialBasic; +}; diff --git a/src/r3-d3-material-phong.js b/src/r3-d3-material-phong.js new file mode 100644 index 0000000..fa50920 --- /dev/null +++ b/src/r3-d3-material-phong.js @@ -0,0 +1,378 @@ +/** + * R3.D3.Material.Phong + * @param graphics + * @param apiMaterialPhong + * @constructor + */ +R3.D3.Material.Phong = function( + graphics, + apiMaterialPhong +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiMaterialPhong)) { + apiMaterialPhong = { + materialType : R3.D3.API.Material.MATERIAL_TYPE_PHONG + }; + } + + R3.D3.API.Material.Phong.call( + this, + apiMaterialPhong, + apiMaterialPhong.alphaMap, + apiMaterialPhong.aoMap, + apiMaterialPhong.aoMapIntensity, + apiMaterialPhong.bumpMap, + apiMaterialPhong.bumpScale, + apiMaterialPhong.color, + apiMaterialPhong.combine, + apiMaterialPhong.displacementMap, + apiMaterialPhong.displacementScale, + apiMaterialPhong.displacementBias, + apiMaterialPhong.emissive, + apiMaterialPhong.emissiveMap, + apiMaterialPhong.emissiveIntensity, + apiMaterialPhong.envMap, + apiMaterialPhong.lightMap, + apiMaterialPhong.lightMapIntensity, + apiMaterialPhong.diffuseMap, + apiMaterialPhong.morphNormals, + apiMaterialPhong.morphTargets, + apiMaterialPhong.normalMap, + apiMaterialPhong.normalScale, + apiMaterialPhong.reflectivity, + apiMaterialPhong.refractionRatio, + apiMaterialPhong.shininess, + apiMaterialPhong.skinning, + apiMaterialPhong.specular, + apiMaterialPhong.specularMap, + apiMaterialPhong.wireframe, + apiMaterialPhong.wireframeLinecap, + apiMaterialPhong.wireframeLinejoin, + apiMaterialPhong.wireframeLinewidth + ); + + if (this.alphaMap instanceof R3.D3.API.Texture) { + this.alphaMap = R3.Component.ConstructFromObject(this.alphaMap); + } + + if (this.aoMap instanceof R3.D3.API.Texture) { + this.aoMap = R3.Component.ConstructFromObject(this.aoMap); + } + + if (this.bumpMap instanceof R3.D3.API.Texture) { + this.bumpMap = R3.Component.ConstructFromObject(this.bumpMap); + } + + this.color = new R3.Color( + this.graphics, + this.color, + this + ); + + if (this.displacementMap instanceof R3.D3.API.Texture) { + this.displacementMap = R3.Component.ConstructFromObject(this.displacementMap); + } + + this.emissive = new R3.Color( + this.graphics, + this.emissive, + this + ); + + if (this.emissiveMap instanceof R3.D3.API.Texture) { + this.emissiveMap = R3.Component.ConstructFromObject(this.emissiveMap); + } + + if (this.envMap instanceof R3.D3.API.Texture) { + this.envMap = R3.Component.ConstructFromObject(this.envMap); + } + + if (this.lightMap instanceof R3.D3.API.Texture) { + this.lightMap = R3.Component.ConstructFromObject(this.lightMap); + } + + if (this.diffuseMap instanceof R3.D3.API.Texture) { + this.diffuseMap = R3.Component.ConstructFromObject(this.diffuseMap); + } + + if (this.normalMap instanceof R3.D3.API.Texture) { + this.normalMap = R3.Component.ConstructFromObject(this.normalMap); + } + + this.specular = new R3.Color( + this.graphics, + this.specular, + this + ); + + if (this.specularMap instanceof R3.D3.API.Texture) { + this.specularMap = R3.Component.ConstructFromObject(this.specularMap); + } + + R3.D3.Material.call( + this, + this.graphics, + this + ); + +}; + +R3.D3.Material.Phong.prototype = Object.create(R3.D3.Material.prototype); +R3.D3.Material.Phong.prototype.constructor = R3.D3.Material.Phong; + +/** + * Creates an instance of our texture object + * @returns {*} + */ +R3.D3.Material.Phong.prototype.createInstance = function() { + + this.instance = new THREE.MeshPhongMaterial( + { + alphaMap : this.alphaMap ? this.alphaMap.instance : null, + aoMap : this.aoMap ? this.aoMap.instance : null, + aoMapIntensity : this.aoMapIntensity, + bumpMap : this.bumpMap ? this.bumpMap.instance : null, + bumpScale : this.bumpScale, + color : this.color.instance, + combine : this.combine, + displacementMap : this.displacementMap ? this.displacementMap.instance : null, + displacementScale : this.displacementScale, + displacementBias : this.displacementBias, + emissive : this.emissive.instance, + emissiveMap : this.emissiveMap ? this.emissiveMap.instance : null, + emissiveIntensity : this.emissiveIntensity, + envMap : this.envMap ? this.envMap.instance : null, + lightMap : this.lightMap ? this.lightMap.instance : null, + lightMapIntensity : this.lightMapIntensity, + map : this.diffuseMap ? this.diffuseMap.instance : null, + morphNormals : this.morphNormals, + morphTargets : this.morphTargets, + normalMap : this.normalMap ? this.normalMap.instance : null, + normalScale : this.normalScale, + reflectivity : this.reflectivity, + refractionRatio : this.refractionRatio, + shininess : this.shininess, + skinning : this.skinning, + specular : this.specular.instance, + specularMap : this.specularMap ? this.specularMap.instance : null, + wireframe : this.wireframe, + wireframeLinecap : this.wireframeLinecap, + wireframeLinejoin : this.wireframeLinejoin, + wireframeLinewidth : this.wireframeLinewidth + } + ); + + R3.D3.Material.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Material.Phong.prototype.updateInstance = function(property) { + + if (property === 'alphaMap') { + this.assignTexture('alphaMap', property); + return; + } + + if (property === 'aoMap') { + this.assignTexture('aoMap', property); + return; + } + + if (property === 'aoMapIntensity') { + this.instance.aoMapIntensity = this.aoMapIntensity; + return; + } + + if (property === 'bumpMap') { + this.assignTexture('bumpMap', property); + return; + } + + if (property === 'bumpScale') { + this.instance.bumpScale = this.bumpScale; + return; + } + + if (property === 'color') { + this.instance.color = this.color.instance; + return; + } + + if (property === 'combine') { + this.instance.combine = this.combine; + this.instance.needsUpdate = true; + return; + } + + if (property === 'displacementMap') { + this.assignTexture('displacementMap', property); + return; + } + + if (property === 'displacementScale') { + this.instance.displacementScale = this.displacementScale; + return; + } + + if (property === 'displacementBias') { + this.instance.displacementBias = this.displacementBias; + return; + } + + if (property === 'emissive') { + this.instance.emissive = this.emissive.instance; + return; + } + + if (property === 'emissiveMap') { + this.assignTexture('emissiveMap', property); + return; + } + + if (property === 'emissiveIntensity') { + this.instance.emissiveIntensity = this.emissiveIntensity; + return; + } + + if (property === 'envMap') { + this.assignTexture('envMap', property); + return; + } + + if (property === 'lightMap') { + this.assignTexture('lightMap', property); + return; + } + + if (property === 'lightMapIntensity') { + this.instance.lightMapIntensity = this.lightMapIntensity; + return; + } + + if (property === 'diffuseMap') { + this.assignTexture('map', property); + return; + } + + if (property === 'morphNormals') { + this.instance.morphNormals = this.morphNormals; + return; + } + + if (property === 'morphTargets') { + this.instance.morphTargets = this.morphTargets; + return; + } + + if (property === 'normalMap') { + this.assignTexture('normalMap', property); + return; + } + + if (property === 'normalScale') { + this.instance.normalScale = this.normalScale; + return; + } + + if (property === 'reflectivity') { + this.instance.reflectivity = this.reflectivity; + return; + } + + if (property === 'refractionRatio') { + this.instance.refractionRatio = this.refractionRatio; + return; + } + + if (property === 'shininess') { + this.instance.shininess = this.shininess; + return; + } + + if (property === 'skinning') { + this.instance.skinning = this.skinning; + return; + } + + if (property === 'specular') { + this.instance.specular = this.specular.instance; + return; + } + + if (property === 'specularMap') { + this.assignTexture('specularMap', property); + return; + } + + if (property === 'wireframe') { + this.instance.wireframe = this.wireframe; + return; + } + + if (property === 'wireframeLinecap') { + this.instance.wireframeLinecap = this.wireframeLinecap; + return; + } + + if (property === 'wireframeLinejoin') { + this.instance.wireframeLinejoin = this.wireframeLinejoin; + return; + } + + if (property === 'wireframeLinewidth') { + this.instance.wireframeLinewidth = this.wireframeLinewidth; + return; + } + + R3.D3.Material.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Material.Phong to a R3.D3.API.Material.Phong + * @returns {R3.D3.API.Material.Phong} + */ +R3.D3.Material.Phong.prototype.toApiObject = function() { + + var apiMaterial = R3.D3.Material.prototype.toApiObject.call(this); + + var apiMaterialPhong = new R3.D3.API.Material.Phong( + apiMaterial, + R3.Utils.IdOrNull(this.alphaMap), + R3.Utils.IdOrNull(this.aoMap), + this.aoMapIntensity, + R3.Utils.IdOrNull(this.bumpMap), + this.bumpScale, + this.color.toApiObject(), + this.combine, + R3.Utils.IdOrNull(this.displacementMap), + this.displacementScale, + this.displacementBias, + this.emissive.toApiObject(), + R3.Utils.IdOrNull(this.emissiveMap), + this.emissiveIntensity, + R3.Utils.IdOrNull(this.envMap), + R3.Utils.IdOrNull(this.lightMap), + this.lightMapIntensity, + R3.Utils.IdOrNull(this.diffuseMap), + this.morphNormals, + this.morphTargets, + R3.Utils.IdOrNull(this.normalMap), + this.normalScale, + this.reflectivity, + this.refractionRatio, + this.shininess, + this.skinning, + this.specular.toApiObject(), + R3.Utils.IdOrNull(this.specularMap), + this.wireframe, + this.wireframeLinecap, + this.wireframeLinejoin, + this.wireframeLinewidth + ); + + return apiMaterialPhong; +}; diff --git a/src/r3-d3-material-points.js b/src/r3-d3-material-points.js new file mode 100644 index 0000000..f8a25ab --- /dev/null +++ b/src/r3-d3-material-points.js @@ -0,0 +1,114 @@ +/** + * R3.D3.Material.Points + * @param graphics + * @param apiMaterialPoints + * @constructor + */ +R3.D3.Material.Points = function( + graphics, + apiMaterialPoints +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiMaterialPoints)) { + apiMaterialPoints = { + materialType : R3.D3.API.Material.MATERIAL_TYPE_POINTS + }; + } + + R3.D3.API.Material.Points.call( + this, + apiMaterialPoints, + apiMaterialPoints.color, + apiMaterialPoints.diffuseMap, + apiMaterialPoints.size, + apiMaterialPoints.sizeAttenuation + ); + + this.color = new R3.Color( + this.graphics, + this.color, + this + ); + + if (this.diffuseMap instanceof R3.D3.API.Texture) { + this.diffuseMap = R3.Component.ConstructFromObject(this.diffuseMap); + } + + R3.D3.Material.call( + this, + this.graphics, + this + ); + +}; + +R3.D3.Material.Points.prototype = Object.create(R3.D3.Material.prototype); +R3.D3.Material.Points.prototype.constructor = R3.D3.Material.Points; + +/** + * Creates an instance of our texture object + * @returns {*} + */ +R3.D3.Material.Points.prototype.createInstance = function() { + + this.instance = new THREE.PointsMaterial( + { + color : this.color.instance, + map : this.diffuseMap ? this.diffuseMap.instance : null, + size : this.size, + sizeAttenuation : this.sizeAttenuation + } + ); + + R3.D3.Material.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Material.Points.prototype.updateInstance = function(property) { + + if (property === 'color') { + this.instance.color = this.color.instance; + return; + } + + if (property === 'diffuseMap') { + this.assignTexture('map', property); + return; + } + + if (property === 'size') { + this.instance.size = this.size; + return; + } + + if (property === 'sizeAttenuation') { + this.instance.sizeAttenuation = this.sizeAttenuation; + this.instance.needsUpdate = true; + return; + } + + R3.D3.Material.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Material.Points to a R3.D3.API.Material.Points + * @returns {R3.D3.API.Material.Points} + */ +R3.D3.Material.Points.prototype.toApiObject = function() { + + var apiMaterial = R3.D3.Material.prototype.toApiObject.call(this); + + var apiMaterialPoints = new R3.D3.API.Material.Points( + apiMaterial, + this.color.toApiObject(), + R3.Utils.IdOrNull(this.diffuseMap), + this.size, + this.sizeAttenuation + ); + + return apiMaterialPoints; +}; diff --git a/src/r3-d3-material-shader-a.js b/src/r3-d3-material-shader-a.js new file mode 100644 index 0000000..02e1fb5 --- /dev/null +++ b/src/r3-d3-material-shader-a.js @@ -0,0 +1,263 @@ +/** + * R3.D3.Material.Shader + * @param graphics + * @param apiMaterialShader + * @constructor + */ +R3.D3.Material.Shader = function( + graphics, + apiMaterialShader +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiMaterialShader)) { + apiMaterialShader = { + materialType : R3.D3.API.Material.MATERIAL_TYPE_SHADER + }; + } + + R3.D3.API.Material.Shader.call( + this, + apiMaterialShader, + apiMaterialShader.clipping, + apiMaterialShader.defaultAttributeValues, + apiMaterialShader.extensions, + apiMaterialShader.fog, + apiMaterialShader.fragmentShader, + apiMaterialShader.index0AttributeName, + apiMaterialShader.linewidth, + apiMaterialShader.morphTargets, + apiMaterialShader.morphNormals, + apiMaterialShader.program, + apiMaterialShader.skinning, + apiMaterialShader.uniforms, + apiMaterialShader.vertexColors, + apiMaterialShader.vertexShader, + apiMaterialShader.wireframe, + apiMaterialShader.wireframeLinewidth + ); + + this.vertexColors = true; + + R3.D3.Material.call( + this, + this.graphics, + this + ); + +}; + +R3.D3.Material.Shader.prototype = Object.create(R3.D3.Material.prototype); +R3.D3.Material.Shader.prototype.constructor = R3.D3.Material.Shader; + +R3.D3.Material.Shader.prototype.commonInstance = function() { +}; + +/** + * Creates an instance of our texture object + * @returns {*} + */ +R3.D3.Material.Shader.prototype.createInstance = function() { + + if (this.instance) { + + /** + * We already have an instance from Child Class + */ + + } else { + + if ( + R3.Utils.UndefinedOrNull(this.vertexShader) || + R3.Utils.UndefinedOrNull(this.vertexShader.instance) + ) { + console.warn('shader material ' + this.name + 'not ready for instance - needs a vertex shader'); + return; + } + + if ( + R3.Utils.UndefinedOrNull(this.fragmentShader) || + R3.Utils.UndefinedOrNull(this.fragmentShader.instance) + ) { + console.warn('shader material ' + this.name + 'not ready for instance - needs a fragment shader'); + return; + } + + this.instance = new THREE.ShaderMaterial( + { + clipping : this.clipping, + defaultAttributeValues : this.defaultAttributeValues, + extensions : this.extensions, + fog : this.fog, + fragmentShader : this.fragmentShader.instance, + linewidth : this.linewidth, + morphTargets : this.morphTargets, + morphNormals : this.morphNormals, + skinning : this.skinning, + uniforms : this.uniforms, + vertexColors : this.vertexColors, + vertexShader : this.vertexShader.instance, + wireframe : this.wireframe, + wireframeLinewidth : this.wireframeLinewidth + } + ); + } + + if (R3.Utils.Defined(this.index0AttributeName)) { + this.instance.index0AttributeName = this.index0AttributeName; + } + + console.log('shader material instance created'); + + R3.D3.Material.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Material.Shader.prototype.updateInstance = function(property) { + + if (!this.instance) { + + if ( + property === 'vertexShader' || + property === 'fragmentShader' + ) { + this.createInstance(); + } + + /** + * If we don't return here - we risk storing this incomplete type with the entity.. + */ + + return; + } + + if (property === 'clipping') { + this.instance.clipping = this.clipping; + return; + } + + if (property === 'defaultAttributeValues') { + this.instance.defaultAttributeValues = this.defaultAttributeValues; + return; + } + + if (property === 'extensions') { + this.instance.extensions = this.extensions; + return; + } + + if (property === 'fog') { + this.instance.fog = this.fog; + return; + } + + if (property === 'fragmentShader') { + + if (this.fragmentShader && this.fragmentShader.instance) { + this.instance.fragmentShader = this.fragmentShader.instance; + this.instance.needsUpdate = true; + } else { + console.warn('fragment shader for material has been removed or not linked - using last valid fragment shader'); + } + return; + } + + if (property === 'index0AttributeName') { + this.instance.index0AttributeName = this.index0AttributeName; + return; + } + + if (property === 'linewidth') { + this.instance.linewidth = this.linewidth; + return; + } + + if (property === 'morphNormals') { + this.instance.morphNormals = this.morphNormals; + return; + } + + if (property === 'morphTargets') { + this.instance.morphTargets = this.morphTargets; + return; + } + + if (property === 'program') { + console.warn('program is read only'); + this.program = this.instance.program; + } + + if (property === 'skinning') { + this.instance.skinning = this.skinning; + return; + } + + if (property === 'uniforms') { + this.instance.uniforms = this.uniforms; + return; + } + + if (property === 'vertexShader') { + + if (this.vertexShader && this.vertexShader.instance) { + this.instance.vertexShader = this.vertexShader.instance; + this.instance.needsUpdate = true; + } else { + console.warn('vertex shader for material has been removed or not linked - using last valid vertex shader'); + } + + return; + } + + if (property === 'vertexColors') { + this.instance.vertexColors = this.vertexColors; + this.instance.needsUpdate = true; + return; + } + + if (property === 'wireframe') { + this.instance.wireframe = this.wireframe; + return; + } + + if (property === 'wireframeLinewidth') { + this.instance.wireframeLinewidth = this.wireframeLinewidth; + return; + } + + R3.D3.Material.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Material.Shader to a R3.D3.API.Material.Shader + * @returns {R3.D3.API.Material.Shader} + */ +R3.D3.Material.Shader.prototype.toApiObject = function() { + + var apiMaterial = R3.D3.Material.prototype.toApiObject.call(this); + + var apiMaterialShader = new R3.D3.API.Material.Shader( + apiMaterial, + this.clipping, + this.defaultAttributeValues, + this.extensions, + this.fog, + R3.Utils.IdOrNull(this.fragmentShader), + this.index0AttributeName, + this.linewidth, + this.morphTargets, + this.morphNormals, + null, + this.skinning, + this.uniforms, + this.vertexColors, + R3.Utils.IdOrNull(this.vertexShader), + this.wireframe, + this.wireframeLinewidth + ); + + return apiMaterialShader; +}; diff --git a/src/r3-d3-material-shader-raw.js b/src/r3-d3-material-shader-raw.js new file mode 100644 index 0000000..ebeb6fa --- /dev/null +++ b/src/r3-d3-material-shader-raw.js @@ -0,0 +1,100 @@ +/** + * R3.D3.Material.Shader.Raw + * @param graphics + * @param apiMaterialShaderRaw + * @constructor + */ +R3.D3.Material.Shader.Raw = function( + graphics, + apiMaterialShaderRaw +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiMaterialShaderRaw)) { + apiMaterialShaderRaw = { + materialType : R3.D3.API.Material.MATERIAL_TYPE_SHADER_RAW + }; + } + + R3.D3.API.Material.Shader.Raw.call( + this, + apiMaterialShaderRaw + ); + + R3.D3.Material.Shader.call( + this, + this.graphics, + this + ); + +}; + +R3.D3.Material.Shader.Raw.prototype = Object.create(R3.D3.Material.Shader.prototype); +R3.D3.Material.Shader.Raw.prototype.constructor = R3.D3.Material.Shader.Raw; + +/** + * Creates an instance of our texture object + * @returns {*} + */ +R3.D3.Material.Shader.Raw.prototype.createInstance = function() { + + if ( + R3.Utils.UndefinedOrNull(this.vertexShader) || + R3.Utils.UndefinedOrNull(this.vertexShader.instance) + ) { + console.warn('shader material ' + this.name + 'not ready for instance - needs a vertex shader'); + return; + } + + if ( + R3.Utils.UndefinedOrNull(this.fragmentShader) || + R3.Utils.UndefinedOrNull(this.fragmentShader.instance) + ) { + console.warn('shader material ' + this.name + 'not ready for instance - needs a fragment shader'); + return; + } + + this.instance = new THREE.RawShaderMaterial( + { + clipping : this.clipping, + defaultAttributeValues : this.defaultAttributeValues, + extensions : this.extensions, + fog : this.fog, + fragmentShader : this.fragmentShader.instance, + linewidth : this.linewidth, + morphTargets : this.morphTargets, + morphNormals : this.morphNormals, + skinning : this.skinning, + uniforms : this.uniforms, + vertexColors : this.vertexColors, + vertexShader : this.vertexShader.instance, + wireframe : this.wireframe, + wireframeLinewidth : this.wireframeLinewidth + } + ); + + R3.D3.Material.Shader.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Material.Shader.Raw.prototype.updateInstance = function(property) { + R3.D3.Material.Shader.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Material.Shader.Raw to a R3.D3.API.Material.Shader.Raw + * @returns {R3.D3.API.Material.Shader.Raw} + */ +R3.D3.Material.Shader.Raw.prototype.toApiObject = function() { + + var apiMaterialShader = R3.D3.Material.Shader.prototype.toApiObject.call(this); + + var apiMaterialShaderRaw = new R3.D3.API.Material.Shader.Raw( + apiMaterialShader + ); + + return apiMaterialShaderRaw; +}; diff --git a/src/r3-d3-material-standard.js b/src/r3-d3-material-standard.js new file mode 100644 index 0000000..925c84c --- /dev/null +++ b/src/r3-d3-material-standard.js @@ -0,0 +1,376 @@ +/** + * R3.D3.Material.Standard + * @param graphics + * @param apiMaterialStandard + * @constructor + */ +R3.D3.Material.Standard = function( + graphics, + apiMaterialStandard +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiMaterialStandard)) { + apiMaterialStandard = { + materialType : R3.D3.API.Material.MATERIAL_TYPE_STANDARD + }; + } + + R3.D3.API.Material.Standard.call( + this, + apiMaterialStandard, + apiMaterialStandard.alphaMap, + apiMaterialStandard.aoMap, + apiMaterialStandard.aoMapIntensity, + apiMaterialStandard.bumpMap, + apiMaterialStandard.bumpScale, + apiMaterialStandard.color, + apiMaterialStandard.displacementMap, + apiMaterialStandard.displacementScale, + apiMaterialStandard.displacementBias, + apiMaterialStandard.emissive, + apiMaterialStandard.emissiveMap, + apiMaterialStandard.emissiveIntensity, + apiMaterialStandard.envMap, + apiMaterialStandard.envMapIntensity, + apiMaterialStandard.lightMap, + apiMaterialStandard.lightMapIntensity, + apiMaterialStandard.diffuseMap, + apiMaterialStandard.metalness, + apiMaterialStandard.metalnessMap, + apiMaterialStandard.morphNormals, + apiMaterialStandard.morphTargets, + apiMaterialStandard.normalMap, + apiMaterialStandard.normalScale, + apiMaterialStandard.refractionRatio, + apiMaterialStandard.roughness, + apiMaterialStandard.roughnessMap, + apiMaterialStandard.skinning, + apiMaterialStandard.wireframe, + apiMaterialStandard.wireframeLinecap, + apiMaterialStandard.wireframeLinejoin, + apiMaterialStandard.wireframeLinewidth + ); + + if (this.alphaMap instanceof R3.D3.API.Texture) { + this.alphaMap = R3.Component.ConstructFromObject(this.alphaMap); + } + + if (this.aoMap instanceof R3.D3.API.Texture) { + this.aoMap = R3.Component.ConstructFromObject(this.aoMap); + } + + if (this.bumpMap instanceof R3.D3.API.Texture) { + this.bumpMap = R3.Component.ConstructFromObject(this.bumpMap); + } + + + this.color = new R3.Color( + this.graphics, + this.color, + this + ); + + if (this.displacementMap instanceof R3.D3.API.Texture) { + this.displacementMap = R3.Component.ConstructFromObject(this.displacementMap); + } + + this.emissive = new R3.Color( + this.graphics, + this.emissive, + this + ); + + if (this.emissiveMap instanceof R3.D3.API.Texture) { + this.emissiveMap = R3.Component.ConstructFromObject(this.emissiveMap); + } + + if (this.envMap instanceof R3.D3.API.Texture) { + this.envMap = R3.Component.ConstructFromObject(this.envMap); + } + + if (this.lightMap instanceof R3.D3.API.Texture) { + this.lightMap = R3.Component.ConstructFromObject(this.lightMap); + } + + if (this.diffuseMap instanceof R3.D3.API.Texture) { + this.diffuseMap = R3.Component.ConstructFromObject(this.diffuseMap); + } + + if (this.metalnessMap instanceof R3.D3.API.Texture) { + this.metalnessMap = R3.Component.ConstructFromObject(this.metalnessMap); + } + + if (this.normalMap instanceof R3.D3.API.Texture) { + this.normalMap = R3.Component.ConstructFromObject(this.normalMap); + } + + if (this.roughnessMap instanceof R3.D3.API.Texture) { + this.roughnessMap = R3.Component.ConstructFromObject(this.roughnessMap); + } + + R3.D3.Material.call( + this, + this.graphics, + this + ); + +}; + +R3.D3.Material.Standard.prototype = Object.create(R3.D3.Material.prototype); +R3.D3.Material.Standard.prototype.constructor = R3.D3.Material.Standard; + +/** + * Creates an instance of our texture object + * @returns {*} + */ +R3.D3.Material.Standard.prototype.createInstance = function() { + + this.instance = new THREE.MeshStandardMaterial( + { + alphaMap : this.alphaMap ? this.alphaMap.instance : null, + aoMap : this.aoMap ? this.aoMap.instance : null, + aoMapIntensity : this.aoMapIntensity, + bumpMap : this.bumpMap ? this.bumpMap.instance : null, + bumpScale : this.bumpScale, + color : this.color.instance, + displacementMap : this.displacementMap ? this.displacementMap.instance : null, + displacementScale : this.displacementScale, + displacementBias : this.displacementBias, + emissive : this.emissive.instance, + emissiveMap : this.emissiveMap ? this.emissiveMap.instance : null, + emissiveIntensity : this.emissiveIntensity, + envMap : this.envMap ? this.envMap.instance : null, + envMapIntensity : this.envMapIntensity, + lightMap : this.lightMap ? this.lightMap.instance : null, + lightMapIntensity : this.lightMapIntensity, + map : this.diffuseMap ? this.diffuseMap.instance : null, + metalness : this.metalness, + metalnessMap : this.metalnessMap ? this.metalnessMap.instance : null, + morphNormals : this.morphNormals, + morphTargets : this.morphTargets, + normalMap : this.normalMap ? this.normalMap.instance : null, + normalScale : this.normalScale, + refractionRatio : this.refractionRatio, + roughness : this.roughness, + roughnessMap : this.roughnessMap ? this.roughnessMap.instance : null, + skinning : this.skinning, + wireframe : this.wireframe, + wireframeLinecap : this.wireframeLinecap, + wireframeLinejoin : this.wireframeLinejoin, + wireframeLinewidth : this.wireframeLinewidth + } + ); + + R3.D3.Material.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Material.Standard.prototype.updateInstance = function(property) { + + if (property === 'alphaMap') { + this.assignTexture('alphaMap', property); + return; + } + + if (property === 'aoMap') { + this.assignTexture('aoMap', property); + return; + } + + if (property === 'aoMapIntensity') { + this.instance.aoMapIntensity = this.aoMapIntensity; + return; + } + + if (property === 'bumpMap') { + this.assignTexture('bumpMap', property); + return; + } + + if (property === 'bumpScale') { + this.instance.bumpScale = this.bumpScale; + return; + } + + if (property === 'color') { + this.instance.color = this.color.instance; + return; + } + + if (property === 'displacementMap') { + this.assignTexture('displacementMap', property); + return; + } + + if (property === 'displacementScale') { + this.instance.displacementScale = this.displacementScale; + return; + } + + if (property === 'displacementBias') { + this.instance.displacementBias = this.displacementBias; + return; + } + + if (property === 'emissive') { + this.instance.emissive = this.emissive.instance; + return; + } + + if (property === 'emissiveMap') { + this.assignTexture('emissiveMap', property); + return; + } + + if (property === 'emissiveIntensity') { + this.instance.emissiveIntensity = this.emissiveIntensity; + return; + } + + if (property === 'envMap') { + this.assignTexture('envMap', property); + return; + } + + if (property === 'envMapIntensity') { + this.instance.envMapIntensity = this.envMapIntensity; + return; + } + + if (property === 'lightMap') { + this.assignTexture('lightMap', property); + return; + } + + if (property === 'lightMapIntensity') { + this.instance.lightMapIntensity = this.lightMapIntensity; + return; + } + + if (property === 'diffuseMap') { + this.assignTexture('map', property); + return; + } + + if (property === 'metalness') { + this.instance.metalness = this.metalness; + return; + } + + if (property === 'metalnessMap') { + this.assignTexture('metalnessMap', property); + return; + } + + if (property === 'morphNormals') { + this.instance.morphNormals = this.morphNormals; + return; + } + + if (property === 'morphTargets') { + this.instance.morphTargets = this.morphTargets; + return; + } + + if (property === 'normalMap') { + this.assignTexture('normalMap', property); + return; + } + + if (property === 'normalScale') { + this.instance.normalScale = this.normalScale; + return; + } + + if (property === 'refractionRatio') { + this.instance.refractionRatio = this.refractionRatio; + return; + } + + if (property === 'roughness') { + this.instance.roughness = this.roughness; + return; + } + + if (property === 'roughnessMap') { + this.assignTexture('roughnessMap', property); + return; + } + + if (property === 'skinning') { + this.instance.skinning = this.skinning; + return; + } + + if (property === 'wireframe') { + this.instance.wireframe = this.wireframe; + return; + } + + if (property === 'wireframeLinecap') { + this.instance.wireframeLinecap = this.wireframeLinecap; + return; + } + + if (property === 'wireframeLinejoin') { + this.instance.wireframeLinejoin = this.wireframeLinejoin; + return; + } + + if (property === 'wireframeLinewidth') { + this.instance.wireframeLinewidth = this.wireframeLinewidth; + return; + } + + R3.D3.Material.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Material.Standard to a R3.D3.API.Material.Standard + * @returns {R3.D3.API.Material.Standard} + */ +R3.D3.Material.Standard.prototype.toApiObject = function() { + + var apiMaterial = R3.D3.Material.prototype.toApiObject.call(this); + + var apiMaterialStandard = new R3.D3.API.Material.Standard( + apiMaterial, + R3.Utils.IdOrNull(this.alphaMap), + R3.Utils.IdOrNull(this.aoMap), + this.aoMapIntensity, + R3.Utils.IdOrNull(this.bumpMap), + this.bumpScale, + this.color.toApiObject(), + R3.Utils.IdOrNull(this.displacementMap), + this.displacementScale, + this.displacementBias, + this.emissive.toApiObject(), + R3.Utils.IdOrNull(this.emissiveMap), + this.emissiveIntensity, + R3.Utils.IdOrNull(this.envMap), + this.envMapIntensity, + R3.Utils.IdOrNull(this.lightMap), + this.lightMapIntensity, + R3.Utils.IdOrNull(this.diffuseMap), + this.metalness, + R3.Utils.IdOrNull(this.metalnessMap), + this.morphNormals, + this.morphTargets, + R3.Utils.IdOrNull(this.normalMap), + this.normalScale, + this.refractionRatio, + this.roughness, + R3.Utils.IdOrNull(this.roughnessMap), + this.skinning, + this.wireframe, + this.wireframeLinecap, + this.wireframeLinejoin, + this.wireframeLinewidth + ); + + return apiMaterialStandard; +}; diff --git a/src/r3-d3-mesh-0.js b/src/r3-d3-mesh-0.js new file mode 100644 index 0000000..bbd2708 --- /dev/null +++ b/src/r3-d3-mesh-0.js @@ -0,0 +1,666 @@ +/** + * R3.D3.Mesh + * @param graphics R3.GraphicsRuntime + * @param apiD3ObjectMesh R3.D3.API.Mesh + * @property geometry + * @constructor + */ +R3.D3.Mesh = function ( + graphics, + apiD3ObjectMesh +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiD3ObjectMesh)) { + apiD3ObjectMesh = { + objectType: R3.D3.API.Object.OBJECT_TYPE_MESH + }; + } + + R3.D3.API.Mesh.call( + this, + apiD3ObjectMesh, + apiD3ObjectMesh.geometry, + apiD3ObjectMesh.materials, + apiD3ObjectMesh.parentMesh, + apiD3ObjectMesh.parentScene, + apiD3ObjectMesh.excludeFromEnvironment, + apiD3ObjectMesh.skeleton, + apiD3ObjectMesh.renderOrder, + apiD3ObjectMesh.visible, + apiD3ObjectMesh.castShadow, + apiD3ObjectMesh.receiveShadow, + apiD3ObjectMesh.drawMode, + apiD3ObjectMesh.morphTargetInfluences, + apiD3ObjectMesh.morphTargetDictionary, + apiD3ObjectMesh.cloneDirection + ); + + if ( + R3.Utils.Defined(this.geometry) && + R3.Utils.Defined(this.geometry.componentType) && + !(this.geometry instanceof R3.D3.Geometry) + ) { + this.geometry = R3.Component.ConstructFromObject(this.geometry); + } + + this.materials = this.materials.map( + function(material) { + + if ( + R3.Utils.Defined(material.componentType) && + !(material instanceof R3.D3.Material) + ) { + return R3.Component.ConstructFromObject(material); + } else { + return material; + } + + }.bind(this) + ); + + if (this.skeleton) { + this.skeleton = new R3.D3.Skeleton( + this.graphics, + this.skeleton + ); + } + + this.cloneDirection = new R3.Vector3( + this.graphics, + this.cloneDirection, + this + ); + + /** + * Runtime meshes have helpers too + * @type {null} + */ + this.helper = null; + + R3.D3.Object.call( + this, + this.graphics, + this + ); +}; + +R3.D3.Mesh.prototype = Object.create(R3.D3.Object.prototype); +R3.D3.Mesh.prototype.constructor = R3.D3.Mesh; + +/** + * Creates a mesh instance or updates it + */ +R3.D3.Mesh.prototype.createInstance = function() { + + if ( + R3.Utils.UndefinedOrNull(this.geometry) || + R3.Utils.UndefinedOrNull(this.geometry.instance) + ) { + console.warn('geometry not ready for this mesh ' + this.name); + return; + } + + this.geometry.parentMesh = this; + this.geometry.updateInstance('parentMesh'); + + var materialInstances = R3.Utils.GetArrayInstances(this.materials); + + if ( + R3.Utils.UndefinedOrNull(materialInstances) + ) { + console.warn('materials not ready for this mesh ' + this.name); + return; + } + + if (this.skeleton) { + + this.instance = new THREE.SkinnedMesh( + this.geometry.instance, + materialInstances + ); + + this.instance.add(this.skeleton.rootBoneInstance); + this.instance.bind(this.skeleton.instance); + + } else { + this.instance = new THREE.Mesh( + this.geometry.instance, + materialInstances + ); + } + + this.instance.name = this.name; + + if (R3.Utils.Defined(this.parentMesh)) { + + if (R3.Utils.UndefinedOrNull(this.parentMesh.instance)) { + console.warn('parent mesh not linked at time of create instance'); + } else { + this.parentMesh.add(this.instance, this); + } + + } + + if ( + R3.Utils.Defined(this.parentScene) && + R3.Utils.Defined(this.parentScene.instance) + ) { + this.parentScene.addObject(this); + } + + this.instance.renderOrder = this.renderOrder; + + this.instance.visible = this.visible; + + this.instance.castShadow = this.castShadow; + + this.instance.receiveShadow = this.receiveShadow; + + this.instance.drawMode = this.drawMode; + + /** + * The rest we update from the instance + */ + this.morphTargetInfluences = this.instance.morphTargetInfluences; + this.morphTargetDictionary = this.instance.morphTargetDictionary; + + R3.D3.Object.prototype.createInstance.call(this); +}; + +/** + * Updates the mesh instance + */ +R3.D3.Mesh.prototype.updateInstance = function(property) { + + if (R3.Utils.UndefinedOrNull(property)) { + console.warn('unknown mesh property update'); + } + + if (property === 'geometry') { + + if (R3.Utils.Defined(this.geometry)) { + + if (R3.Utils.UndefinedOrNull(this.geometry.instance)) { + console.warn('the geometry is not linked or constructed properly'); + return; + } + + this.geometry.parentMesh = this; + this.geometry.updateInstance('parentMesh'); + + if (R3.Utils.UndefinedOrNull(this.instance)) { + this.createInstance(); + } else { + this.instance.geometry = this.geometry.instance; + } + + } + + return; + } + + if (property === 'materials') { + + var materialInstances = R3.Utils.GetArrayInstances(this.materials); + + if (materialInstances) { + + if (R3.Utils.UndefinedOrNull(this.instance)) { + this.createInstance(); + } else { + this.instance.material = materialInstances; + } + + return; + + } else { + + console.warn('materials not ready for this mesh ' + this.name); + + if (R3.Utils.UndefinedOrNull(this.instance)) { + /** + * Do nothing + */ + } else { + + console.warn('warning - assigning no material to this mesh instance'); + /** + * Assign no material to this mesh - ok - I guess you know what you are doing. + * @type {null} + */ + this.instance.material = null; + } + + } + + return; + } + + if (R3.Utils.UndefinedOrNull(this.instance)) { + console.warn('mesh instance not ready - needs a material and geometry'); + return; + } + + if (property === 'name') { + this.instance.name = this.name; + return; + } + + if (property === 'excludeFromEnvironment') { + R3.Event.Emit( + R3.Event.EXCLUDE_FROM_ENVIRONMENT, + { + component : this + } + ) + } + + if (property === 'parentScene') { + /** + * This is handled by LinkingSystem - probably will change soon + */ + } + + if (property === 'parentMesh') { + + /** + * Check if we already have a parent mesh + */ + if (R3.Utils.UndefinedOrNull(this.parentMesh)) { + + /** + * We are detaching this instance from the parent + */ + if (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 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.updateInstance('position'); + + /** + * 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.parentMesh.instance) { + + /** + * Add this as a child to the parent + */ + this.parentMesh.instance.add(this.instance); + } + } + + if (this.parentMesh && this.parentMesh.instance) { + if (this.instance.parent !== this.parentMesh.instance) { + this.instance.parent = this.parentMesh.instance; + } + } + + if (this.helper) { + this.removeHelper(); + this.createHelper(); + } + + return; + } + + if (property === 'renderOrder') { + this.instance.renderOrder = this.renderOrder; + return; + } + + if (property === 'visible') { + this.instance.visible = this.visible; + return; + } + + if (property === 'castShadow') { + this.instance.castShadow = this.castShadow; + return; + } + + if (property === 'receiveShadow') { + this.instance.receiveShadow = this.receiveShadow; + return; + } + + if (property === 'drawMode') { + this.instance.drawMode = this.drawMode; + return; + } + + R3.D3.Object.prototype.updateInstance.call(this, property); + + /** + * Update our helper (if any) + */ + if ( + property === 'useQuaternion' || + property === 'position' || + property === 'rotation' || + property === 'quaternion' || + property === 'scale' || + property === 'up' || + property === 'lookAt' + ) { + if (this.helper) { + this.removeHelper(); + this.createHelper(); + } + } +}; + + +/** + * Converts a R3.D3.Mesh to a R3.D3.API.Mesh + * TODO: morph stuff + * @returns {R3.D3.API.Mesh} + */ +R3.D3.Mesh.prototype.toApiObject = function() { + + var apiD3Object = R3.D3.Object.prototype.toApiObject.call(this); + + var apiMesh = new R3.D3.API.Mesh( + apiD3Object, + + R3.Utils.IdOrNull(this.geometry), + this.materials.map( + function(material) { + return R3.Utils.IdOrNull(material) + } + ), + R3.Utils.IdOrNull(this.parentMesh), + R3.Utils.IdOrNull(this.parentScene), + this.excludeFromEnvironment, + R3.Utils.IdOrNull(this.skeleton), + this.renderOrder, + this.visible, + this.castShadow, + this.receiveShadow, + this.drawMode, + null,//morphTargetInfluences, + null,//morphTargetDictionary + this.cloneDirection.toApiObject() + ); + + return apiMesh; +}; + +R3.D3.Mesh.prototype.clone = function() { + + var name = this.name + '(' + this.cloneNumber + ')'; + + if (this.cloneNumber > 0) { + name = this.name.replace('(' + this.cloneNumber + ')', '(' + (this.cloneNumber + 1) + ')'); + } + + this.cloneNumber += 1; + + var x = this.position.x; + var y = this.position.y; + var z = this.position.z; + + if (this.cloneDirection.x < 0) { + x += this.geometry.boundingBox.min.x * 2; + } + + if (this.cloneDirection.x > 0) { + x += this.geometry.boundingBox.max.x * 2; + } + + if (this.cloneDirection.y < 0) { + y += this.geometry.boundingBox.min.y * 2; + } + + if (this.cloneDirection.y > 0) { + y += this.geometry.boundingBox.max.y * 2; + } + + if (this.cloneDirection.z < 0) { + z += this.geometry.boundingBox.min.z * 2; + } + + if (this.cloneDirection.z > 0) { + z += this.geometry.boundingBox.max.z * 2; + } + + var mesh = new R3.D3.Mesh( + this.graphics, + { + name : name, + materials : this.materials, + geometry : this.geometry, + position: new R3.API.Vector3(x, y, z), + scale: this.scale.toApiObject(), + rotation: this.rotation.toApiObject(), + quaternion: this.quaternion.toApiObject(), + useQuaternion: this.useQuaternion, + castShadow : this.castShadow, + receiveShadow : this.receiveShadow, + visible : this.visible + } + ); + + this.parentScene.addClone(mesh); + + return mesh; +}; + +/** + * Centers the mesh around origin + */ +R3.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; +}; + +/** + * Applies position, rotation and scale to the object vertice data, resets scale, rotation and sets position to origin. + */ +R3.D3.Mesh.prototype.applyPositionRotationScale = function() { + + /** + * Ensure our instance matrix is up to date + */ + this.instance.updateMatrix(); + + /** + * Apply our instance matrix to the geometry + */ + this.instance.geometry.applyMatrix(this.instance.matrix); + + /** + * Update our geometry from the instance + */ + this.geometry.updateFromInstance(); + + /** + * Reset position + * @type {number} + */ + this.position.x = 0; + this.position.y = 0; + this.position.z = 0; + this.updateInstance('position'); + + /** + * Reset scale + * @type {number} + */ + this.scale.x = 1; + this.scale.y = 1; + this.scale.z = 1; + this.updateInstance('scale'); + + /** + * 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.updateInstance('rotation'); +}; + +/** + * Gets all children components of this Mesh (all linked objects only - no object references i.e. string ids) + * @returns {Array} + */ +R3.D3.Mesh.prototype.getChildrenComponents = function() { + + var children = R3.Component.prototype.getChildrenComponents.call(this); + + /** + * Push RigidBodies + */ + R3.EntityManager.Instance.queryComponents(R3.Component.RIGID_BODY).map( + function(rigidBody) { + + if (rigidBody.parentMesh === this) { + R3.Utils.PushUnique(children, rigidBody); + } + + }.bind(this) + ); + + /** + * Push Shapes + */ + R3.EntityManager.Instance.queryComponents(R3.Component.SHAPE).map( + function(shape) { + + if (shape.parentMesh === this) { + R3.Utils.PushUnique(children, shape); + } + + }.bind(this) + ); + + return children; +}; + +/** + * Convenience function for creating a helper for this Mesh - should be called from Systems only + */ +R3.D3.Mesh.prototype.createHelper = function() { + + if (R3.Utils.UndefinedOrNull(this.parentScene) || + R3.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 R3.D3.Helper( + this.graphics, + null, + this.name + ' Helper', + this, + R3.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); + +}; + +/** + * Convenience function for removing a helper for this Mesh - should be called from Systems only + */ +R3.D3.Mesh.prototype.removeHelper = function() { + + if (R3.Utils.UndefinedOrNull(this.parentScene) || + R3.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; +}; diff --git a/src/r3-d3-particle-engine.js b/src/r3-d3-particle-engine.js new file mode 100644 index 0000000..3df577a --- /dev/null +++ b/src/r3-d3-particle-engine.js @@ -0,0 +1,272 @@ +/** + * Creates a ParticleEngine object + * @param graphics R3.GraphicsRuntime + * @param apiParticleEngine R3.D3.API.ParticleEngine + * @constructor + */ +R3.D3.ParticleEngine = function( + graphics, + apiParticleEngine +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiParticleEngine)) { + apiParticleEngine = {}; + } + + R3.D3.API.ParticleEngine.call( + this, + apiParticleEngine.id, + apiParticleEngine.name, + apiParticleEngine.position, + apiParticleEngine.direction, + apiParticleEngine.enabled, + apiParticleEngine.templateParticle, + apiParticleEngine.particlesPerSecond, + apiParticleEngine.frequency, + apiParticleEngine.elapsed, + apiParticleEngine.camera, + apiParticleEngine.pulse, + apiParticleEngine.fired, + apiParticleEngine.parentEntity + ); + + this.position = new R3.Vector3( + graphics, + this.position, + this + ); + + this.direction = new R3.Vector3( + graphics, + this.direction, + this + ); + + if (this.templateParticle instanceof R3.D3.API.Particle) { + this.templateParticle = new R3.D3.Particle( + graphics, + this.templateParticle + ) + } + + this.elapsed = 0; + + this.particles = []; + + this.disabledForRemoval = false; + + R3.Component.call( + this, + { + templateParticle : R3.D3.Particle, + camera : R3.D3.Camera + } + ); + +}; + +R3.D3.ParticleEngine.prototype = Object.create(R3.Component.prototype); +R3.D3.ParticleEngine.prototype.constructor = R3.D3.ParticleEngine; + +/** + * We don't use a 3rd party particle engine right now + * @returns true + */ +R3.D3.ParticleEngine.prototype.createInstance = function() { + + this.instance = true; + + // if (this.templateParticle) { + // + // this.templateParticle.mesh.position.x = this.position.x; + // this.templateParticle.mesh.position.y = this.position.y; + // this.templateParticle.mesh.position.z = this.position.z; + // + // this.templateParticle.direction.x = this.direction.x; + // this.templateParticle.direction.y = this.direction.y; + // this.templateParticle.direction.z = this.direction.z; + // + // this.templateParticle.scale.x = this.scale.x; + // this.templateParticle.scale.y = this.scale.y; + // this.templateParticle.scale.z = this.scale.z; + // } + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.ParticleEngine.prototype.updateInstance = function(property) { + + if (property === 'particlesPerSecond') { + this.frequency = Number(1 / this.particlesPerSecond); + } + + if (property === 'frequency') { + this.particlesPerSecond = Math.round(1 / this.frequency); + } + + if (property === 'position') { + this.position.instance.x = this.position.x; + this.position.instance.y = this.position.y; + this.position.instance.z = this.position.z; + this.templateParticle.mesh.position = this.position.clone(); + this.templateParticle.mesh.updateInstance('position', true); + } + + if (property === 'direction') { + this.direction.instance.x = this.direction.x; + this.direction.instance.y = this.direction.y; + this.direction.instance.z = this.direction.z; + this.templateParticle.direction = this.direction.clone(); + this.templateParticle.direction.updateInstance('direction', true); + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +R3.D3.ParticleEngine.prototype.remove = function() { + + if (this.removeSubscription) { + console.log('already another remove subscription for ' + this.name); + return; + } + + this.removeSubscription = R3.Event.Subscribe( + R3.Event.REMOVE_PARTICLE_ENGINE, + function(data){ + if (data.component === this) { + + if (this.isClone) { + /** + * We only remove the things we cloned, the mesh, particle, and this + */ + R3.Event.Emit( + R3.Event.REMOVE_COMPONENT, + { + component: this.templateParticle.mesh + } + ); + + R3.Event.Emit( + R3.Event.REMOVE_COMPONENT, + { + component: this.templateParticle + } + ); + + R3.Event.Emit( + R3.Event.REMOVE_COMPONENT, + { + component: this + } + ) + } else { + R3.Component.prototype.remove.call(this); + } + + this.removeSubscription.remove(); + + this.removeSubscription = null; + } + }.bind(this) + ); + + /** + * Below signals the particle system to continue processing the particles, but don't create more, and + * we wait for the system to signal REMOVE_PARTICLE_ENGINE so we can destroy ourselves + * @type {boolean} + */ + this.disabledForRemoval = true; +}; + +// R3.D3.ParticleEngine.prototype.getChildrenComponents = function() { +// +// var components = []; +// +// if (this.templateParticle) { +// components.push(this.templateParticle); +// +// if (this.templateParticle.mesh) { +// components.push(this.templateParticle.mesh); +// +// if (this.templateParticle.mesh.materials && this.templateParticle.mesh.materials[0]) { +// +// components.push(this.templateParticle.mesh.materials[0]); +// +// if (this.templateParticle.mesh.materials[0].diffuseMap) { +// components.push(this.templateParticle.mesh.materials[0].diffuseMap); +// } +// } +// } +// } +// +// return components; +// }; + +R3.D3.ParticleEngine.prototype.clone = function() { + var mesh = this.templateParticle.mesh.clone(); + var templateParticle = this.templateParticle.clone(); + templateParticle.mesh = mesh; + templateParticle.instance = mesh.instance; + var engine = R3.Component.prototype.clone.call(this); + engine.templateParticle = templateParticle; + return engine; +}; + +R3.D3.ParticleEngine.prototype.processParticles = function(delta) { + // this.particles = this.particles.reduce( + // function(result, particle){ + // + // particle.position.x += particle.userData.direction.x * delta; + // particle.position.y += particle.userData.direction.y * delta; + // particle.position.z += particle.userData.direction.z * delta; + // + // particle.userData.elapsed += delta; + // if (particle.userData.elapsed > particle.userData.lifeTime) { + // particle.parent.remove(particle); + // } else { + // result.push(particle); + // } + // + // return result; + // }, + // [] + // ); +}; + +R3.D3.ParticleEngine.prototype.createNewParticle = function(camera) { + // + // var particle = this.templateParticle.clone(camera); + // + // this.particles.push(particle); + +}; + +/** + * Converts a R3.D3.ParticleEngine to a new R3.D3.API.ParticleEngine + * @returns {R3.D3.API.ParticleEngine} + */ +R3.D3.ParticleEngine.prototype.toApiObject = function() { + + return new R3.D3.API.ParticleEngine( + this.id, + this.name, + this.position.toApiObject(), + this.direction.toApiObject(), + this.enabled, + R3.Utils.IdOrNull(this.templateParticle), + this.particlesPerSecond, + this.frequency, + this.elapsed, + R3.Utils.IdOrNull(this.camera), + this.pulse, + this.fired, + R3.Utils.IdOrNull(this.parentEntity) + ); + +}; diff --git a/src/r3-d3-particle.js b/src/r3-d3-particle.js new file mode 100644 index 0000000..c1e2e9a --- /dev/null +++ b/src/r3-d3-particle.js @@ -0,0 +1,354 @@ +/** + * Creates a Particle object + * @param graphics R3.GraphicsRuntime + * @param apiParticle R3.D3.API.Particle + * @constructor + */ +R3.D3.Particle = function( + graphics, + apiParticle +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiParticle)) { + apiParticle = {}; + } + + R3.D3.API.Particle.call( + this, + apiParticle.id, + apiParticle.name, + apiParticle.lifeTime, + apiParticle.elapsed, + apiParticle.mesh, + apiParticle.opacityType, + apiParticle.fadeInFactor, + apiParticle.fadeOutFactor, + apiParticle.fadeInAfter, + apiParticle.fadeOutAfter, + 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.parentParticleEngine, + apiParticle.parentEntity + ); + + if (this.mesh instanceof R3.D3.API.Mesh) { + this.mesh = new R3.D3.Mesh( + graphics, + this.mesh + ) + } + + this.positionOffset = new R3.Vector3( + graphics, + this.positionOffset, + this + ); + + this.direction = new R3.Vector3( + graphics, + this.direction, + this + ); + + this.scale = new R3.Vector3( + graphics, + this.scale, + this + ); + + this.rotation = new R3.Vector3( + graphics, + this.rotation, + this + ); + + R3.Component.call( + this, + { + mesh : R3.D3.Mesh, + parentParticleEngine : R3.D3.ParticleEngine + } + ); + +}; + +R3.D3.Particle.prototype = Object.create(R3.Component.prototype); +R3.D3.Particle.prototype.constructor = R3.D3.Particle; + +/** + * Particle create instance + */ +R3.D3.Particle.prototype.createInstance = function() { + + if (!this.mesh) { + console.warn('no mesh to clone from - failed dependency check?'); + return + } + + this.instance = this.mesh.instance; + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Particle.prototype.updateInstance = function(property) { + + if (!this.instance) { + this.createInstance(); + if (!this.instance) { + return; + } + } + + 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; + } + + if (property === 'mesh') { + if (this.mesh) { + this.createInstance(); + } + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + + +/** + * Clones a particle - this only clones 3rd party instances, so we have less overhead of creating these types of objects + */ +R3.D3.Particle.prototype.cloneInstance = function() { + + this.updateInstance('positionOffset'); + this.updateInstance('direction'); + this.updateInstance('scale'); + this.updateInstance('rotation'); + + var clone = R3.Component.prototype.cloneInstance.call(this); + + clone.position = this.parentParticleEngine.position.instance.clone(); + + clone.material = this.mesh.materials[0].instance.clone(); + + clone.visible = true; + + if (this.positionOffsetType === R3.D3.API.Particle.POSITION_OFFSET_TYPE_CONSTANT) { + clone.position.add(this.positionOffset.instance); + } + + var addX = 1; + var addY = 1; + var addZ = 1; + + if (this.positionOffsetType === R3.D3.API.Particle.POSITION_OFFSET_TYPE_RANDOM) { + + addX = R3.Utils.GetRandomIntInclusive(1,2); + addY = R3.Utils.GetRandomIntInclusive(1,2); + addZ = R3.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 === R3.D3.API.Particle.DIRECTION_TYPE_CONSTANT) { + + /** + * Nothing to do + */ + + } else if ( + this.directionType === R3.D3.API.Particle.DIRECTION_TYPE_RANDOM || + this.directionType === R3.D3.API.Particle.DIRECTION_TYPE_RANDOM_NORMALIZED + ) { + + addX = R3.Utils.GetRandomIntInclusive(1,2); + addY = R3.Utils.GetRandomIntInclusive(1,2); + addZ = R3.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 === R3.D3.API.Particle.DIRECTION_TYPE_RANDOM_NORMALIZED) { + clone.userData.direction.normalize(); + } + + } else { + throw new Error('not yet implemented') + } + + + if (this.scaleType === R3.D3.API.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 === R3.D3.API.Particle.SCALE_TYPE_RANDOM) { + + add = R3.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 === R3.D3.API.Particle.SCALE_TYPE_RANDOM_X_EQUALS_Y) { + + add = R3.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; + } + } + + var fadeIn = true; + + if ( + this.opacityType === R3.D3.API.Particle.OPACITY_TYPE_FADE_IN_LINEAR || + this.opacityType === R3.D3.API.Particle.OPACITY_TYPE_FADE_IN_OUT_LINEAR + ) { + clone.material.opacity = 0; + fadeIn = true; + } + + if (this.opacityType === R3.D3.API.Particle.OPACITY_TYPE_FADE_OUT_LINEAR) { + clone.material.opacity = 1; + fadeIn = false; + } + clone.userData.fadeIn = fadeIn; + 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 R3.D3.Particle to a new R3.D3.API.Particle + * @returns {R3.D3.API.Particle} + */ +R3.D3.Particle.prototype.toApiObject = function() { + + return new R3.D3.API.Particle( + this.id, + this.name, + this.lifeTime, + this.elapsed, + R3.Utils.IdOrNull(this.mesh), + this.opacityType, + this.fadeInFactor, + this.fadeOutFactor, + this.fadeInAfter, + this.fadeOutAfter, + 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, + R3.Utils.IdOrNull(this.parentParticleEngine), + R3.Utils.IdOrNull(this.parentEntity) + ); + +}; diff --git a/src/r3-d3-pass-0.js b/src/r3-d3-pass-0.js new file mode 100644 index 0000000..a9e90ce --- /dev/null +++ b/src/r3-d3-pass-0.js @@ -0,0 +1,114 @@ +/** + * R3.D3.Pass + * @param graphics R3.GraphicsRuntime + * @param apiPass R3.D3.API.Pass + * @property passType + * @constructor + */ +R3.D3.Pass = function ( + graphics, + apiPass +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiPass)) { + apiPass = { + passType : R3.D3.API.Pass.PASS_TYPE_NONE + } + } + + R3.D3.API.Pass.call( + this, + apiPass.id, + apiPass.name, + apiPass.passType, + apiPass.parentEntity, + apiPass.renderToScreen + ); + + var linkedObjects = {}; + + switch (this.passType) { + case R3.D3.API.Pass.PASS_TYPE_RENDER: + case R3.D3.API.Pass.PASS_TYPE_SSAO: + linkedObjects.scene = R3.D3.Scene; + linkedObjects.camera = R3.D3.Camera; + break; + default : + break; + } + + R3.Component.call( + this, + linkedObjects + ); +}; + +R3.D3.Pass.prototype = Object.create(R3.Component.prototype); +R3.D3.Pass.prototype.constructor = R3.D3.Pass; + + +/** + * Create Pass instance + * @returns {*} + */ +R3.D3.Pass.prototype.createInstance = function() { + + if (R3.Utils.UndefinedOrNull(this.instance)) { + console.warn('no instance - call the child createInstance() first'); + return; + } + + this.instance.renderToScreen = this.renderToScreen; + + R3.Component.prototype.createInstance.call(this); + +}; + +/** + * Update Pass instance + */ +R3.D3.Pass.prototype.updateInstance = function(property) { + + + if (property === 'passType') { + + var componentType = R3.D3.API.Pass.GetComponentType(this.passType); + + this.replace(componentType); + + return; + } + + if (property === 'renderToScreen') { + this.instance.renderToScreen = this.renderToScreen; + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * Not all passes have setSize, but this is just a safety function in case someone calls setSize on a pass component + * @param property + */ +R3.D3.Pass.prototype.setSize = function(property) { +}; + +/** + * R3.D3.Pass to R3.D3.API.Pass + * @returns {R3.D3.API.Pass} + */ +R3.D3.Pass.prototype.toApiObject = function() { + + var apiPass = new R3.D3.API.Pass( + this.id, + this.name, + this.passType, + R3.Utils.IdOrNull(this.parentEntity), + this.renderToScreen + ); + + return apiPass; +}; diff --git a/src/r3-d3-pass-bloom.js b/src/r3-d3-pass-bloom.js new file mode 100644 index 0000000..66766ca --- /dev/null +++ b/src/r3-d3-pass-bloom.js @@ -0,0 +1,138 @@ +/** + * R3.D3.Pass.Bloom + * @param graphics R3.GraphicsRuntime + * @param apiPassBloom R3.D3.API.Pass.Bloom + * @constructor + */ +R3.D3.Pass.Bloom = function ( + graphics, + apiPassBloom +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiPassBloom)) { + apiPassBloom = { + passType : R3.D3.API.Pass.PASS_TYPE_BLOOM + }; + } + + R3.D3.API.Pass.Bloom.call( + this, + apiPassBloom, + apiPassBloom.autoUpdateSize, + apiPassBloom.width, + apiPassBloom.height, + apiPassBloom.strength, + apiPassBloom.radius, + apiPassBloom.threshold + ); + + R3.D3.Pass.call( + this, + this.graphics, + this + ); +}; + +R3.D3.Pass.Bloom.prototype = Object.create(R3.D3.Pass.prototype); +R3.D3.Pass.Bloom.prototype.constructor = R3.D3.Pass.Bloom; + +/** + * Create Pass.Bloom instance + * @returns {*} + */ +R3.D3.Pass.Bloom.prototype.createInstance = function() { + + if (this.autoUpdateSize) { + R3.Utils.UpdateWindowSize(this); + } + + this.instance = new THREE.UnrealBloomPass( + new THREE.Vector2( + this.width, + this.height + ), + this.strength, + this.radius, + this.threshold + ); + + console.log('Constructed a bloom pass instance'); + + R3.D3.Pass.prototype.createInstance.call(this); +}; + +/** + * Update Pass.Bloom instance + */ +R3.D3.Pass.Bloom.prototype.updateInstance = function(property) { + + if ( + property === 'width' || + property === 'height' || + property === 'autoUpdateSize' + ) { + if (this.autoUpdateSize) { + R3.Utils.UpdateWindowSize(this); + } + + this.instance.setSize( + this.width, + this.height + ); + + return; + } + + if (property === 'strength') { + this.instance.strength = this.strength; + return; + } + + if (property === 'radius') { + this.instance.radius = this.radius; + return; + } + + if (property === 'threshold') { + this.instance.threshold = this.threshold; + return; + } + + R3.D3.Pass.prototype.updateInstance.call(this, property); + +}; + +/** + * Convenience function to set size + * @param width + * @param height + */ +R3.D3.Pass.Bloom.prototype.setSize = function(width, height) { + this.width = width; + this.height = height; + this.updateInstance('width'); +}; + +/** + * R3.D3.Pass.Bloom to R3.D3.API.Pass.Bloom + * @returns {R3.D3.API.Pass.Bloom} + */ +R3.D3.Pass.Bloom.prototype.toApiObject = function() { + + var apiPass = R3.D3.Pass.prototype.toApiObject.call(this); + + var apiBloomPass = new R3.D3.API.Pass.Bloom( + apiPass, + this.autoUpdateSize, + this.width, + this.height, + this.strength, + this.radius, + this.threshold + ); + + return apiBloomPass; +}; diff --git a/src/r3-d3-pass-fxaa.js b/src/r3-d3-pass-fxaa.js new file mode 100644 index 0000000..7f7a4bc --- /dev/null +++ b/src/r3-d3-pass-fxaa.js @@ -0,0 +1,113 @@ +/** + * R3.D3.Pass.FXAA + * @param graphics R3.GraphicsRuntime + * @param apiPassFXAA R3.D3.API.Pass.FXAA + * @constructor + */ +R3.D3.Pass.FXAA = function ( + graphics, + apiPassFXAA +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiPassFXAA)) { + apiPassFXAA = { + passType : R3.D3.API.Pass.PASS_TYPE_FXAA + }; + } + + R3.D3.API.Pass.FXAA.call( + this, + apiPassFXAA, + apiPassFXAA.autoUpdateSize, + apiPassFXAA.width, + apiPassFXAA.height + ); + + R3.D3.Pass.call( + this, + this.graphics, + this + ); +}; + +R3.D3.Pass.FXAA.prototype = Object.create(R3.D3.Pass.prototype); +R3.D3.Pass.FXAA.prototype.constructor = R3.D3.Pass.FXAA; + +/** + * Create Pass.FXAA instance + * @returns {*} + */ +R3.D3.Pass.FXAA.prototype.createInstance = function() { + + this.instance = new THREE.ShaderPass(THREE.FXAAShader); + + if (this.autoUpdateSize) { + R3.Utils.UpdateWindowSize(this); + } + + this.instance.uniforms['resolution'].value.set( + 1 / this.width, + 1 / this.height + ); + + console.log('Constructed an FXAA pass instance'); + + R3.D3.Pass.prototype.createInstance.call(this); +}; + +/** + * Update Pass.FXAA instance + */ +R3.D3.Pass.FXAA.prototype.updateInstance = function(property) { + + if ( + property === 'width' || + property === 'height' || + property === 'autoUpdateSize' + ) { + if (this.autoUpdateSize) { + R3.Utils.UpdateWindowSize(this); + } + + this.instance.uniforms['resolution'].value.set( + 1 / this.width, + 1 / this.height + ); + return; + } + + R3.D3.Pass.prototype.updateInstance.call(this, property); + +}; + +/** + * Convenience function to set size + * @param width + * @param height + */ +R3.D3.Pass.FXAA.prototype.setSize = function(width, height) { + this.width = width; + this.height = height; + this.updateInstance('width'); +}; + +/** + * R3.D3.Pass.FXAA to R3.D3.API.Pass.FXAA + * @returns {R3.D3.API.Pass.FXAA} + */ +R3.D3.Pass.FXAA.prototype.toApiObject = function() { + + var apiPass = R3.D3.Pass.prototype.toApiObject.call(this); + + var apiFXAAPass = new R3.D3.API.Pass.FXAA( + apiPass, + this.autoUpdateSize, + this.width, + this.height + ); + + return apiFXAAPass; +}; diff --git a/src/r3-d3-pass-render.js b/src/r3-d3-pass-render.js new file mode 100644 index 0000000..00b5ecf --- /dev/null +++ b/src/r3-d3-pass-render.js @@ -0,0 +1,130 @@ +/** + * R3.D3.Pass.Render + * @param graphics R3.GraphicsRuntime + * @param apiPassRender R3.D3.API.Pass.Render + * @constructor + */ +R3.D3.Pass.Render = function ( + graphics, + apiPassRender +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiPassRender)) { + apiPassRender = { + passType : R3.D3.API.Pass.PASS_TYPE_RENDER + }; + } + + R3.D3.API.Pass.Render.call( + this, + apiPassRender, + apiPassRender.scene, + apiPassRender.camera + ); + + if (this.scene instanceof R3.D3.API.Scene) { + this.scene = new R3.D3.Scene( + this.graphics, + this.scene + ) + } + + if (this.camera instanceof R3.D3.API.Camera) { + this.camera = new R3.D3.Camera( + this.graphics, + this.camera + ) + } + + R3.D3.Pass.call( + this, + this.graphics, + this + ); +}; + +R3.D3.Pass.Render.prototype = Object.create(R3.D3.Pass.prototype); +R3.D3.Pass.Render.prototype.constructor = R3.D3.Pass.Render; + +/** + * Create Pass.Render instance + * @returns {*} + */ +R3.D3.Pass.Render.prototype.createInstance = function() { + + if (R3.Utils.UndefinedOrNull(this.scene) || + R3.Utils.UndefinedOrNull(this.scene.instance) + ) { + console.warn('scene not ready'); + return; + } + + if (R3.Utils.UndefinedOrNull(this.camera) || + R3.Utils.UndefinedOrNull(this.camera.instance) + ) { + console.warn('camera not ready'); + return; + } + + this.instance = new THREE.RenderPass( + this.scene.instance, + this.camera.instance + ); + + console.log('Constructed a render pass instance'); + + R3.D3.Pass.prototype.createInstance.call(this); +}; + +/** + * Update Pass.Render instance + */ +R3.D3.Pass.Render.prototype.updateInstance = function(property) { + + if (property === 'scene') { + if (R3.Utils.UndefinedOrNull(this.instance)) { + this.createInstance(); + } + + if (this.instance && this.scene.instance) { + this.instance.scene = this.scene.instance; + } + + return; + } + + if (property === 'camera') { + if (R3.Utils.UndefinedOrNull(this.instance)) { + this.createInstance(); + } + + if (this.instance && this.camera.instance) { + this.instance.camera = this.camera.instance; + } + + return; + } + + R3.D3.Pass.prototype.updateInstance.call(this, property); + +}; + +/** + * R3.D3.Pass.Render to R3.D3.API.Pass.Render + * @returns {R3.D3.API.Pass.Render} + */ +R3.D3.Pass.Render.prototype.toApiObject = function() { + + var apiPass = R3.D3.Pass.prototype.toApiObject.call(this); + + var apiRenderPass = new R3.D3.API.Pass.Render( + apiPass, + R3.Utils.IdOrNull(this.scene), + R3.Utils.IdOrNull(this.camera) + ); + + return apiRenderPass; +}; diff --git a/src/r3-d3-pass-ssao.js b/src/r3-d3-pass-ssao.js new file mode 100644 index 0000000..92b5001 --- /dev/null +++ b/src/r3-d3-pass-ssao.js @@ -0,0 +1,160 @@ +/** + * R3.D3.Pass.SSAO + * @param graphics R3.GraphicsRuntime + * @param apiPassSSAO R3.D3.API.Pass.SSAO + * @constructor + */ +R3.D3.Pass.SSAO = function ( + graphics, + apiPassSSAO +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiPassSSAO)) { + apiPassSSAO = { + passType : R3.D3.API.Pass.PASS_TYPE_SSAO + }; + } + + R3.D3.API.Pass.SSAO.call( + this, + apiPassSSAO, + apiPassSSAO.scene, + apiPassSSAO.camera, + apiPassSSAO.radius, + apiPassSSAO.onlyAO, + apiPassSSAO.aoClamp, + apiPassSSAO.lumInfluence + ); + + if (this.scene instanceof R3.D3.API.Scene) { + this.scene = new R3.D3.Scene( + this.graphics, + this.scene + ) + } + + if (this.camera instanceof R3.D3.API.Camera) { + this.camera = new R3.D3.Camera( + this.graphics, + this.camera + ) + } + + R3.D3.Pass.call( + this, + this.graphics, + this + ); +}; + +R3.D3.Pass.SSAO.prototype = Object.create(R3.D3.Pass.prototype); +R3.D3.Pass.SSAO.prototype.constructor = R3.D3.Pass.SSAO; + +/** + * Create Pass.SSAO instance + * @returns {*} + */ +R3.D3.Pass.SSAO.prototype.createInstance = function() { + + if (R3.Utils.UndefinedOrNull(this.scene) || + R3.Utils.UndefinedOrNull(this.scene.instance) + ) { + console.warn('scene not ready'); + return; + } + + if (R3.Utils.UndefinedOrNull(this.camera) || + R3.Utils.UndefinedOrNull(this.camera.instance) + ) { + console.warn('camera not ready'); + return; + } + + this.instance = new THREE.SSAOPass( + this.scene.instance, + this.camera.instance + ); + + this.instance.radius = this.radius; + + this.instance.onlyAO = this.onlyAO; + + this.instance.aoClamp = this.aoClamp; + + this.instance.lumInfluence = this.lumInfluence; + + console.log('Constructed an SSAO pass instance'); + + R3.D3.Pass.prototype.createInstance.call(this); +}; + +/** + * Update Pass.SSAO instance + */ +R3.D3.Pass.SSAO.prototype.updateInstance = function(property) { + + if (property === 'scene') { + if (R3.Utils.UndefinedOrNull(this.instance)) { + this.createInstance(); + } + return; + } + + if (property === 'camera') { + if (R3.Utils.UndefinedOrNull(this.instance)) { + this.createInstance(); + } + return; + } + + if (!this.instance) { + return; + } + + if (property === 'radius') { + this.instance.radius = this.radius; + return; + } + + if (property === 'onlyAO') { + this.instance.onlyAO = this.onlyAO; + return; + } + + if (property === 'aoClamp') { + this.instance.aoClamp = this.aoClamp; + return; + } + + if (property === 'lumInfluence') { + this.instance.lumInfluence = this.lumInfluence; + return; + } + + R3.D3.Pass.prototype.updateInstance.call(this, property); + +}; + +/** + * R3.D3.Pass.SSAO to R3.D3.API.Pass.SSAO + * @returns {R3.D3.API.Pass.SSAO} + */ +R3.D3.Pass.SSAO.prototype.toApiObject = function() { + + var apiPass = R3.D3.Pass.prototype.toApiObject.call(this); + + var apiSSAOPass = new R3.D3.API.Pass.SSAO( + apiPass, + R3.Utils.IdOrNull(this.scene), + R3.Utils.IdOrNull(this.camera), + this.radius, + this.onlyAO, + this.aoClamp, + this.lumInfluence + ); + + return apiSSAOPass; +}; diff --git a/src/r3-d3-physics-world.js b/src/r3-d3-physics-world.js new file mode 100644 index 0000000..e278f0a --- /dev/null +++ b/src/r3-d3-physics-world.js @@ -0,0 +1,1044 @@ +/** + * World SuperSet - contains the custom world instance + * @constructor + * @param physics + * @param apiWorld + */ +R3.D3.PhysicsWorld = function( + physics, + apiWorld +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (R3.Utils.UndefinedOrNull(apiWorld)) { + apiWorld = {}; + } + + R3.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 R3.API.Vector3) { + this.gravity = new R3.Vector3( + this.physics, + this.gravity, + this + ); + } + + if (this.broadphase instanceof R3.D3.API.Broadphase) { + this.broadphase = new R3.D3.Broadphase( + this.physics, + this.broadphase + ); + } + + if (this.solver instanceof R3.D3.API.Solver) { + this.solver = new R3.D3.Solver( + this.physics, + this.solver + ); + } + + this.rigidBodies = this.rigidBodies.map( + function(rigidBody) { + if (rigidBody instanceof R3.D3.API.RigidBody) { + return new R3.D3.RigidBody( + this.physics, + rigidBody + ); + } + return rigidBody; + }.bind(this) + ); + + this.contactMaterials = this.contactMaterials.map( + function(contactMaterial) { + if (contactMaterial instanceof R3.D3.API.FrictionContactMaterial) { + return new R3.D3.FrictionContactMaterial( + this.physics, + contactMaterial + ); + } + return contactMaterial; + }.bind(this) + ); + + if (this.defaultContactMaterial instanceof R3.D3.API.FrictionContactMaterial) { + this.defaultContactMaterial = new R3.D3.FrictionContactMaterial( + this.physics, + this.defaultContactMaterial + ) + } + + R3.Component.call( + this, + { + 'broadphase' : R3.D3.Broadphase, + 'solver' : R3.D3.Solver, + 'rigidBodies' : [R3.D3.RigidBody], + 'contactMaterials' : [R3.D3.FrictionContactMaterial], + 'defaultContactMaterial' : R3.D3.FrictionContactMaterial + } + ); +}; + +R3.D3.PhysicsWorld.prototype = Object.create(R3.Component.prototype); +R3.D3.PhysicsWorld.prototype.constructor = R3.D3.PhysicsWorld; + +/** + * private + * @returns {R3.D3.PhysicsWorld|R3.PhysicsRuntime.World|*} + */ +R3.D3.PhysicsWorld.prototype.createInstance = function() { + + if (R3.Utils.UndefinedOrNull(this.broadphase)) { + throw new Error('no broadphase'); + } + + if (R3.Utils.UndefinedOrNull(this.broadphase.instance)) { + throw new Error('no broadphase instance'); + } + + if (R3.Utils.UndefinedOrNull(this.solver)) { + throw new Error('no solver'); + } + + if (R3.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 (R3.Utils.UndefinedOrNull(contactMaterial)) { + throw new Error('no contact material'); + } + + if (R3.Utils.UndefinedOrNull(contactMaterial.instance)) { + throw new Error('no contact material instance'); + } + + this.instance.addContactMaterial(contactMaterial.instance); + + }.bind(this) + ); + + this.rigidBodies.map( + function (rigidBody) { + + if (R3.Utils.UndefinedOrNull(rigidBody)) { + throw new Error('no rigidbody'); + } + + if (R3.Utils.UndefinedOrNull(rigidBody.instance)) { + throw new Error('no rigidbody instance'); + } + + rigidBody.parentPhysicsWorld = 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; + + R3.Component.prototype.createInstance.call(this); +}; + +R3.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 parentPhysicsWorld for this rigidBody + * @type {R3.D3.PhysicsWorld} + */ + rigidBody.parentPhysicsWorld = this; + + /** + * Ensure this rigidBody is in our rigidBodies array, just not too many times.. + */ + R3.Utils.PushUnique(this.rigidBodies, rigidBody); + + } else { + console.warn('Attempt to add rigidBody ' + rigidBody.name + ' without an instance'); + } +}; + +/** + * + * @param rigidBody + */ +R3.D3.PhysicsWorld.prototype.removeRigidBody = function(rigidBody) { + + if (!rigidBody instanceof R3.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 parentPhysicsWorld for this rigidBody + * @type {R3.D3.PhysicsWorld} + */ + rigidBody.parentPhysicsWorld = 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'); + } + +}; + + +/** + * + */ +R3.D3.PhysicsWorld.prototype.updateInstance = function(property) { + + 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; + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * R3.D3.PhysicsWorld to R3.D3.API.PhysicsWorld + * @returns {R3.D3.API.PhysicsWorld} + */ +R3.D3.PhysicsWorld.prototype.toApiObject = function() { + + var apiWorld = new R3.D3.API.PhysicsWorld( + this.id, + this.name, + this.gravity.toApiObject(), + R3.Utils.IdOrNull(this.broadphase), + R3.Utils.IdOrNull(this.solver), + this.rigidBodies.map(function(body){ + return R3.Utils.IdOrNull(body); + }), + this.contactMaterials.map(function(contactMaterial){ + return R3.Utils.IdOrNull(contactMaterial); + }), + this.allowSleep, + R3.Utils.IdOrNull(this.defaultContactMaterial), + R3.Utils.IdOrNull(this.parentEntity) + ); + + return apiWorld; +}; + +/** + * R3.D3.PhysicsWorld from Object World + * @param graphics + * @param objectComponent + * @returns {R3.D3.PhysicsWorld} + * @constructor + */ +R3.D3.PhysicsWorld.FromObject = function(graphics, objectComponent) { + var apiWorld = R3.D3.API.PhysicsWorld.FromObject(objectComponent); + return new R3.D3.PhysicsWorld( + graphics, + apiWorld + ); +}; + +// +// R3.D3.PhysicsWorld.prototype.step = function( +// fixedStep, +// dtStep +// ) { +// +// }; +// +// R3.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 R3.D3.Shape +// * @param normalLength Number +// * @param scale R3.API.Vector3 +// * @param opacity Number +// * @param wireframeColor HexCode +// * @param graphics THREE +// * @returns {THREE.Mesh|this.meshes} +// * @constructor +// */ +// R3.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 R3.GraphicsRuntime +// * @param graphicsMesh THREE.Mesh +// * @param mass Number +// * @param friction Number +// * @param createCollisionSubMeshes Boolean +// * @param facesPerSubsection Number +// * @param subsectionsToMerge Number +// * @returns {Object} +// * @constructor +// */ +// R3.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++; +// } +// }; +// +// R3.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 R3.D3.Shape(this.engine, R3.D3.Shape.SHAPE_TYPE_CONVEX_HULL, {x:1,y:1,z:1},convexVertices, convexIndices); +// +// var body = new R3.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 R3.GraphicsRuntime +// * @param graphicsMesh THREE.Mesh +// * @returns {R3.D3.Shape} +// * @constructor +// */ +// R3.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 R3.D3.Shape(this.engine, R3.D3.Shape.SHAPE_TYPE_TRIMESH, {x : 1, y : 1, z : 1}, vertices, faces); +// }; +// +// /** +// * @param triangleMeshBody R3.D3.RigidBody +// * @param rayscale Number +// * @param maxTriangleDistance Number +// * @param createCompoundShape Boolean +// * @param graphics R3.GraphicsRuntime +// * @param triangleMeshShapes R3.D3.Shape[] +// * @param createDebugView Boolean +// * @returns {R3.D3.RigidBody} +// * @constructor +// */ +// R3.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 R3.D3.Shape(this.engine, R3.D3.Shape.SHAPE_TYPE_TRIMESH, { x : 1, y : 1, z : 1 }, element.vertices, element.indices); +// +// if(createCompoundShape) { +// triangleMeshBody.addShape(shape); +// } else { +// +// var body = new R3.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 +// }; +// }; \ No newline at end of file diff --git a/src/r3-d3-poly-vertex.js b/src/r3-d3-poly-vertex.js new file mode 100644 index 0000000..7cd2410 --- /dev/null +++ b/src/r3-d3-poly-vertex.js @@ -0,0 +1,36 @@ +/** + * Contains a Poly vertex data structure + * @param localIndex + * @param mvertIndex + * @param uv R3.API.Vector2 + * @param materialIndex + * @param edgeIndex + * @constructor + */ +R3.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 {R3.D3.PolyVertex} + */ +R3.D3.PolyVertex.prototype.clone = function() { + return new R3.D3.PolyVertex( + this.localIndex, + this.mvertIndex, + this.uv.copy(), + this.materialIndex, + this.edgeIndex + ) +}; \ No newline at end of file diff --git a/src/r3-d3-raycast-vehicle.js b/src/r3-d3-raycast-vehicle.js new file mode 100644 index 0000000..0d78718 --- /dev/null +++ b/src/r3-d3-raycast-vehicle.js @@ -0,0 +1,173 @@ +/** + * RaycastVehicle Runtime + * @param physics R3.GraphicsRuntime + * @param apiRaycastVehicle R3.D3.API.RaycastVehicle + * @constructor + */ +R3.D3.RaycastVehicle = function ( + physics, + apiRaycastVehicle +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (R3.Utils.UndefinedOrNull(apiRaycastVehicle)) { + apiRaycastVehicle = {}; + } + + R3.D3.API.RaycastVehicle.call( + this, + apiRaycastVehicle.id, + apiRaycastVehicle.name, + apiRaycastVehicle.chassis, + apiRaycastVehicle.wheels, + apiRaycastVehicle.raycastWheels, + apiRaycastVehicle.parentPhysicsWorld, + apiRaycastVehicle.parentEntity + ); + + if (this.chassis instanceof R3.D3.API.RaycastVehicle) { + this.chassis = new R3.D3.RaycastVehicle( + this.physics, + this.chassis + ) + } + + this.wheels = this.wheels.map(function(wheel){ + if (wheel instanceof R3.D3.API.RigidBody) { + return new R3.D3.RigidBody( + this.physics, + wheel + ) + } else { + return wheel; + } + }.bind(this)); + + this.raycastWheels = this.raycastWheels.map(function(raycastWheel){ + if (raycastWheel instanceof R3.D3.API.RaycastWheel) { + return new R3.D3.RaycastWheel( + this.physics, + raycastWheel + ) + } else { + return raycastWheel; + } + }.bind(this)); + + R3.Component.call( + this, + { + 'chassis' : R3.D3.RigidBody, + 'wheels' : [R3.D3.RigidBody], + 'raycastWheels' : [R3.D3.RaycastWheel], + 'parentPhysicsWorld' : R3.D3.PhysicsWorld + } + ); +}; + +R3.D3.RaycastVehicle.prototype = Object.create(R3.Component.prototype); +R3.D3.RaycastVehicle.prototype.constructor = R3.D3.RaycastVehicle; + +/** + * + * @returns {*} + */ +R3.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 {R3.D3.RaycastVehicle|R3.D3.API.RaycastVehicle|*} + */ + + if (R3.Utils.UndefinedOrNull(this.chassis)) { + throw new Error('no chassis'); + } + + if (R3.Utils.UndefinedOrNull(this.chassis.instance)) { + throw new Error('no chassis instance'); + } + + if (R3.Utils.UndefinedOrNull(this.parentPhysicsWorld)) { + throw new Error('no parent world'); + } + + if (R3.Utils.UndefinedOrNull(this.parentPhysicsWorld.instance)) { + throw new Error('no parent world instance'); + } + + this.instance = new CANNON.RaycastVehicle({ + chassisBody: this.chassis.instance + }); + + this.raycastWheels.map( + function(wheel){ + + if (R3.Utils.UndefinedOrNull(wheel)) { + throw new Error('no wheel'); + } + + if (R3.Utils.UndefinedOrNull(wheel.instance)) { + throw new Error('no wheel instance'); + } + + this.instance.addWheel(wheel.instance); + + }.bind(this) + ); + + this.instance.addToWorld(this.parentPhysicsWorld.instance); + + R3.Component.prototype.createInstance.call(this); + +}; + +R3.D3.RaycastVehicle.prototype.updateInstance = function(property) { + // this.instance.chassisBody = this.chassis.instance; + //TODO: add / remove wheels? + console.log('TODO: update raycast vehicle instance'); + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * R3.D3.RaycastVehicle to R3.D3.API.RaycastVehicle + * @returns {R3.D3.API.RaycastVehicle} + */ +R3.D3.RaycastVehicle.prototype.toApiObject = function() { + + var apiRaycastVehicle = new R3.D3.API.RaycastVehicle( + this.id, + this.name, + R3.Utils.IdOrNull(this.chassis), + this.wheels.map(function(wheel){ + return R3.Utils.IdOrNull(wheel); + }), + this.raycastWheels.map(function(raycastWheel){ + return R3.Utils.IdOrNull(raycastWheel); + }), + R3.Utils.IdOrNull(this.parentPhysicsWorld), + R3.Utils.IdOrNull(this.parentEntity) + ); + + return apiRaycastVehicle; +}; + +/** + * R3.D3.RaycastVehicle from Object RaycastVehicle + * @param physics + * @param objectComponent + * @returns {R3.D3.RaycastVehicle} + * @constructor + */ +R3.D3.RaycastVehicle.FromObject = function(physics, objectComponent) { + + var apiRaycastVehicle = R3.D3.API.RaycastVehicle.FromObject(objectComponent); + + return new R3.D3.RaycastVehicle( + physics, + apiRaycastVehicle + ); +}; diff --git a/src/r3-d3-raycast-wheel.js b/src/r3-d3-raycast-wheel.js new file mode 100644 index 0000000..790e30b --- /dev/null +++ b/src/r3-d3-raycast-wheel.js @@ -0,0 +1,170 @@ +/** + * RaycastWheel Runtime + * @param physics R3.GraphicsRuntime + * @param apiRaycastWheel R3.D3.API.RaycastWheel + * @constructor + */ +R3.D3.RaycastWheel = function ( + physics, + apiRaycastWheel +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (R3.Utils.UndefinedOrNull(apiRaycastWheel)) { + apiRaycastWheel = {}; + } + + R3.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.parentMesh, + apiRaycastWheel.parentEntity + ); + + this.directionLocal = new R3.Vector3( + this.physics, + this.directionLocal, + this + ); + + this.axleLocal = new R3.Vector3( + this.physics, + this.axleLocal, + this + ); + + this.chassisConnectionPointLocal = new R3.Vector3( + this.physics, + this.chassisConnectionPointLocal, + this + ); + + R3.Component.call( + this, + { + 'parentMesh' : R3.D3.Mesh + } + ); +}; + +R3.D3.RaycastWheel.prototype = Object.create(R3.Component.prototype); +R3.D3.RaycastWheel.prototype.constructor = R3.D3.RaycastWheel; + +/** + * + * @returns {*} + */ +R3.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 + }; + + R3.Component.prototype.createInstance.call(this); +}; + +R3.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; +}; + +/** + * R3.D3.RaycastWheel to R3.D3.API.RaycastWheel + * @returns {R3.D3.API.RaycastWheel} + */ +R3.D3.RaycastWheel.prototype.toApiObject = function() { + + var apiRaycastWheel = new R3.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, + R3.Utils.IdOrNull(this.parentMesh), + R3.Utils.IdOrNull(this.parentEntity) + ); + + return apiRaycastWheel; +}; + +/** + * R3.D3.RaycastWheel from Object RaycastWheel + * @param physics + * @param objectComponent + * @returns {R3.D3.RaycastWheel} + * @constructor + */ +R3.D3.RaycastWheel.FromObject = function(physics, objectComponent) { + + var apiRaycastWheel = R3.D3.API.RaycastWheel.FromObject(objectComponent); + + return new R3.D3.RaycastWheel( + physics, + apiRaycastWheel + ); +}; + +R3.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; + +}; \ No newline at end of file diff --git a/src/r3-d3-raycaster.js b/src/r3-d3-raycaster.js new file mode 100644 index 0000000..21e45f8 --- /dev/null +++ b/src/r3-d3-raycaster.js @@ -0,0 +1,250 @@ +/** + * Raycaster for R3.D3 + * @param graphics R3.GraphicsRuntime + * @param apiRaycaster + * @constructor + */ +R3.D3.Raycaster = function( + graphics, + apiRaycaster +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiRaycaster)) { + apiRaycaster = {}; + } + + R3.D3.API.Raycaster.call( + this, + apiRaycaster.id, + apiRaycaster.name, + apiRaycaster.parentEntity, + apiRaycaster.position, + apiRaycaster.direction + ); + + this.position = new R3.Vector3( + this.graphics, + this.position, + this + ); + + this.direction = new R3.Vector3( + this.graphics, + this.direction, + this + ); + + R3.Component.call(this); +}; + +R3.D3.Raycaster.prototype = Object.create(R3.Component.prototype); +R3.D3.Raycaster.prototype.constructor = R3.D3.Raycaster; + +/** + * Creates or updates a raycaster instance + */ +R3.D3.Raycaster.prototype.createInstance = function() { + + this.instance = new THREE.Raycaster(); + this.instance.set( + this.position.instance, + this.direction.instance + ); + + R3.Component.prototype.createInstance.call(this); +}; + +R3.D3.Raycaster.prototype.updateInstance = function(property) { + + if (property === 'position') { + this.position.instance.x = this.position.x; + this.position.instance.y = this.position.y; + this.position.instance.z = this.position.z; + this.instance.setPosition(this.position.instance); + return; + } + + if (property === 'direction') { + this.direction.instance.x = this.direction.x; + this.direction.instance.y = this.direction.y; + this.direction.instance.z = this.direction.z; + this.instance.setDirection(this.direction.instance); + return; + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +R3.D3.Raycaster.prototype.toApiObject = function() { + return new R3.D3.API.Raycaster( + this.id, + this.name, + R3.Utils.IdOrNull(this.parentEntity), + this.position.toApiObject(), + this.direction.toApiObject() + ) +}; + +/** + * Sets the direction and position of this raycaster + * @param position R3.Vector3 + * @param direction R3.Vector3 + */ +R3.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 R3.Vector3 + */ +R3.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 R3.Vector3 + */ +R3.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 + */ +R3.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 R3.D3.Mesh objects + * @param meshes [R3.D3.Mesh] + */ +R3.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, + face: mesh.geometry.faces[intersects[0].faceIndex], + faceIndex: intersects[0].faceIndex, + uv : { + x : intersects[0].uv.x, + y : intersects[0].uv.y + } + } + ); + } + + return result; + }.bind(this), + [] + ); +}; + +/** + * Returns the face normal (if any) of an intersection between current ray position, direction and a provided mesh + * @param mesh R3.D3.Mesh + * @returns {null | R3.Vector3} + */ +R3.D3.Raycaster.prototype.getFaceNormal = function(mesh) { + + var normal = null; + + var intersect = this.instance.intersectObject( + mesh.instance + ); + + if (intersect && intersect.length > 0) { + + normal = new R3.Vector3( + this.graphics, + new R3.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 R3.D3.Mesh + * @returns {null | R3.Vector3} + */ +R3.D3.Raycaster.prototype.getIntersectPoint = function(mesh) { + + var point = null; + + var intersect = this.instance.intersectObject( + mesh.instance + ); + + if (intersect && intersect.length > 0) { + point = new R3.Vector3( + this.graphics, + new R3.API.Vector3( + intersect[0].point.x, + intersect[0].point.y, + intersect[0].point.z + ), + this + ); + } + + return point; +}; diff --git a/src/r3-d3-render-target-a.js b/src/r3-d3-render-target-a.js new file mode 100644 index 0000000..c085061 --- /dev/null +++ b/src/r3-d3-render-target-a.js @@ -0,0 +1,335 @@ +/** + * Renders a scene with a camera + * @param graphics R3.GraphicsRuntime + * @param apiRenderTarget R3.D3.API.RenderTarget + * @constructor + */ +R3.D3.RenderTarget = function ( + graphics, + apiRenderTarget +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiRenderTarget)) { + apiRenderTarget = { + renderTargetType : R3.D3.API.RenderTarget.TARGET_TYPE_NORMAL + }; + } + + R3.D3.API.RenderTarget.call( + this, + apiRenderTarget.id, + apiRenderTarget.name, + apiRenderTarget.renderTargetType, + apiRenderTarget.parentEntity, + apiRenderTarget.autoUpdateSize, + apiRenderTarget.width, + apiRenderTarget.height, + apiRenderTarget.scissor, + apiRenderTarget.scissorTest, + apiRenderTarget.viewport, + apiRenderTarget.texture, + apiRenderTarget.depthBuffer, + apiRenderTarget.depthTexture, + apiRenderTarget.stencilBuffer, + apiRenderTarget.textureParameters + ); + + this.scissor = new R3.Vector4( + this.graphics, + this.scissor, + this + ); + + if (this.viewport instanceof R3.D3.API.Viewport) { + this.viewport = new R3.D3.Viewport( + this.graphics, + this.viewport + ); + } + + if (this.texture instanceof R3.D3.API.Texture) { + this.texture = new R3.D3.Texture( + this.graphics, + this.texture + ) + } + + if (this.depthTexture instanceof R3.D3.API.Texture) { + this.depthTexture = new R3.D3.Texture( + this.graphics, + this.depthTexture + ) + } + + R3.Component.call( + this, + { + 'texture' : R3.D3.Texture, + 'depthTexture' : R3.D3.Texture, + 'viewport' : R3.D3.Viewport + } + ); +}; + +R3.D3.RenderTarget.prototype = Object.create(R3.Component.prototype); +R3.D3.RenderTarget.prototype.constructor = R3.D3.RenderTarget; + +R3.D3.RenderTarget.prototype.applyToInstance = function() { + + this.instance.scissor = this.scissor.instance; + this.instance.scissorTest = this.scissorTest; + this.instance.viewport = this.viewport.instance; + this.instance.depthBuffer = this.depthBuffer; + this.instance.stencilBuffer = this.stencilBuffer; + + if (this.instance.texture) { + + if (R3.Utils.UndefinedOrNull(this.texture)) { + this.texture = new R3.D3.Texture(this.graphics); + this.texture.instance = this.instance.texture; + this.texture.updateFromInstance(); + } else { + this.texture.instance = this.instance.texture; + this.texture.applyToInstance(); + } + + this.publish( + R3.Event.TEXTURE_INSTANCE_UPDATED, + { + texture : this.texture + } + ); + } + + if (this.instance.depthTexture) { + + if (R3.Utils.UndefinedOrNull(this.depthTexture)) { + this.depthTexture = new R3.D3.Texture(this.graphics); + this.depthTexture.instance = this.instance.depthTexture; + this.depthTexture.updateFromInstance(); + } else { + this.depthTexture.instance = this.instance.depthTexture; + this.depthTexture.applyToInstance(); + } + + this.publish( + R3.Event.TEXTURE_INSTANCE_UPDATED, + { + texture : this.depthTexture + } + ); + } + +}; + +/** + * Creates a Render Target instance + * @returns {*} + */ +R3.D3.RenderTarget.prototype.createInstance = function() { + + if (this.autoUpdateSize) { + R3.Utils.UpdateWindowSize(this); + } + + /** + * Only create the instance if it does not already exist - it could be created by a child + */ + if (R3.Utils.UndefinedOrNull(this.instance)) { + this.instance = new THREE.WebGLRenderTarget( + this.width, + this.height, + this.textureParameters + ); + } + + /** + * We have two cases - our texure is null, in this case, we create one and update it from instance, + * Or, we loaded it from API, so our texture is up to date, and we should update our instance + */ + + if (R3.Utils.UndefinedOrNull(this.texture)) { + + /** + * We need to generate a new texture and update it from the instance (we provide an overrideInstance) + */ + this.texture = new R3.D3.Texture( + this.graphics, + null, + this.instance.texture + ); + + } else { + + /** + * This texture is loaded from the API, we assign the instance to it, and then apply our settings to it + */ + this.texture.instance = this.instance.texture; + this.texture.applyToInstance(); + + } + + if (R3.Utils.Defined(this.depthTexture)) { + this.depthTexture.instance = this.instance.depthTexture; + this.depthTexture.applyToInstance(); + } + + this.applyToInstance(); + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * updates instance + */ +R3.D3.RenderTarget.prototype.updateInstance = function(property) { + + if ( + property === 'width' || + property === 'height' || + property === 'autoUpdateSize' + ) { + + if (this.autoUpdateSize) { + R3.Utils.UpdateWindowSize(this); + } + + this.instance.setSize(this.width, this.height); + } + + if (property === 'renderTargetType') { + console.warn('todo : update renderTargetType'); + return; + } + + if (property === 'parentEntity') { + console.warn('todo : update parentEntity'); + return; + } + + if (property === 'scissor') { + console.warn('todo : update scissor'); + return; + } + + if (property === 'scissorTest') { + this.instance.scissorTest = this.scissorTest; + return; + } + + if (property === 'viewport') { + if (this.viewport && this.viewport.instance) { + this.instance.viewport = this.viewport.instance; + } else { + this.instance.viewport = null; + } + return; + } + + if (property === 'texture') { + console.warn('experimental texture change'); + if (this.texture && this.texture.instance) { + this.instance.texture = this.texture.instance; + } + return; + } + + if (property === 'depthBuffer') { + this.instance.depthBuffer = this.depthBuffer; + return; + } + + if (property === 'depthTexture') { + console.warn('experimental depthTexture change'); + if (this.depthTexture && this.depthTexture.instance) { + this.instance.depthTexture = this.depthTexture.instance; + } + return; + } + + if (property === 'stencilBuffer') { + this.instance.stencilBuffer = this.stencilBuffer; + return; + } + + if (property === 'textureParameters') { + console.warn('todo: texture parameters change'); + return; + } + + R3.Component.prototype.updateInstance.call(this, property); + +}; + +/** + * Render Target to API Render Target + * @returns {R3.D3.API.RenderTarget} + */ +R3.D3.RenderTarget.prototype.toApiObject = function() { + + var apiRenderTarget = new R3.D3.API.RenderTarget( + this.id, + this.name, + this.renderTargetType, + R3.Utils.IdOrNull(this.parentEntity), + this.autoUpdateSize, + this.width, + this.height, + this.scissor.toApiObject(), + this.scissorTest, + R3.Utils.IdOrNull(this.viewport), + R3.Utils.IdOrNull(this.texture), + this.depthBuffer, + R3.Utils.IdOrNull(this.depthTexture), + this.stencilBuffer, + this.textureParameters + ); + + return apiRenderTarget; +}; + +/** + * Updates R3.D3.RenderTarget from instance + */ +R3.D3.RenderTarget.prototype.updateFromInstance = function() { + + this.width = this.instance.width; + this.height = this.instance.height; + + this.scissor.x = this.instance.scissor.x; + this.scissor.y = this.instance.scissor.y; + this.scissor.z = this.instance.scissor.z; + this.scissor.w = this.instance.scissor.w; + + this.scissorTest = this.instance.scissorTest; + + this.viewport.x = this.instance.viewport.x; + this.viewport.y = this.instance.viewport.y; + this.viewport.width = this.instance.viewport.z; + this.viewport.height = this.instance.viewport.w; + + if (this.texture.instance) { + if (R3.Utils.UndefinedOrNull(this.texture)) { + this.texture = new R3.D3.Texture(this.graphics); + } + this.texture.instance = this.instance.texture; + this.texture.updateFromInstance(); + } + + this.depthBuffer = this.instance.depthBuffer; + + if (this.instance.depthTexture) { + + if (R3.Utils.UndefinedOrNull(this.depthTexture)) { + this.depthTexture = new R3.D3.Texture(this.graphics); + } + + this.depthTexture.instance = this.instance.depthTexture; + this.depthTexture.updateFromInstance(); + } + + this.stencilBuffer = this.instance.stencilBuffer; +}; \ No newline at end of file diff --git a/src/r3-d3-render-target-cube.js b/src/r3-d3-render-target-cube.js new file mode 100644 index 0000000..0254f79 --- /dev/null +++ b/src/r3-d3-render-target-cube.js @@ -0,0 +1,73 @@ +/** + * Renders a scene with a camera + * @param graphics R3.GraphicsRuntime + * @param apiRenderTargetCube R3.D3.API.RenderTarget.Cube + * @constructor + */ +R3.D3.RenderTarget.Cube = function ( + graphics, + apiRenderTargetCube +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiRenderTargetCube)) { + apiRenderTargetCube = { + renderTargetType : R3.D3.API.RenderTarget.TARGET_TYPE_CUBE + }; + } + + R3.D3.API.RenderTarget.Cube.call( + this, + apiRenderTargetCube + ); + + R3.D3.RenderTarget.call( + this, + this.graphics, + this + ); +}; + +R3.D3.RenderTarget.Cube.prototype = Object.create(R3.D3.RenderTarget.prototype); +R3.D3.RenderTarget.Cube.prototype.constructor = R3.D3.RenderTarget.Cube; + +/** + * Creates a Render Target instance + * @returns {*} + */ +R3.D3.RenderTarget.Cube.prototype.createInstance = function() { + + this.instance = new THREE.WebGLRenderTargetCube( + this.width, + this.height, + this.textureParameters + ); + + R3.D3.RenderTarget.prototype.createInstance.call(this); +}; + +/** + * updates instance + */ +R3.D3.RenderTarget.Cube.prototype.updateInstance = function(property) { + R3.D3.RenderTarget.prototype.updateInstance.call(this, property); +}; + +/** + * Render Target to API Render Target + * @returns {R3.D3.API.RenderTarget.Cube} + */ +R3.D3.RenderTarget.Cube.prototype.toApiObject = function() { + + var apiRenderTarget = R3.D3.RenderTarget.prototype.toApiObject.call( + this + ); + + var apiRenderTargetCube = new R3.D3.API.RenderTarget.Cube( + apiRenderTarget + ); + + return apiRenderTargetCube; +}; diff --git a/src/r3-d3-rigid-body.js b/src/r3-d3-rigid-body.js new file mode 100644 index 0000000..8127368 --- /dev/null +++ b/src/r3-d3-rigid-body.js @@ -0,0 +1,288 @@ +/** + * RigidBody Runtime + * @param physics R3.GraphicsRuntime + * @param apiRigidBody R3.D3.API.RigidBody + * @constructor + */ +R3.D3.RigidBody = function ( + physics, + apiRigidBody +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (R3.Utils.UndefinedOrNull(apiRigidBody)) { + apiRigidBody = {}; + } + + R3.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.parentPhysicsWorld, + apiRigidBody.parentEntity + ); + + this.position = new R3.Vector3( + this.physics, + this.position, + this + ); + + this.quaternion = new R3.Quaternion( + this.physics, + this.quaternion, + this + ); + + this.velocity = new R3.Vector3( + this.physics, + this.velocity, + this + ); + + this.angularVelocity = new R3.Vector3( + this.physics, + this.angularVelocity, + this + ); + + this.force = new R3.Vector3( + this.physics + ); + + this.forcePoint = new R3.Vector3( + this.physics + ); + + R3.Component.call( + this, + { + 'shapes' : [R3.D3.Shape], + 'parentMesh' : R3.D3.Mesh, + 'parentPhysicsWorld' : R3.D3.PhysicsWorld + } + ); +}; + +R3.D3.RigidBody.prototype = Object.create(R3.Component.prototype); +R3.D3.RigidBody.prototype.constructor = R3.D3.RigidBody; + +/** + * + * @returns {*} + */ +R3.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 (R3.Utils.UndefinedOrNull(shape)) { + throw new Error('no shape'); + } + + if (R3.Utils.UndefinedOrNull(shape.instance)) { + throw new Error('no shape instance'); + } + + this.instance.addShape(shape.instance) + + }.bind(this) + ); + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * + */ +R3.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; + + R3.Component.prototype.updateInstance.call(this, property); +}; + +R3.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(); + +}; + +/** + * R3.D3.RigidBody to R3.D3.API.RigidBody + * @returns {R3.D3.API.RigidBody} + */ +R3.D3.RigidBody.prototype.toApiObject = function() { + + var apiRigidBody = new R3.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 R3.Utils.IdOrNull(shape)}), + this.kinematic, + R3.Utils.IdOrNull(this.parentMesh), + R3.Utils.IdOrNull(this.parentPhysicsWorld), + R3.Utils.IdOrNull(this.parentEntity) + ); + + return apiRigidBody; +}; + +/** + * R3.D3.RigidBody from Object RigidBody + * @param physics + * @param objectComponent + * @returns {R3.D3.RigidBody} + * @constructor + */ +R3.D3.RigidBody.FromObject = function(physics, objectComponent) { + + var apiRigidBody = R3.D3.API.RigidBody.FromObject(objectComponent); + + return new R3.D3.RigidBody( + physics, + apiRigidBody + ); +}; + +R3.D3.RigidBody.prototype.applyForce = function() { + this.instance.applyForce( + this.force.instance, + this.forcePoint.instance + ) +}; + + +R3.D3.RigidBody.prototype.applyLocalForce = function() { + this.instance.applyLocalForce( + this.force.instance, + this.forcePoint.instance + ) +}; diff --git a/src/r3-d3-scene.js b/src/r3-d3-scene.js new file mode 100644 index 0000000..cb798eb --- /dev/null +++ b/src/r3-d3-scene.js @@ -0,0 +1,577 @@ +/** + * Scene Superset - The apiScene properties get moved into the Scene object itself, and then the instance is + * created + * @param graphics + * @param apiScene R3.D3.API.Scene + * @constructor + */ +R3.D3.Scene = function ( + graphics, + apiScene +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiScene)) { + apiScene = {}; + } + + R3.D3.API.Scene.call( + this, + apiScene.id, + apiScene.name, + apiScene.meshes, + apiScene.lights, + apiScene.textures, + apiScene.materials, + apiScene.images, + apiScene.fog, + apiScene.showGrid, + apiScene.showAxis, + apiScene.gridSize, + apiScene.gridColor, + apiScene.camera, + apiScene.parentEntity + ); + + this.textures = this.textures.map( + function(apiTexture) { + + if (typeof apiTexture === 'string') { + return apiTexture; + } + + return new R3.D3.Texture( + this.graphics, + apiTexture + ); + + }.bind(this) + ); + + this.materials = this.materials.map( + function(apiMaterial) { + + if (typeof apiMaterial === 'string') { + return apiMaterial; + } + + return new R3.D3.Material( + this.graphics, + apiMaterial + ); + + }.bind(this) + ); + + this.images = this.images.map( + function(apiImage) { + + if (typeof apiImage === 'string') { + return apiImage; + } + + return new R3.Image( + this.graphics, + apiImage + ); + + }.bind(this) + ); + + if (this.fog instanceof R3.D3.API.Fog) { + this.fog = new R3.D3.Fog( + this.graphics, + this.fog + ) + }; + + this.gridColor = new R3.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; + + R3.Component.call( + this, + { + 'meshes' : [R3.D3.Mesh], + 'lights' : [R3.D3.Light], + 'textures' : [R3.D3.Texture], + 'materials' : [R3.D3.Material], + 'images' : [R3.Image], + 'fog' : R3.D3.Fog, + 'camera' : R3.D3.Camera + } + ); +}; + +R3.D3.Scene.prototype = Object.create(R3.Component.prototype); +R3.D3.Scene.prototype.constructor = R3.D3.Scene; + +/** + * Creates an instance scene + * @returns {THREE.Scene} + */ +R3.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 (R3.Utils.UndefinedOrNull(mesh)) { + throw new Error('no mesh'); + } + + if (R3.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 (R3.Utils.UndefinedOrNull(light)) { + throw new Error('no light'); + } + + if (R3.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(); + } + + R3.Component.prototype.createInstance.call(this); + +}; + +R3.D3.Scene.prototype.updateInstance = function(property) { + + if (property === 'name') { + this.instance.name = this.name; + return; + } + + if (property === 'fog') { + if (this.fog && this.fog.instance !== this.instance.fog) { + this.instance.fog = this.fog.instance; + } + } + + if (property === 'meshes') { + + /** + * Add missing meshes + */ + this.meshes.map( + function (mesh) { + if (this.instance.children.indexOf(mesh.instance === -1)) { + this.instance.add(mesh.instance); + } + }.bind(this) + ); + } + + if (property === 'lights') { + + /** + * Add missing lights + */ + this.lights.map( + function (light) { + if (this.instance.children.indexOf(light.instance) === -1) { + this.instance.add(light.instance); + } + }.bind(this) + ); + } + + if ( + property === 'meshes' || + property === 'lights' + ) { + /** + * 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) + ); + return; + } + + 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(); + } + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Scene to a R3.D3.API.Scene + * @returns {R3.D3.API.Scene} + */ +R3.D3.Scene.prototype.toApiObject = function() { + + var apiMeshes = []; + + if (this.storeClones) { + this.clones.map( + function (clone) { + R3.Utils.PushUnique( + apiMeshes, + R3.Utils.IdOrNull(clone) + ); + } + ); + } + + this.meshes.map( + function(mesh) { + R3.Utils.PushUnique( + apiMeshes, + R3.Utils.IdOrNull(mesh) + ); + } + ); + + return new R3.D3.API.Scene( + this.id, + this.name, + apiMeshes, + this.lights.map( + function(light) { + return R3.Utils.IdOrNull(light); + } + ), + this.textures.map( + function(texture) { + return R3.Utils.IdOrNull(texture); + } + ), + this.materials.map( + function(material) { + return R3.Utils.IdOrNull(material); + } + ), + this.images.map( + function(image) { + return R3.Utils.IdOrNull(image); + } + ), + R3.Utils.IdOrNull(this.fog), + this.showGrid, + this.showAxis, + this.gridSize, + this.gridColor.toApiObject(), + R3.Utils.IdOrNull(this.camera), + R3.Utils.IdOrNull(this.parentEntity) + ); +}; + +/** + * Adds a mesh to the scene + * @param object R3.D3.Mesh + */ +R3.D3.Scene.prototype.addObject = function(object) { + + if (object instanceof R3.D3.Mesh) { + if (this.meshes.indexOf(object.id) === -1) { + R3.Utils.PushUnique(this.meshes, object); + } + } + + if (object instanceof R3.D3.Light) { + if (this.lights.indexOf(object.id) === -1) { + R3.Utils.PushUnique(this.lights, object); + } + } + + object.parentScene = this; + + if ( + this.instance && + object.instance + ) { + if (this.instance.children.indexOf(object.instance) === -1) { + this.instance.add(object.instance); + } + } else { + // console.warn('either scene or mesh instance not ready'); + } + + // if (this.parentEntity) { + // this.parentEntity.addComponent(object); + // } + +}; + +R3.D3.Scene.prototype.addClone = function(component) { + + if (component instanceof R3.D3.Mesh || + component instanceof R3.D3.Light + ) { + if (this.instance && component.instance) { + if (this.instance.children.indexOf(component.instance) === -1) { + this.instance.add(component.instance); + } + } + + component.isClone = true; + + R3.Utils.PushUnique(this.clones, component); + + var index = this.meshes.indexOf(component); + + if (index !== -1) { + this.meshes.splice(index, 1); + } + + component.parentScene = this; + } +}; + +/** + * + * @param object + */ +R3.D3.Scene.prototype.removeObject = function(object) { + + var index = -1; + + if (object instanceof R3.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 R3.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; + } + // + // if (this.parentEntity) { + // this.parentEntity.removeComponent(object); + // } + // this.buildIdToObject(); +}; + +R3.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); + } +}; + +R3.D3.Scene.prototype.removeGrid = function() { + this.grid.map( + function(object) { + this.instance.remove(object); + }.bind(this) + ); +}; + +R3.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); +}; + +R3.D3.Scene.prototype.removeAxis = function() { + this.axis.map( + function(object) { + this.instance.remove(object); + }.bind(this) + ); +}; diff --git a/src/r3-d3-shader-a.js b/src/r3-d3-shader-a.js new file mode 100644 index 0000000..3f594e5 --- /dev/null +++ b/src/r3-d3-shader-a.js @@ -0,0 +1,97 @@ +/** + * R3.D3.Shader + * @param graphics R3.GraphicsRuntime + * @param apiShader R3.D3.API.Shader + * @constructor + */ +R3.D3.Shader = function( + graphics, + apiShader +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiShader)) { + apiShader = {}; + } + + R3.D3.API.Shader.call( + this, + apiShader.id, + apiShader.name, + apiShader.shaderType, + apiShader.parentEntity, + apiShader.parentMaterialShader, + apiShader.code + ); + + R3.Component.call( + this, + { + parentMaterialShader : R3.D3.Material.Shader + } + ); +}; + +R3.D3.Shader.prototype = Object.create(R3.CustomCode.prototype); +R3.D3.Shader.prototype.constructor = R3.D3.Shader; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Shader.prototype.createInstance = function() { + + this.instance = this.code; + + /** + * We don't actually call the CustomCode createInstance - since these aren't javascript functions, they are + * GLSL code + */ + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Shader.prototype.updateInstance = function(property) { + + if (R3.Utils.UndefinedOrNull(property)) { + console.warn('no property for Shader: ' + this.name); + } + + if (property === 'code') { + this.instance = this.code; + + if (this.parentMaterialShader && this.parentMaterialShader.instance) { + + this.parentMaterialShader.instance.program.destroy(); + +// this.parentMaterialShader.instance.needsUpdate = true; + + } else { + console.warn('parent material shader not running or linked'); + } + + return; + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Shader to a R3.D3.API.Shader + * @returns {R3.D3.API.Shader} + */ +R3.D3.Shader.prototype.toApiObject = function() { + return new R3.D3.API.Shader( + this.id, + this.name, + this.shaderType, + R3.Utils.IdOrNull(this.parentEntity), + R3.Utils.IdOrNull(this.parentMaterialShader), + this.code + ); +}; diff --git a/src/r3-d3-shader-fragment.js b/src/r3-d3-shader-fragment.js new file mode 100644 index 0000000..97caae3 --- /dev/null +++ b/src/r3-d3-shader-fragment.js @@ -0,0 +1,59 @@ +/** + * R3.D3.Shader.Fragment + * @param graphics R3.GraphicsRuntime + * @param apiFragmentShader + * @constructor + */ +R3.D3.Shader.Fragment = function( + graphics, + apiFragmentShader +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiFragmentShader)) { + apiFragmentShader = { + shaderType : R3.D3.API.Shader.SHADER_TYPE_FRAGMENT + }; + } + + R3.D3.API.Shader.Fragment.call( + this, + apiFragmentShader + ); + + R3.D3.Shader.call( + this, + this.graphics, + apiFragmentShader + ); + +}; + +R3.D3.Shader.Fragment.prototype = Object.create(R3.D3.Shader.prototype); +R3.D3.Shader.Fragment.prototype.constructor = R3.D3.Shader.Fragment; + +/** + * Creates a shader instance + * @returns {*} + */ +R3.D3.Shader.Fragment.prototype.createInstance = function() { + R3.D3.Shader.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Shader.Fragment.prototype.updateInstance = function(property) { + R3.D3.Shader.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Shader to a R3.D3.API.Shader + * @returns {R3.D3.API.Shader} + */ +R3.D3.Shader.Fragment.prototype.toApiObject = function() { + var apiShader = R3.D3.Shader.prototype.toApiObject.call(this); + return apiShader; +}; diff --git a/src/r3-d3-shader-vertex.js b/src/r3-d3-shader-vertex.js new file mode 100644 index 0000000..dc97deb --- /dev/null +++ b/src/r3-d3-shader-vertex.js @@ -0,0 +1,59 @@ +/** + * R3.D3.Shader.Vertex + * @param graphics R3.GraphicsRuntime + * @param apiVertexShader + * @constructor + */ +R3.D3.Shader.Vertex = function( + graphics, + apiVertexShader +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiVertexShader)) { + apiVertexShader = { + shaderType : R3.D3.API.Shader.SHADER_TYPE_VERTEX + }; + } + + R3.D3.API.Shader.Vertex.call( + this, + apiVertexShader + ); + + R3.D3.Shader.call( + this, + this.graphics, + apiVertexShader + ); + +}; + +R3.D3.Shader.Vertex.prototype = Object.create(R3.D3.Shader.prototype); +R3.D3.Shader.Vertex.prototype.constructor = R3.D3.Shader.Vertex; + +/** + * Creates a shader instance + * @returns {*} + */ +R3.D3.Shader.Vertex.prototype.createInstance = function() { + R3.D3.Shader.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Shader.Vertex.prototype.updateInstance = function(property) { + R3.D3.Shader.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Shader to a R3.D3.API.Shader + * @returns {R3.D3.API.Shader} + */ +R3.D3.Shader.Vertex.prototype.toApiObject = function() { + var apiShader = R3.D3.Shader.prototype.toApiObject.call(this); + return apiShader; +}; diff --git a/src/r3-d3-shadow-a.js b/src/r3-d3-shadow-a.js new file mode 100644 index 0000000..44522a9 --- /dev/null +++ b/src/r3-d3-shadow-a.js @@ -0,0 +1,136 @@ +/** + * R3.D3.Shadow + * @param graphics R3.GraphicsRuntime + * @param apiShadow R3.D3.API.Shadow + * @constructor + */ +R3.D3.Shadow = function( + graphics, + apiShadow +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiShadow)) { + apiShadow = { + shadowType : R3.D3.API.Shadow.SHADOW_TYPE_NORMAL + }; + } + + R3.D3.API.Shadow.call( + this, + apiShadow.id, + apiShadow.name, + apiShadow.shadowType, + apiShadow.camera, + apiShadow.bias, + apiShadow.mapSize, + apiShadow.radius, + apiShadow.parentEntity + ); + + if (this.camera instanceof R3.D3.API.Camera.Perspective) { + this.camera = new R3.D3.Camera.Perspective( + this.graphics, + this.camera + ) + } + + this.mapSize = new R3.Vector2( + this.graphics, + this.mapSize, + this + ); + + R3.Component.call( + this, + { + camera : R3.D3.Camera + } + ); +}; + +R3.D3.Shadow.prototype = Object.create(R3.Component.prototype); +R3.D3.Shadow.prototype.constructor = R3.D3.Shadow; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Shadow.prototype.createInstance = function() { + + /** + * Shadow objects are not responsible for creating their instances right now - + * They are implicitly created through threejs light instances. This means, + * they only update their instances. + * @type {Object} + */ + this.instance = {}; + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Shadow.prototype.updateInstance = function(property) { + + if (typeof this.instance !== 'object') { + console.warn('this shadow instance is not ready for an update: ' + this.name); + return; + } + + if (R3.Utils.UndefinedOrNull(property)) { + console.warn('no property for light: ' + this.name); + } + + if (property === 'shadowType') { + console.warn('changing shadowType has no effect'); + } + + if (property === 'camera') { + this.instance.camera = this.camera.instance; + } + + if (property === 'bias') { + this.instance.bias = this.bias; + } + + if (property === 'mapSize') { + this.instance.mapSize.x = this.mapSize.x; + this.instance.mapSize.y = this.mapSize.y; + } + + if (property === 'radius') { + this.instance.radius = this.radius; + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Shadow to a R3.D3.API.Shadow + * @returns {R3.D3.API.Shadow} + */ +R3.D3.Shadow.prototype.toApiObject = function() { + return new R3.D3.API.Shadow( + this.id, + this.name, + this.shadowType, + R3.Utils.IdOrNull(this.camera), + this.bias, + this.mapSize.toApiObject(), + this.radius, + R3.Utils.IdOrNull(this.parentEntity) + ); +}; + +R3.D3.Shadow.prototype.updateFromInstance = function() { + this.bias = this.instance.bias; + this.mapSize.x = this.instance.mapSize.x; + this.mapSize.y = this.instance.mapSize.y; + this.radius = this.instance.radius; + this.camera.instance = this.instance.camera; + this.camera.updateFromInstance(); +}; \ No newline at end of file diff --git a/src/r3-d3-shadow-directional.js b/src/r3-d3-shadow-directional.js new file mode 100644 index 0000000..5820e28 --- /dev/null +++ b/src/r3-d3-shadow-directional.js @@ -0,0 +1,90 @@ +/** + * R3.D3.Shadow.Directional + * @param graphics R3.GraphicsRuntime + * @param apiDirectionalShadow + * @constructor + */ +R3.D3.Shadow.Directional = function( + graphics, + apiDirectionalShadow +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiDirectionalShadow)) { + apiDirectionalShadow = { + shadowType : R3.D3.API.Shadow.SHADOW_TYPE_DIRECTIONAL + }; + } + + R3.D3.API.Shadow.Directional.call( + this, + apiDirectionalShadow + ); + + if (this.camera instanceof R3.D3.API.Camera.Orthographic) { + this.camera = new R3.D3.Camera.Orthographic( + this.graphics, + this.camera + ) + } + + R3.D3.Shadow.call( + this, + this.graphics, + this + ); + +}; + +R3.D3.Shadow.Directional.prototype = Object.create(R3.D3.Shadow.prototype); +R3.D3.Shadow.Directional.prototype.constructor = R3.D3.Shadow.Directional; + +/** + * Creates a shadow instance + * @returns {*} + */ +R3.D3.Shadow.Directional.prototype.createInstance = function() { + + this.instance = {}; + + R3.D3.Shadow.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Shadow.Directional.prototype.updateInstance = function(property) { + + if (property === 'camera') { + + //console.warn('todo: updateInstance for directional shadow camera instance'); + + return; + } + + R3.D3.Shadow.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Shadow to a R3.D3.API.Shadow + * @returns {R3.D3.API.Shadow} + */ +R3.D3.Shadow.Directional.prototype.toApiObject = function() { + + var apiShadow = R3.D3.Shadow.prototype.toApiObject.call(this); + + var apiDirectionalShadow = new R3.D3.API.Shadow.Directional( + apiShadow + ); + + return apiDirectionalShadow; +}; + +R3.D3.Shadow.Directional.prototype.updateFromInstance = function() { + + + R3.D3.Shadow.prototype.updateFromInstance.call(this); + +}; \ No newline at end of file diff --git a/src/r3-d3-shadow-spot.js b/src/r3-d3-shadow-spot.js new file mode 100644 index 0000000..eabfe11 --- /dev/null +++ b/src/r3-d3-shadow-spot.js @@ -0,0 +1,83 @@ +/** + * R3.D3.Shadow.Spot + * @param graphics R3.GraphicsRuntime + * @param apiSpotShadow + * @constructor + */ +R3.D3.Shadow.Spot = function( + graphics, + apiSpotShadow +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiSpotShadow)) { + apiSpotShadow = { + shadowType : R3.D3.API.Shadow.SHADOW_TYPE_SPOT + }; + } + + R3.D3.API.Shadow.Spot.call( + this, + apiSpotShadow + ); + + if (this.camera instanceof R3.D3.API.Camera.Perspective) { + this.camera = new R3.D3.Camera.Perspective( + this.graphics, + this.camera + ) + } + + R3.D3.Shadow.call( + this, + this.graphics, + apiSpotShadow + ); + +}; + +R3.D3.Shadow.Spot.prototype = Object.create(R3.D3.Shadow.prototype); +R3.D3.Shadow.Spot.prototype.constructor = R3.D3.Shadow.Spot; + +/** + * Creates a shadow instance + * @returns {*} + */ +R3.D3.Shadow.Spot.prototype.createInstance = function() { + + this.instance = {}; + + R3.D3.Shadow.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Shadow.Spot.prototype.updateInstance = function(property) { + + if (property === 'camera') { + + console.warn('todo: updateInstance for spot shadow camera instance'); + + return; + } + + R3.D3.Shadow.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Shadow to a R3.D3.API.Shadow + * @returns {R3.D3.API.Shadow} + */ +R3.D3.Shadow.Spot.prototype.toApiObject = function() { + + var apiShadow = R3.D3.Shadow.prototype.toApiObject.call(this); + + var apiSpotShadow = new R3.D3.API.Shadow.Spot( + apiShadow + ); + + return apiSpotShadow; +}; diff --git a/src/r3-d3-shape-0.js b/src/r3-d3-shape-0.js new file mode 100644 index 0000000..061f96c --- /dev/null +++ b/src/r3-d3-shape-0.js @@ -0,0 +1,108 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics R3.PhysicsRuntime + * @param apiShape R3.D3.API.Shape + * @constructor + */ +R3.D3.Shape = function ( + physics, + apiShape +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (R3.Utils.UndefinedOrNull(apiShape)) { + apiShape = { + shapeType : R3.D3.API.Shape.SHAPE_TYPE_NONE + }; + } + + R3.D3.API.Shape.call( + this, + apiShape.id, + apiShape.name, + apiShape.shapeType, + apiShape.boundingSphereRadius, + apiShape.collisionResponse, + apiShape.frictionMaterial, + apiShape.parentMesh, + apiShape.parentEntity + ); + + var linkedObjects = { + frictionMaterial : R3.D3.FrictionMaterial, + parentMesh : R3.D3.Mesh + }; + + R3.Component.call( + this, + linkedObjects + ); +}; + +R3.D3.Shape.prototype = Object.create(R3.Component.prototype); +R3.D3.Shape.prototype.constructor = R3.D3.Shape; + + +/** + * Creates a shape instance or updates it + */ +R3.D3.Shape.prototype.createInstance = function() { + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the mesh instance + */ +R3.D3.Shape.prototype.updateInstance = function(property) { + throw new Error('Do not instantiate this class directly - use a child class instead'); + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Shape to a R3.D3.API.Shape + * @returns {R3.D3.API.Shape} + */ +R3.D3.Shape.prototype.toApiObject = function() { + + var apiShape = new R3.D3.API.Shape( + this.id, + this.name, + this.shapeType, + this.boundingSphereRadius, + this.collisionResponse, + R3.Utils.IdOrNull(this.frictionMaterial), + R3.Utils.IdOrNull(this.parentMesh), + R3.Utils.IdOrNull(this.parentEntity) + ); + + return apiShape; +}; + +/** + * Converts a standard object mesh to a R3.D3.Shape + * @param physics R3.PhysicsRuntime + * @param objectShape {Object} + * @constructor + */ +R3.D3.Shape.FromObject = function(physics, objectShape) { + throw ('not implemented'); +}; + +R3.D3.Shape.prototype.stopVisualize = function() { + R3.Event.Emit( + R3.Event.STOP_VISUALIZE, + { + mesh : this.mesh + } + ) +}; + +R3.D3.Shape.prototype.visualize = function() { + R3.Event.Emit( + R3.Event.VISUALIZE, + { + shape : this + } + ) +}; \ No newline at end of file diff --git a/src/r3-d3-shape-box.js b/src/r3-d3-shape-box.js new file mode 100644 index 0000000..64c6ab9 --- /dev/null +++ b/src/r3-d3-shape-box.js @@ -0,0 +1,115 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape R3.D3.API.Shape + * @param halfExtents + * @constructor + */ +R3.D3.Shape.Box = function ( + physics, + apiShape, + halfExtents +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (R3.Utils.UndefinedOrNull(apiShape)) { + apiShape = { + shapeType : R3.D3.API.Shape.SHAPE_TYPE_BOX + }; + } + + if (R3.Utils.UndefinedOrNull(halfExtents)) { + halfExtents = new R3.Vector3( + physics, + new R3.API.Vector3( + 1,1,1 + ) + ); + } else if (halfExtents instanceof R3.API.Vector3) { + halfExtents = new R3.Vector3( + this.physics, + halfExtents, + this + ) + } + this.halfExtents = halfExtents; + + R3.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +R3.D3.Shape.Box.prototype = Object.create(R3.D3.Shape.prototype); +R3.D3.Shape.Box.prototype.constructor = R3.D3.Shape.Box; + +/** + * + * @returns {R3.D3.Shape.Box|*|SEA3D.Box} + */ +R3.D3.Shape.Box.prototype.createInstance = function() { + + if (R3.Utils.UndefinedOrNull(this.halfExtents)) { + throw new Error('no halfExtents'); + } + + if (R3.Utils.UndefinedOrNull(this.halfExtents.instance)) { + throw new Error('no halfExtents instance'); + } + + this.instance = new CANNON.Box( + this.halfExtents.instance + ); + + R3.D3.Shape.prototype.createInstance.call(this); + +}; + +R3.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(); +}; + +R3.D3.Shape.Box.prototype.toApiObject = function() { + + var apiShape = R3.D3.Shape.prototype.toApiObject.call(this); + + apiShape.halfExtents = this.halfExtents.toApiObject(); + + return apiShape; +}; + +R3.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(); +}; + +R3.D3.Shape.Box.FromObject = function(physics, objectShape) { + + var apiShape = R3.D3.API.Shape.FromObject(objectShape); + + apiShape.halfExtents = R3.API.Vector3.FromObject(objectShape.halfExtents); + + return new R3.D3.Shape.Box( + physics, + apiShape, + apiShape.halfExtents + ); + +}; \ No newline at end of file diff --git a/src/r3-d3-shape-convex-hull-0.js b/src/r3-d3-shape-convex-hull-0.js new file mode 100644 index 0000000..5e246ec --- /dev/null +++ b/src/r3-d3-shape-convex-hull-0.js @@ -0,0 +1,281 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape R3.D3.API.Shape + * @param faces + * @param uniqueAxes + * @param uniqueEdges + * @param vertices + * @constructor + */ +R3.D3.Shape.ConvexHull = function ( + physics, + apiShape, + vertices, + faces, + uniqueAxes, + uniqueEdges +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (R3.Utils.UndefinedOrNull(apiShape)) { + apiShape = { + shapeType : R3.D3.API.Shape.SHAPE_TYPE_CONVEX_HULL + }; + } + + if (R3.Utils.UndefinedOrNull(vertices)) { + vertices = []; + } + this.vertices = vertices; + + if (R3.Utils.UndefinedOrNull(faces)) { + faces = []; + } + this.faces = faces; + + if (R3.Utils.UndefinedOrNull(uniqueAxes)) { + uniqueAxes = []; + } + this.uniqueAxes = uniqueAxes; + + if (R3.Utils.UndefinedOrNull(uniqueEdges)) { + uniqueEdges = []; + } + this.uniqueEdges = uniqueEdges; + + this.vertices = this.vertices.map(function(vertex){ + if (vertex instanceof R3.D3.API.Vertex){ + return new R3.D3.Vertex( + this.physics, + vertex + ) + } + return vertex; + }.bind(this)); + + this.faces = this.faces.map(function(face){ + if (face instanceof R3.D3.API.Face){ + return new R3.D3.Face( + this.physics, + face + ) + } + return face; + }.bind(this)); + + this.uniqueAxes = this.uniqueAxes.map(function(axis){ + if (axis instanceof R3.API.Vector3) { + return new R3.Vector3( + this.physics, + axis, + this + ) + } + return axis; + }.bind(this)); + + this.uniqueEdges = this.uniqueEdges.map(function(edge){ + if (edge instanceof R3.API.Vector3) { + return new R3.Vector3( + this.physics, + edge, + this + ) + } + return edge; + }.bind(this)); + + R3.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +R3.D3.Shape.ConvexHull.prototype = Object.create(R3.D3.Shape.prototype); +R3.D3.Shape.ConvexHull.prototype.constructor = R3.D3.Shape.ConvexHull; + +/** + * Create instance + * @returns {R3.D3.Shape.ConvexHull} + */ +R3.D3.Shape.ConvexHull.prototype.createInstance = function() { + + var faceNormals = []; + + this.instance = new CANNON.ConvexPolyhedron( + this.vertices.map( + function(vertex) { + + if (R3.Utils.UndefinedOrNull(vertex)) { + throw new Error('no vertex'); + } + + if (R3.Utils.UndefinedOrNull(vertex.position)) { + throw new Error('no vertex position'); + } + + if (R3.Utils.UndefinedOrNull(vertex.position.instance)) { + throw new Error('no vertex position instance'); + } + + return vertex.position.instance; + } + ), + this.faces.map( + function(face) { + + if (R3.Utils.UndefinedOrNull(face)) { + throw new Error('no face'); + } + + if (R3.Utils.UndefinedOrNull(face.normal)) { + throw new Error('no face normal'); + } + + if (R3.Utils.UndefinedOrNull(face.normal.instance)) { + throw new Error('no face normal instance'); + } + + if (R3.Utils.UndefinedOrNull(face.v0index)) { + throw new Error('no face v0index'); + } + + if (R3.Utils.UndefinedOrNull(face.v1index)) { + throw new Error('no face v1index'); + } + + if (R3.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; + + R3.D3.Shape.prototype.createInstance.call(this); +}; + +/** + * Update instance + */ +R3.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(); +}; + +R3.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 r3 classes :)'); +}; + +R3.D3.Shape.ConvexHull.prototype.toApiObject = function() { + + var apiShape = R3.D3.Shape.prototype.toApiObject.call(this); + + apiShape.vertices = this.vertices.map( + function(vertex) { + if (vertex instanceof R3.D3.Vertex) { + return vertex.toApiObject(); + } + return vertex; + } + ); + + apiShape.faces = this.faces.map( + function(face) { + if (face instanceof R3.D3.Face){ + return face.toApiObject(); + } + return face; + } + ); + + apiShape.uniqueAxes = this.uniqueAxes.map( + function(axis){ + if (axis instanceof R3.Vector3) { + return axis.toApiObject(); + } + return axis; + } + ); + + apiShape.uniqueEdges = this.uniqueEdges.map( + function(edge) { + if (edge instanceof R3.Vector3) { + return edge.toApiObject(); + } + return edge; + } + ); + + return apiShape; +}; + +R3.D3.Shape.ConvexHull.prototype.setFromMesh = function() { + console.log('todo: set convex hull from mesh'); + this.updateInstance(); +}; + +R3.D3.Shape.ConvexHull.InheritableProperties = function(physics, objectShape) { + var vertices = objectShape.vertices.map( + function(objectVertex) { + return R3.D3.Vertex.FromObject(physics, objectVertex); + } + ); + + var faces = objectShape.faces.map( + function(objectFace) { + return R3.D3.Face.FromObject(physics, objectFace); + } + ); + + var uniqueAxes = objectShape.uniqueAxes.map( + function(axis) { + return R3.API.Vector3.FromObject(axis); + } + ); + + var uniqueEdges = objectShape.uniqueEdges.map( + function(edge) { + return R3.API.Vector3.FromObject(edge); + } + ); + + return { + vertices : vertices, + faces : faces, + uniqueAxes : uniqueAxes, + uniqueEdges : uniqueEdges + }; +}; + +R3.D3.Shape.ConvexHull.FromObject = function(physics, objectShape) { + + var apiShape = R3.D3.API.Shape.FromObject(objectShape); + + var inheritableProperties = R3.D3.Shape.ConvexHull.InheritableProperties(physics, objectShape); + + return new R3.D3.Shape.ConvexHull.call( + this, + physics, + apiShape, + inheritableProperties.vertices, + inheritableProperties.faces, + inheritableProperties.uniqueAxes, + inheritableProperties.uniqueEdges + ); +}; \ No newline at end of file diff --git a/src/r3-d3-shape-convex-hull-cylinder.js b/src/r3-d3-shape-convex-hull-cylinder.js new file mode 100644 index 0000000..56b99ca --- /dev/null +++ b/src/r3-d3-shape-convex-hull-cylinder.js @@ -0,0 +1,133 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape R3.D3.API.Shape + * @param radiusTop + * @param radiusBottom + * @param height + * @param numSegments + * @constructor + */ +R3.D3.Shape.ConvexHull.Cylinder = function ( + physics, + apiShape, + radiusTop, + radiusBottom, + height, + numSegments +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (R3.Utils.UndefinedOrNull(apiShape)) { + apiShape = { + shapeType : R3.D3.API.Shape.SHAPE_TYPE_CONVEX_HULL_CYLINDER + }; + } + + if (R3.Utils.UndefinedOrNull(radiusTop)) { + radiusTop = 1; + } + this.radiusTop = radiusTop; + + if (R3.Utils.UndefinedOrNull(radiusBottom)) { + radiusBottom = 1; + } + this.radiusBottom = radiusBottom; + + if (R3.Utils.UndefinedOrNull(height)) { + height = radiusBottom / 2; + } + this.height = height; + + if (R3.Utils.UndefinedOrNull(numSegments)) { + numSegments = 20; + } + this.numSegments = numSegments; + + R3.D3.Shape.ConvexHull.call( + this, + this.physics, + apiShape + ); +}; + +R3.D3.Shape.ConvexHull.Cylinder.prototype = Object.create(R3.D3.Shape.ConvexHull.prototype); +R3.D3.Shape.ConvexHull.Cylinder.prototype.constructor = R3.D3.Shape.ConvexHull.Cylinder; + +/** + * + * @returns {R3.D3.Shape.Cylinder|*|SEA3D.Cylinder} + */ +R3.D3.Shape.ConvexHull.Cylinder.prototype.createInstance = function() { + + this.instance = new CANNON.Cylinder( + this.radiusTop, + this.radiusBottom, + this.height, + this.numSegments + ); + + R3.D3.Shape.prototype.createInstance.call(this); +}; + +R3.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(); +}; + +R3.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; +}; + +R3.D3.Shape.ConvexHull.Cylinder.prototype.toApiObject = function() { + + var apiShape = R3.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; +}; + + +R3.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 = R3.D3.Shape.ConvexHull.FromObject(physics, objectShape); + * + * Instead, do this: + */ + var apiShape = R3.D3.API.Shape.FromObject(objectShape); + + var inheritableProperties = R3.D3.Shape.ConvexHull.InheritableProperties(physics, objectShape); + + for (var property in inheritableProperties) { + if (inheritableProperties.hasOwnProperty(property)) { + apiShape[property] = inheritableProperties[property]; + } + } + + return new R3.D3.Shape.ConvexHull.Cylinder( + physics, + apiShape, + objectShape.radiusTop, + objectShape.radiusBottom, + objectShape.height, + objectShape.numSegments + ); + +}; \ No newline at end of file diff --git a/src/r3-d3-shape-height-map.js b/src/r3-d3-shape-height-map.js new file mode 100644 index 0000000..4a79ff9 --- /dev/null +++ b/src/r3-d3-shape-height-map.js @@ -0,0 +1,171 @@ +/** + * + * @param physics + * @param apiShape + * @param heightData + * @param minValue + * @param maxValue + * @param elementSize + * @constructor + */ +R3.D3.Shape.HeightMap = function ( + physics, + apiShape, + heightData, + minValue, + maxValue, + elementSize +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (R3.Utils.UndefinedOrNull(apiShape)) { + apiShape = { + shapeType : R3.D3.API.Shape.SHAPE_TYPE_HEIGHT_MAP + }; + } + + if (R3.Utils.UndefinedOrNull(heightData)) { + heightData = [[10, 10, 10], [10, 10, 10], [10, 10, 10]]; + } + this.heightData = heightData; + + if (R3.Utils.UndefinedOrNull(minValue)) { + minValue = 0; + } + this.minValue = minValue; + + if (R3.Utils.UndefinedOrNull(maxValue)) { + maxValue = 10; + } + this.maxValue = maxValue; + + if (R3.Utils.UndefinedOrNull(elementSize)) { + elementSize = 1; + } + this.elementSize = elementSize; + + R3.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +R3.D3.Shape.HeightMap.prototype = Object.create(R3.D3.Shape.prototype); +R3.D3.Shape.HeightMap.prototype.constructor = R3.D3.Shape.HeightMap; + +/** + * Create instance + * @returns {R3.D3.Shape.HeightMap} + */ +R3.D3.Shape.HeightMap.prototype.createInstance = function() { + + //TODO: initialize properly and throw when errors + + this.instance = new CANNON.Heightfield( + this.heightData, + { + elemSize : this.elementSize + } + ); + + R3.D3.Shape.prototype.createInstance.call(this); +}; + +/** + * Update instance + */ +R3.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(); +}; + + +R3.D3.Shape.HeightMap.prototype.toApiObject = function() { + var apiShape = R3.D3.Shape.prototype.toApiObject.call(this); + apiShape.heightData = this.heightData; + apiShape.minValue = this.minValue; + apiShape.maxValue = this.maxValue; + apiShape.elemSize = this.elemSize; + return apiShape; +}; + +R3.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(); +}; + +R3.D3.Shape.HeightMap.FromObject = function(physics, objectShape) { + + var apiShape = R3.D3.API.Shape.FromObject(objectShape); + + return new R3.D3.Shape.HeightMap( + physics, + apiShape, + objectShape.heightData, + objectShape.minValue, + objectShape.maxValue, + objectShape.elemSize + ); +}; \ No newline at end of file diff --git a/src/r3-d3-shape-plane.js b/src/r3-d3-shape-plane.js new file mode 100644 index 0000000..c7d1151 --- /dev/null +++ b/src/r3-d3-shape-plane.js @@ -0,0 +1,53 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape R3.D3.API.Shape + * @constructor + */ +R3.D3.Shape.Plane = function ( + physics, + apiShape +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (R3.Utils.UndefinedOrNull(apiShape)) { + apiShape = { + shapeType : R3.D3.API.Shape.SHAPE_TYPE_PLANE + }; + } + + R3.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +R3.D3.Shape.Plane.prototype = Object.create(R3.D3.Shape.prototype); +R3.D3.Shape.Plane.prototype.constructor = R3.D3.Shape.Plane; + +/** + * + * @returns {R3.D3.Shape.Plane|*|SEA3D.Plane} + */ +R3.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(); + R3.D3.Shape.prototype.createInstance.call(this); +}; + +R3.D3.Shape.Plane.prototype.updateInstance = function() { +}; + +R3.D3.Shape.Plane.FromObject = function(physics, objectShape) { + + var apiShape = R3.D3.API.Shape.FromObject(objectShape); + + return new R3.D3.Shape.Plane( + physics, + apiShape + ); +}; \ No newline at end of file diff --git a/src/r3-d3-shape-sphere.js b/src/r3-d3-shape-sphere.js new file mode 100644 index 0000000..3a9f3b6 --- /dev/null +++ b/src/r3-d3-shape-sphere.js @@ -0,0 +1,71 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape R3.D3.API.Shape + * @param radius + * @constructor + */ +R3.D3.Shape.Sphere = function ( + physics, + apiShape, + radius +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (R3.Utils.UndefinedOrNull(apiShape)) { + apiShape = { + shapeType : R3.D3.API.Shape.SHAPE_TYPE_SPHERE + }; + } + + if (R3.Utils.UndefinedOrNull(radius)) { + radius = 1; + } + this.radius = radius; + + R3.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +R3.D3.Shape.Sphere.prototype = Object.create(R3.D3.Shape.prototype); +R3.D3.Shape.Sphere.prototype.constructor = R3.D3.Shape.Sphere; + +/** + * + * @returns {R3.D3.Shape.Sphere|*|SEA3D.Sphere} + */ +R3.D3.Shape.Sphere.prototype.createInstance = function() { + + this.instance = new CANNON.Sphere( + this.radius + ); + + R3.D3.Shape.prototype.createInstance.call(this); +}; + +R3.D3.Shape.Sphere.prototype.updateInstance = function() { + this.instance.radius = this.radius; + this.instance.updateBoundingSphereRadius(); +}; + + +R3.D3.Shape.Sphere.prototype.toApiObject = function() { + var apiShape = R3.D3.Shape.prototype.toApiObject.call(this); + apiShape.radius = this.radius; + return apiShape; +}; + +R3.D3.Shape.Sphere.FromObject = function(physics, objectShape) { + + var apiShape = R3.D3.API.Shape.FromObject(objectShape); + + return new R3.D3.Shape.Sphere( + physics, + apiShape, + objectShape.radius + ); +}; \ No newline at end of file diff --git a/src/r3-d3-shape-tri-mesh.js b/src/r3-d3-shape-tri-mesh.js new file mode 100644 index 0000000..4777627 --- /dev/null +++ b/src/r3-d3-shape-tri-mesh.js @@ -0,0 +1,70 @@ +/** + * Shape Superset - The apiShape properties get moved into the Shape object itself, and then the instance is created + * @param physics + * @param apiShape R3.D3.API.Shape + * @param vertices + * @param indices + * @constructor + */ +R3.D3.Shape.TriMesh = function ( + physics, + apiShape, + vertices, + indices +) { + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (R3.Utils.UndefinedOrNull(apiShape)) { + apiShape = { + shapeType : R3.D3.API.Shape.SHAPE_TYPE_TRIMESH + }; + } + + if (R3.Utils.UndefinedOrNull(vertices)) { + vertices = []; + } + this.vertices = vertices; + + if (R3.Utils.UndefinedOrNull(indices)) { + indices = []; + } + this.indices = indices; + + R3.D3.Shape.call( + this, + this.physics, + apiShape + ); +}; + +R3.D3.Shape.TriMesh.prototype = Object.create(R3.D3.Shape.prototype); +R3.D3.Shape.TriMesh.prototype.constructor = R3.D3.Shape.TriMesh; + +/** + * Create instance + * @returns {R3.D3.Shape.TriMesh} + */ +R3.D3.Shape.TriMesh.prototype.createInstance = function() { + + this.instance = new CANNON.TriMesh( + this.vertices, + this.indices + ); + + R3.D3.Shape.prototype.createInstance.call(this); + +}; + +/** + * Update instance + */ +R3.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(); +}; \ No newline at end of file diff --git a/src/r3-d3-skeleton.js b/src/r3-d3-skeleton.js new file mode 100644 index 0000000..0a7769c --- /dev/null +++ b/src/r3-d3-skeleton.js @@ -0,0 +1,236 @@ +/** + * Skeleton Superset + * @constructor + * @param graphics R3.GraphicsRuntime + * @param apiSkeleton R3.D3.API.Skeleton + */ +R3.D3.Skeleton = function Skeleton( + graphics, + apiSkeleton +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiSkeleton)) { + apiSkeleton = {}; + } + + R3.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 R3.D3.API.Bone) { + return new R3.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 R3.API.Matrix4) { + return new R3.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 R3.API.Matrix4) { + return new R3.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) + ); + + R3.Component.call( + this, + { + 'bones' : [R3.D3.Bone] + } + ); +}; + +R3.D3.Skeleton.prototype = Object.create(R3.Component.prototype); +R3.D3.Skeleton.prototype.constructor = R3.D3.Skeleton; + + +/** + * Creates an instance skeleton + * @param update boolean + */ +R3.D3.Skeleton.prototype.createInstance = function(update) { + + var boneInstances = this.bones.map ( + function (bone) { + + if (R3.Utils.UndefinedOrNull(bone)) { + throw new Error('no bone'); + } + + if (R3.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 (R3.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(); + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance + */ +R3.D3.Skeleton.prototype.updateInstance = function(property) { + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Skeleton to R3.D3.API.Skeleton + * @returns {R3.D3.API.Skeleton} + */ +R3.D3.Skeleton.prototype.toApiObject = function() { + + var apiSkeleton = new R3.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, + R3.Utils.IdOrNull(this.parentEntity) + ); + + return apiSkeleton; +}; + +/** + * Returns a R3.D3.Skeleton from a skeleton Object + * @param graphics R3.GraphicsRuntime + * @param objectSkeleton Object + * @returns {R3.D3.Skeleton} + * @constructor + */ +R3.D3.Skeleton.FromObject = function( + graphics, + objectSkeleton +) { + + if (!objectSkeleton) { + return null; + } + + var apiSkeleton = R3.D3.API.Skeleton.FromObject(objectSkeleton); + + var skeleton = new R3.D3.Skeleton( + graphics, + apiSkeleton + ); + + return skeleton; +}; \ No newline at end of file diff --git a/src/r3-d3-solver.js b/src/r3-d3-solver.js new file mode 100644 index 0000000..61aba53 --- /dev/null +++ b/src/r3-d3-solver.js @@ -0,0 +1,111 @@ +/** + * Solver Runtime + * @param physics R3.GraphicsRuntime + * @param apiSolver R3.D3.API.Solver + * @constructor + */ +R3.D3.Solver = function ( + physics, + apiSolver +) { + + this.physics = physics; + this.physics.isNotCannonThrow(); + + if (R3.Utils.UndefinedOrNull(apiSolver)) { + apiSolver = {}; + } + + R3.D3.API.Solver.call( + this, + apiSolver.id, + apiSolver.name, + apiSolver.solverType, + apiSolver.iterations, + apiSolver.tolerance, + apiSolver.parentEntity + ); + + R3.Component.call(this); +}; + +R3.D3.Solver.prototype = Object.create(R3.Component.prototype); +R3.D3.Solver.prototype.constructor = R3.D3.Solver; + +/** + * + * @returns {*} + */ +R3.D3.Solver.prototype.createInstance = function() { + + if (this.solverType === R3.D3.API.Solver.GS_SOLVER) { + this.instance = new CANNON.GSSolver(); + } else if (this.solverType === R3.D3.API.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; + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * + */ +R3.D3.Solver.prototype.updateInstance = function(property) { + + if (this.solverType === R3.D3.API.Solver.GS_SOLVER) { + if (!(this.instance instanceof CANNON.GSSolver)) { + this.instance = new CANNON.GSSolver(); + } + } + + if (this.solverType === R3.D3.API.Solver.SPLIT_SOLVER) { + if (!(this.instance instanceof CANNON.SplitSolver)) { + this.instance = new CANNON.SplitSolver(); + } + } + + this.instance.iterations = this.iterations; + this.instance.tolerance = this.tolerance; + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * R3.D3.Solver to R3.D3.API.Solver + * @returns {R3.D3.API.Solver} + */ +R3.D3.Solver.prototype.toApiObject = function() { + + var apiSolver = new R3.D3.API.Solver( + this.id, + this.name, + this.solverType, + this.iterations, + this.tolerance, + R3.Utils.IdOrNull(this.parentEntity) + ); + + return apiSolver; +}; + +/** + * R3.D3.Solver from Object Solver + * @param graphics + * @param objectComponent + * @returns {R3.D3.Solver} + * @constructor + */ +R3.D3.Solver.FromObject = function(graphics, objectComponent) { + + var apiSolver = R3.D3.API.Solver.FromObject(objectComponent); + + return new R3.D3.Solver( + graphics, + apiSolver + ); +}; diff --git a/src/r3-d3-spline.js b/src/r3-d3-spline.js new file mode 100644 index 0000000..859ee8a --- /dev/null +++ b/src/r3-d3-spline.js @@ -0,0 +1,143 @@ +/** + * Spline constructor + * @param graphics R3.GraphicsRuntime + * @param apiSpline R3.D3.API.Spline + * @constructor + */ +R3.D3.Spline = function ( + graphics, + apiSpline +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiSpline)) { + apiSpline = {}; + } + + R3.D3.API.Spline.call( + this, + apiSpline.id, + apiSpline.name, + apiSpline.vertices, + apiSpline.parentEntity + ); + + this.vertices = this.vertices.map( + function (vertex) { + return new R3.Vector3( + graphics, + vertex, + this + ) + } + ); + + R3.Component.call(this); +}; + +R3.D3.Spline.prototype = Object.create(R3.Component.prototype); +R3.D3.Spline.prototype.constructor = R3.D3.Spline; + +/** + * Creates an instance spline + */ +R3.D3.Spline.prototype.createInstance = function() { + + var vertices = this.vertices.map( + function (vertex) { + + if (R3.Utils.UndefinedOrNull(vertex)) { + throw new Error('no vertex') + } + + if (R3.Utils.UndefinedOrNull(vertex.instance)) { + throw new Error('no vertex instance') + } + + return vertex.instance; + } + ); + + this.instance = THREE.CatmullRomCurve3(vertices); + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance + */ +R3.D3.Spline.prototype.updateInstance = function(property) { + + var vertices = this.vertices.map( + function (vertex) { + + if (R3.Utils.UndefinedOrNull(vertex)) { + throw new Error('no vertex') + } + + if (R3.Utils.UndefinedOrNull(vertex.instance)) { + throw new Error('no vertex instance') + } + + return vertex.instance; + } + ); + + this.instance = new THREE.CatmullRomCurve3(vertices); + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Spline to R3.D3.API.Spline + * @returns {R3.D3.API.Spline} + */ +R3.D3.Spline.prototype.toApiObject = function() { + + return new R3.D3.API.Spline( + this.id, + this.name, + this.vertices.map( + function (vertex) { + return vertex.toApiObject() + } + ), + R3.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Returns a R3.D3.Spline from a spline Object + * @param graphics R3.GraphicsRuntime + * @param objectComponent Object + * @returns {R3.D3.Spline} + * @constructor + */ +R3.D3.Spline.FromObject = function( + graphics, + objectComponent +) { + var apiSpline = R3.D3.API.Spline.FromObject(objectComponent); + + return new R3.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 {*} + */ +R3.D3.Spline.prototype.getPointAt = function(proper) { + var point = this.instance.getPointAt(proper); + return new R3.Vector3( + this.graphics, + new R3.API.Vector3(point.x, point.y, point.z), + this, + 0.1 + ); +}; diff --git a/src/r3-d3-text.js b/src/r3-d3-text.js new file mode 100644 index 0000000..b4df960 --- /dev/null +++ b/src/r3-d3-text.js @@ -0,0 +1,116 @@ +/** + * Text object + * @param graphics + * @param apiText + * @returns {R3.D3.Text} + * @constructor + */ +R3.D3.Text = function( + graphics, + apiText +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiText)) { + apiText = {}; + } + + R3.D3.API.Text.call( + this, + apiText.id, + apiText.name, + apiText.offset, + apiText.font, + apiText.fillStyle, + apiText.value, + apiText.parentCanvas, + apiText.parentEntity + ); + + this.offset = new R3.Vector2( + this.graphics, + this.offset, + this + ); + + R3.Component.call(this); +}; + +R3.D3.Text.prototype = Object.create(R3.Component.prototype); +R3.D3.Text.prototype.constructor = R3.D3.Text; + +/** + * Creates a light instance + * @returns {*} + */ +R3.D3.Text.prototype.createInstance = function() { + + this.instance = true; + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Text.prototype.updateInstance = function(property) { + + if (R3.Utils.UndefinedOrNull(property)) { + console.warn('unknown property update for Text: ' + property); + } + + if ( + property === 'offset' || + property === 'font' || + property === 'fillStyle' || + property === 'value' + ) { + if (!this.parentCanvas) { + console.warn('no parent canvas set'); + return; + } + + this.parentCanvas.updateInstance('texts'); + } + + if (property === 'parentCanvas') { + + R3.EntityManager.Instance.queryComponents(R3.Component.CANVAS).map( + function(canvas) { + + var index = canvas.texts.indexOf(this); + + if (index !== -1) { + canvas.texts.splice(index, 1); + canvas.texts.updateInstance('texts'); + } + }.bind(this) + ); + + if (this.parentCanvas) { + R3.Utils.PushUnique(this.parentCanvas.texts, this); + this.parentCanvas.updateInstance('texts'); + } + } + + R3.Component.prototype.updateInstance.call(this, property); + +}; + +/** + * Converts a R3.D3.Text to a R3.D3.API.Text + * @returns {R3.D3.API.Text} + */ +R3.D3.Text.prototype.toApiObject = function() { + return new R3.D3.API.Text( + this.id, + this.name, + this.offset.toApiObject(), + this.font, + this.fillStyle, + this.value, + R3.Utils.IdOrNull(this.parentCanvas), + R3.Utils.IdOrNull(this.parentEntity) + ); +}; \ No newline at end of file diff --git a/src/r3-d3-texture-a.js b/src/r3-d3-texture-a.js new file mode 100644 index 0000000..219455b --- /dev/null +++ b/src/r3-d3-texture-a.js @@ -0,0 +1,387 @@ +/** + * Texture Superset - The apiTexture properties get moved into the Texture object itself, and then the instance is + * created + * @param apiTexture + * @param graphics R3.GraphicsRuntime + * @param overrideInstance + * @property textureType + * @constructor + */ +R3.D3.Texture = function( + graphics, + apiTexture, + overrideInstance +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(overrideInstance)) { + overrideInstance = null; + } + this.overrideInstance = overrideInstance; + + if (R3.Utils.UndefinedOrNull(apiTexture)) { + apiTexture = { + textureType : R3.D3.API.Texture.TEXTURE_TYPE_NONE + }; + } + + R3.D3.API.Texture.call( + this, + apiTexture.id, + apiTexture.name, + apiTexture.textureType, + apiTexture.parentEntity, + apiTexture.parentMaterials, + apiTexture.mipmaps, + apiTexture.mapping, + apiTexture.wrapS, + apiTexture.wrapT, + apiTexture.magFilter, + apiTexture.minFilter, + apiTexture.anisotropy, + apiTexture.format, + apiTexture.storageType, + apiTexture.offset, + apiTexture.repeat, + apiTexture.rotation, + apiTexture.center, + apiTexture.matrixAutoUpdate, + apiTexture.generateMipMaps, + apiTexture.premultiplyAlpha, + apiTexture.flipY, + apiTexture.unpackAlignment, + apiTexture.encoding, + apiTexture.version, + apiTexture.animated, + apiTexture.reverseAnimation, + apiTexture.forward + ); + + this.offset = new R3.Vector2( + this.graphics, + this.offset, + this + ); + + this.repeat = new R3.Vector2( + this.graphics, + this.repeat, + this + ); + + this.center = new R3.Vector2( + this.graphics, + this.center, + this + ); + + var linkedObjects = {}; + + switch (apiTexture.textureType) { + case R3.D3.API.Texture.TEXTURE_TYPE_NONE : + break; + case R3.D3.API.Texture.TEXTURE_TYPE_IMAGE : + linkedObjects.image = R3.Image; + break; + case R3.D3.API.Texture.TEXTURE_TYPE_CUBE : + linkedObjects.images = [R3.Image]; + break; + case R3.D3.API.Texture.TEXTURE_TYPE_CANVAS : + linkedObjects.canvas = R3.Canvas; + break; + default : + throw new Error('Unhandled texture type : ' + this.textureType); + } + + R3.Component.call( + this, + linkedObjects + ); +}; + +R3.D3.Texture.prototype = Object.create(R3.Component.prototype); +R3.D3.Texture.prototype.constructor = R3.D3.Texture; + +/** + * Apply our settings to the instance (which are OK to be applied) + */ +R3.D3.Texture.prototype.applyToInstance = function() { + + this.instance.name = this.name; + this.instance.wrapS = this.wrapS; + this.instance.wrapT = this.wrapT; + this.instance.magFilter = this.magFilter; + this.instance.minFilter = this.minFilter; + this.instance.anisotropy = this.anisotropy; + 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.rotation = this.rotation; + this.instance.center.x = this.center.x; + this.instance.center.y = this.center.y; + this.instance.matrixAutoUpdate = this.matrixAutoUpdate; + this.instance.generateMipMaps = this.generateMipMaps; + this.instance.premultiplyAlpha = this.premultiplyAlpha; + this.instance.flipY = this.flipY; + + this.instance.needsUpdate = true; +}; + +/** + * Creates an instance of our texture object + * @returns {*} + */ +R3.D3.Texture.prototype.createInstance = function() { + + if (this.overrideInstance) { + + this.instance = this.overrideInstance; + this.updateFromInstance(); + + } else { + + if (R3.Utils.UndefinedOrNull(this.instance)) { + + /** + * We have no instance - create one + */ + this.instance = new THREE.Texture(); + } + } + + /** + * Some settings we copy from the instance + */ + this.mipmaps = this.instance.mipmaps; + this.mapping = this.instance.mapping; + this.encoding = this.instance.encoding; + this.format = this.instance.format; + this.storageType = this.instance.type; + this.unpackAlignment = this.instance.unpackAlignment; + this.version = this.instance.version; + + /** + * Others we apply to the instance + */ + this.applyToInstance(); + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Texture.prototype.updateInstance = function(property) { + + if (R3.Utils.UndefinedOrNull(this.instance)) { + console.warn('no texture instance'); + return; + } + + if (R3.Utils.UndefinedOrNull(property)) { + console.warn('no texture property'); + return; + } + + if (property === 'name') { + this.instance.name = this.name; + return; + } + + if (property === 'textureType') { + console.warn('todo: texture type change here'); + return; + } + + if (property === 'mipmaps') { + console.warn('todo: mipmaps change here'); + return; + } + + if (property === 'mapping') { + this.instance.mapping = this.mapping; + } + + if (property === 'wrapS') { + this.instance.wrapS = this.wrapS; + } + + if (property === 'wrapT') { + this.instance.wrapT = this.wrapT; + } + + if (property === 'magFilter') { + this.instance.magFilter = this.magFilter; + } + + if (property === 'minFilter') { + this.instance.minFilter = this.minFilter; + } + + if (property === 'anisotropy') { + this.instance.anisotropy = this.anisotropy; + } + + if (property === 'format') { + this.instance.format = this.format; + } + + if (property === 'storageType') { + this.instance.type = this.storageType; + } + + if (property === 'offset') { + this.instance.offset.x = this.offset.x; + this.instance.offset.y = this.offset.y; + return; + } + + if (property === 'repeat') { + this.instance.repeat.x = this.repeat.x; + this.instance.repeat.y = this.repeat.y; + return; + } + + if (property === 'rotation') { + this.instance.rotation = this.rotation; + return; + } + + if (property === 'center') { + this.instance.center.x = this.center.x; + this.instance.center.y = this.center.y; + return; + } + + if (property === 'matrixAutoUpdate') { + this.instance.matrixAutoUpdate = this.matrixAutoUpdate; + return; + } + + if (property === 'generateMipMaps') { + this.instance.generateMipMaps = this.generateMipMaps; + return; + } + + if (property === 'premultiplyAlpha') { + this.instance.premultiplyAlpha = this.premultiplyAlpha; + return; + } + + if (property === 'flipY') { + this.instance.flipY = this.flipY; + } + + if (property === 'unpackAlignment') { + this.instance.unpackAlignment = this.unpackAlignment; + } + + if (property === 'encoding') { + this.instance.encoding = this.encoding; + } + + if (property === 'version') { + console.warn('version is read-only'); + } + + if (property === 'animated') { + R3.Event.Emit( + R3.Event.TEXTURE_ANIMATED_CHANGE, + { + texture: this + } + ) + } + + if (property === 'needsUpdate') { + this.needsUpdate = false; + } + + /** + * So if you don't return earlier - the instance will re-compile its shader + * @type {boolean} + */ + this.instance.needsUpdate = true; + this.version = this.instance.version; + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Texture to a R3.D3.API.Texture + * @returns {R3.D3.API.Texture} + */ +R3.D3.Texture.prototype.toApiObject = function() { + + var apiTexture = new R3.D3.API.Texture( + this.id, + this.name, + this.textureType, + R3.Utils.IdOrNull(this.parentEntity), + this.parentMaterials.map( + function(parentMaterial) { + return R3.Utils.IdOrNull(parentMaterial); + } + ), + this.mipmaps, + this.mapping, + this.wrapS, + this.wrapT, + this.magFilter, + this.minFilter, + this.anisotropy, + this.format, + this.storageType, + this.offset.toApiObject(), + this.repeat.toApiObject(), + this.rotation, + this.center.toApiObject(), + this.matrixAutoUpdate, + this.generateMipMaps, + this.premultiplyAlpha, + this.flipY, + this.unpackAlignment, + this.encoding, + this.version, + this.animated, + this.reverseAnimation, + this.forward + ); + + return apiTexture; +}; + +/** + * Updates R3.D3.Texture from instance + */ +R3.D3.Texture.prototype.updateFromInstance = function() { + this.name = this.instance.name; + this.mipmaps = this.instance.mipmaps; + this.mapping = this.instance.mapping; + this.wrapS = this.instance.wrapS; + this.wrapT = this.instance.wrapT; + this.magFilter = this.instance.magFilter; + this.minFilter = this.instance.minFilter; + this.anisotropy = this.instance.anisotropy; + this.format = this.instance.format; + this.storageType = this.instance.storageType; + this.offset.x = this.instance.offset.x; + this.offset.y = this.instance.offset.y; + this.repeat.x = this.instance.repeat.x; + this.repeat.y = this.instance.repeat.y; + this.rotation = this.instance.rotation; + this.center.x = this.instance.center.x; + this.center.y = this.instance.center.y; + this.matrixAutoUpdate = this.instance.matrixAutoUpdate; + this.generateMipMaps = this.instance.generateMipMaps; + this.premultiplyAlpha = this.instance.premultiplyAlpha; + this.flipY = this.instance.flipY; + this.unpackAlignment = this.instance.unpackAlignment; + this.encoding = this.instance.encoding; + this.version = this.instance.version; + this.animated = this.instance.animated; + this.reverseAnimation = this.instance.reverseAnimation; + this.forward = this.instance.forward; +}; \ No newline at end of file diff --git a/src/r3-d3-texture-canvas.js b/src/r3-d3-texture-canvas.js new file mode 100644 index 0000000..f320a22 --- /dev/null +++ b/src/r3-d3-texture-canvas.js @@ -0,0 +1,96 @@ +/** + * R3.D3.Texture.Canvas + * @param graphics + * @param apiTextureCanvas + * @constructor + */ +R3.D3.Texture.Canvas = function( + graphics, + apiTextureCanvas +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiTextureCanvas)) { + apiTextureCanvas = { + textureType : R3.D3.API.Texture.TEXTURE_TYPE_CANVAS + }; + } + + R3.D3.API.Texture.Canvas.call( + this, + apiTextureCanvas, + apiTextureCanvas.canvas + ); + + if (this.canvas instanceof R3.API.Canvas) { + this.canvas = new R3.Canvas( + this.graphics, + this.canvas + ); + } + + R3.D3.Texture.call( + this, + this.graphics, + this + ); + +}; + +R3.D3.Texture.Canvas.prototype = Object.create(R3.D3.Texture.prototype); +R3.D3.Texture.Canvas.prototype.constructor = R3.D3.Texture.Canvas; + +/** + * Creates an instance of our texture object + * @returns {*} + */ +R3.D3.Texture.Canvas.prototype.createInstance = function() { + + if ( + R3.Utils.UndefinedOrNull(this.canvas) || + R3.Utils.UndefinedOrNull(this.canvas.instance) + ) { + console.warn('canvas not ready at time of texture create instance'); + return; + } + + this.canvas.parentTexture = this; + + this.instance = new THREE.Texture( + this.canvas.instance + ); + + R3.D3.Texture.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Texture.Canvas.prototype.updateInstance = function(property) { + + if (property === 'canvas') { + + this.createInstance(); + + return; + } + + R3.D3.Texture.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Texture.Canvas to a R3.D3.API.Texture.Canvas + * @returns {R3.D3.API.Texture.Canvas} + */ +R3.D3.Texture.Canvas.prototype.toApiObject = function() { + + var apiTexture = R3.D3.Texture.prototype.toApiObject.call(this); + + var apiTextureCanvas = new R3.D3.API.Texture.Canvas( + apiTexture, + R3.Utils.IdOrNull(this.canvas) + ); + + return apiTextureCanvas; +}; diff --git a/src/r3-d3-texture-cube.js b/src/r3-d3-texture-cube.js new file mode 100644 index 0000000..e1c2da6 --- /dev/null +++ b/src/r3-d3-texture-cube.js @@ -0,0 +1,140 @@ +/** + * R3.D3.Texture.Cube + * @param graphics + * @param apiTextureCube + * @constructor + */ +R3.D3.Texture.Cube = function( + graphics, + apiTextureCube +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiTextureCube)) { + apiTextureCube = { + textureType : R3.D3.API.Texture.TEXTURE_TYPE_CUBE + }; + } + + R3.D3.API.Texture.Cube.call( + this, + apiTextureCube, + apiTextureCube.images + ); + + this.images = this.images.map( + function(image) { + if (image instanceof R3.API.Image) { + return new R3.Image(image); + } else { + return image; + } + } + ); + + R3.D3.Texture.call( + this, + this.graphics, + this + ); + +}; + +R3.D3.Texture.Cube.prototype = Object.create(R3.D3.Texture.prototype); +R3.D3.Texture.Cube.prototype.constructor = R3.D3.Texture.Cube; + +/** + * Returns all image instances, or null if one of the images are not loaded + */ +R3.D3.Texture.Cube.prototype.getImageInstances = function() { + + return this.images.reduce( + function(result, image) { + + /** + * If we have a null result return early + */ + + if (result === null) { + return result; + } + + if (R3.Utils.UndefinedOrNull(image.instance)) { + result = null; + } else { + result.push(image.instance); + } + + return result; + + }, + [] + ); +}; + +/** + * Creates an instance of our texture object + * @returns {*} + */ +R3.D3.Texture.Cube.prototype.createInstance = function() { + + var imageInstances = this.getImageInstances(); + + if (!imageInstances) { + console.warn('cube texture not ready'); + return; + } + + this.instance = new THREE.CubeTexture(imageInstances); + + R3.D3.Texture.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Texture.Cube.prototype.updateInstance = function(property) { + + if (property === 'images') { + + + var imageInstances = this.getImageInstances(); + + if (imageInstances) { + console.log('updating cube texture image instances'); + this.image = imageInstances; + } + + this.publish( + R3.Event.TEXTURE_INSTANCE_UPDATED, + { + texture : this + } + ); + + return; + } + + R3.D3.Texture.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Texture.Cube to a R3.D3.API.Texture.Cube + * @returns {R3.D3.API.Texture.Cube} + */ +R3.D3.Texture.Cube.prototype.toApiObject = function() { + + var apiTexture = R3.D3.Texture.prototype.toApiObject.call(this); + + var apiTextureCube = new R3.D3.API.Texture.Cube( + apiTexture, + this.images.map( + function(image) { + return R3.Utils.IdOrNull(image); + } + ) + ); + + return apiTextureCube; +}; diff --git a/src/r3-d3-texture-image.js b/src/r3-d3-texture-image.js new file mode 100644 index 0000000..b22543e --- /dev/null +++ b/src/r3-d3-texture-image.js @@ -0,0 +1,138 @@ +/** + * R3.D3.Texture.Image + * @param graphics + * @param apiTextureImage + * @param overrideInstance - if we pass an instance to the constructor, we want to skip the construction of this texture + * @constructor + */ +R3.D3.Texture.Image = function( + graphics, + apiTextureImage, + overrideInstance +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiTextureImage)) { + apiTextureImage = { + textureType : R3.D3.API.Texture.TEXTURE_TYPE_IMAGE + }; + } + + if (R3.Utils.UndefinedOrNull(overrideInstance)) { + overrideInstance = null; + } + this.overrideInstance = overrideInstance; + + R3.D3.API.Texture.Image.call( + this, + apiTextureImage, + apiTextureImage.image + ); + + if (this.image instanceof R3.API.Image) { + this.image = new R3.Image( + this.image + ); + } + + R3.D3.Texture.call( + this, + this.graphics, + this + ); + +}; + +R3.D3.Texture.Image.prototype = Object.create(R3.D3.Texture.prototype); +R3.D3.Texture.Image.prototype.constructor = R3.D3.Texture.Image; + +/** + * Creates an instance of our texture object + * @returns {*} + */ +R3.D3.Texture.Image.prototype.createInstance = function() { + + if ( + R3.Utils.UndefinedOrNull(this.image) || + R3.Utils.UndefinedOrNull(this.image.instance) + ) { + console.warn('image not ready at time of texture create instance'); + return; + } + + /** + * At this point - our image object exists + */ + + if (this.overrideInstance) { + + this.instance = this.overrideInstance; + this.updateFromInstance(); + + } else { + + this.instance = new THREE.Texture( + this.image.instance + ); + + } + + R3.D3.Texture.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.D3.Texture.Image.prototype.updateInstance = function(property) { + + if (property === 'image') { + + if (this.image && this.image.instance) { + this.instance.image = this.image.instance; + this.instance.needsUpdate = true; + } + + this.publish( + R3.Event.TEXTURE_INSTANCE_UPDATED, + { + texture : this + } + ); + + return; + } + + R3.D3.Texture.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.D3.Texture.Image to a R3.D3.API.Texture.Image + * @returns {R3.D3.API.Texture.Image} + */ +R3.D3.Texture.Image.prototype.toApiObject = function() { + + var apiTexture = R3.D3.Texture.prototype.toApiObject.call(this); + + var apiTextureImage = new R3.D3.API.Texture.Image( + apiTexture, + R3.Utils.IdOrNull(this.image) + ); + + return apiTextureImage; +}; + +/** + * Updates R3.D3.Texture.Image from instance + */ +R3.D3.Texture.Image.prototype.updateFromInstance = function() { + + this.image.instance = this.instance.image; + + if (this.image.instance) { + this.image.updateFromInstance(); + } + + R3.D3.Texture.prototype.updateFromInstance.call(this); + +}; \ No newline at end of file diff --git a/src/r3-d3-triangle-edge.js b/src/r3-d3-triangle-edge.js new file mode 100644 index 0000000..7d6257a --- /dev/null +++ b/src/r3-d3-triangle-edge.js @@ -0,0 +1,13 @@ +/** + * TriangleEdge + * @param triangle + * @param edge + * @constructor + */ +R3.D3.TriangleEdge = function( + triangle, + edge +) { + this.triangle = triangle; + this.edge = edge; +}; \ No newline at end of file diff --git a/src/r3-d3-vertex.js b/src/r3-d3-vertex.js new file mode 100644 index 0000000..18912ac --- /dev/null +++ b/src/r3-d3-vertex.js @@ -0,0 +1,59 @@ +/** + * R3.D3.Vertex + * @param implementation + * @param apiVertex + * @constructor + */ +R3.D3.Vertex = function Vertex( + implementation, + apiVertex +) { + this.implementation = implementation; + this.implementation.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiVertex)) { + apiVertex = {}; + } + + R3.D3.API.Vertex.call( + this, + apiVertex.position, + apiVertex.boneWeights + ); + + this.position = new R3.Vector3( + this.implementation, + this.position, + this + ); + + this.boneWeights = this.boneWeights.map( + function(boneWeight) { + return new R3.Vector4( + this.graphics, + boneWeight + ) + } + ); + +}; + +R3.D3.Vertex.prototype = Object.create(R3.Component.prototype); +R3.D3.Vertex.prototype.constructor = R3.D3.Vertex; + +/** + * Converts a R3.D3.Vertex to R3.D3.API.Vertex + * @returns {R3.D3.API.Vertex} + */ +R3.D3.Vertex.prototype.toApiObject = function() { + + return new R3.D3.API.Vertex( + this.position.toApiObject(), + this.boneWeights.map( + function(boneWeight){ + return boneWeight.toApiObject(); + } + ) + ); + +}; diff --git a/src/r3-d3-viewport.js b/src/r3-d3-viewport.js new file mode 100644 index 0000000..35e7980 --- /dev/null +++ b/src/r3-d3-viewport.js @@ -0,0 +1,88 @@ +/** + * Viewport Runtime + * @param graphics R3.GraphicsRuntime + * @param apiViewport R3.D3.API.Viewport + * @constructor + */ +R3.D3.Viewport = function ( + graphics, + apiViewport +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiViewport)) { + apiViewport = {}; + } + + R3.D3.API.Viewport.call( + this, + apiViewport.id, + apiViewport.name, + apiViewport.width, + apiViewport.height, + apiViewport.x, + apiViewport.y, + apiViewport.parentEntity + ); + + R3.Component.call(this); +}; + +R3.D3.Viewport.prototype = Object.create(R3.Component.prototype); +R3.D3.Viewport.prototype.constructor = R3.D3.Viewport; + +/** + * + * @returns {boolean} + */ +R3.D3.Viewport.prototype.createInstance = function() { + + this.instance = new THREE.Vector4( + this.x, + this.y, + this.width, + this.height + ); + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * + */ +R3.D3.Viewport.prototype.updateInstance = function(property) { + + if ( + property === 'x' || + property === 'y' || + property === 'width' || + property === 'height' + ) { + this.instance.x = this.x; + this.instance.y = this.y; + this.instance.z = this.width; + this.instance.w = this.height; + } + +}; + +/** + * R3.D3.Viewport to R3.D3.API.Viewport + * @returns {R3.D3.API.Viewport} + */ +R3.D3.Viewport.prototype.toApiObject = function() { + + var apiViewport = new R3.D3.API.Viewport( + this.id, + this.name, + this.width, + this.height, + this.x, + this.y, + R3.Utils.IdOrNull(this.parentEntity) + ); + + return apiViewport; +}; diff --git a/src/r3-dom-element.js b/src/r3-dom-element.js new file mode 100644 index 0000000..cf6c68a --- /dev/null +++ b/src/r3-dom-element.js @@ -0,0 +1,119 @@ +/** + * Runtime domElement for updating instance objects + * @param apiDomElement R3.API.DomElement + * @constructor + */ +R3.DomElement = function (apiDomElement) { + + if (R3.Utils.UndefinedOrNull(apiDomElement)) { + apiDomElement = {}; + } + + R3.API.DomElement.call( + this, + apiDomElement.id, + apiDomElement.name, + apiDomElement.domElementId, + apiDomElement.parentEntity + ); + + this.fullscreen = false; + + R3.Component.call(this); +}; + +R3.DomElement.prototype = Object.create(R3.Component.prototype); +R3.DomElement.prototype.constructor = R3.DomElement; + +/** + * Creates an instance domElement + * @returns {*} + */ +R3.DomElement.prototype.createInstance = function() { + this.instance = document.getElementById(this.domElementId); + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates instance domElement + */ +R3.DomElement.prototype.updateInstance = function(property) { + if (property === 'domElementId') { + this.createInstance() + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * Converts runtime DomElement to API DomElement + * @returns {R3.API.DomElement} + */ +R3.DomElement.prototype.toApiObject = function() { + return new R3.API.DomElement( + this.id, + this.name, + this.domElementId, + R3.Utils.IdOrNull(this.parentEntity) + ); +}; + +/** + * Appends domInstance to DOM instance + * @param domInstance + */ +R3.DomElement.prototype.append = function(domInstance) { + this.instance.appendChild(domInstance); +}; + +/** + * Clears DOM instance + */ +R3.DomElement.prototype.clear = function() { + this.instance.innerHTML = ''; +}; + + +R3.DomElement.prototype.requestFullscreen = function(event) { + + var docEl = document.documentElement; + + if (docEl.requestFullscreen) { + docEl.requestFullscreen(); + } else if (docEl.msRequestFullscreen) { + docEl.msRequestFullscreen(); + } else if (docEl.mozRequestFullScreen) { + docEl.mozRequestFullScreen(); + } else if (docEl.webkitRequestFullscreen) { + docEl.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); + } + + this.fullscreen = true; +}; + + +R3.DomElement.prototype.exitFullscreen = function(event) { + + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.msExitFullscreen) { + document.msExitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } + + this.fullscreen = false; +}; + +R3.DomElement.FromObject = function(objectDom) { + + var apiDomElement = R3.API.DomElement.FromObject(objectDom); + + var domElement = new R3.DomElement( + apiDomElement + ); + + return domElement; +}; \ No newline at end of file diff --git a/src/r3-draw-range.js b/src/r3-draw-range.js new file mode 100644 index 0000000..1075c17 --- /dev/null +++ b/src/r3-draw-range.js @@ -0,0 +1,89 @@ +/** + * R3.DrawRange + * @param implementation + * @param apiDrawRange + * @param parentGeometry + * @constructor + */ +R3.DrawRange = function ( + implementation, + apiDrawRange, + parentGeometry +) { + + this.implementation = implementation; + this.implementation.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiDrawRange)) { + apiDrawRange = {}; + } + + if (R3.Utils.UndefinedOrNull(parentGeometry)) { + parentGeometry = null; + } + this.parentGeometry = parentGeometry; + + /** + * Mongo doesn't store Infinity + */ + if (apiDrawRange.count === null) { + apiDrawRange.count = Infinity; + } + + R3.API.DrawRange.call( + this, + apiDrawRange.id, + apiDrawRange.name, + apiDrawRange.parentEntity, + apiDrawRange.start, + apiDrawRange.count + ); + + this.createInstance(); +}; + +R3.DrawRange.prototype = Object.create(R3.Component.prototype); +R3.DrawRange.prototype.constructor = R3.DrawRange; + +/** + * Creates an instance R3.DrawRange + * @returns {*} + */ +R3.DrawRange.prototype.createInstance = function() { + + this.instance = { + start : this.start, + count : this.count + } + +}; + +/** + * Updates R3.DrawRange instance + * @param property + */ +R3.DrawRange.prototype.updateInstance = function(property) { + + console.warn('update the geometry instead'); + + if (property === 'start') { + } + + if (property === 'count') { + } + +}; + +/** + * R3.DrawRange to R3.API.DrawRange + * @returns {R3.API.DrawRange} + */ +R3.DrawRange.prototype.toApiObject = function() { + return new R3.API.DrawRange( + this.id, + this.name, + R3.Utils.IdOrNull(this.parentEntity), + this.start, + this.count + ); +}; diff --git a/src/r3-entity-manager.js b/src/r3-entity-manager.js new file mode 100644 index 0000000..d98ae1c --- /dev/null +++ b/src/r3-entity-manager.js @@ -0,0 +1,418 @@ +/** + * R3.EntityManager + * @constructor + */ +R3.EntityManager = function(apiEntityManager) { + + if (R3.Utils.UndefinedOrNull(apiEntityManager)) { + apiEntityManager = {}; + } + + R3.API.EntityManager.call( + this, + apiEntityManager.id, + apiEntityManager.name, + apiEntityManager.entities, + apiEntityManager.defaultEntity, + apiEntityManager.parentEntity + ); + + /** + * 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 = {}; + + this.idRegister = {}; + + R3.Event.Subscribe( + R3.Event.COMPONENT_REGISTER, + this.registerComponent.bind(this) + ); + + R3.Event.Subscribe( + R3.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + R3.Event.Subscribe( + R3.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + R3.Event.Subscribe( + R3.Event.ENTITY_LOADED, + this.entityLoaded.bind(this) + ); + + + R3.Component.call( + this, + { + 'entities' : [R3.Entity], + 'defaultEntity' : R3.Entity + } + ); +}; + +R3.EntityManager.prototype = Object.create(R3.Component.prototype); +R3.EntityManager.prototype.constructor = R3.EntityManager; + +R3.EntityManager.prototype.createInstance = function() { + this.instance = R3.EntityManager.Instance; + R3.Component.prototype.createInstance.call(this); +}; + +R3.EntityManager.prototype.updateInstance = function() { + console.log('todo: entitymanager updateInstance()') +}; + +R3.EntityManager.prototype.instanceCreated = function(data) { + if (data.component instanceof R3.Entity) { + this.addEntity(data.component); + } +}; + +R3.EntityManager.prototype.entityLoaded = function(data) { + this.defaultEntity = data.entity; +}; + +R3.EntityManager.prototype.registerComponent = function(data) { + + var updated = false; + + if (R3.Utils.UndefinedOrNull(this.register[data.component.componentType])) { + this.register[data.component.componentType] = {}; + R3.Event.Emit( + R3.Event.COMPONENT_TYPES_UPDATE, + { + componentType : data.component.componentType, + componentTypes : Object.keys(this.register) + } + ); + updated = true; + } + + if (R3.Utils.UndefinedOrNull(this.register[data.component.componentType][data.component.id])) { + this.register[data.component.componentType][data.component.id] = data.component; + updated = true; + } + + if (R3.Utils.UndefinedOrNull(this.idRegister[data.component.id])) { + this.idRegister[data.component.id] = data.component; + updated = true; + } + + if (updated) { + R3.Event.Emit( + R3.Event.REGISTER_UPDATE, + { + componentType : data.component.componentType, + components : this.register[data.component.componentType], + idRegister : this.idRegister, + register : this.register + } + ); + } +}; + +R3.EntityManager.prototype.removeComponent = function(data) { + + var updated = true; + + if (R3.Utils.UndefinedOrNull(this.register[data.component.componentType]) || + R3.Utils.UndefinedOrNull(this.register[data.component.componentType][data.component.id]) || + R3.Utils.UndefinedOrNull(this.idRegister[data.component.id]) + ) { + console.warn('register out of sync'); + updated = false; + } else { + delete this.register[data.component.componentType][data.component.id]; + + if (R3.Utils.IsEmpty(this.register[data.component.componentType])) { + delete this.register[data.component.componentType]; + R3.Event.Emit( + R3.Event.COMPONENT_TYPES_UPDATE, + { + componentType : data.component.componentType, + componentTypes : Object.keys(this.register) + } + ); + } + + delete this.idRegister[data.component.id]; + } + + if (updated) { + R3.Event.Emit( + R3.Event.REGISTER_UPDATE, + { + componentType : data.component.componentType, + components : this.register[data.component.componentType], + idRegister : this.idRegister, + register : this.register + } + ); + } + +}; + +/** + * Returns an entity by ID or null + * @param id + * @returns {*} + */ +R3.EntityManager.prototype.findEntityById = function(id) { + + var entity = this.register[R3.Component.ENTITY][id]; + + if (entity) { + return entity; + } + + return null; +}; + +R3.EntityManager.prototype.findComponentById = function(id) { + return this.idRegister[id]; +}; + +R3.EntityManager.prototype.findComponentByName = function(name) { + + return Object.keys(this.idRegister).reduce( + function(result, componentId) { + + if (this.idRegister[componentId].name === name) { + result = this.idRegister[componentId]; + } + + return result; + + }.bind(this), + null + ); + +}; + +R3.EntityManager.prototype.findHelperByObject = function(object) { + + if (typeof this.register[R3.Component.HELPER] === 'undefined') { + return null; + } + + return Object.keys(this.register[R3.Component.HELPER]).reduce( + function(result, helperId) { + + if (this.register[R3.Component.HELPER][helperId].object === object) { + result = this.register[R3.Component.HELPER][helperId]; + } + + return result; + }.bind(this), + null + ); + +}; + +R3.EntityManager.prototype.findSceneByObject = function(object) { + + return Object.keys(this.register[R3.Component.SCENE]).reduce( + function(result, sceneId) { + + if ( + this.register[R3.Component.SCENE][sceneId].meshes.indexOf(object) !== -1 || + this.register[R3.Component.SCENE][sceneId].lights.indexOf(object) !== -1 + ) { + result = this.register[R3.Component.SCENE][sceneId]; + } + + return result; + }.bind(this), + null + ); + +}; + + +/** + * Adds an entity to this manager + * @param entity R3.Entity + */ +R3.EntityManager.prototype.addEntity = function(entity) { + this.entities.push(entity); +}; + +/** + * Returns entity by name + * @param name + * @returns {*} + */ +R3.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 R3.D3.Entity + * @returns boolean true if successful + */ +R3.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); + + return true; +}; + +/** + * Returns all the entities with the following components + * @param components R3.Component[] + */ +// R3.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 + * More efficient + * @param componentTypes (array of component types or a single component type) + */ +R3.EntityManager.prototype.queryComponents = function(componentTypes) { + + var result = []; + + if (componentTypes instanceof Array) { + componentTypes.map( + function(componentType) { + + if (typeof this.register[componentType] === 'undefined') { + return; + } + + Object.keys(this.register[componentType]).map( + function(componentId) { + result.push(this.register[componentType][componentId]); + }.bind(this) + ) + }.bind(this) + ) + } else { + + if (typeof this.register[componentTypes] === 'undefined') { + return result; + } + + Object.keys(this.register[componentTypes]).map( + function(componentId) { + result.push(this.register[componentTypes][componentId]); + }.bind(this) + ) + } + + return result; +}; + +/** + * Slower way of retrieving objects + * @param constructors (array of constructors, or a constructor) + * @returns {*} + */ +R3.EntityManager.prototype.queryComponentsByConstructor = function(constructors) { + return Object.keys(this.idRegister).reduce( + function(result, componentId) { + if (constructors instanceof Array) { + + constructors.map( + function(constructor) { + if (this.idRegister[componentId] instanceof constructor) { + result.push(this.idRegister[componentId]); + } + }.bind(this) + ) + + } else { + + if (this.idRegister[componentId] instanceof constructors) { + result.push(this.idRegister[componentId]); + } + } + + return result; + }.bind(this), + [] + ); +}; + +/** + * Converts a R3.Entity to R3.API.Entity + * @returns {R3.API.EntityManager} + */ +R3.EntityManager.prototype.toApiObject = function() { + + var apiEntities = this.entities.map( + function (entity) { + return R3.Utils.IdOrNull(entity); + } + ); + + var apiEntityManager = new R3.API.EntityManager( + this.id, + this.name, + apiEntities, + this.defaultEntity, + R3.Utils.IdOrNull(this.parentEntity) + ); + + return apiEntityManager; +}; + +/** + * Returns an EntityManager from an Object entity manager + * @param objectEntityManager Object + * @constructor + */ +R3.EntityManager.FromObject = function(objectEntityManager) { + + var apiEntityManager = R3.API.EntityManager.FromObject(objectEntityManager); + + var entityManager = new R3.EntityManager(apiEntityManager); + + return entityManager; +}; diff --git a/src/r3-entity.js b/src/r3-entity.js new file mode 100644 index 0000000..f95117b --- /dev/null +++ b/src/r3-entity.js @@ -0,0 +1,286 @@ +/** + * Runtime Entity + * @param apiEntity R3.D3.API.Entity + * @constructor + */ +R3.Entity = function ( + apiEntity +) { + if (R3.Utils.UndefinedOrNull(apiEntity)) { + apiEntity = {}; + } + + R3.API.Entity.call( + this, + apiEntity.id, + apiEntity.name, + apiEntity.components, + apiEntity.parentEntity + ); + + this.instanceCreatedEventSubscription = this.subscribe( + R3.Event.INSTANCE_CREATED, + this.instanceCreatedEvent + ); + + this.removeComponentSubscription = this.subscribe( + R3.Event.REMOVE_COMPONENT, + this.removeComponentEvent + ); + + this.idRegister = {}; + + R3.Component.call( + this, + { + 'components' : [R3.Component] + } + ); +}; + +R3.Entity.prototype = Object.create(R3.Component.prototype); +R3.Entity.prototype.constructor = R3.Entity; + +/** + * Links a component to its parent entity + */ +R3.Entity.prototype.instanceCreatedEvent = function(data) { + + if (data.component === this) { + /** + * do nothing + */ + return; + } + + + if (data.component.parentEntity === this.id) { + this.addComponent(data.component); + } +}; + +R3.Entity.prototype.removeComponentEvent = function(data) { + + if (data.component === this) { + /** + * do nothing + */ + return; + } + + if (data.component.parentEntity === this) { + this.removeComponent(data.component); + } +}; + +/** + * Creates an entity instance + */ +R3.Entity.prototype.createInstance = function() { + + this.components.map( + function(component) { + component.parentEntity = this; + + Object.keys(component.idToObject).map( + function(componentId) { + R3.Utils.PushUnique(this.components, component.idToObject[componentId]); + component.idToObject[componentId].parentEntity = this; + }.bind(this) + ); + + }.bind(this) + ); + + this.buildIdRegister(); + + this.instance = true; + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Adds a component to this entity through the instance (should notify the entity manager instance) + * @param component + */ +R3.Entity.prototype.addComponent = function(component) { + + component.parentEntity = this; + + /** + * Could be that this entity is not loaded and needs to be linked still + */ + if (this.components.indexOf(component.id) !== -1) { + console.log('the entity still has to load'); + return; + } + + R3.Utils.PushUnique(this.components, component); + + if (R3.Utils.UndefinedOrNull(this.idRegister[component.componentType])) { + this.idRegister[component.componentType] = []; + } + + R3.Utils.PushUnique(this.idRegister[component.componentType], component); + + component.buildIdToObject(); + + Object.keys(component.idToObject).map( + function(componentId) { + + if (component.id !== componentId) { + this.addComponent(component.idToObject[componentId]); + } + + }.bind(this) + ); +}; + +R3.Entity.prototype.removeComponent = function(component) { + + component.parentEntity = null; + + var index = this.components.indexOf(component); + + if (index === -1) { + console.warn('component not found in entity'); + } else { + this.components.splice(index, 1); + } + + if (R3.Utils.UndefinedOrNull(this.idRegister[component.componentType])) { + console.warn('component type not found in entity register'); + } else { + + index = this.idRegister[component.componentType].indexOf(component); + + if (index === -1) { + console.warn('component ' + component.name + ' not found in id register of entity ' + this.name); + } else { + this.idRegister[component.componentType].splice(index, 1); + } + + /** + * Remove the hash completely if it was the last one + */ + if (this.idRegister[component.componentType].length === 0) { + delete this.idRegister[component.componentType]; + } + + } +}; + +/** + * Returns all components of type 'constructor' - slower than queryComponents + * @param constructor + */ +R3.Entity.prototype.queryComponentsByConstructor = function(constructor) { + + var components = this.components.reduce( + function(result, component) { + if (component instanceof constructor) { + result.push(component); + } + return result; + }, + [] + ); + + return components; +}; + +/** + * Returns all child components of this entity by component type (via hash reference - very fast) + * @param componentType + * @returns {*} + */ +R3.Entity.prototype.queryComponents = function(componentType) { + return this.idRegister[componentType] || []; +}; + +/** + * Returns true when this entity has a certain component, false otherwise + * @param constructor + */ +// R3.Entity.prototype.hasComponent = function(constructor) { +// +// var has = this.components.reduce( +// function(result, component) { +// if (component instanceof constructor) { +// result = true; +// } +// return result; +// }, +// false +// ); +// +// return has; +// }; + +R3.Entity.prototype.buildIdRegister = function() { + console.log('updating id register for entity : ' + this.name); + + this.idRegister = {}; + + this.components.map( + function(component) { + + if (R3.Utils.UndefinedOrNull(this.idRegister[component.componentType])) { + this.idRegister[component.componentType] = []; + } + + this.idRegister[component.componentType].push(component); + + }.bind(this) + ); + + console.log('done updating idRegister'); +}; + +/** + * Updates an entity instance + */ +R3.Entity.prototype.updateInstance = function(property) { + + if (property === 'components') { + + this.buildIdRegister(); + + return; + } + + R3.Component.prototype.updateInstance.call(this, property); + +}; + +/** + * Converts a R3.Entity to R3.API.Entity + * @returns {R3.API.Entity} + */ +R3.Entity.prototype.toApiObject = function() { + + var apiComponents = this.components.map( + function(component) { + return R3.Utils.IdOrNull(component); + } + ); + + return new R3.API.Entity( + this.id, + this.name, + apiComponents, + R3.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Cleanup our subscriptions first + */ +R3.Entity.prototype.remove = function() { + + this.instanceCreatedEventSubscription.remove(); + this.removeComponentSubscription.remove(); + + R3.Component.prototype.remove.call(this); +}; \ No newline at end of file diff --git a/src/r3-graphics-runtime-a.js b/src/r3-graphics-runtime-a.js new file mode 100644 index 0000000..27dfe6e --- /dev/null +++ b/src/r3-graphics-runtime-a.js @@ -0,0 +1,71 @@ +/** + * Graphics + * @constructor + * @param apiGraphics + */ +R3.GraphicsRuntime = function( + apiGraphics +) { + + if (R3.Utils.UndefinedOrNull(apiGraphics)) { + apiGraphics = { + graphicsType : R3.API.GraphicsRuntime.GRAPHICS_TYPE_NONE + }; + } + + R3.API.GraphicsRuntime.call( + this, + apiGraphics.id, + apiGraphics.name, + apiGraphics.graphicsType, + apiGraphics.parentEntity + ); + + R3.Component.call(this); +}; + +R3.GraphicsRuntime.prototype = Object.create(R3.Component.prototype); +R3.GraphicsRuntime.prototype.constructor = R3.GraphicsRuntime; + +R3.GraphicsRuntime.prototype.createInstance = function() { + console.log(this.graphicsType + ' graphics runtime created'); + R3.Component.prototype.createInstance.call(this); +}; + +R3.GraphicsRuntime.prototype.updateInstance = function(property) { + + if (property === 'graphicsType') { + var componentType = R3.API.Renderer.GetComponentType(this.graphicsType); + + this.replace(componentType); + + return; + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +R3.GraphicsRuntime.prototype.toApiObject = function(property) { + + return new R3.API.GraphicsRuntime( + this.id, + this.name, + this.graphicsType, + R3.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Logs a warning and throws an error if not cannon + */ +R3.GraphicsRuntime.prototype.isNotThreeThrow = function() { + if (this.instance !== THREE) { + console.error('Only THREE supported'); + throw new Error('Only THREE supported'); + } +}; + +R3.GraphicsRuntime.prototype.isThree = function() { + return (this.instance === THREE); +}; \ No newline at end of file diff --git a/src/r3-graphics-runtime-impact.js b/src/r3-graphics-runtime-impact.js new file mode 100644 index 0000000..b84b8b0 --- /dev/null +++ b/src/r3-graphics-runtime-impact.js @@ -0,0 +1,116 @@ +/** + * R3.GraphicsRuntime.Impact + * @param apiGraphicsRuntimeImpact + * @constructor + */ +R3.GraphicsRuntime.Impact = function ( + apiGraphicsRuntimeImpact +) { + + if (R3.Utils.UndefinedOrNull(apiGraphicsRuntimeImpact)) { + apiGraphicsRuntimeImpact = { + graphicsType : R3.API.GraphicsRuntime.GRAPHICS_TYPE_IMPACT_JS + }; + } + + R3.API.GraphicsRuntime.Impact.call( + this, + apiGraphicsRuntimeImpact + ); + + R3.GraphicsRuntime.call( + this, + this + ); + +}; + +R3.GraphicsRuntime.Impact.prototype = Object.create(R3.GraphicsRuntime.prototype); +R3.GraphicsRuntime.Impact.prototype.constructor = R3.GraphicsRuntime.Impact; + +/** + * Create R3.GraphicsRuntime.Impact Instance + * @returns {*} + */ +R3.GraphicsRuntime.Impact.prototype.createInstance = function() { + + this.instance = ig; + + /** + * We override the game load to lookup the canvas from our game-lib and not the DOM, since our canvas + * does not necessarily live inside the DOM + */ + ig.System.inject({ + init : function( canvasId, fps, width, height, scale ) { + this.fps = fps; + + this.clock = new ig.Timer(); + this.canvas = R3.EntityManager.Instance.findComponentById(canvasId).instance; + this.resize( width, height, scale ); + this.context = this.canvas.getContext('2d'); + + this.getDrawPos = ig.System.drawMode; + + // Automatically switch to crisp scaling when using a scale + // other than 1 + if( this.scale !== 1 ) { + ig.System.scaleMode = ig.System.SCALE.CRISP; + } + + ig.System.scaleMode( this.canvas, this.context ); + } + }); + + /** + * We override image loading to specify that it loads from cross-origins + */ + ig.Image.inject({ + load: function( loadCallback ) { + if( this.loaded ) { + if( loadCallback ) { + loadCallback( this.path, true ); + } + return; + } + else if( !this.loaded && ig.ready ) { + this.loadCallback = loadCallback || null; + + this.data = new Image(); + this.data.crossOrigin = 'anonymous'; + this.data.onload = this.onload.bind(this); + this.data.onerror = this.onerror.bind(this); + this.data.src = ig.prefix + this.path + ig.nocache; + } + else { + ig.addResource( this ); + } + + ig.Image.cache[this.path] = this; + } + }); + + R3.GraphicsRuntime.prototype.createInstance.call(this); +}; + +/** + * Update GraphicsRuntime.Impact Instance + */ +R3.GraphicsRuntime.Impact.prototype.updateInstance = function(property) { + + R3.GraphicsRuntime.prototype.updateInstance.call(this, property); +}; + +/** + * + * @returns {R3.API.GraphicsRuntime.Impact} + */ +R3.GraphicsRuntime.Impact.prototype.toApiObject = function() { + + var apiGraphicsRuntime = R3.GraphicsRuntime.prototype.toApiObject.call(this); + + var apiGraphicsRuntimeImpact = new R3.API.GraphicsRuntime.Impact( + apiGraphicsRuntime + ); + + return apiGraphicsRuntimeImpact; +}; diff --git a/src/r3-graphics-runtime-three.js b/src/r3-graphics-runtime-three.js new file mode 100644 index 0000000..1c49685 --- /dev/null +++ b/src/r3-graphics-runtime-three.js @@ -0,0 +1,63 @@ +/** + * R3.GraphicsRuntime.Three + * @param apiGraphicsRuntimeThree + * @constructor + */ +R3.GraphicsRuntime.Three = function ( + apiGraphicsRuntimeThree +) { + + if (R3.Utils.UndefinedOrNull(apiGraphicsRuntimeThree)) { + apiGraphicsRuntimeThree = { + graphicsType : R3.API.GraphicsRuntime.GRAPHICS_TYPE_THREE_JS + }; + } + + R3.API.GraphicsRuntime.Three.call( + this, + apiGraphicsRuntimeThree + ); + + R3.GraphicsRuntime.call( + this, + this + ); + +}; + +R3.GraphicsRuntime.Three.prototype = Object.create(R3.GraphicsRuntime.prototype); +R3.GraphicsRuntime.Three.prototype.constructor = R3.GraphicsRuntime.Three; + +/** + * Create R3.GraphicsRuntime.Three Instance + * @returns {*} + */ +R3.GraphicsRuntime.Three.prototype.createInstance = function() { + + this.instance = THREE; + + R3.GraphicsRuntime.prototype.createInstance.call(this); +}; + +/** + * Update GraphicsRuntime.Three Instance + */ +R3.GraphicsRuntime.Three.prototype.updateInstance = function(property) { + + R3.GraphicsRuntime.prototype.updateInstance.call(this, property); +}; + +/** + * + * @returns {R3.API.GraphicsRuntime.Three} + */ +R3.GraphicsRuntime.Three.prototype.toApiObject = function() { + + var apiGraphicsRuntime = R3.GraphicsRuntime.prototype.toApiObject.call(this); + + var apiGraphicsRuntimeThree = new R3.API.GraphicsRuntime.Three( + apiGraphicsRuntime + ); + + return apiGraphicsRuntimeThree; +}; diff --git a/src/r3-group.js b/src/r3-group.js new file mode 100644 index 0000000..90421ff --- /dev/null +++ b/src/r3-group.js @@ -0,0 +1,97 @@ +/** + * R3.Group + * @param implementation + * @param apiGroup + * @param parentGeometry + * @constructor + */ +R3.Group = function ( + implementation, + apiGroup, + parentGeometry +) { + + this.implementation = implementation; + this.implementation.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(parentGeometry)) { + parentGeometry = null; + } + this.parentGeometry = parentGeometry; + + if (R3.Utils.UndefinedOrNull(apiGroup)) { + apiGroup = {}; + } + + R3.API.Group.call( + this, + apiGroup.id, + apiGroup.name, + apiGroup.parentEntity, + apiGroup.start, + apiGroup.count, + apiGroup.materialIndex + ); + + R3.Component.call(this); +}; + +R3.Group.prototype = Object.create(R3.Component.prototype); +R3.Group.prototype.constructor = R3.Group; + +/** + * Creates an instance R3.Group + * @returns {*} + */ +R3.Group.prototype.createInstance = function() { + + this.instance = { + start : this.start, + count : this.count, + materialIndex : this.materialIndex + }; + + R3.Component.prototype.createInstance.call(this); + +}; + +/** + * Updates R3.Group instance + * @param property + */ +R3.Group.prototype.updateInstance = function(property) { + + console.warn('update the geometry instead'); + + if (property === 'start') { + this.instance.start = this.start; + return; + } + + if (property === 'count') { + this.instance.count = this.count; + return; + } + + if (property === 'materialIndex') { + this.instance.materialIndex = this.materialIndex; + return; + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * R3.Group to R3.API.Group + * @returns {R3.API.Group} + */ +R3.Group.prototype.toApiObject = function() { + return new R3.API.Group( + this.id, + this.name, + R3.Utils.IdOrNull(this.parentEntity), + this.start, + this.count, + this.materialIndex + ); +}; diff --git a/src/r3-gui-runtime.js b/src/r3-gui-runtime.js new file mode 100644 index 0000000..b964ddc --- /dev/null +++ b/src/r3-gui-runtime.js @@ -0,0 +1,59 @@ +/** + * GUI + * @param id + * @param name + * @param guiType + * @constructor + */ +R3.GUIRuntime = function( + id, + name, + guiType +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'GUI (' + id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(guiType)) { + guiType = R3.GUIRuntime.TYPE_DAT_GUI; + } + this.guiType = guiType; + + this.createInstance(); +}; + +/** + * R3.GUIRuntime Types + * @type {number} + */ +R3.GUIRuntime.TYPE_DAT_GUI = 0x1; + +R3.GUIRuntime.prototype.createInstance = function() { + if (this.guiType === R3.GUIRuntime.TYPE_DAT_GUI) { + this.instance = dat.GUI; + } else { + this.instance = null; + } +}; + +R3.GUIRuntime.prototype.updateInstance = function(property) { + if (property === 'guiType') { + this.createInstance(); + } +}; + +/** + * Logs a warning and throws an error if not cannon + */ +R3.GUIRuntime.prototype.isNotDatGuiThrow = function() { + if (this.instance !== dat.GUI) { + console.error('Only dat.gui supported'); + throw new Error('Only dat.gui supported'); + } +}; diff --git a/src/r3-gui.js b/src/r3-gui.js new file mode 100644 index 0000000..49d87ae --- /dev/null +++ b/src/r3-gui.js @@ -0,0 +1,116 @@ +/** + * GUI component + * @param guiRuntime + * @param apiGUI + * @constructor + */ +R3.GUI = function( + guiRuntime, + apiGUI +) { + this.guiRuntime = guiRuntime; + this.guiRuntime.isNotDatGuiThrow(); + + if (R3.Utils.UndefinedOrNull(apiGUI)) { + apiGUI = {}; + } + + R3.API.GUI.call( + this, + apiGUI.id, + apiGUI.name, + apiGUI.domElement, + apiGUI.parentEntity + ); + + R3.Component.call( + this, + { + 'domElement': R3.DomElement + } + ); +}; + +R3.GUI.prototype = Object.create(R3.Component.prototype); +R3.GUI.prototype.constructor = R3.GUI; + +/** + * Creates a helper instance + */ +R3.GUI.prototype.createInstance = function() { + this.instance = new this.guiRuntime.instance( { autoPlace: false } ); + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.GUI.prototype.updateInstance = function(property) { + console.log('todo: implement gui update instance:' + property); +}; + +/** + * Converts a R3.GUI to a new R3.API.GUI + * @returns {R3.API.GUI} + */ +R3.GUI.prototype.toApiObject = function() { + + return new R3.API.GUI( + this.id, + this.name, + R3.Utils.IdOrNull(this.domElement), + R3.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Converts from an Object GUI to a R3.GUI + * @param guiRuntime R3.GUIRuntime + * @param objectGUI Object + * @returns {R3.GUI} + * @constructor + */ +R3.GUI.FromObject = function(guiRuntime, objectGUI) { + + var apiGUI = R3.API.GUI.FromObject(objectGUI); + + return new R3.GUI( + guiRuntime, + apiGUI + ); + +}; + +/** + * Removes empty folders from instance + */ +R3.GUI.prototype.removeEmtpyFolders = function() { + this.instance.removeEmptyFolders(); +}; + +/** + * Remove all folders from instance + */ +R3.GUI.prototype.removeAllFolders = function() { + this.instance.removeAllFolders(); +}; + +/** + * Adds a folder to instance + * @param folderName + * @returns {*} + */ +R3.GUI.prototype.addFolder = function(folderName) { + try { + return this.instance.addFolder(folderName); + } catch (e) { + try { + folderName += ' duplicate (' + R3.Utils.RandomId() + ')'; + return this.instance.addFolder(folderName); + } catch (e) { + console.log(e.message); + return null; + } + } +}; diff --git a/src/r3-image.js b/src/r3-image.js new file mode 100644 index 0000000..03302b4 --- /dev/null +++ b/src/r3-image.js @@ -0,0 +1,205 @@ +/** + * Image + * @constructor + * @param apiImage + */ +R3.Image = function( + apiImage +) { + + if (R3.Utils.UndefinedOrNull(apiImage)) { + apiImage = {}; + } + + R3.API.Image.call( + this, + apiImage.id, + apiImage.name, + apiImage.parentEntity, + apiImage.parentTexture, + apiImage.fileName, + apiImage.extension, + apiImage.path, + apiImage.contentType, + apiImage.size, + apiImage.width, + apiImage.height + ); + + R3.Component.call( + this, + { + parentTexture : R3.D3.Texture + } + ); +}; + +R3.Image.prototype = Object.create(R3.Component.prototype); +R3.Image.prototype.constructor = R3.Image; + +/** + * Creates an image instance + * @returns {*} + */ +R3.Image.prototype.createInstance = function() { + + R3.Event.Emit( + R3.Event.LOAD_IMAGE, + { + image : this + }, + function(imageInstance) { + this.instance = imageInstance; + + this.width = this.instance.width; + this.height = this.instance.height; + + R3.Component.prototype.createInstance.call(this); + }.bind(this), + function(error) { + console.error(error); + this.instance = null; + R3.Component.prototype.createInstance.call(this); + }.bind(this) + ); + +}; + +/** + * Updates the instance with the current state + */ +R3.Image.prototype.updateInstance = function(property) { + + if (R3.Utils.UndefinedOrNull(property)) { + console.warn('unknown property update for Image: ' + property); + } + + if ( + property === 'fileName' || + property === 'extension' || + property === 'path' + ) { + this.createInstance(); + return; + } + + if (R3.Utils.UndefinedOrNull(this.instance)) { + console.warn('image not ready yet'); + return; + } + + if ( + property === 'width' || + property === 'height' + ) { + console.warn('width and height is read only'); + this.width = this.instance.width; + this.height = this.instance.height; + return; + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +R3.Image.prototype.updateFromRawObject = function(rawObject) { + this.id = rawObject.id; + this.name = rawObject.name; + this.fileName = rawObject.fileName; + this.extension = rawObject.extension; + this.path = rawObject.path; + this.contentType = rawObject.contentType; + this.size = rawObject.size; + this.width = rawObject.width; + this.height = rawObject.height; +}; + +/** + * + * @returns {R3.API.Image} + */ +R3.Image.prototype.toApiObject = function() { + + var apiImage = new R3.API.Image( + this.id, + this.name, + R3.Utils.IdOrNull(this.parentEntity), + R3.Utils.IdOrNull(this.parentTexture), + this.fileName, + this.extension, + this.path, + this.contentType, + this.size, + this.width, + this.height + ); + + return apiImage; +}; + +/** + * Updates R3.Image from instance + */ +R3.Image.prototype.updateFromInstance = function() { + this.fileName = this.instance.fileName || 'no filename'; + this.extension = this.instance.extension || 'no extension'; + this.path = this.instance.path || 'no path'; + this.contentType = this.instance.contentType || 'no content type'; + this.size = this.instance.size || 0; + this.width = this.instance.width || 0; + this.height = this.instance.height || 0; +}; + +R3.Image.prototype.getPixelData = function() { + + var canvas = document.createElement( 'canvas' ); + canvas.width = this.width; + canvas.height = this.height; + var context = canvas.getContext( '2d' ); + + context.drawImage(this.instance, 0, 0, canvas.width, canvas.height); + + var imageData = context.getImageData(0, 0, this.width, this.height); + var pixels = imageData.data; + + return pixels; +}; + +/** + * Returns an array of Height Data for this image + * @returns {Float32Array | null} + */ +R3.Image.prototype.getHeightData = function() { + + if (R3.Utils.UndefinedOrNull(this.instance)) { + console.warn('this image is not ready to have its height data processed'); + return null; + } + + var pixels = this.getPixelData(); + + + var data = new Float32Array( this.width * this.height ); + + var height, i, j = 0; + + for (i = 0; i < pixels.length; i += 4) { + + /** + * We ignore the alpha channel for now + */ + height = (pixels[i] + pixels[i+1] + pixels[i+2]); + + /** + * Clamp values to zero or a number between 0 and 1 + */ + if (height > 3) { + height = height / 768; + } else { + height = 0; + } + + data[j++] = height; + } + + return data; +}; \ No newline at end of file diff --git a/src/r3-matrix-4.js b/src/r3-matrix-4.js new file mode 100644 index 0000000..9ec6eec --- /dev/null +++ b/src/r3-matrix-4.js @@ -0,0 +1,311 @@ +/** + * Runtime Matrix4 + * @param graphics + * @param parentObject + * @param apiMatrix4 + * @param grain + * @constructor + */ +R3.Matrix4 = function( + graphics, + apiMatrix4, + parentObject, + grain +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiMatrix4)) { + apiMatrix4 = {}; + } + + R3.API.Matrix4.call( + this, + apiMatrix4.rows[0], + apiMatrix4.rows[1], + apiMatrix4.rows[2], + apiMatrix4.rows[3] + ); + + if (R3.Utils.UndefinedOrNull(parentObject)) { + parentObject = null; + } + this.parentObject = parentObject; + + if (R3.Utils.UndefinedOrNull(grain)) { + grain = 0.001; + } + this.grain = grain; + + this.rows = this.rows.map( + function(row) { + + return new R3.Vector4( + this.graphics, + row, + this, + this.grain + ); + + }.bind(this) + ); + + this.forward = new R3.Vector4( + this.graphics, + this.forward, + this, + this.grain + ); + + this.left = new R3.Vector4( + this.graphics, + this.left, + this, + this.grain + ); + + this.up = new R3.Vector4( + this.graphics, + this.up, + this, + this.grain + ); + + this.createInstance(); +}; + +R3.Matrix4.prototype = Object.create(R3.Component.prototype); +R3.Matrix4.prototype.constructor = R3.Matrix4; + +/** + * Creates a matrix 4 instance (currently from graphics lib) + * @param update + */ +R3.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 + */ +R3.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(); + } +}; + +/** + * R3.Matrix4 to R3.API.Matrix4 + * @returns {*} + */ +R3.Matrix4.prototype.toApiObject = function () { + + return new R3.API.Matrix4( + this.rows[0].toApiObject(), + this.rows[1].toApiObject(), + this.rows[2].toApiObject(), + this.rows[3].toApiObject() + ); + +}; + +/** + * Creates a R3.Matrix4 from an Object matrix + * @param graphics R3.GraphicsRuntime + * @param objectMatrix Object + * @param parentObject + * @returns {R3.Matrix4} + * @constructor + */ +R3.Matrix4.FromObject = function(graphics, objectMatrix, parentObject) { + + var apiMatrix = new R3.API.Matrix4.FromObject(objectMatrix); + + return new R3.Matrix4( + graphics, + parentObject, + apiMatrix + ) +}; + +/** + * Lookat + * @param position + * @param target + * @param up + * @returns {R3.Matrix4} + */ +R3.Matrix4.prototype.lookAt = function (position, target, up) { + + var pv = new R3.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 + */ +R3.Matrix4.prototype.identity = function () { + this.rows = [ + new R3.Vector4( + this.graphics, + new R3.API.Vector4(1,0,0,0), + this, + this.grain + ), + new R3.Vector4( + this.graphics, + new R3.API.Vector4(0,1,0,0), + this, + this.grain + ), + new R3.Vector4( + this.graphics, + new R3.API.Vector4(0,0,1,0), + this, + this.grain + ), + new R3.Vector4( + this.graphics, + new R3.API.Vector4(0,0,0,1), + this, + this.grain + ) + ]; +}; + +/** + * Transpose + * @returns {R3.Matrix4} + */ +R3.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; +}; diff --git a/src/r3-mouse.js b/src/r3-mouse.js new file mode 100644 index 0000000..6f7b69f --- /dev/null +++ b/src/r3-mouse.js @@ -0,0 +1,67 @@ +/** + * Runtime Mouse + * @param apiMouse + * @returns {R3.Mouse} + * @constructor + */ +R3.Mouse = function (apiMouse) { + + if (R3.Utils.UndefinedOrNull(apiMouse)){ + apiMouse = {}; + } + + R3.API.Mouse.call( + this, + apiMouse.id, + apiMouse.name, + apiMouse.parentEntity, + apiMouse.x, + apiMouse.y + ); + + R3.Component.call(this); +}; + +R3.Mouse.prototype = Object.create(R3.Component.prototype); +R3.Mouse.prototype.constructor = R3.Mouse; + +/** + * createInstance + */ +R3.Mouse.prototype.createInstance = function() { + this.instance = {}; + R3.Component.prototype.createInstance.call(this); +}; + +/** + * updateInstance + * @param property + */ +R3.Mouse.prototype.updateInstance = function(property) { + + if ( + property === 'x' || + property === 'y' + ) { + this.instance.x = this.x; + this.instance.y = this.y; + return; + } + + R3.Component.prototype.updateInstance.call(this, property); + +}; + +/** + * Converts R3.Mouse vector to R3.API.Mouse + * @returns {R3.API.Mouse} + */ +R3.Mouse.prototype.toApiObject = function() { + return new R3.API.Mouse( + this.id, + this.name, + R3.Utils.IdOrNull(this.parentEntity), + this.x, + this.y + ); +}; diff --git a/src/r3-number.js b/src/r3-number.js new file mode 100644 index 0000000..b057fde --- /dev/null +++ b/src/r3-number.js @@ -0,0 +1,76 @@ +/** + * Runtime vector2 for updating instance objects + * @param apiNumber R3.API.Number + * @param parentObject + * @constructor + */ +R3.Number = function ( + apiNumber, + parentObject +) { + + if (R3.Utils.UndefinedOrNull(apiNumber)) { + apiNumber = {}; + } + + R3.API.Number.call( + this, + apiNumber + ); + + if (R3.Utils.UndefinedOrNull(parentObject)) { + parentObject = null; + } + this.parentObject = parentObject; + + this.createInstance(); +}; + +R3.Number.prototype = Object.create(R3.API.Number.prototype); +R3.Number.prototype.constructor = R3.Number; + + +/** + * Creates an instance vector2 + * @returns {*} + */ +R3.Number.prototype.createInstance = function() { + this.instance = {}; +}; + +/** + * Updates the instance vector, calls updateInstance on the parent object + */ +R3.Number.prototype.updateInstance = function(property, parentProperty) { + + if (property === 'value') { + if (this.parentObject && this.parentObject.updateInstance) { + this.parentObject.updateInstance(parentProperty); + } + } + + if (property === 'grain') { + console.warn('todo: update number instance grain'); + } + + if (property === 'min') { + console.warn('todo: update number instance min'); + } + + if (property === 'max') { + console.warn('todo: update number instance max'); + } +}; + +/** + * Converts runtime vector to API Vector + * @returns {R3.API.Number} + */ +R3.Number.prototype.toApiObject = function() { + return new R3.API.Number( + this.value, + this.grain, + this.min, + this.max + ); +}; \ No newline at end of file diff --git a/src/r3-physics-runtime.js b/src/r3-physics-runtime.js new file mode 100644 index 0000000..f2fb777 --- /dev/null +++ b/src/r3-physics-runtime.js @@ -0,0 +1,59 @@ +/** + * Physics + * @param id + * @param name + * @param physicsType + * @constructor + */ +R3.PhysicsRuntime = function( + id, + name, + physicsType +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Physics (' + id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(physicsType)) { + physicsType = R3.PhysicsRuntime.TYPE_CANNON_JS; + } + this.physicsType = physicsType; + + this.createInstance(); +}; + +/** + * R3.PhysicsRuntime Types + * @type {number} + */ +R3.PhysicsRuntime.TYPE_CANNON_JS = 0x1; + +R3.PhysicsRuntime.prototype.createInstance = function() { + if (this.physicsType === R3.PhysicsRuntime.TYPE_CANNON_JS) { + this.instance = CANNON; + } else { + this.instance = null; + } +}; + +R3.PhysicsRuntime.prototype.updateInstance = function(property) { + if (property === 'physicsType') { + this.createInstance(); + } +}; + +/** + * Logs a warning and throws an error if not cannon + */ +R3.PhysicsRuntime.prototype.isNotCannonThrow = function() { + if (this.instance !== CANNON) { + console.error('Only CANNON supported'); + throw new Error('Only CANNON supported'); + } +}; diff --git a/src/r3-plane.js b/src/r3-plane.js new file mode 100644 index 0000000..4e737bb --- /dev/null +++ b/src/r3-plane.js @@ -0,0 +1,101 @@ +/** + * Creates a Plane object + * @param graphics R3.GraphicsRuntime + * @param apiPlane R3.API.Plane + * @constructor + */ +R3.Plane = function( + graphics, + apiPlane +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiPlane)) { + apiPlane = {}; + } + + R3.API.Plane.call( + this, + apiPlane.id, + apiPlane.name, + apiPlane.normal, + apiPlane.constant, + apiPlane.parentEntity + ); + + this.normal = new R3.Vector3( + this.graphics, + this.normal, + this + ); + + R3.Component.call(this); +}; + +R3.Plane.prototype = Object.create(R3.Component.prototype); +R3.Plane.prototype.constructor = R3.Plane; + +R3.Plane.prototype.createInstance = function() { + + this.instance = new THREE.Plane( + this.normal.instance, + this.constant + ); + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.Plane.prototype.updateInstance = function(property) { + + if (property === 'normal') { + + this.normal.normalize(); + + this.instance.normal.x = this.normal.x; + this.instance.normal.y = this.normal.y; + this.instance.normal.z = this.normal.z; + } + + if (property === 'constant') { + this.instance.constant = this.constant; + } + + R3.D3.Texture.prototype.updateInstance.call(this, property); + +}; + +/** + * Converts a R3.Plane to a new R3.API.Plane + * @returns {R3.API.Plane} + */ +R3.Plane.prototype.toApiObject = function() { + + return new R3.API.Plane( + this.id, + this.name, + this.normal.toApiObject(), + this.constant, + R3.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Converts from an Object Plane to a R3.Plane + * @param graphics R3.GraphicsRuntime + * @param objectPlane Object + * @returns {R3.Plane} + * @constructor + */ +R3.Plane.FromObject = function(graphics, objectPlane) { + var apiPlane = R3.API.Plane.FromObject(objectPlane); + return new R3.Plane( + graphics, + apiPlane + ); +}; diff --git a/src/r3-quaternion.js b/src/r3-quaternion.js new file mode 100644 index 0000000..abcae2a --- /dev/null +++ b/src/r3-quaternion.js @@ -0,0 +1,157 @@ +/** + * Runtime quaternion for updating instance objects + * @param implementation + * @param parentObject R3.D3.* + * @param apiQuaternion R3.API.Quaternion + * @param grain Number + * @constructor + */ +R3.Quaternion = function ( + implementation, + apiQuaternion, + parentObject, + grain +) { + this.implementation = implementation; + + if (implementation instanceof R3.GraphicsRuntime) { + this.physics = null; + this.graphics = implementation; + this.graphics.isNotThreeThrow(); + } else if (implementation instanceof R3.PhysicsRuntime) { + this.graphics = null; + this.physics = implementation; + this.physics.isNotCannonThrow(); + } else { + throw new Error('Unhandled implementation : ' + implementation); + } + + if (R3.Utils.UndefinedOrNull(apiQuaternion)) { + apiQuaternion = {}; + } + + R3.API.Quaternion.call( + this, + apiQuaternion.x, + apiQuaternion.y, + apiQuaternion.z, + apiQuaternion.w, + apiQuaternion.axis, + apiQuaternion.angle + ); + + if (R3.Utils.UndefinedOrNull(parentObject)) { + parentObject = null; + } + this.parentObject = parentObject; + + this.axis = new R3.Vector3( + this.implementation, + this.axis, + this, + this.grain + ); + + Object.defineProperty( + this, + 'angle', + R3.Utils.LimitToPI('angle', this.angle) + ); + + if (R3.Utils.UndefinedOrNull(grain)) { + grain = 0.001; + } + this.grain = grain; + + this.createInstance(); +}; + +R3.Quaternion.prototype = Object.create(R3.Component.prototype); +R3.Quaternion.prototype.constructor = R3.Quaternion; + +/** + * Creates an instance quaternion + * @returns {*} + */ +R3.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 + */ +R3.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 {*} + */ +R3.Quaternion.prototype.toApiObject = function() { + return new R3.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} + */ +R3.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 + ); + +}; + +R3.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; +}; + +R3.Quaternion.prototype.copy = function(quaternion) { +console.log('todo'); +}; \ No newline at end of file diff --git a/src/r3-render-configuration.js b/src/r3-render-configuration.js new file mode 100644 index 0000000..cf67929 --- /dev/null +++ b/src/r3-render-configuration.js @@ -0,0 +1,255 @@ +/** + * R3.RenderConfiguration + * @param graphics + * @param apiRenderConfiguration R3.API.RenderConfiguration + * @constructor + */ +R3.RenderConfiguration = function ( + graphics, + apiRenderConfiguration +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiRenderConfiguration)) { + apiRenderConfiguration = {}; + } + + R3.API.RenderConfiguration.call( + this, + apiRenderConfiguration.id, + apiRenderConfiguration.name, + apiRenderConfiguration.parentEntity, + apiRenderConfiguration.logicalSize, + apiRenderConfiguration.aspectRatio, + apiRenderConfiguration.scaleMode, + apiRenderConfiguration.activeCamera, + apiRenderConfiguration.activeScenes, + apiRenderConfiguration.activeRenderer, + apiRenderConfiguration.activeComposer, + apiRenderConfiguration.activeEffect, + apiRenderConfiguration.enableComposer, + apiRenderConfiguration.enableEffect + ); + + this.logicalSize = new R3.Vector2( + this.graphics, + this.logicalSize, + this + ); + + R3.Component.call( + this, + { + 'activeCamera' : R3.D3.Camera, + 'activeScenes' : [R3.D3.Scene], + 'activeRenderer' : R3.Renderer, + 'activeComposer' : R3.D3.Composer, + 'activeEffect' : R3.D3.Effect + } + ); + +}; + +R3.RenderConfiguration.prototype = Object.create(R3.Component.prototype); +R3.RenderConfiguration.prototype.constructor = R3.RenderConfiguration; + +/** + * Create RenderConfiguration Instance + * @returns {*} + */ +R3.RenderConfiguration.prototype.createInstance = function() { + + this.instance = {}; + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Update RenderConfiguration Instance + */ +R3.RenderConfiguration.prototype.updateInstance = function(property) { + + if ( + property === 'logicalSize' || + property === 'aspectRatio' || + property === 'scaleMode' + ) { + + console.log('todo: implement fixed aspect ratios for different scale modes'); + + if ( + R3.Utils.Defined(this.activeCamera) && + R3.Utils.Defined(this.activeCamera.instance) + ) { + + /** + * For now - just use normal aspect ratio + */ + R3.Event.Emit( + R3.Event.GET_WINDOW_SIZE, + {}, + function(data) { + + if (data.width === data.height) { + console.log('square'); + } + + if (data.width > data.height) { + console.log('landscape'); + } + + if (data.width < data.height) { + console.log('portrait'); + } + + this.activeCamera.aspect = data.width / data.height; + this.activeCamera.updateInstance('aspect'); + + }.bind(this) + ) + } + + return; + } + + if (property === 'activeCamera') { + + if ( + R3.Utils.Defined(this.activeCamera) && + R3.Utils.Defined(this.activeCamera.instance) + ) { + /** + * Update the aspect ratio for the active camera + */ + this.updateInstance('aspectRatio'); + + R3.EntityManager.Instance.queryComponents(R3.Component.PASS_RENDER).map( + function(renderPass) { + renderPass.camera = this.activeCamera; + renderPass.updateInstance('camera'); + }.bind(this) + ) + } + } + + if ( + property === 'activeScenes' || + property === 'activeRenderer' + ) { + console.log('todo: active component update'); + return; + } + + if ( + property === 'activeComposer' + ) { + + if (this.activeComposer === null) { + if (this.enableComposer) { + console.warn('no composer active - nothing will render'); + } + return; + } + + if ( + this.activeComposer.passes.length === 0 + ) { + console.warn('this composer has no passes - nothing will render when this composer is enabled'); + } + + return; + } + + if ( + property === 'activeEffect' + ) { + + if (this.activeEffect === null) { + if (this.enableEffect) { + console.warn('no effects active - nothing will render'); + } + } + + return; + } + + if ( + property === 'enableComposer' + ) { + + if (this.enableComposer) { + if (this.enableEffect) { + this.enableComposer = false; + console.warn('Only one of effect or composer can be enabled, not both at the same time'); + return; + } + + if ( + this.activeComposer === null + ) { + console.warn('no composer active - nothing will render'); + return; + } + + if ( + this.activeComposer.passes.length === 0 + ) { + console.warn('this composer has no passes - nothing will render'); + } + + } + + return; + } + + if ( + property === 'enableEffect' + ) { + + if (this.enableEffect) { + if (this.enableComposer) { + this.enableEffect = false; + console.warn('Only one of effect or composer can be enabled, not both at the same time'); + return; + } + + if (this.activeEffect === null) { + console.warn('no effect active - nothing will render'); + } + } + + return; + } + +}; + +/** + * + * @returns {R3.API.RenderConfiguration} + */ +R3.RenderConfiguration.prototype.toApiObject = function() { + + var apiRenderConfiguration = new R3.API.RenderConfiguration( + this.id, + this.name, + R3.Utils.IdOrNull(this.parentEntity), + this.logicalSize.toApiObject(), + this.aspectRatio, + this.scaleMode, + R3.Utils.IdOrNull(this.activeCamera), + this.activeScenes.map( + function(activeScene) { + return R3.Utils.IdOrNull(activeScene); + } + ), + R3.Utils.IdOrNull(this.activeRenderer), + R3.Utils.IdOrNull(this.activeComposer), + R3.Utils.IdOrNull(this.activeEffect), + this.enableComposer, + this.enableEffect + ); + + return apiRenderConfiguration; +}; diff --git a/src/r3-renderer-a.js b/src/r3-renderer-a.js new file mode 100644 index 0000000..3ebb5c6 --- /dev/null +++ b/src/r3-renderer-a.js @@ -0,0 +1,156 @@ +/** + * R3.Renderer + * @param graphics + * @param apiRenderer R3.API.Renderer + * @property rendererType + * @constructor + */ +R3.Renderer = function ( + graphics, + apiRenderer +) { + + if (R3.Utils.UndefinedOrNull(graphics)) { + graphics = null; + } + this.graphics = graphics; + + if (R3.Utils.UndefinedOrNull(apiRenderer)) { + apiRenderer = { + rendererType : R3.API.Renderer.RENDERER_TYPE_NONE + }; + } + + R3.API.Renderer.call( + this, + apiRenderer.id, + apiRenderer.name, + apiRenderer.rendererType, + apiRenderer.parentEntity, + apiRenderer.width, + apiRenderer.height, + apiRenderer.offset, + apiRenderer.canvas + ); + + this.offset = new R3.Vector2( + this.graphics, + this.offset, + this + ); + + if (this.canvas instanceof R3.API.Canvas) { + this.canvas = new R3.Canvas( + this.graphics, + this.canvas + ); + } + + R3.Component.call( + this, + R3.Renderer.GetLinkedObjects(this.rendererType) + ); + +}; + +R3.Renderer.prototype = Object.create(R3.Component.prototype); +R3.Renderer.prototype.constructor = R3.Renderer; + +R3.Renderer.GetLinkedObjects = function(rendererType) { + + var linkedObjects = { + 'canvas' : R3.Canvas + }; + + switch (rendererType) { + case R3.API.Renderer.RENDERER_TYPE_3D : + linkedObjects.renderTarget = R3.D3.RenderTarget; + linkedObjects.clippingPlanes = [R3.Plane]; + linkedObjects.viewports = [R3.D3.Viewport]; + break; + } + + return linkedObjects; + +}; + +/** + * Create Renderer Instance + * @returns {*} + */ +R3.Renderer.prototype.createInstance = function() { + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Update Renderer Instance + */ +R3.Renderer.prototype.updateInstance = function(property) { + + if (!property) { + throw new Error('no renderer property'); + } + + if (!this.instance) { + throw new Error('no renderer instance'); + } + + if (property === 'rendererType') { + + var componentType = R3.API.Renderer.GetComponentType(this.rendererType); + + this.replace(componentType); + + return; + } + + if ( + property === 'width' || + property === 'height' + ) { + console.log('todo: width and height'); + return; + } + + if (property === 'offset') { + + var size = R3.Utils.GetWindowSize(); + + this.canvas.offset.x = this.offset.x * size.width; + this.canvas.offset.y = this.offset.y * size.height; + + this.canvas.updateInstance('offset'); + return; + } + + if (property === 'canvas') { + console.log('todo: canvas update'); + return; + } + + R3.Component.prototype.updateInstance.call(this, property); +}; + +/** + * + * @returns {R3.API.Renderer} + */ +R3.Renderer.prototype.toApiObject = function() { + + var apiRenderer = new R3.API.Renderer( + this.id, + this.name, + this.rendererType, + R3.Utils.IdOrNull(this.parentEntity), + this.width, + this.height, + this.offset.toApiObject(), + R3.Utils.IdOrNull(this.canvas) + ); + + return apiRenderer; +}; + +R3.Renderer.prototype.setSize = function(width, height) { + console.warn('please implement me in child class'); +}; diff --git a/src/r3-renderer-d2.js b/src/r3-renderer-d2.js new file mode 100644 index 0000000..0c51b0d --- /dev/null +++ b/src/r3-renderer-d2.js @@ -0,0 +1,94 @@ +/** + * R3.Renderer.D2 + * @param graphics + * @param apiRendererD2 R3.API.Renderer.D2 + * @constructor + */ +R3.Renderer.D2 = function ( + graphics, + apiRendererD2 +) { + + if (R3.Utils.UndefinedOrNull(graphics)) { + graphics = R3.GraphicsRuntime(null, null, R3.GraphicsRuntime.GRAPHICS_RUNTIME_IMPACT); + } + this.graphics = graphics; + + if (R3.Utils.UndefinedOrNull(apiRendererD2)) { + apiRendererD2 = { + rendererType : R3.API.Renderer.RENDERER_TYPE_2D + }; + } + + R3.API.Renderer.D2.call( + this, + apiRendererD2 + ); + + R3.Renderer.call( + this, + this.graphics, + this + ); + +}; + +R3.Renderer.D2.prototype = Object.create(R3.Renderer.prototype); +R3.Renderer.D2.prototype.constructor = R3.Renderer.D2; + +/** + * Create R3.Renderer.D2 Instance + * @returns {*} + */ +R3.Renderer.D2.prototype.createInstance = function() { + + if ( + R3.Utils.UndefinedOrNull(this.canvas) || + R3.Utils.UndefinedOrNull(this.canvas.instance) + ) { + console.warn('no canvas instance'); + return; + } + + this.instance = true; + + R3.Renderer.prototype.createInstance.call(this); +}; + +/** + * Update Renderer.D2 Instance + */ +R3.Renderer.D2.prototype.updateInstance = function(property) { + + if (!property) { + throw new Error('no renderer property'); + } + + if (!this.instance) { + throw new Error('no renderer instance'); + } + + R3.Renderer.prototype.updateInstance.call(this, property); +}; + +/** + * + * @returns {R3.API.Renderer.D2} + */ +R3.Renderer.D2.prototype.toApiObject = function() { + + var apiRenderer = R3.Renderer.prototype.toApiObject.call(this); + + var apiRendererD2 = new R3.API.Renderer.D2( + apiRenderer + ); + + return apiRendererD2; +}; + +/** + * set size + */ +R3.Renderer.D2.prototype.setSize = function(width, height) { + R3.Renderer.prototype.setSize.call(this); +}; diff --git a/src/r3-renderer-d3.js b/src/r3-renderer-d3.js new file mode 100644 index 0000000..e2eafcc --- /dev/null +++ b/src/r3-renderer-d3.js @@ -0,0 +1,540 @@ +/** + * R3.Renderer.D3 + * @param graphics R3.GraphicsRuntime + * @param apiRendererD3 R3.API.Renderer.D3 + * @constructor + */ +R3.Renderer.D3 = function ( + graphics, + apiRendererD3 +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiRendererD3)) { + apiRendererD3 = { + rendererType : R3.API.Renderer.RENDERER_TYPE_3D + }; + } + + R3.API.Renderer.D3.call( + this, + apiRendererD3, + apiRendererD3.renderMode, + apiRendererD3.autoClear, + apiRendererD3.autoClearColor, + apiRendererD3.autoClearDepth, + apiRendererD3.autoClearStencil, + apiRendererD3.gammaFactor, + apiRendererD3.gammaInput, + apiRendererD3.gammaOutput, + apiRendererD3.maxMorphTargets, + apiRendererD3.maxMorphNormals, + apiRendererD3.physicallyCorrectLights, + apiRendererD3.shadowMapEnabled, + apiRendererD3.shadowMapAutoUpdate, + apiRendererD3.shadowMapNeedsUpdate, + apiRendererD3.shadowMapType, + apiRendererD3.shadowMapRenderReverseSided, + apiRendererD3.shadowMapRenderSingleSided, + apiRendererD3.sortObjects, + apiRendererD3.toneMapping, + apiRendererD3.toneMappingExposure, + apiRendererD3.toneMappingWhitePoint, + apiRendererD3.premultipliedAlpha, + apiRendererD3.antialias, + apiRendererD3.stencil, + apiRendererD3.preserveDrawingBuffer, + apiRendererD3.depth, + apiRendererD3.logarithmicDepthBuffer, + apiRendererD3.localClippingEnabled, + apiRendererD3.renderTarget, + apiRendererD3.clippingPlanes, + apiRendererD3.clearColor, + apiRendererD3.viewports + ); + + if (this.renderTarget instanceof R3.D3.API.RenderTarget) { + this.renderTarget = new R3.D3.RenderTarget( + this.graphics, + this.renderTarget + ) + } + + this.clippingPlanes = this.clippingPlanes.map(function(clippingPlane){ + if (clippingPlane instanceof R3.API.Plane) { + return new R3.Plane( + this.graphics, + clippingPlane + ); + } else { + return clippingPlane; + } + }.bind(this)); + + this.clearColor = new R3.Color( + this.graphics, + this.clearColor, + this + ); + + this.viewports = this.viewports.map(function(viewport){ + if (viewport instanceof R3.D3.API.Viewport) { + return new R3.D3.Viewport( + this.graphics, + viewport + ); + } else { + return viewport; + } + }.bind(this)); + + R3.Renderer.call( + this, + this.graphics, + this + ); + +}; + +R3.Renderer.D3.prototype = Object.create(R3.Renderer.prototype); +R3.Renderer.D3.prototype.constructor = R3.Renderer.D3; + +/** + * Create R3.Renderer.D3 Instance + * @returns {*} + */ +R3.Renderer.D3.prototype.createInstance = function() { + + if ( + R3.Utils.UndefinedOrNull(this.canvas) || + R3.Utils.UndefinedOrNull(this.canvas.instance) + ) { + console.warn('no canvas instance'); + return; + } + + this.instance = new THREE.WebGLRenderer( + { + canvas : this.canvas.instance, + alpha : this.alpha, + premultipliedAlpha : this.premultipliedAlpha, + antialias : this.antialias, + stencil : this.stencil, + preserveDrawingBuffer : this.preserveDrawingBuffer, + depth : this.depth, + logarithmicDepthBuffer : this.logarithmicDepthBuffer + } + ); + + this.instance.setPixelRatio(window.devicePixelRatio); + + this.updateInstance('width'); + + this.instance.autoClear = this.autoClear; + this.instance.autoClearColor = this.autoClearColor; + this.instance.autoClearDepth = this.autoClearDepth; + this.instance.autoClearStencil = this.autoClearStencil; + + this.instance.gammaFactor = this.gammaFactor; + this.instance.gammaInput = this.gammaInput; + this.instance.gammaOutput = this.gammaOutput; + + this.instance.maxMorphTargets = this.maxMorphTargets; + this.instance.maxMorphNormals = this.maxMorphNormals; + + this.instance.physicallyCorrectLights = this.physicallyCorrectLights; + + this.instance.shadowMap.enabled = this.shadowMapEnabled; + this.instance.shadowMap.autoUpdate = this.shadowMapAutoUpdate; + this.instance.shadowMap.needsUpdate = this.shadowMapNeedsUpdate; + this.instance.shadowMap.type = this.shadowMapType; + this.instance.shadowMap.renderReverseSided = this.shadowMapRenderReverseSided; + this.instance.shadowMap.renderSingleSided = this.shadowMapRenderSingleSided; + + this.instance.sortObjects = this.sortObjects; + + this.instance.toneMapping = this.toneMapping; + this.instance.toneMappingExposure = this.toneMappingExposure; + this.instance.toneMappingWhitePoint = this.toneMappingWhitePoint; + + this.instance.premultipliedAlpha = this.premultipliedAlpha; + + this.instance.localClippingEnabled = this.localClippingEnabled; + + if (this.renderTarget) { + this.instance.setRenderTarget(this.renderTarget.instance); + } + + if (this.clippingPlanes.length > 0) { + this.instance.clippingPlanes = this.clippingPlanes.map( + function(clippingPlane) { + return clippingPlane.instance; + } + ) + } + + this.instance.setClearColor( + new THREE.Color( + this.clearColor.r, + this.clearColor.g, + this.clearColor.b + ), + 1 - this.clearColor.a + ); + + R3.Renderer.prototype.createInstance.call(this); +}; + +/** + * Update Renderer.D3 Instance + */ +R3.Renderer.D3.prototype.updateInstance = function(property) { + + if (!property) { + throw new Error('no renderer property'); + } + + if (!this.instance) { + throw new Error('no renderer instance'); + } + + if ( + property === 'width' || + property === 'height' + ) { + var size = R3.Utils.GetWindowSize(); + this.instance.setSize(size.width, size.height, false); + return; + } + + if (property === 'renderMode') { + console.log('render mode change'); + return; + } + + if (property === 'autoClear') { + this.instance.autoClear = this.autoClear; + return; + } + + if (property === 'autoClearColor') { + this.instance.autoClearColor = this.autoClearColor; + return; + } + + if (property === 'autoClearDepth') { + this.instance.autoClearDepth = this.autoClearDepth; + return; + } + + if (property === 'autoClearStencil') { + this.instance.autoClearStencil = this.autoClearStencil; + return; + } + + if (property === 'gammaFactor') { + this.instance.gammaFactor = this.gammaFactor; + return; + } + + if (property === 'gammaInput') { + this.instance.gammaInput = this.gammaInput; + return; + } + + if (property === 'gammaOutput') { + this.instance.gammaOutput = this.gammaOutput; + return; + } + + if (property === 'maxMorphTargets') { + this.instance.maxMorphTargets = this.maxMorphTargets; + return; + } + + if (property === 'maxMorphNormals') { + this.instance.maxMorphNormals = this.maxMorphNormals; + return; + } + + if (property === 'physicallyCorrectLights') { + this.instance.physicallyCorrectLights = this.physicallyCorrectLights; + return; + } + + if (property === 'shadowMapEnabled') { + this.instance.shadowMap.enabled = this.shadowMapEnabled; + return; + } + + if (property === 'shadowMapAutoUpdate') { + this.instance.shadowMap.autoUpdate = this.shadowMapAutoUpdate; + return; + } + + if (property === 'shadowMapNeedsUpdate') { + this.instance.shadowMap.needsUpdate = this.shadowMapNeedsUpdate; + return; + } + + if (property === 'shadowMapType') { + this.instance.shadowMap.type = this.shadowMapType; + return; + } + + if (property === 'shadowMapRenderReverseSided') { + this.instance.shadowMap.renderReverseSided = this.shadowMapRenderReverseSided; + return; + } + + if (property === 'shadowMapRenderSingleSided') { + this.instance.shadowMap.renderSingleSided = this.shadowMapRenderSingleSided; + return; + } + + if (property === 'sortObjects') { + this.instance.sortObjects = this.sortObjects; + return; + } + + if (property === 'toneMapping') { + this.instance.toneMapping = this.toneMapping; + return; + } + + if (property === 'toneMappingExposure') { + this.instance.toneMappingExposure = this.toneMappingExposure; + return; + } + + if (property === 'toneMappingWhitePoint') { + this.instance.toneMappingWhitePoint = this.toneMappingWhitePoint; + return; + } + + if (property === 'premultipliedAlpha') { + this.instance.premultipliedAlpha = this.premultipliedAlpha; + return; + } + + if (property === 'premultipliedAlpha') { + this.instance.premultipliedAlpha = this.premultipliedAlpha; + return; + } + + if (property === 'antialias') { + this.instance.antialias = this.antialias; + return; + } + + if (property === 'stencil') { + this.instance.stencil = this.stencil; + return; + } + + if (property === 'preserveDrawingBuffer') { + this.instance.preserveDrawingBuffer = this.preserveDrawingBuffer; + return; + } + + if (property === 'depth') { + this.instance.depth = this.depth; + return; + } + + if (property === 'logarithmicDepthBuffer') { + this.instance.logarithmicDepthBuffer = this.logarithmicDepthBuffer; + return; + } + + if (property === 'localClippingEnabled') { + this.instance.localClippingEnabled = this.localClippingEnabled; + return; + } + + if (property === 'canvas') { + + if (R3.Utils.UndefinedOrNull(this.instance)) { + this.createInstance(); + } else { + console.warn('experimental canvas change for renderer'); + this.instance.dispose(); + this.createInstance(); + } + + return; + } + + if (property === 'renderTarget') { + + if ( + R3.Utils.Defined(this.instance) && + R3.Utils.Defined(this.renderTarget) && + R3.Utils.Defined(this.renderTarget.instance) + ) { + this.instance.setRenderTarget(this.renderTarget.instance); + console.log('updated render target on render instance'); + } + + return; + } + + if (property === 'clippingPlanes') { + console.warn('todo: clipping planes change'); + return; + } + + if (property === 'clearColor') { + this.instance.setClearColor( + new THREE.Color( + this.clearColor.r, + this.clearColor.g, + this.clearColor.b + ), + 1 - this.clearColor.a + ); + return; + } + + if (property === 'viewports') { + console.warn('todo: viewports change'); + } + + R3.Renderer.prototype.updateInstance.call(this, property); +}; + +/** + * Wrapper for clear() + */ +R3.Renderer.D3.prototype.clear = function() { + return this.instance.clear(); +}; + +/** + * Convenience function to set size + * @param width + * @param height + */ +R3.Renderer.D3.prototype.setSize = function(width, height) { + + this.instance.setSize( + this.width * width, + this.height * height, + false + ); + + //this.instance.setPixelRatio(window.devicePixelRatio); +}; + +/** + * Convenience function to get size + * @returns {{width, height}} + */ +R3.Renderer.D3.prototype.getSize = function() { + return this.instance.getSize(); +}; + +/** + * Convenience function to set viewport + * @param x + * @param y + * @param width + * @param height + */ +R3.Renderer.D3.prototype.setViewport = function( + x, + y, + width, + height +) { + this.instance.setViewport( + x, + y, + width, + height + ); +}; + +/** + * Renders to this.renderTarget + * @param scene + * @param camera + */ +R3.Renderer.D3.prototype.renderToTarget = function(scene, camera) { + + this.instance.render( + scene.instance, + camera.instance, + this.renderTarget.instance + ); + +}; + +/** + * Renders normally + * @param scene + * @param camera + */ +R3.Renderer.D3.prototype.render = function(scene, camera) { + this.instance.render( + scene.instance, + camera.instance + ) +}; + + +/** + * + * @returns {R3.API.Renderer.D3} + */ +R3.Renderer.D3.prototype.toApiObject = function() { + + var apiRenderer = R3.Renderer.prototype.toApiObject.call(this); + + var apiRendererD3 = new R3.API.Renderer.D3( + apiRenderer, + this.renderMode, + this.autoClear, + this.autoClearColor, + this.autoClearDepth, + this.autoClearStencil, + this.gammaFactor, + this.gammaInput, + this.gammaOutput, + this.maxMorphTargets, + this.maxMorphNormals, + this.physicallyCorrectLights, + this.shadowMapEnabled, + this.shadowMapAutoUpdate, + this.shadowMapNeedsUpdate, + this.shadowMapType, + this.shadowMapRenderReverseSided, + this.shadowMapRenderSingleSided, + this.sortObjects, + this.toneMapping, + this.toneMappingExposure, + this.toneMappingWhitePoint, + this.premultipliedAlpha, + this.antialias, + this.stencil, + this.preserveDrawingBuffer, + this.depth, + this.logarithmicDepthBuffer, + this.localClippingEnabled, + R3.Utils.IdOrNull(this.renderTarget), + this.clippingPlanes.map( + function(clippingPlane){ + return R3.Utils.IdOrNull(clippingPlane); + } + ), + this.clearColor.toApiObject(), + this.viewports.map( + function(viewport){ + return R3.Utils.IdOrNull(viewport); + } + ) + ); + + return apiRendererD3; +}; diff --git a/src/r3-server.js b/src/r3-server.js new file mode 100644 index 0000000..d5b5c10 --- /dev/null +++ b/src/r3-server.js @@ -0,0 +1,87 @@ +/** + * Creates a Server object + * @param apiServer R3.API.Server + * @constructor + */ +R3.Server = function( + apiServer +) { + + if (R3.Utils.UndefinedOrNull(apiServer)) { + apiServer = {}; + } + + R3.API.Server.call( + this, + apiServer.id, + apiServer.name, + apiServer.protocol, + apiServer.ip, + apiServer.port, + apiServer.protocols, + apiServer.parentEntity + ); + + this.connected = false; + + R3.Component.call(this); +}; + +R3.Server.prototype = Object.create(R3.Component.prototype); +R3.Server.prototype.constructor = R3.Server; + +R3.Server.prototype.createInstance = function() { + + this.instance = true; + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.Server.prototype.updateInstance = function(property) { + if (property === 'protocol') { + console.log('todo: server protocol update'); + } + if (property === 'ip') { + console.log('todo: server ip update'); + } + if (property === 'port') { + console.log('todo: server port update'); + } + if (property === 'protocols') { + console.log('todo: server protocols update'); + } + + R3.D3.Texture.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.Server to a new R3.API.Server + * @returns {R3.API.Server} + */ +R3.Server.prototype.toApiObject = function() { + + return new R3.API.Server( + this.id, + this.name, + this.protocol, + this.ip, + this.port, + this.protocols, + R3.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Converts from an Object Server to a R3.Server + * @param objectServer Object + * @returns {R3.Server} + * @constructor + */ +R3.Server.FromObject = function(objectServer) { + var apiServer = R3.API.Server.FromObject(objectServer); + return new R3.Server(apiServer); +}; diff --git a/src/r3-socket-0.js b/src/r3-socket-0.js new file mode 100644 index 0000000..f0ffc7d --- /dev/null +++ b/src/r3-socket-0.js @@ -0,0 +1,115 @@ +/** + * Creates a Socket object + * @param socket R3.Socket + * @param apiSocket R3.API.Socket + * @constructor + */ +R3.Socket = function( + socket, + apiSocket +) { + + this.socket = socket; + this.socket.isNotWebSocketThrow(); + + if (R3.Utils.UndefinedOrNull(apiSocket)) { + apiSocket = {}; + } + + R3.API.Socket.call( + this, + apiSocket.id, + apiSocket.name, + apiSocket.socketType, + apiSocket.roomId, + apiSocket.peerId, + apiSocket.server, + apiSocket.parentEntity + ); + + if (this.server instanceof R3.API.Server) { + this.server = new R3.Server(this.server); + } + + this.connected = false; + + var linkedObjects = { + server : R3.Server + }; + + if (this.socketType === R3.API.Socket.TYPE_CAST) { + linkedObjects.source = R3.Component; + } + + if (this.socketType === R3.API.Socket.TYPE_RECEIVE) { + linkedObjects.destination = R3.Component; + } + + R3.Component.call( + this, + linkedObjects + ); + +}; + +R3.Socket.prototype = Object.create(R3.Component.prototype); +R3.Socket.prototype.constructor = R3.Socket; + +R3.Socket.prototype.createInstance = function() { + + this.instance = true; + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.Socket.prototype.updateInstance = function(property) { + if (property === 'socketType') { + console.log('todo: implement socket socketType update'); + } + if (property === 'roomId') { + console.log('todo: implement socket roomId update'); + } + if (property === 'peerId') { + console.log('todo: implement socket peerId update'); + } + if (property === 'server') { + console.log('todo: implement socket server update'); + } + R3.D3.Texture.prototype.updateInstance.call(this, property); +}; + +/** + * Converts a R3.Socket to a new R3.API.Socket + * @returns {R3.API.Socket} + */ +R3.Socket.prototype.toApiObject = function() { + + return new R3.API.Socket( + this.id, + this.name, + this.socketType, + this.roomId, + this.peerId, + R3.Utils.IdOrNull(this.server), + R3.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Converts from an Object Socket to a R3.Socket + * @param sockets R3.SocketsRuntime + * @param objectSocket Object + * @returns {R3.Socket} + * @constructor + */ +R3.Socket.FromObject = function(sockets, objectSocket) { + var apiSocket = R3.API.Socket.FromObject(objectSocket); + return new R3.Socket( + sockets, + apiSocket + ); +}; diff --git a/src/r3-socket-cast.js b/src/r3-socket-cast.js new file mode 100644 index 0000000..533b77e --- /dev/null +++ b/src/r3-socket-cast.js @@ -0,0 +1,119 @@ +/** + * Creates a Cast object + * @param socket R3.Socket + * @param apiSocketCast + * @constructor + */ +R3.Socket.Cast = function( + socket, + apiSocketCast +) { + + this.socket = socket; + this.socket.isNotWebSocketThrow(); + + if (R3.Utils.UndefinedOrNull(apiSocketCast)) { + apiSocketCast = { + socketType : R3.API.Socket.TYPE_CAST + }; + } + + R3.API.Socket.Cast.call( + this, + apiSocketCast, + apiSocketCast.castType, + apiSocketCast.source, + apiSocketCast.sourceProperties + ); + + R3.Socket.call( + this, + socket, + apiSocketCast + ); +}; + +R3.Socket.Cast.prototype = Object.create(R3.Socket.prototype); +R3.Socket.Cast.prototype.constructor = R3.Socket.Cast; + +R3.Socket.Cast.prototype.createInstance = function() { + + this.instance = true; + + R3.Socket.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.Socket.Cast.prototype.updateInstance = function(property) { + + R3.Socket.prototype.updateInstance.call( + this, + property + ); + + if (property === 'castType') { + console.log('todo: implement socket.receive.castType update'); + } + + if (property === 'source') { + if (this.source !== null) { + this.sourceProperties = R3.Utils.ObjectPropertiesAsBoolean(this.source); + } else { + this.sourceProperties = {}; + } + + R3.Event.Emit( + R3.Event.CAST_SOURCE_CHANGED, + { + component:this + } + ) + } + + if (property === 'sourceProperties') { + console.log('todo: implement socket.receive.sourceProperties update'); + } + +}; + +/** + * Converts a R3.Socket.Cast to a new R3.API.Socket.Cast + * @returns {R3.API.Socket.Cast} + */ +R3.Socket.Cast.prototype.toApiObject = function() { + + var apiSocket = new R3.API.Socket( + this.id, + this.name, + this.socketType, + this.roomId, + this.peerId, + R3.Utils.IdOrNull(this.server), + R3.Utils.IdOrNull(this.parentEntity) + ); + + return new R3.API.Socket.Cast( + apiSocket, + this.castType, + R3.Utils.IdOrNull(this.source), + this.sourceProperties + ); + +}; + +/** + * Converts from an Object Cast to a R3.Socket.Cast + * @param sockets R3.SocketsRuntime + * @param objectCast Object + * @returns {R3.Socket.Cast} + * @constructor + */ +R3.Socket.Cast.FromObject = function(sockets, objectCast) { + var apiCast = R3.API.Socket.Cast.FromObject(objectCast); + return new R3.Socket.Cast( + sockets, + apiCast + ); +}; diff --git a/src/r3-socket-receive.js b/src/r3-socket-receive.js new file mode 100644 index 0000000..ea8b493 --- /dev/null +++ b/src/r3-socket-receive.js @@ -0,0 +1,123 @@ +/** + * Creates a Receive object + * @param socket R3.Socket + * @param apiSocketReceive R3.API.Socket.Receive + * @constructor + */ +R3.Socket.Receive = function( + socket, + apiSocketReceive +) { + + this.socket = socket; + this.socket.isNotWebSocketThrow(); + + if (R3.Utils.UndefinedOrNull(apiSocketReceive)) { + apiSocketReceive = { + socketType : R3.API.Socket.TYPE_RECEIVE + }; + } + + R3.API.Socket.Receive.call( + this, + apiSocketReceive, + apiSocketReceive.receiveType, + apiSocketReceive.destination, + apiSocketReceive.destinationProperties + ); + + R3.Socket.call( + this, + socket, + apiSocketReceive + ); + +}; + +R3.Socket.Receive.prototype = Object.create(R3.Socket.prototype); +R3.Socket.Receive.prototype.constructor = R3.Socket.Receive; + +R3.Socket.Receive.prototype.createInstance = function() { + + this.instance = true; + + R3.Socket.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.Socket.Receive.prototype.updateInstance = function(property) { + + R3.Socket.prototype.updateInstance.call( + this, + property + ); + + if (property === 'receiveType') { + console.log('todo: implement socket.receive.receiveType update'); + } + + if (property === 'destination') { + + if (this.destination !== null) { + this.destinationProperties = R3.Utils.ObjectPropertiesAsBoolean(this.destination); + } else { + this.destinationProperties = {}; + } + + R3.Event.Emit( + R3.Event.RECEIVE_DESTINATION_CHANGED, + { + component:this + } + ) + } + + if (property === 'destinationProperties') { + console.log('todo: implement socket.receive.destinationProperties update'); + } +}; + +/** + * Converts a R3.Socket.Receive to a new R3.API.Socket.Receive + * @returns {R3.API.Socket.Receive} + */ +R3.Socket.Receive.prototype.toApiObject = function() { + + var apiSocket = new R3.API.Socket( + this.id, + this.name, + this.socketType, + this.roomId, + this.peerId, + R3.Utils.IdOrNull(this.server), + R3.Utils.IdOrNull(this.parentEntity) + ); + + return new R3.API.Socket.Receive( + apiSocket, + this.receiveType, + this.destination, + this.destinationProperties + ); + +}; + +/** + * Converts from an Object Receive to a R3.Socket.Receive + * @param sockets R3.SocketsRuntime + * @param objectReceive Object + * @returns {R3.Socket.Receive} + * @constructor + */ +R3.Socket.Receive.FromObject = function(sockets, objectReceive) { + + var apiSocketReceive = R3.API.Socket.Receive.FromObject(objectReceive); + + return new R3.Socket.Receive( + sockets, + apiSocketReceive + ); + +}; diff --git a/src/r3-sockets-runtime.js b/src/r3-sockets-runtime.js new file mode 100644 index 0000000..31c6a66 --- /dev/null +++ b/src/r3-sockets-runtime.js @@ -0,0 +1,66 @@ +/** + * Sockets + * @param id + * @param name + * @param socketsType + * @constructor + */ +R3.SocketsRuntime = function( + id, + name, + socketsType +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Sockets (' + id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(socketsType)) { + socketsType = R3.SocketsRuntime.TYPE_WEB_SOCKET; + } + this.socketsType = socketsType; + + this.connections = []; + + this.createInstance(); +}; + +/** + * R3.SocketsRuntime Types + * @type {number} + */ +R3.SocketsRuntime.TYPE_WEB_SOCKET = 0x1; + +R3.SocketsRuntime.prototype.createInstance = function() { + if (this.socketsType === R3.SocketsRuntime.TYPE_WEB_SOCKET) { + this.instance = WebSocket; + } else { + this.instance = null; + } +}; + +R3.SocketsRuntime.prototype.connect = function(server) { + var connection = new WebSocket(server.protocol + '://' + server.ip + ':' + server.port , server.protocols); + this.connections.push(connection); +}; + +R3.SocketsRuntime.prototype.updateInstance = function(property) { + if (property === 'socketsType') { + this.createInstance(); + } +}; + +/** + * Logs a warning and throws an error if not cannon + */ +R3.SocketsRuntime.prototype.isNotWebSocketThrow = function() { + if (this.instance !== WebSocket) { + console.error('Only WebSocket supported'); + throw new Error('Only WebSocket supported'); + } +}; diff --git a/src/r3-sphere.js b/src/r3-sphere.js new file mode 100644 index 0000000..4e40e69 --- /dev/null +++ b/src/r3-sphere.js @@ -0,0 +1,86 @@ +/** + * R3.Sphere + * @param implementation + * @param apiSphere + * @param parentObject + * @constructor + */ +R3.Sphere = function ( + implementation, + apiSphere, + parentObject +) { + + this.implementation = implementation; + this.implementation.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(parentObject)) { + parentObject = null; + } + this.parentObject = parentObject; + + if (R3.Utils.UndefinedOrNull(apiSphere)) { + apiSphere = {}; + } + + R3.API.Sphere.call( + this, + apiSphere.center, + apiSphere.radius + ); + + this.center = new R3.Vector3( + this.implementation, + this.center, + this + ); + + this.createInstance(); +}; + +R3.Sphere.prototype = Object.create(R3.API.Sphere.prototype); +R3.Sphere.prototype.constructor = R3.Sphere; + +/** + * Creates an instance R3.Sphere + * @returns {*} + */ +R3.Sphere.prototype.createInstance = function() { + + this.instance = new THREE.Sphere( + this.center.instance, + this.radius + ); + +}; + +/** + * Updates R3.Sphere instance + * @param property + */ +R3.Sphere.prototype.updateInstance = function(property) { + + if (property === 'center') { + this.instance.center.x = this.center.x; + this.instance.center.y = this.center.y; + this.instance.center.z = this.center.z; + return; + } + + if (property === 'radius') { + this.instance.radius = this.radius; + return; + } + +}; + +/** + * R3.Sphere to R3.API.Sphere + * @returns {R3.API.Sphere} + */ +R3.Sphere.prototype.toApiObject = function() { + return new R3.API.Sphere( + this.center.toApiObject(), + this.radius + ); +}; diff --git a/src/r3-statistics-runtime.js b/src/r3-statistics-runtime.js new file mode 100644 index 0000000..269703d --- /dev/null +++ b/src/r3-statistics-runtime.js @@ -0,0 +1,59 @@ +/** + * Statistics + * @param id + * @param name + * @param statisticsType + * @constructor + */ +R3.StatisticsRuntime = function( + id, + name, + statisticsType +) { + if (R3.Utils.UndefinedOrNull(id)) { + id = R3.Utils.RandomId(); + } + this.id = id; + + if (R3.Utils.UndefinedOrNull(name)) { + name = 'Statistics (' + id + ')'; + } + this.name = name; + + if (R3.Utils.UndefinedOrNull(statisticsType)) { + statisticsType = R3.StatisticsRuntime.TYPE_STATS; + } + this.statisticsType = statisticsType; + + this.createInstance(); +}; + +/** + * R3.StatisticsRuntime Types + * @type {number} + */ +R3.StatisticsRuntime.TYPE_STATS = 0x1; + +R3.StatisticsRuntime.prototype.createInstance = function() { + if (this.statisticsType === R3.StatisticsRuntime.TYPE_STATS) { + this.instance = Stats; + } else { + this.instance = null; + } +}; + +R3.StatisticsRuntime.prototype.updateInstance = function(property) { + if (property === 'statisticsType') { + this.createInstance(); + } +}; + +/** + * Logs a warning and throws an error if not cannon + */ +R3.StatisticsRuntime.prototype.isNotStatsThrow = function() { + if (this.instance !== Stats) { + console.error('Only stats supported'); + throw new Error('Only stats supported'); + } +}; diff --git a/src/r3-stats.js b/src/r3-stats.js new file mode 100644 index 0000000..6152df2 --- /dev/null +++ b/src/r3-stats.js @@ -0,0 +1,103 @@ +/** + * Stats component for displaying some render statistics (framerate, memory consumption, etc) + * @param statisticsRuntime + * @param apiStats + * @constructor + */ +R3.Stats = function( + statisticsRuntime, + apiStats +) { + this.stats = statisticsRuntime; + this.stats.isNotStatsThrow(); + + if (R3.Utils.UndefinedOrNull(apiStats)) { + apiStats = {}; + } + + R3.API.Stats.call( + this, + apiStats.id, + apiStats.name, + apiStats.domElement, + apiStats.parentEntity + ); + + R3.Component.call( + this, + { + 'domElement': R3.DomElement + } + ); +}; + +R3.Stats.prototype = Object.create(R3.Component.prototype); +R3.Stats.prototype.constructor = R3.Stats; + +/** + * Creates a helper instance + */ +R3.Stats.prototype.createInstance = function() { + + this.instance = this.stats.instance(); + + this.resize(); + + this.domElement.instance.parentElement.appendChild(this.instance.dom); + + R3.Component.prototype.createInstance.call(this); +}; + +/** + * Updates the instance with the current state + */ +R3.Stats.prototype.updateInstance = function() { + this.instance = new this.stats(); +}; + + +/** + * Converts a R3.Stats to a new R3.API.Stats + * @returns {R3.API.Stats} + */ +R3.Stats.prototype.toApiObject = function() { + + return new R3.API.Stats( + this.id, + this.name, + R3.Utils.IdOrNull(this.domElement), + R3.Utils.IdOrNull(this.parentEntity) + ); + +}; + +/** + * Converts from an Object Stats to a R3.Stats + * @param statisticsRuntime R3.StatisticsRuntime + * @param objectStats Object + * @returns {R3.Stats} + * @constructor + */ +R3.Stats.FromObject = function(statisticsRuntime, objectStats) { + + var apiStats = R3.API.Stats.FromObject(objectStats); + + return new R3.Stats( + statisticsRuntime, + apiStats + ); + +}; + +R3.Stats.prototype.resize = function() { + console.log('override stats resize per implementation'); +}; + + +R3.Stats.prototype.start = function() { + this.instance.begin(); +}; + +R3.Stats.prototype.end = function() { + this.instance.end(); +}; diff --git a/src/r3-system-0.js b/src/r3-system-0.js new file mode 100644 index 0000000..a5b3657 --- /dev/null +++ b/src/r3-system-0.js @@ -0,0 +1,104 @@ +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem R3.API.System + * @constructor + */ +R3.System = function( + apiSystem +) { + + if (R3.Utils.UndefinedOrNull(apiSystem)) { + apiSystem = {}; + } + + R3.API.System.call( + this, + apiSystem.id, + apiSystem.name, + apiSystem.systemType, + apiSystem.parentEntity + ); + + this.started = false; + + this.paused = false; + + var linkedObjects = {}; + + if (apiSystem.systemType === R3.System.SYSTEM_TYPE_INPUT) { + linkedObjects.mouseControls = [R3.Controls.Mouse]; + linkedObjects.keyboardControls = [R3.Controls.Keyboard]; + linkedObjects.touchControls = [R3.Controls.Touch]; + linkedObjects.editorControls = [R3.Controls.D3.Editor]; + } + + if (apiSystem.systemType === R3.System.SYSTEM_TYPE_AUDIO) { + linkedObjects.audioComponents = [R3.D3.Audio]; + } + + R3.Component.call( + this, + linkedObjects + ); + +}; + +R3.System.prototype = Object.create(R3.Component.prototype); +R3.System.prototype.constructor = R3.System; + +R3.System.SYSTEM_TYPE_NONE = 0x0; +R3.System.SYSTEM_TYPE_RENDER = 0x1; +R3.System.SYSTEM_TYPE_ANIMATION = 0x2; +R3.System.SYSTEM_TYPE_INPUT = 0x4; +R3.System.SYSTEM_TYPE_STORAGE = 0x8; +R3.System.SYSTEM_TYPE_GUI = 0x10; +R3.System.SYSTEM_TYPE_PHYSICS = 0x20; +R3.System.SYSTEM_TYPE_LINKING = 0x40; +R3.System.SYSTEM_TYPE_CUSTOM = 0x80; +R3.System.SYSTEM_TYPE_VISUALIZATION = 0x100; +R3.System.SYSTEM_TYPE_PARTICLE = 0x200; +R3.System.SYSTEM_TYPE_AUDIO = 0x400; +R3.System.SYSTEM_TYPE_SOCKET = 0x800; +R3.System.SYSTEM_TYPE_ALL = 0xFFFF; + +R3.System.prototype.createInstance = function() { + this.instance = true; + R3.Component.prototype.createInstance.call(this); +}; + +/** + * @callback + * @override + */ +R3.System.prototype.start = function() { + this.started = true; +// console.log('starting ' + this.name); +}; + +/** + * @callback + * @override + */ +R3.System.prototype.stop = function() { + this.started = false; +// console.log('stopping ' + this.name); +}; + +/** + * Converts runtime vector to API Vector + * @returns {R3.API.System} + */ +R3.System.prototype.toApiObject = function() { + return new R3.API.System( + this.id, + this.name, + this.systemType, + R3.Utils.IdOrNull(this.parentEntity) + ); +}; + +R3.System.prototype.restart = function() { + console.log('restarting system : ' + this.name); + this.stop(); + this.start(); +}; \ No newline at end of file diff --git a/src/r3-system-animation.js b/src/r3-system-animation.js new file mode 100644 index 0000000..c5d7455 --- /dev/null +++ b/src/r3-system-animation.js @@ -0,0 +1,1162 @@ +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem R3.API.System + * @constructor + */ +R3.System.Animation = function( + apiSystem +) { + R3.System.call( + this, + apiSystem + ); + + this.animations = []; + // this.textures = []; + // this.textureIds = []; + +// 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 R3.Texture + */ + this.animateTextureInstanceSubscription = null; +}; + +R3.System.Animation.prototype = Object.create(R3.System.prototype); +R3.System.Animation.prototype.constructor = R3.System.Animation; + +R3.System.Animation.prototype.start = function() { + + R3.System.prototype.start.call(this); + + this.beforeRenderSubscription = R3.Event.Subscribe( + R3.Event.BEFORE_RENDER, + this.beforeRender.bind(this) + ); + + this.animations = R3.EntityManager.Instance.queryComponents(R3.Component.ANIMATION); + + // + // animations.map(function(animation){ + // animation.meshes.map( + // function(mesh) { + // this.attachAnimation(animation, mesh); + // }.bind(this) + // ); + // this.animations[animation.id] = animation; + // }.bind(this)); + + // this.animationMeshAddedSubscription = R3.Event.Subscribe( + // R3.Event.ANIMATION_MESH_ADDED, + // function(data) { + // this.attachAnimation(data.animation, data.mesh); + // }.bind(this) + // ); + // + // this.animationMeshRemovedSubscription = R3.Event.Subscribe( + // R3.Event.ANIMATION_MESH_REMOVED, + // function(data) { + // this.detachAnimation(data.mesh); + // }.bind(this) + // ); + + this.instanceCreatedSubscription = R3.Event.Subscribe( + R3.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + this.removeComponentSubscription = R3.Event.Subscribe( + R3.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + this.textureAnimatedSubscription = R3.Event.Subscribe( + R3.Event.TEXTURE_ANIMATED_CHANGE, + this.textureAnimatedChange.bind(this) + ); + + this.animateTextureInstanceSubscription = R3.Event.Subscribe( + R3.Event.ANIMATE_TEXTURE_INSTANCE, + this.animateTextureInstance.bind(this) + ) +}; + +R3.System.Animation.prototype.instanceCreated = function(data) { + + if ( + data.component instanceof R3.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); + } + + if (data.component instanceof R3.D3.Animation) { + + R3.Utils.PushUnique(this.animations, data.component); + // + // this.animations[data.component.id] = data.component; + // data.component.meshes.map( + // function(mesh){ + // this.attachAnimation(data.component, mesh) + // }.bind(this) + // ); + } +}; + +R3.System.Animation.prototype.removeComponent = function(data) { + + if ( + data.component instanceof R3.D3.Texture && + data.component.animated + ) { + if (R3.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); + } + } + + if (data.component instanceof R3.D3.Animation) { + + var index = this.animations.indexOf(data.component); + + if (index === -1) { + console.warn('animation index out of sync'); + } else { + this.animations.splice(index, 1); + } + } + + if (data.component instanceof R3.D3.Mesh) { + this.animations.map( + function(animation) { + + var index = animation.meshes.indexOf(data.component); + + if (index !== -1) { + animation.meshes.splice(index, 1); + animation.updateInstance('meshes'); + } + } + ) + } +}; + +R3.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 (R3.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 R3 component and linking + * system, which adds too much overhead for managing textures + * @param data + */ +R3.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); +}; + +/** + * Performs a slight change on object[property][subProperty] from instance towards object + * @param object + * @param property + * @param subProperty + * @param increment + * @returns {boolean} + */ +R3.System.Animation.prototype.slightChange = function(object, property, subProperty, increment) { + + var current = object.instance[property][subProperty]; + var target = object[property][subProperty]; + + if (Math.abs(target - current) < increment) { + object.instance[property][subProperty] = object[property][subProperty]; + return false; + } else if (current > target) { + object.instance[property][subProperty] -= increment; + } else { + object.instance[property][subProperty] += increment; + } + + return true; +}; + +R3.System.Animation.prototype.beforeRender = function(data) { + + if (this.paused) { + return; + } + + var increment = 0; + + this.animations.map( + function(animation) { + animation.meshes.map( + function(mesh) { + + if (animation.rotationSpeed) { + /** + * Apply slight rotation to mesh + */ + increment = animation.rotationSpeed * data.delta; + + this.slightChange(mesh, 'rotation', 'x', increment); + this.slightChange(mesh, 'rotation', 'y', increment); + this.slightChange(mesh, 'rotation', 'z', increment); + } + + if (animation.translationSpeed) { + /** + * Apply slight translation to mesh + */ + increment = animation.translationSpeed * data.delta; + + this.slightChange(mesh, 'position', 'x', increment); + this.slightChange(mesh, 'position', 'y', increment); + this.slightChange(mesh, 'position', 'z', increment); + } + + if (animation.scaleSpeed) { + /** + * Apply slight scale to mesh + */ + increment = animation.scaleSpeed * data.delta; + + this.slightChange(mesh, 'scale', 'x', increment); + this.slightChange(mesh, 'scale', 'y', increment); + this.slightChange(mesh, 'scale', 'z', increment); + } + }.bind(this) + ) + }.bind(this) + ); + + 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) + ) +}; + +/** + * Stop Animation System + */ +R3.System.Animation.prototype.stop = function() { + + R3.System.prototype.stop.call(this); + + this.beforeRenderSubscription.remove(); + + // this.animationMeshAddedSubscription.remove(); + // + // this.animationMeshRemovedSubscription.remove(); + // + this.animations = []; + + this.instanceCreatedSubscription.remove(); + + this.removeComponentSubscription.remove(); + + this.textureAnimatedSubscription.remove(); + + this.animateTextureInstanceSubscription.remove(); +}; + + + +/* +R3.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('position'); + mesh.updateInstance('rotation'); + mesh.updateInstance('scale'); + } + +}; +*/ + +//R3.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 + } + ); +}; +*/ +// R3.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 = []; +// } +// }; +// } +// }; +// +// R3.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); +// +// // R3.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 = R3.Event.Subscribe( +// R3.Event.BEFORE_RENDER, +// function(data) { +// +// var increment = Math.abs(animation.rotationSpeed); +// +// if (!mesh.animationObject.angleIncrement) { +// increment *= -1; +// } +// +// animateRotation(data.delta * increment); +// } +// ); +// } +// }; +// +// R3.System.Animation.prototype.getQuaternionAxisX = function(mesh, animation) { +// return function() { +// return this.latest[mesh.id].quaternion.axis.x; +// }.bind(this); +// }; +// +// R3.System.Animation.prototype.setQuaternionAxisX = function(mesh, animation) { +// return function(value) { +// this.latest[mesh.id].quaternion.axis.x = value; +// }.bind(this); +// }; +// +// R3.System.Animation.prototype.getQuaternionAxisY = function(mesh, animation) { +// return function() { +// return this.latest[mesh.id].quaternion.axis.y; +// }.bind(this); +// }; +// +// R3.System.Animation.prototype.setQuaternionAxisY = function(mesh, animation) { +// return function(value) { +// this.latest[mesh.id].quaternion.axis.y = value; +// }.bind(this); +// }; +// +// R3.System.Animation.prototype.getQuaternionAxisZ = function(mesh, animation) { +// return function() { +// return this.latest[mesh.id].quaternion.axis.z; +// }.bind(this); +// }; +// +// R3.System.Animation.prototype.setQuaternionAxisZ = function(mesh, animation) { +// return function(value) { +// this.latest[mesh.id].quaternion.axis.z = value; +// }.bind(this); +// }; +// +// R3.System.Animation.prototype.getSubProperty = function(mesh, axis, property, subProperty) { +// return function() { +// return this.latest[mesh.id][property][subProperty][axis]; +// }.bind(this); +// }; + +// R3.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) +// }; + +// R3.System.Animation.prototype.getProperty = function(mesh, axis, property) { +// return function() { +// return this.latest[mesh.id][property][axis]; +// }.bind(this); +// }; +// +// R3.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) +// }; + diff --git a/src/r3-system-audio.js b/src/r3-system-audio.js new file mode 100644 index 0000000..42962d4 --- /dev/null +++ b/src/r3-system-audio.js @@ -0,0 +1,292 @@ +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem R3.API.System + * @constructor + */ +R3.System.Audio = function( + apiSystem +) { + R3.System.call( + this, + apiSystem + ); + + this.instanceCreatedSubscription = null; + + this.removeComponentSubscription = null; + + this.playAudioSubscription = null; + + this.pauseAllAudioSubscription = null; + + this.muteAudioSubscription = null; + + this.continueAllAudioSubscription = null; + + this.stopAudioSubscription = null; + + this.stopAllAudioSubscription = null; + + this.mute = false; + + this.paused = []; + + this.audioComponents = []; + + this.toPlay = []; +}; + +R3.System.Audio.prototype = Object.create(R3.System.prototype); +R3.System.Audio.prototype.constructor = R3.System.Audio; + +/** + * Start this system (add all event listeners) + */ +R3.System.Audio.prototype.start = function() { + + R3.System.prototype.start.call(this); + + this.instanceCreatedSubscription = R3.Event.Subscribe( + R3.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + this.removeComponentSubscription = R3.Event.Subscribe( + R3.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + this.playAudioSubscription = R3.Event.Subscribe( + R3.Event.PLAY_AUDIO, + this.playAudio.bind(this) + ); + + this.pauseAllAudioSubscription = R3.Event.Subscribe( + R3.Event.PAUSE_ALL_AUDIO, + this.pauseAllAudio.bind(this) + ); + + this.muteAudioSubscription = R3.Event.Subscribe( + R3.Event.MUTE_AUDIO, + this.muteAudio.bind(this) + ); + + this.continueAllAudioSubscription = R3.Event.Subscribe( + R3.Event.CONTINUE_ALL_AUDIO, + this.continueAllAudio.bind(this) + ); + + this.stopAudioSubscription = R3.Event.Subscribe( + R3.Event.STOP_AUDIO, + this.stopAudio.bind(this) + ); + + this.stopAllAudioSubscription = R3.Event.Subscribe( + R3.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 + */ +R3.System.Audio.prototype.instanceCreated = function(data) { + + if (data.component instanceof R3.D3.Audio) { + + R3.Utils.PushUnique(this.audioComponents, data.component); + + data.component.instance.onEnded = function() { + this.isPlaying = false; + R3.Event.Emit( + R3.Event.AUDIO_ENDED, + { + audio : data.component + } + ); + }; + + var index = this.toPlay.indexOf(data.component.name); + + if (index !== -1) { + + R3.Event.Emit( + R3.Event.PLAY_AUDIO, + { + name : data.component.name + } + ); + + this.toPlay.splice(index, 1); + } + } +}; + +/** + * Removes a particle engine from this system + * @param data + */ +R3.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 (this.mute && typeof audio.backupVolume === 'undefined') { + // audio.backupVolume = audio.volume; + // audio.volume = 0; + // audio.updateInstance('volume'); + // } + // + // if (!this.mute && typeof audio.backupVolume === 'number') { + // audio.volume = audio.backupVolume; + // delete audio.backupVolume; + // audio.updateInstance('volume'); + // } + + if (audio.overplay) { + if (audio.instance.isPlaying) { + audio.instance.stop(); + } + audio.instance.offset = 0; + audio.instance.play(); + } else if (!audio.instance.isPlaying) { + audio.instance.play(); + } + } + }.bind(this) + ); + + if (!found) { + /** + * This audio still has to load + */ + console.log('delaying audio play until loaded for: ' + data.name); + this.toPlay.push(data.name); + } +}; + +R3.System.Audio.prototype.pauseAllAudio = function(data) { + + this.paused = []; + + this.audioComponents.map( + function(audio) { + if (audio.instance.isPlaying) { + this.paused.push(audio); + // audio.currentTime = audio.instance.context.currentTime; + audio.paused = true; + audio.updateInstance('paused'); + + } + }.bind(this) + ) +}; + +R3.System.Audio.prototype.continueAllAudio = function(data) { + + this.paused.map( + function(audio) { + // audio.instance.context.currentTime = audio.currentTime; + audio.paused = false; + audio.updateInstance('paused'); + } + ); + + this.paused = []; + +}; + +R3.System.Audio.prototype.stopAllAudio = function(data) { + this.audioComponents.map( + function(audio) { + if (audio.instance.isPlaying) { + audio.instance.stop(); + } + } + ) +}; + + +R3.System.Audio.prototype.stopAudio = function(data) { + this.audioComponents.map( + function(audio) { + if (audio.name === data.name) { + if (audio.instance.isPlaying) { + audio.instance.stop(); + } + } + } + ) +}; + + +R3.System.Audio.prototype.removeComponent = function(data) { + +}; + +R3.System.Audio.prototype.muteAudio = function() { + + this.mute = !this.mute; + + if (this.mute) { + this.audioVolumes = this.audioComponents.reduce( + function(result, audio) { + result.push( + { + audio : audio, + volume : audio.volume + } + ); + + audio.volume = 0; + audio.updateInstance('volume'); + + return result; + }, + [] + ); + + R3.Event.Emit(R3.Event.AUDIO_MUTED, {audioSystem:this}); + + } else { + + this.audioVolumes.map( + function(audioVolume) { + audioVolume.audio.volume = audioVolume.volume; + audioVolume.audio.updateInstance('volume'); + } + ); + + R3.Event.Emit(R3.Event.AUDIO_UNMUTED, {audioSystem:this}); + } +}; + + +/** + * Stop this system (remove all event listeners) + */ +R3.System.Audio.prototype.stop = function() { + + R3.System.prototype.stop.call(this); + + this.instanceCreatedSubscription.remove(); + this.removeComponentSubscription.remove(); + this.playAudioSubscription.remove(); + this.pauseAllAudioSubscription.remove(); + this.muteAudioSubscription.remove(); + this.continueAllAudioSubscription.remove(); + this.stopAudioSubscription.remove(); + this.stopAllAudioSubscription.remove(); + +}; diff --git a/src/r3-system-custom-code.js b/src/r3-system-custom-code.js new file mode 100644 index 0000000..4112cfa --- /dev/null +++ b/src/r3-system-custom-code.js @@ -0,0 +1,157 @@ +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem R3.API.System + * @constructor + */ +R3.System.CustomCode = function( + apiSystem +) { + + R3.System.call( + this, + apiSystem + ); + + this.instanceCreatedSubscription = null; + this.removeComponentSubscription = null; + this.compileSuccessSubscription = null; + this.compileFailedSubscription = null; + this.eventIdUpdateSubscription = null; + + this.subscriptions = {}; + +}; + +R3.System.CustomCode.prototype = Object.create(R3.System.prototype); +R3.System.CustomCode.prototype.constructor = R3.System.CustomCode; + +/** + * Start the rendering system + */ +R3.System.CustomCode.prototype.start = function() { + + R3.System.prototype.start.call(this); + + R3.EntityManager.Instance.queryComponents(R3.Component.CUSTOM_CODE).map( + function(component) { + this.subscriptions[component.id] = R3.Event.Subscribe( + component.eventId, + component.instance + ); + }.bind(this) + ); + + this.instanceCreatedSubscription = R3.Event.Subscribe( + R3.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + this.removeComponentSubscription = R3.Event.Subscribe( + R3.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + this.compileSuccessSubscription = R3.Event.Subscribe( + R3.Event.COMPILE_SUCCESS, + this.compileSuccess.bind(this) + ); + + this.compileFailedSubscription = R3.Event.Subscribe( + R3.Event.COMPILE_FAILED, + this.compileFailed.bind(this) + ); + + this.eventIdUpdateSubscription = this.subscribe( + R3.Event.EVENT_ID_UPDATE, + this.compileSuccess + ); + +}; + +R3.System.CustomCode.prototype.instanceCreated = function(data) { + if (data.component instanceof R3.CustomCode) { + + if (this.subscriptions[data.component.id]) { + console.warn('a component already existed'); + this.subscriptions[data.component.id].remove(); + } + + this.subscriptions[data.component.id] = R3.Event.Subscribe( + data.component.eventId, + data.component.instance + ); + } +}; + +R3.System.CustomCode.prototype.removeComponent = function(data) { + if (data.component instanceof R3.CustomCode) { + if (this.subscriptions[data.component.id]) { + this.subscriptions[data.component.id].remove(); + delete this.subscriptions[data.component.id]; + } + } +}; + +R3.System.CustomCode.prototype.compileSuccess = function(data) { + + if (this.subscriptions[data.component.id]) { + this.subscriptions[data.component.id].remove(); + } + + this.subscriptions[data.component.id] = R3.Event.Subscribe( + data.component.eventId, + data.component.instance + ); +}; + +R3.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 + */ +R3.System.CustomCode.prototype.stop = function() { + + R3.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; + } + + if (this.eventIdUpdateSubscription) { + this.eventIdUpdateSubscription.remove(); + this.eventIdUpdateSubscription = null; + } + + Object.keys(this.subscriptions).map( + function(componentId) { + if (this.subscriptions[componentId]) { + this.subscriptions[componentId].remove(); + delete this.subscriptions[componentId]; + } + }.bind(this) + ); + +}; + diff --git a/src/r3-system-gui.js b/src/r3-system-gui.js new file mode 100644 index 0000000..6961912 --- /dev/null +++ b/src/r3-system-gui.js @@ -0,0 +1,2311 @@ +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem R3.API.System + * @constructor + */ +R3.System.GUI = function( + apiSystem +) { + R3.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.faces = []; + + this.exclusiveMode = false; + + this.buildGUISubscription = null; + + this.meshDeletedSubscription = null; + + this.meshSelectedSubscription = null; + + this.meshDeselectedSubscription = null; + + this.newEntitySubscription = null; + + this.meshSelectionObjects = {}; + + this.sourceChangedSubscription = null; + + this.instanceCreatedSubscription = null; + + this.removeComponentSubscription = null; + + this.windowResizeSubscription = null; + + this.meshFaceSelectedSubscription = null; + + this.meshFaceDeselectedSubscription = null; + +}; + +R3.System.GUI.prototype = Object.create(R3.System.prototype); +R3.System.GUI.prototype.constructor = R3.System.GUI; + +R3.System.GUI.prototype.windowResize = function(data) { + this.guis.map( + function(gui) { + gui.instance.domElement.getElementsByTagName('ul')[0].style.maxHeight = data.height - 93 + 'px'; + } + ); +}; + +R3.System.GUI.prototype.initialize = function(gui) { + + var length = this.guis.length; + + gui.instance.domElement.style.position = 'absolute'; + gui.instance.domElement.style.top = length * 34 + 'px'; + gui.instance.domElement.style.right = '0px'; + + gui.domElement.instance.parentElement.appendChild(gui.instance.domElement); + + gui.instance.domElement.getElementsByTagName('ul')[0].style.maxHeight = window.screen.availHeight - 93 + 'px'; +}; + +R3.System.GUI.prototype.instanceCreated = function(data) { + if (data.component instanceof R3.GUI) { + R3.Utils.PushUnique(this.guis, data.component); + this.initialize(data.component); + } +}; + +R3.System.GUI.prototype.removeComponent = function(data) { + + if (data.component instanceof R3.GUI) { + var index = this.guis.indexOf(data.component); + + if (index === -1) { + console.warn('gui system out of sync'); + } else { + var gui = this.guis[index]; + + gui.domElement.instance.parentElement.removeChild(gui.instance.domElement); + + this.guis.splice(index, 1); + } + } + +}; + +R3.System.GUI.prototype.start = function() { + + R3.System.prototype.start.call(this); + + this.instanceCreatedSubscription = R3.Event.Subscribe( + R3.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + this.removeComponentSubscription = R3.Event.Subscribe( + R3.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + this.windowResizeSubscription = R3.Event.Subscribe( + R3.Event.WINDOW_RESIZE, + this.windowResize.bind(this) + ); + + this.meshFaceSelectedSubscription = R3.Event.Subscribe( + R3.Event.MESH_FACE_SELECTED, + this.meshFaceSelected.bind(this) + ); + + this.meshFaceDeselectedSubscription = R3.Event.Subscribe( + R3.Event.MESH_FACE_DESELECTED, + this.meshFaceDeselected.bind(this) + ); + + this.guis = R3.EntityManager.Instance.queryComponents(R3.Component.GUI); + this.guis.map( + function(gui){ + this.initialize(gui); + }.bind(this) + ); + + /** + * 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.buildGUISubscription = this.subscribe( + R3.Event.BUILD_GUI, + this.buildGUI + ); + + this.meshDeletedSubscription = this.subscribe( + R3.Event.REMOVE_MESH, + this.meshDeleted + ); + + this.meshSelectedSubscription = this.subscribe( + R3.Event.MESH_SELECTED, + this.meshSelected + ); + + this.meshDeselectedSubscription = this.subscribe( + R3.Event.MESH_DESELECTED, + this.meshDeslected + ); + + this.componentRemovedSubscription = this.subscribe( + R3.Event.REMOVE_COMPONENT, + this.removeComponent + ); + + this.sourceChangedSubscription = this.subscribe( + R3.Event.CAST_SOURCE_CHANGED, + this.castSourceChanged + ); + + this.destinationChangedSubscription = this.subscribe( + R3.Event.RECEIVE_DESTINATION_CHANGED, + this.receiveDestinationChanged + ); + +}; + +R3.System.GUI.prototype.onChange = function(property, subProperty, affected) { + return function(value) { + affected.map(function(component){ + + component[property][subProperty] = value; + + if (component instanceof R3.D3.Mesh && property === 'rotation') { + component.useQuaternion = false; + } + + if (component instanceof R3.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); + } + + }); + } +}; + +R3.System.GUI.prototype.controller = function(folder, object, property, subProperty, step, listen, affected, min, max) { + + if (R3.Utils.UndefinedOrNull(min)) { + min = -1000; + } + + if (R3.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' || + property === 'position' + ) { + min = -100; + max = 100; + step = 0.0001; + } + + if ( + property === 'scale' + ) { + min = -10; + max = 10; + step = 0.001; + } + + if ( + property === 'rotation' + ) { + min = -Math.PI * 2; + max = Math.PI * 2; + step = 0.0001; + } + + if ( + property === 'mapSize' + ) { + min = 16; + max = 4096; + step = 16; + } + + 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; +}; + +R3.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'); + }) + } + ); + +}; + +R3.System.GUI.prototype.buildVectorControl = function(folder, componentTemplate, property) { + + var step = 0.001; + + 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 (R3.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 ( + R3.Utils.isVector3(object[property]) || + R3.Utils.isVector4(object[property]) + ) { + controllers.push(this.controller(folder, object, property, 'z', step, listen, affected)); + } + +}; + +/** + * Builds a Parent Selection control + * @param folder + * @param componentTemplate + * @param property + */ +R3.System.GUI.prototype.buildParentSelectionControl = function(folder, componentTemplate, property) { + + var type = R3.Utils.UpperCaseUnderscore(property.replace('parent','')); + + var componentType = R3.Component[type]; + + var constructor = R3.Component.GetComponentConstructor(componentType); + + var options = R3.EntityManager.Instance.queryComponentsByConstructor(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 = R3.EntityManager.Instance.findComponentById(value); + } + + affected.map( + function(component) { + + component[property] = newComponent; + component.updateInstance(property); + + if (property === 'parentPhysicsWorld') { + R3.Event.Emit( + R3.Event.PARENT_WORLD_CHANGE, + { + originalWorld : this.initialValue, + newWorld : newComponent, + object : component + } + ) + } + + if (property === 'parentScene') { + R3.Event.Emit( + R3.Event.PARENT_SCENE_CHANGE, + { + originalScene: this.initialValue, + newScene: newComponent, + object: component + } + ); + } + + }.bind(this) + ); + + if (property === 'parentEntity') { + R3.Event.Emit( + R3.Event.BUILD_GUI, + null + ); + } + + this.initialValue = newComponent; + } + ); +}; + +R3.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); + component.updateInstance(property); + folder.remove(controller); + }); + } + }, + 'remove' + ).name('remove ' + property + '[' + index + '] - ' + name); + + folder.updateDisplay(); + }; + + array.map(addArrayItem); + + var idObject = {}; + + var selectionObject = R3.EntityManager.Instance.queryComponentsByConstructor(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); + + R3.Event.Emit( + R3.Event.ARRAY_ITEM_ADDED, + { + component : component, + property : property, + item : activeSelection.component + } + ); + + component.updateInstance(property, activeSelection.component); + + // addArrayItem(activeSelection.component, component[property].length - 1); + //} + }); + + R3.Event.Emit( + R3.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); + +}; + +/** + * This is only for uvs right now + */ +R3.System.GUI.prototype.buildUVManagerControl = function( + folder, + componentTemplate, + property +) { + + var object = componentTemplate.template; + + var array = object[property]; + + array.map( + function(uvs, uvSet) { + /** + * uvs should be an array of three vector2's + */ + uvs.map( + function(uv, uvIndex) { + + var onChange = function(__uvSet, __uvIndex, __property) { + return function(value) { + componentTemplate.affected.map( + function (component) { + component.uvs[__uvSet][__uvIndex][__property] = value; + component.updateInstance('uvs', __uvSet, __uvIndex); + } + ); + } + }; + + folder.add(uv, 'x').name('uvs[' + uvSet + '][' + uvIndex +'].x').onChange(onChange(uvSet, uvIndex, 'x')).listen(); + folder.add(uv, 'y').name('uvs[' + uvSet + '][' + uvIndex +'].y').onChange(onChange(uvSet, uvIndex, 'y')).listen(); + } + ) + + } + ); + + +}; + +R3.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); + } + ) + } + ) + +}; + +R3.System.GUI.prototype.buildObjectControl = function(folder, componentTemplate, property) { + + var object = componentTemplate.template[property]; + + if (object === null) { + return; + } + + if ( + property === 'sourceProperties' || + property === 'destinationProperties' + ) { + Object.keys(object).map( + function(propertyId) { + folder.add( + object, + propertyId + ).name(property + '.' + propertyId).listen().onChange( + function(value) { + componentTemplate.affected.map( + function(component){ + component[property][propertyId] = value; + component.updateInstance(property); + } + ); + } + ); + } + ); + } +}; + +R3.System.GUI.prototype.buildSelectControl = function(folder, componentTemplate, property) { + + /** + * We need to discover the constructor for this component + */ + var constructors = null; + + if (componentTemplate.template.linkedObjects && componentTemplate.template.linkedObjects[property]) { + constructors = componentTemplate.template.linkedObjects[property]; + } else { + if (componentTemplate.template[property]) { + constructors = componentTemplate.template[property].constructor; + } + } + + if (!constructors) { + console.log('cannot determine constructor'); + return; + } + + var object = componentTemplate.template; + + var objects = R3.EntityManager.Instance.queryComponentsByConstructor(constructors); + + 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; + } + ); +}; + +R3.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 ( + R3.Utils.isString(object[property]) || + R3.Utils.isBoolean(object[property]) + ) { + controllers.push(folder.add(object, property)); + } + + if (R3.Utils.isNumber(object[property])) { + + var grain = 0.001; + + if (object.grain) { + grain = object.grain; + } + + if (property === 'componentType') { + + var readOnly = { + componentType : R3.Component.GetComponentInfo(object[property]).name + }; + + controllers.push( + folder.add( + readOnly, + 'componentType' + ) + ); + } else if (property === 'systemType') { + controllers.push( + folder.add( + object, + property, + { + 'animation' : R3.System.SYSTEM_TYPE_ANIMATION, + 'gui' : R3.System.SYSTEM_TYPE_GUI, + 'input' : R3.System.SYSTEM_TYPE_INPUT, + 'render' : R3.System.SYSTEM_TYPE_RENDER, + 'storage' : R3.System.SYSTEM_TYPE_STORAGE, + 'linking' : R3.System.SYSTEM_TYPE_LINKING, + 'physics' : R3.System.SYSTEM_TYPE_PHYSICS, + 'custom code' : R3.System.SYSTEM_TYPE_CUSTOM + } + ) + ); + } else if (property === 'controlsType') { + controllers.push( + folder.add( + object, + property, + { + 'touch' : R3.API.Controls.CONTROLS_TYPE_TOUCH, + 'mouse' : R3.API.Controls.CONTROLS_TYPE_MOUSE, + 'keyboard' : R3.API.Controls.CONTROLS_TYPE_KEYBOARD, + 'editor' : R3.API.Controls.CONTROLS_TYPE_EDITOR + } + ) + ); + } else if (property === 'stereoMode') { + controllers.push( + folder.add( + object, + property, + { + 'stereo' : R3.D3.API.Camera.Stereo.STEREO_MODE_STEREO, + 'anaglyph' : R3.D3.API.Camera.Stereo.STEREO_MODE_ANAGLYPH, + 'parallax' : R3.D3.API.Camera.Stereo.STEREO_MODE_PARALLAX + } + ) + ); + } else if (property === 'aspectRatioMode') { + controllers.push( + folder.add( + object, + property, + { + 'none' : R3.D3.API.Camera.Orthographic.ASPECT_RATIO_MODE_NONE, + 'fixed' : R3.D3.API.Camera.Orthographic.ASPECT_RATIO_MODE_FIXED, + 'based on current' : R3.D3.API.Camera.Orthographic.ASPECT_RATIO_MODE_BASED_ON_CURRENT + } + ) + ); + } else if (property === 'socketType') { + controllers.push( + folder.add( + object, + property, + { + 'none' : R3.API.Socket.TYPE_NONE, + 'cast' : R3.API.Socket.TYPE_CAST, + 'receive' : R3.API.Socket.TYPE_RECEIVE + } + ) + ); + } else if (property === 'castType') { + controllers.push( + folder.add( + object, + property, + { + 'room': R3.API.Socket.Cast.CAST_TYPE_ROOM, + 'peer': R3.API.Socket.Cast.CAST_TYPE_PEER , + 'all': R3.API.Socket.Cast.CAST_TYPE_ALL, + 'all but peer': R3.API.Socket.Cast.CAST_TYPE_ALL_BUT_PEER + } + ) + ); + } else if (property === 'receiveType') { + controllers.push( + folder.add( + object, + property, + { + 'room': R3.API.Socket.Receive.RECEIVE_TYPE_ROOM, + 'peer': R3.API.Socket.Cast.RECEIVE_TYPE_PEER + } + ) + ); + } else if (property === 'renderMode') { + controllers.push( + folder.add( + object, + property, + { + 'canvas': R3.API.Renderer.MODE_CANVAS, + 'target': R3.API.Renderer.MODE_TARGET, + 'canvas and target': R3.API.Renderer.MODE_CANVAS_AND_TARGET + } + ) + ); + } else if (property === 'drawMode') { + controllers.push( + folder.add( + object, + property, + { + 'triangles' : R3.D3.API.Mesh.DRAW_MODE_TRIANGLES, + 'triangle strip' : R3.D3.API.Mesh.DRAW_MODE_TRIANGLE_STRIP, + 'triangle fan' : R3.D3.API.Mesh.DRAW_MODE_TRIANGLE_FAN + } + ) + ); + } else if (property === 'shadowType') { + controllers.push( + folder.add( + object, + property, + { + 'directional': R3.D3.API.Shadow.SHADOW_TYPE_DIRECTIONAL, + 'spot': R3.D3.API.Shadow.SHADOW_TYPE_SPOT + } + ) + ); + } else if (property === 'shadowMapType') { + controllers.push( + folder.add( + object, + property, + { + 'basic': R3.API.Renderer.SHADOW_MAP_TYPE_BASIC, + 'pcf': R3.API.Renderer.SHADOW_MAP_TYPE_PCF, + 'pcf soft': R3.API.Renderer.SHADOW_MAP_TYPE_PCF_SOFT + } + ) + ); + } else if (property === 'toneMapping') { + controllers.push( + folder.add( + object, + property, + { + 'linear': R3.API.Renderer.TONE_MAPPING_LINEAR, + 'reinhard': R3.API.Renderer.TONE_MAPPING_REINHARD, + 'uncharted 2': R3.API.Renderer.TONE_MAPPING_UNCHARTED_2, + 'cineon': R3.API.Renderer.TONE_MAPPING_CINEON + } + ) + ); + } else if (property === 'opacityType') { + controllers.push( + folder.add( + object, + property, + { + 'constant': R3.D3.API.Particle.OPACITY_TYPE_CONSTANT, + 'fade out': R3.D3.API.Particle.OPACITY_TYPE_FADE_OUT_LINEAR, + 'fade in': R3.D3.API.Particle.OPACITY_TYPE_FADE_IN_LINEAR, + 'fade in / out': R3.D3.API.Particle.OPACITY_TYPE_FADE_IN_OUT_LINEAR + } + ) + ); + } else if (property === 'positionOffsetType') { + controllers.push( + folder.add( + object, + property, + { + 'constant': R3.D3.API.Particle.POSITION_OFFSET_TYPE_CONSTANT, + 'random': R3.D3.API.Particle.POSITION_OFFSET_TYPE_RANDOM, + 'function': R3.D3.API.Particle.POSITION_OFFSET_TYPE_FUNCTION + } + ) + ); + } else if (property === 'directionType') { + controllers.push( + folder.add( + object, + property, + { + 'constant': R3.D3.API.Particle.DIRECTION_TYPE_CONSTANT, + 'random': R3.D3.API.Particle.DIRECTION_TYPE_RANDOM, + 'random normalized': R3.D3.API.Particle.DIRECTION_TYPE_RANDOM_NORMALIZED, + 'function': R3.D3.API.Particle.DIRECTION_TYPE_FUNCTION + } + ) + ); + } else if (property === 'speedType') { + controllers.push( + folder.add( + object, + property, + { + 'constant': R3.D3.API.Particle.SPEED_TYPE_CONSTANT, + 'linear': R3.D3.API.Particle.SPEED_TYPE_LINEAR, + 'exponential': R3.D3.API.Particle.SPEED_TYPE_EXPONENTIAL, + 'logarithmic': R3.D3.API.Particle.SPEED_TYPE_LOGARITHMIC, + '1 / log': R3.D3.API.Particle.SPEED_TYPE_ONE_OVER_LOG, + 'exp' : R3.D3.API.Particle.SPEED_TYPE_EXP, + '1 / exp' : R3.D3.API.Particle.SPEED_TYPE_ONE_OVER_EXP + } + ) + ); + } else if (property === 'scaleType') { + controllers.push( + folder.add( + object, + property, + { + 'constant': R3.D3.API.Particle.SCALE_TYPE_CONSTANT, + 'linear': R3.D3.API.Particle.SCALE_TYPE_LINEAR, + 'exponential': R3.D3.API.Particle.SCALE_TYPE_EXPONENTIAL, + 'random': R3.D3.API.Particle.SCALE_TYPE_RANDOM, + 'random (x = y)': R3.D3.API.Particle.SCALE_TYPE_RANDOM_X_EQUALS_Y, + 'function': R3.D3.API.Particle.SCALE_TYPE_FUNCTION + } + ) + ); + } else if (property === 'rotationType') { + controllers.push( + folder.add( + object, + property, + { + 'constant': R3.D3.API.Particle.ROTATION_TYPE_CONSTANT, + 'random': R3.D3.API.Particle.ROTATION_TYPE_RANDOM, + 'random - x': R3.D3.API.Particle.ROTATION_TYPE_RANDOM_X, + 'random - y': R3.D3.API.Particle.ROTATION_TYPE_RANDOM_Y, + 'random - z': R3.D3.API.Particle.ROTATION_TYPE_RANDOM_Z, + 'function': R3.D3.API.Particle.ROTATION_TYPE_FUNCTION + } + ) + ); + } else if (property === 'broadphaseType') { + controllers.push( + folder.add( + object, + property, + { + 'naive': R3.D3.Broadphase.BROADPHASE_TYPE_NAIVE, + 'grid': R3.D3.Broadphase.BROADPHASE_TYPE_GRID, + 'sap': R3.D3.Broadphase.BROADPHASE_TYPE_SAP + } + ) + ); + } else if (property === 'solverType') { + controllers.push( + folder.add( + object, + property, + { + 'gs': R3.D3.API.Solver.GS_SOLVER, + 'split': R3.D3.API.Solver.SPLIT_SOLVER + } + ) + ); + } else if (property === 'meshType') { + controllers.push( + folder.add( + object, + property, + { + 'normal' : R3.D3.API.Object.OBJECT_TYPE_MESH, + 'curve' : R3.D3.API.Object.OBJECT_TYPE_MESH_CURVE, + 'skinned' : R3.D3.API.Object.OBJECT_TYPE_MESH_SKINNED, + 'plane' : R3.D3.API.Object.OBJECT_TYPE_MESH_PLANE, + 'sphere' : R3.D3.API.Object.OBJECT_TYPE_MESH_SPHERE, + 'box' : R3.D3.API.Object.OBJECT_TYPE_MESH_BOX, + 'cylinder' : R3.D3.API.Object.OBJECT_TYPE_MESH_CYLINDER, + 'text' : R3.D3.API.Object.OBJECT_TYPE_MESH_TEXT + } + ) + ); + } else if (property === 'cameraType') { + controllers.push( + folder.add( + object, + property, + { + 'perspective' : R3.D3.API.Object.OBJECT_TYPE_CAMERA_PERSPECTIVE, + 'orthographic' : R3.D3.API.Object.OBJECT_TYPE_CAMERA_ORTHOGRAPHIC, + 'stereo' : R3.D3.API.Object.OBJECT_TYPE_CAMERA_STEREO, + 'cube' : R3.D3.API.Object.OBJECT_TYPE_CAMERA_CUBE + } + ) + ); + } else if (property === 'passType') { + controllers.push( + folder.add( + object, + property, + { + 'ssao': R3.D3.API.Pass.PASS_TYPE_SSAO, + 'bloom': R3.D3.API.Pass.PASS_TYPE_BLOOM, + 'fxaa': R3.D3.API.Pass.PASS_TYPE_FXAA, + 'render': R3.D3.API.Pass.PASS_TYPE_RENDER + } + ) + ); + } else if (property === 'rendererType') { + controllers.push( + folder.add( + object, + property, + { + '2D': R3.API.Renderer.RENDERER_TYPE_2D, + '3D': R3.API.Renderer.RENDERER_TYPE_3D + } + ) + ); + } else if (property === 'materialType') { + controllers.push( + folder.add( + object, + property, + { + 'standard': R3.D3.API.Material.MATERIAL_TYPE_STANDARD, + 'basic': R3.D3.API.Material.MATERIAL_TYPE_BASIC, + 'phong': R3.D3.API.Material.MATERIAL_TYPE_PHONG, + 'shader': R3.D3.API.Material.MATERIAL_TYPE_SHADER, + 'raw shader': R3.D3.API.Material.MATERIAL_TYPE_SHADER_RAW, + 'points': R3.D3.API.Material.MATERIAL_TYPE_POINTS + // 'toon': R3.D3.API.Material.MATERIAL_TYPE_TOON, + // 'line basic' : R3.D3.API.Material.MATERIAL_TYPE_LINE_BASIC + } + ) + ); + } else if (property === 'side') { + controllers.push( + folder.add( + object, + property, + { + 'double': R3.D3.API.Material.TYPE_DOUBLE_SIDE, + 'front': R3.D3.API.Material.TYPE_FRONT_SIDE, + 'back': R3.D3.API.Material.TYPE_BACK_SIDE + } + ) + ); + } else if (property === 'combine') { + controllers.push( + folder.add( + object, + property, + { + 'multiply': R3.D3.API.Material.COMBINE_MULTIPLY_OPERATION, + 'mix': R3.D3.API.Material.COMBINE_MIX_OPERATION, + 'add': R3.D3.API.Material.COMBINE_ADD_OPERATION + } + ) + ); + } else if (property === 'vertexColors') { + controllers.push( + folder.add( + object, + property, + { + 'none': R3.D3.API.Material.TYPE_NO_COLORS, + 'face': R3.D3.API.Material.TYPE_FACE_COLORS, + 'vertex': R3.D3.API.Material.TYPE_VERTEX_COLORS + } + ) + ); + } else if (property === 'blending') { + controllers.push( + folder.add( + object, + property, + { + 'none': R3.D3.API.Material.TYPE_NO_BLENDING, + 'normal': R3.D3.API.Material.TYPE_NORMAL_BLENDING, + 'additive': R3.D3.API.Material.TYPE_ADDITIVE_BLENDING, + 'subtractive': R3.D3.API.Material.TYPE_SUBTRACTIVE_BLENDING, + 'multiply': R3.D3.API.Material.TYPE_MULTIPLY_BLENDING, + 'custom': R3.D3.API.Material.TYPE_CUSTOM_BLENDING + } + ) + ); + } else if (property === 'blendSrc') { + controllers.push( + folder.add( + object, + property, + { + 'zero': R3.D3.API.Material.TYPE_ZERO_FACTOR, + 'one': R3.D3.API.Material.TYPE_ONE_FACTOR, + 'source color': R3.D3.API.Material.TYPE_SRC_COLOR_FACTOR, + 'one minus source color': R3.D3.API.Material.TYPE_ONE_MINUS_SRC_COLOR_FACTOR, + 'source alpha': R3.D3.API.Material.TYPE_SRC_ALPHA_FACTOR, + 'one minus source alpha': R3.D3.API.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR, + 'destination alpha': R3.D3.API.Material.TYPE_DST_ALPHA_FACTOR, + 'one minus destination alpha': R3.D3.API.Material.TYPE_ONE_MINUS_DST_ALPHA_FACTOR, + 'destination color': R3.D3.API.Material.TYPE_DST_COLOR_FACTOR, + 'one minus destination color': R3.D3.API.Material.TYPE_ONE_MINUS_DST_COLOR_FACTOR, + 'source alpha saturate': R3.D3.API.Material.TYPE_SRC_ALPHA_SATURATE_FACTOR + } + ) + ); + } else if (property === 'blendDst') { + controllers.push( + folder.add( + object, + property, + { + 'zero': R3.D3.API.Material.TYPE_ZERO_FACTOR, + 'one': R3.D3.API.Material.TYPE_ONE_FACTOR, + 'source color': R3.D3.API.Material.TYPE_SRC_COLOR_FACTOR, + 'one minus source color': R3.D3.API.Material.TYPE_ONE_MINUS_SRC_COLOR_FACTOR, + 'source alpha': R3.D3.API.Material.TYPE_SRC_ALPHA_FACTOR, + 'one minus source alpha': R3.D3.API.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR, + 'destination alpha': R3.D3.API.Material.TYPE_DST_ALPHA_FACTOR, + 'one minus destination alpha': R3.D3.API.Material.TYPE_ONE_MINUS_DST_ALPHA_FACTOR, + 'destination color': R3.D3.API.Material.TYPE_DST_COLOR_FACTOR, + 'one minus destination color': R3.D3.API.Material.TYPE_ONE_MINUS_DST_COLOR_FACTOR, + 'source alpha saturate': R3.D3.API.Material.TYPE_SRC_ALPHA_SATURATE_FACTOR + } + ) + ); + } else if (property === 'blendEquation') { + controllers.push( + folder.add( + object, + property, + { + 'add': R3.D3.API.Material.TYPE_ADD_EQUATION, + 'subtract': R3.D3.API.Material.TYPE_SUBTRACT_EQUATION, + 'reverse subtract': R3.D3.API.Material.TYPE_REVERSE_SUBTRACT_EQUATION, + 'min': R3.D3.API.Material.TYPE_MIN_EQUATION, + 'max': R3.D3.API.Material.TYPE_MAX_EQUATION + } + ) + ); + } else if (property === 'depthFunc') { + controllers.push( + folder.add( + object, + property, + { + 'never': R3.D3.API.Material.TYPE_NEVER_DEPTH, + 'always': R3.D3.API.Material.TYPE_ALWAYS_DEPTH, + 'less depth': R3.D3.API.Material.TYPE_LESS_DEPTH, + 'less equal depth': R3.D3.API.Material.TYPE_LESS_EQUAL_DEPTH, + 'equal depth': R3.D3.API.Material.TYPE_EQUAL_DEPTH, + 'greated equal depth': R3.D3.API.Material.TYPE_GREATER_EQUAL_DEPTH, + 'greated depth': R3.D3.API.Material.TYPE_GREATER_DEPTH, + 'not equal depth': R3.D3.API.Material.TYPE_NOT_EQUAL_DEPTH + } + ) + ); + } else if (property === 'wrapS') { + controllers.push( + folder.add( + object, + property, + { + 'repeat': R3.D3.API.Texture.TYPE_REPEAT_WRAPPING, + 'clamp': R3.D3.API.Texture.TYPE_CLAMP_TO_EDGE_WRAPPING, + 'mirrored repeat': R3.D3.API.Texture.TYPE_MIRRORED_REPEAT_WRAPPING + } + ) + ); + } else if (property === 'wrapT') { + controllers.push( + folder.add( + object, + property, + { + 'repeat': R3.D3.API.Texture.TYPE_REPEAT_WRAPPING, + 'clamp': R3.D3.API.Texture.TYPE_CLAMP_TO_EDGE_WRAPPING, + 'mirrored repeat': R3.D3.API.Texture.TYPE_MIRRORED_REPEAT_WRAPPING + } + ) + ); + } else if (property === 'format') { + controllers.push( + folder.add( + object, + property, + { + 'alpha': R3.D3.API.Texture.TYPE_ALPHA_FORMAT, + 'rgb': R3.D3.API.Texture.TYPE_RGB_FORMAT, + 'rgba': R3.D3.API.Texture.TYPE_RGBA_FORMAT, + 'luminance': R3.D3.API.Texture.TYPE_LUMINANCE_FORMAT, + 'luminance alpha': R3.D3.API.Texture.TYPE_LUMINANCE_ALPHA_FORMAT, + 'depth': R3.D3.API.Texture.TYPE_DEPTH_FORMAT + } + ) + ); + } else if (property === 'mapping') { + controllers.push( + folder.add( + object, + property, + { + 'uv': R3.D3.API.Texture.TYPE_UV_MAPPING, + 'cube reflection': R3.D3.API.Texture.TYPE_CUBE_REFLECTION_MAPPING, + 'cube refraction': R3.D3.API.Texture.TYPE_CUBE_REFRACTION_MAPPING, + 'equi rectangular reflection': R3.D3.API.Texture.TYPE_EQUI_RECTANGULAR_REFLECTION_MAPPING, + 'equi rectangular refraction': R3.D3.API.Texture.TYPE_EQUI_RECTANGULAR_REFRACTION_MAPPING, + 'spherical reflection': R3.D3.API.Texture.TYPE_SPHERICAL_REFLECTION_MAPPING, + 'cube uv reflection': R3.D3.API.Texture.TYPE_CUBE_UV_REFLECTION_MAPPING, + 'cube uv refraction': R3.D3.API.Texture.TYPE_CUBE_UV_REFRACTION_MAPPING + } + ) + ); + } else if (property === 'magFilter') { + controllers.push( + folder.add( + object, + property, + { + 'nearest': R3.D3.API.Texture.TYPE_NEAREST_FILTER, + 'nearest mipmap nearest': R3.D3.API.Texture.TYPE_NEAREST_MIPMAP_NEAREST_FILTER, + 'nearest mipmap linear': R3.D3.API.Texture.TYPE_NEAREST_MIPMAP_LINEAR_FILTER, + 'linear': R3.D3.API.Texture.TYPE_LINEAR_FILTER, + 'linear mipmap nearest': R3.D3.API.Texture.TYPE_LINEAR_MIPMAP_NEAREST_FILTER, + 'linear mipmap linear': R3.D3.API.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER + } + ) + ); + } else if (property === 'minFilter') { + controllers.push( + folder.add( + object, + property, + { + 'nearest': R3.D3.API.Texture.TYPE_NEAREST_FILTER, + 'nearest mipmap nearest': R3.D3.API.Texture.TYPE_NEAREST_MIPMAP_NEAREST_FILTER, + 'nearest mipmap linear': R3.D3.API.Texture.TYPE_NEAREST_MIPMAP_LINEAR_FILTER, + 'linear': R3.D3.API.Texture.TYPE_LINEAR_FILTER, + 'linear mipmap nearest': R3.D3.API.Texture.TYPE_LINEAR_MIPMAP_NEAREST_FILTER, + 'linear mipmap linear': R3.D3.API.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER + } + ) + ); + } else if (property === 'textureType') { + controllers.push( + folder.add( + object, + property, + { + 'normal': R3.D3.API.Texture.TEXTURE_TYPE_NONE, + 'image': R3.D3.API.Texture.TEXTURE_TYPE_IMAGE, + 'cube': R3.D3.API.Texture.TEXTURE_TYPE_CUBE, + 'canvas': R3.D3.API.Texture.TEXTURE_TYPE_CANVAS + } + ) + ); + } else if (property === 'storageType') { + controllers.push( + folder.add( + object, + property, + { + 'unsigned byte': R3.D3.API.Texture.TYPE_UNSIGNED_BYTE, + 'byte': R3.D3.API.Texture.TYPE_BYTE, + 'short': R3.D3.API.Texture.TYPE_SHORT, + 'unsigned short': R3.D3.API.Texture.TYPE_UNSIGNED_SHORT, + 'int': R3.D3.API.Texture.TYPE_INT, + 'unsigned int': R3.D3.API.Texture.TYPE_UNSIGNED_INT, + 'float': R3.D3.API.Texture.TYPE_FLOAT, + 'half float': R3.D3.API.Texture.TYPE_HALF_FLOAT + } + ) + ); + } else if (property === 'aspectRatio') { + controllers.push( + folder.add( + object, + property, + { + 'none': R3.API.Renderer.ASPECT_RATIO_NONE, + '4:3 (1.3333)': R3.API.Renderer.ASPECT_RATIO_4_3, + '3:2 (1.5)': R3.API.Renderer.ASPECT_RATIO_3_2, + '16:10 (1.6667)': R3.API.Renderer.ASPECT_RATIO_16_10, + '17:10 (1.7)': R3.API.Renderer.ASPECT_RATIO_17_10, + '16:9 (1.7778)': R3.API.Renderer.ASPECT_RATIO_16_9 + } + ) + ); + } else if (property === 'scaleMode') { + controllers.push( + folder.add( + object, + property, + { + 'none': R3.API.Renderer.SCALE_MODE_NONE, + 'letterbox': R3.API.Renderer.SCALE_MODE_LETTERBOX, + 'zoom-bigger': R3.API.Renderer.SCALE_MODE_ZOOM_TO_BIGGER, + 'non-uniform': R3.API.Renderer.SCALE_MODE_NON_UNIFORM + } + ) + ); + } else if (property === 'encoding') { + controllers.push( + folder.add( + object, + property, + { + 'linear': R3.D3.API.Texture.TYPE_LINEAR_ENCODING, + 'srgb': R3.D3.API.Texture.TYPE_SRGB_ENCODING, + 'gamma': R3.D3.API.Texture.TYPE_GAMMA_ENCODING, + 'rgbe': R3.D3.API.Texture.TYPE_RGBE_ENCODING, + 'log luv': R3.D3.API.Texture.TYPE_LOG_LUV_ENCODING, + 'rgbm7': R3.D3.API.Texture.TYPE_RGBM7_ENCODING, + 'rgbm16': R3.D3.API.Texture.TYPE_RGBM16_ENCODING, + 'rgbd': R3.D3.API.Texture.TYPE_RGBD_ENCODING + } + ) + ); + } else if (property === 'lightType') { + controllers.push( + folder.add( + object, + property, + { + 'ambient': R3.D3.API.Light.LIGHT_TYPE_AMBIENT, + 'directional': R3.D3.API.Light.LIGHT_TYPE_DIRECTIONAL, + 'spot': R3.D3.API.Light.LIGHT_TYPE_SPOT, + 'point': R3.D3.API.Light.LIGHT_TYPE_POINT, + 'hemisphere': R3.D3.API.Light.LIGHT_TYPE_HEMISPHERE, + 'rect area': R3.D3.API.Light.LIGHT_TYPE_RECT_AREA + } + ) + ); + } else if (property === 'eventId') { + + var options = {}; + + for (var i = 0; i < 200; i++) { + try { + options[R3.Event.GetEventName(i)] = i; + } catch (error) { + + } + } + + controllers.push( + folder.add( + object, + property, + options + ) + ); + } else if (property === 'functionType') { + controllers.push( + folder.add( + object, + property, + { + 'rotation': R3.D3.Animation.ANIMATION_FUNCTION_TYPE_ROTATION, + 'translation': R3.D3.Animation.ANIMATION_FUNCTION_TYPE_TRANSLATION, + 'scale': R3.D3.Animation.ANIMATION_FUNCTION_TYPE_SCALE + } + ) + ); + } else { + + /** + * Try to guess a scale for this property + */ + if ( + property === 'opacity' || + property === 'fadeInFactor' || + property === 'fadeOutFactor' || + property === 'metalness' || + property === 'roughness' || + property === 'aoClamp' || + property === 'lumInfluence' || + property === 'volume' + ) { + controllers.push(folder.add(object, property, 0, 1.0, 0.001)); + } else if ( + property === 'cubeResolution' + ) { + controllers.push(folder.add(object, property, 16, 4096, 16)); + } 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 === 'lightMapIntensity' || + property === 'aoMapIntensity' || + property === 'envMapIntensity' || + 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' + ) { + controllers.push(folder.add(object, property, 0, 4096, 0.001)); + } else if ( + property === 'depth' || + property === 'radius' + ) { + + if (object instanceof R3.D3.Pass.Bloom) { + controllers.push(folder.add(object, property, -10, 10, 0.001)); + } else { + 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' || + property === 'speed' + ) { + controllers.push(folder.add(object, property, 0, 100, 0.01)); + } 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' || + property === 'bias' || + property === 'threshold' + ) { + controllers.push(folder.add(object, property, 0, 1, 0.0001)); + } else if ( + property === 'strength' || + property === 'power' + ) { + controllers.push(folder.add(object, property, 0, 25, 0.01)); + } else if ( + property === 'thetaLength' || + property === 'angle' + ) { + controllers.push(folder.add(object, property, -Math.PI * 2, Math.PI * 2, 0.01)); + } else if ( + property === 'port' || + property === 'far' + ) { + controllers.push(folder.add(object, property, 1, 65536, 1)); + } else if ( + property === 'eyeSep' + ) { + controllers.push(folder.add(object, property, -2, 2, 0.0001)); + } else if ( + property === 'arc' || + property === 'size' + ) { + controllers.push(folder.add(object, property, 0, 200, 0.001)); + } 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 + */ +R3.System.GUI.prototype.meshSelected = function(data) { + + if (this.exclusiveMode) { + R3.Utils.PushUnique(this.backupComponents, data.mesh); + } else { + R3.Utils.PushUnique(this.components, data.mesh); + } + +}; + +/** + * Same as selected above, but removes the mesh from the components + * @param data + */ +R3.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); + } + } + +}; + +R3.System.GUI.prototype.meshFaceSelected = function(data) { + + this.faces.push(data.face); + + this.buildGUI({ + components : this.faces + }) +}; + +R3.System.GUI.prototype.meshFaceDeselected = function(data) { + + var index = this.faces.indexOf(data.face); + + if (index !== -1) { + this.faces.splice(index, 1); + + if (this.faces.length === 0) { + this.buildGUI({}); + } else { + this.buildGUI({components : this.faces}) + } + + } else { + console.warn('could not remove face'); + } +}; + +/** + * 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 + */ +R3.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 R3.D3.Mesh); + } + ); + } + + /** + * Check if we have components to build a GUI for + */ + if (R3.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(); + + R3.Utils.PushUnique(result, component); + + components.map(function(component){ + R3.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) { + R3.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 R3.Vector2 || + result.template[property] instanceof R3.Vector3 || + result.template[property] instanceof R3.Vector4 || + result.template[property] instanceof R3.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 (R3.Utils.UndefinedOrNull(componentTemplate.template.name)) { + name = R3.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 R3.Vector2 || + componentTemplate.template[templateProperty] instanceof R3.Vector3 || + componentTemplate.template[templateProperty] instanceof R3.Vector4 + ) { + this.buildVectorControl(folder, componentTemplate, templateProperty); + continue; + } + + if (componentTemplate.template[templateProperty] instanceof R3.Quaternion) { + this.buildQuaternionControl(folder, componentTemplate, templateProperty); + } + + if ( + templateProperty.indexOf('parent') === 0 + ) { + + if (componentTemplate.template[templateProperty] instanceof Array) { + console.warn('read-only property :' + templateProperty); + } else { + this.buildParentSelectionControl(folder, componentTemplate, templateProperty); + } + + continue; + } + + if (componentTemplate.template[templateProperty] instanceof Array) { + + if ( + templateProperty === 'vertices' || + templateProperty === 'faces' + ) { + continue; + } + + if (templateProperty === 'uvs') { + this.buildUVManagerControl(folder, componentTemplate, templateProperty); + } + + if ( + componentTemplate.template.linkedObjects && + componentTemplate.template.linkedObjects[templateProperty] instanceof Array + ) { + this.buildArrayManagerControl(folder, componentTemplate, templateProperty); + } + + continue; + } + + if (componentTemplate.template[templateProperty] instanceof R3.Color) { + this.buildColorControl(folder, componentTemplate, templateProperty); + continue; + } + + if (typeof componentTemplate.template[templateProperty] === 'object') { + + if ( + componentTemplate.template[templateProperty] instanceof R3.Component || + ( + componentTemplate.template.linkedObjects && + componentTemplate.template.linkedObjects[templateProperty] + ) + ) { + this.buildSelectControl(folder, componentTemplate, templateProperty) + } else { + this.buildObjectControl(folder, componentTemplate, templateProperty); + } + continue; + } + + this.buildControl(folder, componentTemplate, templateProperty); + } + } + }.bind(this) + ); + }.bind(this)); + +}; + +R3.System.GUI.prototype.meshDeleted = function(data) { + + data.meshes.map(function(mesh){ + this.meshDeslected({ + mesh : mesh + }) + }.bind(this)); + + this.buildGUI(null); +}; + +R3.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); + } + +}; + +R3.System.GUI.prototype.castSourceChanged = function(data) { + this.buildGUI(null); +}; + +R3.System.GUI.prototype.receiveDestinationChanged = function(data) { + this.buildGUI(null); +}; + +R3.System.GUI.prototype.stop = function() { + + R3.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.sourceChangedSubscription.remove(); + + this.destinationChangedSubscription.remove(); + + this.instanceCreatedSubscription.remove(); + + this.removeComponentSubscription.remove(); + + this.windowResizeSubscription.remove(); + + this.meshFaceSelectedSubscription.remove(); + + this.meshFaceDeselectedSubscription.remove(); + + this.guis = []; +}; + diff --git a/src/r3-system-input.js b/src/r3-system-input.js new file mode 100644 index 0000000..ee1b38f --- /dev/null +++ b/src/r3-system-input.js @@ -0,0 +1,1793 @@ +/** + * System takes care of updating all the entities (based on their component data) + * @param graphics + * @param apiSystem R3.API.System + * @constructor + */ +R3.System.Input = function( + graphics, + apiSystem +) { + R3.System.call( + this, + apiSystem + ); + + this.selectAll = false; + + this.editMode = false; + + this.controlLeft = false; + + this.sensitivityCounter = 0; + + this.playAudio = true; + + this.editorControls = []; + this.orbitControls = []; + this.firstPersonControls = []; + this.touchControls = []; + this.keyboardControls = []; + this.mouseControls = []; + + /** + * Touch Controls + * @type {null} + */ + this.touchStart = this.onTouchStart.bind(this); + this.touchMove = this.onTouchMove.bind(this); + this.touchEnd = this.onTouchEnd.bind(this); + this.touchCancel = this.onTouchCancel.bind(this); + + /** + * Keyboard Controls + * @type {null} + */ + this.keyboardKeyUp = this.onKeyboardKeyUp.bind(this); + this.keyboardKeyDown = this.onKeyboardKeyDown.bind(this); + + /** + * Mouse Controls + * @type {null} + */ + this.mouseDown = this.onMouseDown.bind(this); + this.mouseMove = this.onMouseMove.bind(this); + this.mouseWheel = this.onMouseWheel.bind(this); + this.mouseUp = this.onMouseUp.bind(this); + + /** + * Editor Controls + * @type {null} + */ + this.keyDownEdit = this.onKeyDownEdit.bind(this); + this.keyUpEdit = this.onKeyUpEdit.bind(this); + this.mouseDownEdit = this.onMouseDownEdit.bind(this); + this.mouseMoveEdit = this.onMouseMoveEdit.bind(this); + this.mouseWheelEdit = this.onMouseWheelEdit.bind(this); + this.mouseUpEdit = this.onMouseUpEdit.bind(this); + + this.delayedInstanceEncounteredSubscription = null; + this.instanceCreatedSubscription = null; + this.removeComponentSubscription = null; + this.canvasChangeSubscription = null; + this.selectionModeChangeSubscription = null; + + this.selectionMode = R3.System.Input.SELECTION_MODE_DEFAULT; + + this.mouse = new R3.Mouse(); + this.raycaster = new R3.D3.Raycaster(graphics); +}; + +R3.System.Input.prototype = Object.create(R3.System.prototype); +R3.System.Input.prototype.constructor = R3.System.Input; + +R3.System.Input.SELECTION_MODE_MESH = 0x1; +R3.System.Input.SELECTION_MODE_FACE = 0x2; +R3.System.Input.SELECTION_MODE_DEFAULT = 0x1; + +R3.System.Input.KEY_CANCEL = 3; +R3.System.Input.KEY_HELP = 6; +R3.System.Input.KEY_BACK_SPACE = 8; +R3.System.Input.KEY_TAB = 9; +R3.System.Input.KEY_CLEAR = 12; +R3.System.Input.KEY_RETURN = 13; +R3.System.Input.KEY_ENTER = 14; +R3.System.Input.KEY_SHIFT = 16; +R3.System.Input.KEY_CONTROL = 17; +R3.System.Input.KEY_ALT = 18; +R3.System.Input.KEY_PAUSE = 19; +R3.System.Input.KEY_CAPS_LOCK = 20; +R3.System.Input.KEY_ESCAPE = 27; +R3.System.Input.KEY_SPACE = 32; +R3.System.Input.KEY_PAGE_UP = 33; +R3.System.Input.KEY_PAGE_DOWN = 34; +R3.System.Input.KEY_END = 35; +R3.System.Input.KEY_HOME = 36; +R3.System.Input.KEY_LEFT = 37; +R3.System.Input.KEY_UP = 38; +R3.System.Input.KEY_RIGHT = 39; +R3.System.Input.KEY_DOWN = 40; +R3.System.Input.KEY_PRINTSCREEN = 44; +R3.System.Input.KEY_INSERT = 45; +R3.System.Input.KEY_DELETE = 46; +R3.System.Input.KEY_0 = 48; +R3.System.Input.KEY_1 = 49; +R3.System.Input.KEY_2 = 50; +R3.System.Input.KEY_3 = 51; +R3.System.Input.KEY_4 = 52; +R3.System.Input.KEY_5 = 53; +R3.System.Input.KEY_6 = 54; +R3.System.Input.KEY_7 = 55; +R3.System.Input.KEY_8 = 56; +R3.System.Input.KEY_9 = 57; +R3.System.Input.KEY_SEMICOLON = 59; +R3.System.Input.KEY_EQUALS = 61; +R3.System.Input.KEY_A = 65; +R3.System.Input.KEY_B = 66; +R3.System.Input.KEY_C = 67; +R3.System.Input.KEY_D = 68; +R3.System.Input.KEY_E = 69; +R3.System.Input.KEY_F = 70; +R3.System.Input.KEY_G = 71; +R3.System.Input.KEY_H = 72; +R3.System.Input.KEY_I = 73; +R3.System.Input.KEY_J = 74; +R3.System.Input.KEY_K = 75; +R3.System.Input.KEY_L = 76; +R3.System.Input.KEY_M = 77; +R3.System.Input.KEY_N = 78; +R3.System.Input.KEY_O = 79; +R3.System.Input.KEY_P = 80; +R3.System.Input.KEY_Q = 81; +R3.System.Input.KEY_R = 82; +R3.System.Input.KEY_S = 83; +R3.System.Input.KEY_T = 84; +R3.System.Input.KEY_U = 85; +R3.System.Input.KEY_V = 86; +R3.System.Input.KEY_W = 87; +R3.System.Input.KEY_X = 88; +R3.System.Input.KEY_Y = 89; +R3.System.Input.KEY_Z = 90; +R3.System.Input.KEY_CONTEXT_MENU = 93; +R3.System.Input.KEY_NUMPAD0 = 96; +R3.System.Input.KEY_NUMPAD1 = 97; +R3.System.Input.KEY_NUMPAD2 = 98; +R3.System.Input.KEY_NUMPAD3 = 99; +R3.System.Input.KEY_NUMPAD4 = 100; +R3.System.Input.KEY_NUMPAD5 = 101; +R3.System.Input.KEY_NUMPAD6 = 102; +R3.System.Input.KEY_NUMPAD7 = 103; +R3.System.Input.KEY_NUMPAD8 = 104; +R3.System.Input.KEY_NUMPAD9 = 105; +R3.System.Input.KEY_MULTIPLY = 106; +R3.System.Input.KEY_ADD = 107; +R3.System.Input.KEY_SEPARATOR = 108; +R3.System.Input.KEY_SUBTRACT = 109; +R3.System.Input.KEY_DECIMAL = 110; +R3.System.Input.KEY_DIVIDE = 111; +R3.System.Input.KEY_F1 = 112; +R3.System.Input.KEY_F2 = 113; +R3.System.Input.KEY_F3 = 114; +R3.System.Input.KEY_F4 = 115; +R3.System.Input.KEY_F5 = 116; +R3.System.Input.KEY_F6 = 117; +R3.System.Input.KEY_F7 = 118; +R3.System.Input.KEY_F8 = 119; +R3.System.Input.KEY_F9 = 120; +R3.System.Input.KEY_F10 = 121; +R3.System.Input.KEY_F11 = 122; +R3.System.Input.KEY_F12 = 123; +R3.System.Input.KEY_F13 = 124; +R3.System.Input.KEY_F14 = 125; +R3.System.Input.KEY_F15 = 126; +R3.System.Input.KEY_F16 = 127; +R3.System.Input.KEY_F17 = 128; +R3.System.Input.KEY_F18 = 129; +R3.System.Input.KEY_F19 = 130; +R3.System.Input.KEY_F20 = 131; +R3.System.Input.KEY_F21 = 132; +R3.System.Input.KEY_F22 = 133; +R3.System.Input.KEY_F23 = 134; +R3.System.Input.KEY_F24 = 135; +R3.System.Input.KEY_NUM_LOCK = 144; +R3.System.Input.KEY_SCROLL_LOCK = 145; +R3.System.Input.KEY_COMMA = 188; +R3.System.Input.KEY_PERIOD = 190; +R3.System.Input.KEY_SLASH = 191; +R3.System.Input.KEY_BACK_QUOTE = 192; +R3.System.Input.KEY_OPEN_BRACKET = 219; +R3.System.Input.KEY_BACK_SLASH = 220; +R3.System.Input.KEY_CLOSE_BRACKET = 221; +R3.System.Input.KEY_QUOTE = 222; +R3.System.Input.KEY_META = 224; + +/** + * + */ +R3.System.Input.prototype.start = function() { + + R3.System.prototype.start.call(this); + + this.instanceCreatedSubscription = R3.Event.Subscribe( + R3.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + this.removeComponentSubscription = R3.Event.Subscribe( + R3.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + this.delayedInstanceEncounteredSubscription = R3.Event.Subscribe( + R3.Event.DELAYED_INSTANCE_ENCOUNTERED, + this.delayedInstanceEncountered.bind(this) + ); + + this.canvasChangeSubscription = R3.Event.Subscribe( + R3.Event.CANVAS_CHANGE, + this.canvasChange.bind(this) + ); + + this.beforeRenderSubscription = R3.Event.Subscribe( + R3.Event.BEFORE_RENDER, + this.beforeRender.bind(this) + ); + + this.selectionModeChangeSubscription = R3.Event.Subscribe( + R3.Event.SELECTION_MODE_CHANGE, + this.selectionModeChange.bind(this) + ); + + /** + * Normal Controls + */ + this.touchControls = R3.EntityManager.Instance.queryComponents(R3.Component.CONTROLS_TOUCH); + + this.keyboardControls = R3.EntityManager.Instance.queryComponents(R3.Component.CONTROLS_KEYBOARD); + + this.mouseControls = R3.EntityManager.Instance.queryComponents(R3.Component.CONTROLS_MOUSE); + + /** + * Edit Mode Controls + */ + this.editorControls = R3.EntityManager.Instance.queryComponents(R3.Component.CONTROLS_EDITOR); + + this.orbitControls = R3.EntityManager.Instance.queryComponents(R3.Component.CONTROLS_ORBIT); + + this.firstPersonControls = R3.EntityManager.Instance.queryComponents(R3.Component.CONTROLS_FIRST_PERSON); + + this.setMode(); +}; + +/** + * + */ +R3.System.Input.prototype.stop = function() { + + R3.System.prototype.stop.call(this); + + this.instanceCreatedSubscription.remove(); + + this.removeComponentSubscription.remove(); + + this.delayedInstanceEncounteredSubscription.remove(); + + this.canvasChangeSubscription.remove(); + + this.selectionModeChangeSubscription.remove(); + + this.beforeRenderSubscription.remove(); + + if (this.editMode) { + this.deRegisterEditModeControls(); + } else { + this.touchControls.map( + function(touchControl){ + this.deRegisterTouchControl(touchControl); + }.bind(this) + ); + + this.keyboardControls.map( + function(keyboardControl){ + this.deRegisterKeyboardControl(keyboardControl); + }.bind(this) + ); + + this.mouseControls.map( + function(mouseControl){ + this.deRegisterMouseControl(mouseControl); + }.bind(this) + ); + } + + this.editorControls = []; + + this.firstPersonControls = []; + + this.orbitControls = []; + + this.touchControls = []; + + this.keyboardControls = []; + + this.mouseControls = []; + +}; + +R3.System.Input.prototype.setMode = function() { + + /** + * De-Register everything + */ + this.deRegisterNormalModeControls(); + + this.deRegisterEditModeControls(); + + /** + * Now register the required controls + */ + if (this.editMode) { + + this.registerEditModeControls(); + + } else { + + this.registerNormalModeControls(); + + } + +}; + +/** + * + * @param data + */ +R3.System.Input.prototype.canvasChange = function(data) { + if (data.component instanceof R3.Controls) { + console.log('todo: implement dom element change'); + } +}; + +/** + * Changes the selection mode from face to mesh etc. + * @param data + */ +R3.System.Input.prototype.selectionModeChange = function(data) { + this.selectionMode = data.selectionMode; +}; + + +R3.System.Input.prototype.beforeRender = function(data) { + + if (this.editMode) { + + this.firstPersonControls.map( + function(control) { + if (control && control.instance) { + control.instance.update(data.delta); + } + } + ); + + this.orbitControls.map( + function (control) { + if (control && control.instance) { + control.instance.update(data.delta); + } + } + ); + } else { + + /** + * We don't update anything at the moment for normal controls + */ + + } + +}; + + +/** + * From now on we want to track everything about a component, only from the systems that are active + * @param data + */ +R3.System.Input.prototype.instanceCreated = function(data) { + + if (data.component instanceof R3.Controls.Touch) { + + if (this.touchControls.indexOf(data.component) !== -1) { + console.warn('Touch controls already registered'); + return; + } + + this.touchControls.push(data.component); + this.setMode(); + } + + if (data.component instanceof R3.Controls.Keyboard) { + + if (this.keyboardControls.indexOf(data.component) !== -1) { + console.warn('Keyboard controls already registered'); + return; + } + + this.keyboardControls.push(data.component); + this.setMode(); + } + + if (data.component instanceof R3.Controls.Mouse) { + + if (this.mouseControls.indexOf(data.component) !== -1) { + console.warn('Mouse controls already registered'); + return; + } + + this.mouseControls.push(data.component); + this.setMode(); + } +}; + +/** + * Removes controls from this system + * @param data + */ +R3.System.Input.prototype.removeComponent = function(data) { + + var index; + + if (data.component instanceof R3.Controls.Touch) { + + index = this.touchControls.indexOf(data.component); + + if (index === -1) { + console.warn('Failed to find the touch controls in the system - probably it was ignored - ' + data.component.name); + return; + } + + console.log('removing touch controls from system'); + + this.deRegisterTouchControl(data.component); + + this.touchControls.splice(index, 1); + + this.setMode(); + } + + if (data.component instanceof R3.Controls.Keyboard) { + + index = this.keyboardControls.indexOf(data.component); + + if (index === -1) { + console.warn('Failed to find the keyboard controls in the system - probably it was ignored - ' + data.component.name); + return; + } + + console.log('removing keyboard controls from system'); + + this.deRegisterKeyboardControl(data.component); + + this.keyboardControls.splice(index, 1); + + this.setMode(); + } + + if (data.component instanceof R3.Controls.Mouse) { + + index = this.mouseControls.indexOf(data.component); + + if (index === -1) { + console.warn('Failed to find the mouse controls in the system - probably it was ignored - ' + data.component.name); + return; + } + + console.log('removing mouse controls from system'); + + this.deRegisterMouseControl(data.component); + + this.mouseControls.splice(index, 1); + + this.setMode(); + } + + if (data.component instanceof R3.Controls.D3.Editor) { + + console.log('removing editor controls from system'); + + index = this.editorControls.indexOf(data.component); + + if (index === -1) { + console.warn('Failed to find the editor controls in the system - probably it was ignored - ' + data.component.name); + return; + } + + if (data.component.instance) { + data.component.instance.dispose(); + } + + this.editorControls.splice(index, 1); + + this.setMode(); + } + + if (data.component instanceof R3.Controls.D3.FirstPerson) { + + console.log('removing first person controls from system'); + + index = this.firstPersonControls.indexOf(data.component); + + if (index === -1) { + console.warn('Failed to find the first person controls in the system - probably it was ignored - ' + data.component.name); + return; + } + + if (data.component.instance) { + data.component.instance.dispose(); + } + + this.firstPersonControls.splice(index, 1); + + this.setMode(); + } + + if (data.component instanceof R3.Controls.D3.Orbit) { + + console.log('removing orbit controls from system'); + + index = this.orbitControls.indexOf(data.component); + + if (index === -1) { + console.warn('Failed to find the orbit controls in the system - probably it was ignored - ' + data.component.name); + return; + } + + if (data.component.instance) { + data.component.instance.dispose(); + } + + this.orbitControls.splice(index, 1); + + this.setMode(); + } + +}; + +/** + * Delayed Instance - we need to check if editControls will block the loading process (since only one will be created) + * @param data + */ +R3.System.Input.prototype.delayedInstanceEncountered = function(data) { + + if (data.component instanceof R3.Controls.D3.Editor) { + + if (this.editorControls.indexOf(data.component) !== -1) { + console.warn('Editor controls already registered'); + return; + } + + this.editorControls.push(data.component); + this.setMode(); + } + + + if (data.component instanceof R3.Controls.D3.FirstPerson) { + + if (this.firstPersonControls.indexOf(data.component) !== -1) { + console.warn('First Person Controls already registered'); + return; + } + + this.firstPersonControls.push(data.component); + this.setMode(); + } + + if (data.component instanceof R3.Controls.D3.Orbit) { + + if (this.orbitControls.indexOf(data.component) !== -1) { + console.warn('Orbit Controls already registered'); + return; + } + + this.orbitControls.push(data.component); + this.setMode(); + } + +}; + +R3.System.Input.prototype.registerTouchControl = function(touchControl) { + + if (!touchControl.canvas || !touchControl.canvas.instance) { + console.warn('no canvas at time of registration of touch controls - this part will be skipped'); + return; + } + + touchControl.canvas.instance.addEventListener( + 'touchstart', + this.touchStart, + true + ); + + touchControl.canvas.instance.addEventListener( + 'touchmove', + this.touchMove, + true + ); + touchControl.canvas.instance.addEventListener( + 'touchend', + this.touchEnd, + true + ); + touchControl.canvas.instance.addEventListener( + 'touchcancel', + this.touchCancel, + true + ); +}; + +R3.System.Input.prototype.registerKeyboardControl = function(keyboardControl) { + + if (!keyboardControl.canvas || !keyboardControl.canvas.instance) { + console.warn('no canvas at time of registration of keyboard controls - this part will be skipped'); + return; + } + + keyboardControl.canvas.instance.addEventListener( + 'keyup', + this.keyboardKeyUp, + true + ); + + keyboardControl.canvas.instance.addEventListener( + 'keydown', + this.keyboardKeyDown, + true + ); +}; + +R3.System.Input.prototype.registerMouseControl = function(mouseControl) { + + if (!mouseControl.canvas || !mouseControl.canvas.instance) { + console.warn('no canvas at time of registration of mouse controls - this part will be skipped'); + return; + } + + mouseControl.canvas.instance.addEventListener( + 'mousedown', + this.mouseDown, + false + ); + + mouseControl.canvas.instance.addEventListener( + 'mousemove', + this.mouseMove, + false + ); + + mouseControl.canvas.instance.addEventListener( + 'wheel', + this.mouseWheel, + false + ); + + mouseControl.canvas.instance.addEventListener( + 'mouseup', + this.mouseUp, + false + ); +}; + +/** + * Register all normal mode controls (Touch, Keyboard and Mouse) + */ +R3.System.Input.prototype.registerNormalModeControls = function() { + + this.touchControls.map( + function(touchControl){ + this.registerTouchControl(touchControl); + }.bind(this) + ); + + this.keyboardControls.map( + function(keyboardControl){ + this.registerKeyboardControl(keyboardControl); + }.bind(this) + ); + + this.mouseControls.map( + function(mouseControl){ + this.registerMouseControl(mouseControl); + }.bind(this) + ); +}; + +/** + * Register all edit mode controls - (Editor, Firs Person and Orbit) + */ +R3.System.Input.prototype.registerEditModeControls = function() { + + /** + * Right now - all edit mode controls happen to live in the namespace R3.Controls.D3 + * They are Editor, First Person and Orbit controls + */ + + R3.EntityManager.Instance.queryComponentsByConstructor(R3.Controls.D3).map( + + function(control) { + + if (!control.canvas || !control.canvas.instance) { + console.warn('no canvas at time of registration of controls - are you sure you know what you are doing?'); + return; + } + + control.canvas.instance.addEventListener( + 'mousedown', + this.mouseDownEdit, + true + ); + + control.canvas.instance.addEventListener( + 'mousemove', + this.mouseMoveEdit, + true + ); + + control.canvas.instance.addEventListener( + 'keydown', + this.keyDownEdit, + true + ); + + control.canvas.instance.addEventListener( + 'keyup', + this.keyUpEdit, + true + ); + + /** + * The order of creation is important here - it changes the way the DOM reacts to events + */ + this.editorControls.map( + function(editorControl) { + editorControl.createInstance(); + } + ); + + this.orbitControls.map( + function(orbitControl) { + orbitControl.createInstance(); + } + ); + + this.firstPersonControls.map( + function(firstPersonControl) { + firstPersonControl.createInstance(); + } + ); + + /** + * We append the wheel controls after so we can update our camera information + */ + control.canvas.instance.addEventListener( + 'wheel', + this.mouseWheelEdit, + true + ); + + control.canvas.instance.addEventListener( + 'mouseup', + this.mouseUpEdit, + true + ); + + }.bind(this) + ); + +}; + +/** + * Remove all normal mode event listeners + */ +R3.System.Input.prototype.deRegisterNormalModeControls = function() { + this.touchControls.map( + function(touchControl){ + this.deRegisterTouchControl(touchControl); + }.bind(this) + ); + + this.keyboardControls.map( + function(keyboardControl){ + this.deRegisterKeyboardControl(keyboardControl); + }.bind(this) + ); + + this.mouseControls.map( + function(mouseControl){ + this.deRegisterMouseControl(mouseControl); + }.bind(this) + ); +}; + +R3.System.Input.prototype.deRegisterEditModeControls = function() { + + + R3.EntityManager.Instance.queryComponentsByConstructor(R3.Controls.D3).map( + + function(control) { + + if (!control.canvas || !control.canvas.instance) { + console.warn('no canvas at time of registration of controls - are you sure you know what you are doing?'); + return; + } + + control.canvas.instance.removeEventListener( + 'mousedown', + this.mouseDownEdit, + true + ); + + control.canvas.instance.removeEventListener( + 'mousemove', + this.mouseMoveEdit, + true + ); + + control.canvas.instance.removeEventListener( + 'keydown', + this.keyDownEdit, + true + ); + + control.canvas.instance.removeEventListener( + 'keyup', + this.keyUpEdit, + true + ); + + this.editorControls.map( + function(editorControl) { + if (editorControl.instance) { + editorControl.instance.dispose(); + } + } + ); + + this.orbitControls.map( + function(orbitControl) { + if (orbitControl.instance) { + orbitControl.instance.dispose(); + } + } + ); + + this.firstPersonControls.map( + function(firstPersonControl) { + if (firstPersonControl.instance) { + firstPersonControl.instance.dispose(); + } + } + ); + + control.canvas.instance.removeEventListener( + 'wheel', + this.mouseWheelEdit, + true + ); + + control.canvas.instance.removeEventListener( + 'mouseup', + this.mouseUpEdit, + true + ); + + }.bind(this) + ); + +}; + +R3.System.Input.prototype.deRegisterTouchControl = function(touchControl) { + + touchControl.canvas.instance.removeEventListener( + 'touchstart', + this.touchStart, + true + ); + + touchControl.canvas.instance.removeEventListener( + 'touchmove', + this.touchMove, + true + ); + + touchControl.canvas.instance.removeEventListener( + 'touchend', + this.touchEnd, + true + ); + + touchControl.canvas.instance.removeEventListener( + 'touchcancel', + this.touchCancel, + true + ); + +}; + +R3.System.Input.prototype.deRegisterKeyboardControl = function(keyboardControl) { + + keyboardControl.canvas.instance.removeEventListener( + 'keydown', + this.keyboardKeyDown, + true + ); + + keyboardControl.canvas.instance.removeEventListener( + 'keyup', + this.keyboardKeyUp, + true + ); + +}; + + +R3.System.Input.prototype.deRegisterMouseControl = function(mouseControl) { + + mouseControl.canvas.instance.removeEventListener( + 'mousedown', + this.mouseDown, + false + ); + + mouseControl.canvas.instance.removeEventListener( + 'mousemove', + this.mouseMove, + false + ); + + mouseControl.canvas.instance.removeEventListener( + 'wheel', + this.mouseWheel, + false + ); + + mouseControl.canvas.instance.removeEventListener( + 'mouseup', + this.mouseUp, + false + ); + +}; + +R3.System.Input.prototype.onKeyboardKeyUp = function(event) { + R3.Event.Emit( + R3.Event.KEY_DOWN, + { + code : event.code || event.key, + keyCode : event.keyCode + } + ); + +}; + +R3.System.Input.prototype.onKeyboardKeyDown = function(event) { + R3.Event.Emit( + R3.Event.KEY_UP, + { + code : event.code || event.key, + keyCode : event.keyCode + } + ); + +}; + +R3.System.Input.prototype.onTouchStart = function(event) { + + if (this.playAudio) { + + // var audio = new Audio('http://live-api-v1.cybafelo.com/uploads/cybafelo/root/root/test/dummy.mp3'); + // + // try { + // audio.play(); + // } catch (error) { + // console.log('could not load dummy audio'); + // } + + this.playAudio = false; + } + + 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; + + R3.Event.Emit( + R3.Event.TOUCH_START, + this.touches + ) +}; + +R3.System.Input.prototype.onTouchMove = function (event) { + + this.sensitivityCounter++; + + var id = null; + + var leftTouch = null; + var rightTouch = null; + var bottomTouch = null; + var topTouch = null; + + var inward = false; + var outward = false; + var pinch = false; + var zoom = false; + + var totalUp = 0; + var totalDown = 0; + var totalLeft = 0; + var totalRight = 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; + + totalLeft += left; + totalRight += right; + totalUp += up; + totalDown += down; + } + } + + if (event.changedTouches.length === 2) { + if (event.changedTouches[0].pageX < event.changedTouches[1].pageX) { + leftTouch = this.touches[event.changedTouches[0].identifier]; + rightTouch = this.touches[event.changedTouches[1].identifier]; + } else { + leftTouch = this.touches[event.changedTouches[1].identifier]; + rightTouch = this.touches[event.changedTouches[0].identifier]; + } + + if (event.changedTouches[0].pageY < event.changedTouches[1].pageY) { + bottomTouch = this.touches[event.changedTouches[1].identifier]; + topTouch = this.touches[event.changedTouches[0].identifier]; + } else { + bottomTouch = this.touches[event.changedTouches[0].identifier]; + topTouch = this.touches[event.changedTouches[1].identifier]; + } + } + + if (leftTouch && leftTouch.left && rightTouch && rightTouch.right) { + outward = true; + } + + if (leftTouch && leftTouch.right && rightTouch && rightTouch.left) { + inward = true; + } + + if (bottomTouch && bottomTouch.up && topTouch && topTouch.down) { + pinch = true; + } + + if (bottomTouch && bottomTouch.down && topTouch && topTouch.up) { + zoom = true; + } + + this.touches.event = event; + + this.touches.meta = { + inward : inward, + outward : outward, + pinch : pinch, + zoom : zoom, + totalLeft : totalLeft, + totalRight : totalRight, + totalUp : totalUp, + totalDown : totalDown + }; + + // if (this.sensitivityCounter >= this.touchSensitivity) { + // + // this.sensitivityCounter = 0; + + R3.Event.Emit( + R3.Event.TOUCH_MOVE, + this.touches + + ); + + // } + +}; + +R3.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; + R3.Event.Emit( + R3.Event.TOUCH_CANCEL, + this.touches[event.changedTouches[t].identifier] + ); + delete this.touches[event.changedTouches[t].identifier]; + } +}; + +R3.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; + R3.Event.Emit( + R3.Event.TOUCH_END, + this.touches[event.changedTouches[t].identifier] + ); + delete this.touches[event.changedTouches[t].identifier]; + } +}; + +R3.System.Input.prototype.onKeyDownEdit = function(event) { + + console.log('input system emitted keypress ' + event.code); + + R3.Event.Emit( + R3.Event.KEY_DOWN, + { + code : event.code || event.key, + keyCode : event.keyCode + } + ); + + var meshes = null; + + if (event.code === 'Delete') { + + meshes = R3.EntityManager.Instance.queryComponentsByConstructor(R3.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) + ); + + R3.Event.Emit( + R3.Event.REMOVE_MESH, + { + meshes : deletedMeshes + } + ); + + } + + if (event.code === 'ControlLeft') { + this.controlLeft = true; + } + + if (event.code === 'KeyA') { + + this.selectAll = !this.selectAll; + + if (this.selectionMode === R3.System.Input.SELECTION_MODE_MESH) { + + meshes = R3.EntityManager.Instance.queryComponentsByConstructor(R3.D3.Mesh); + + meshes.map(function (mesh) { + if (this.selectAll) { + this.selectMesh(mesh); + } else { + this.deselectMesh(mesh); + } + }.bind(this)); + } else { + console.warn('todo: implement face select all'); + } + + R3.Event.Emit( + R3.Event.BUILD_GUI, + null + ) + + } + + if (event.code === 'KeyP') { + R3.Event.Emit(R3.Event.GAME_PAUSE); + } +}; + +R3.System.Input.prototype.onKeyUpEdit = function(event) { + + R3.Event.Emit( + R3.Event.KEY_UP, + { + code : event.code || event.key, + keyCode : event.keyCode + } + ); + + if (event.code === 'ControlLeft') { + this.controlLeft = false; + } +}; + +R3.System.Input.prototype.onMouseDown = function(event) { + + R3.Event.Emit( + R3.Event.MOUSE_DOWN, + { + event : event + } + ) +}; + +R3.System.Input.prototype.onMouseMove = function(event) { + + R3.Event.Emit( + R3.Event.MOUSE_MOVE, + { + event : event + } + ) +}; + +R3.System.Input.prototype.onMouseWheel = function(event) { + + R3.Event.Emit( + R3.Event.MOUSE_WHEEL, + { + event : event + } + ) +}; + +R3.System.Input.prototype.onMouseUp = function(event) { + + R3.Event.Emit( + R3.Event.MOUSE_UP, + { + event : event + } + ) +}; + +R3.System.Input.prototype.onMouseDownEdit = function(event) { + + if (event.button === 2) { + + R3.EntityManager.Instance.queryComponentsByConstructor(R3.Controls.D3).map( + + function(control) { + + if (this.controlLeft) { + return; + } + + this.mouse.x = (event.offsetX / event.target.width ) * 2 - 1; + this.mouse.y = -(event.offsetY / event.target.height) * 2 + 1; + + R3.Event.Emit( + R3.Event.GET_RENDER_CONFIGURATION, + null, + function(configuration) { + + var scenes = configuration.activeScenes; + + var camera = configuration.activeCamera; + + var intersects = scenes.reduce( + + function (result, scene) { + + this.raycaster.setFromCamera( + this.mouse, + camera + ); + + this.raycaster.getIntersectedObjects(scene.meshes).map( + function (intersect) { + result.push(intersect); + } + ); + + this.raycaster.getIntersectedObjects(scene.clones).map( + function (intersect) { + result.push(intersect); + } + ); + + return result; + }.bind(this), + [] + ); + + if (intersects.length < 1) { + return; + } + + /** + * Find the closest intersected mesh + */ + intersects.sort( + function (a, b) { + if (a.distance < b.distance) { + return -1; + } + + if (a.distance > b.distance) { + return 1; + } + + return 0; + } + ); + + var mesh = intersects[0].mesh; + var face = intersects[0].face; + + /** + * Prevent default action (like context menu or whatever) + */ + event.preventDefault(); + + /** + * Prevent other event listeners for 'mousedown' from executing their actions + */ + event.stopImmediatePropagation(); + + if (this.selectionMode === R3.System.Input.SELECTION_MODE_MESH) { + + if (mesh.selected) { + this.deselectMesh(mesh); + } else { + this.selectMesh(mesh); + } + + } else { + if (face.selected) { + this.deselectFace(mesh, face); + } else { + this.selectFace(mesh, face); + } + } + + /** + * Notify our GUI system to build a GUI + */ + R3.Event.Emit( + R3.Event.BUILD_GUI, + null + ) + }.bind(this) + ); + + }.bind(this) + ); + } +}; + +/** + * + * @param event + */ +R3.System.Input.prototype.onMouseMoveEdit = function(event) { + + R3.EntityManager.Instance.queryComponents(R3.Component.MOUSE).map( + function(mouse) { + mouse.x = event.clientX; + mouse.y = event.clientY; + } + ); + + R3.EntityManager.Instance.queryComponentsByConstructor(R3.Controls.D3).map( + function(control) { + + control.camera.position.x = control.camera.instance.position.x; + control.camera.position.y = control.camera.instance.position.y; + control.camera.position.z = control.camera.instance.position.z; + + control.camera.rotation.x = control.camera.instance.rotation.x; + control.camera.rotation.y = control.camera.instance.rotation.y; + control.camera.rotation.z = control.camera.instance.rotation.z; + + control.camera.quaternion.x = control.camera.instance.quaternion.x; + control.camera.quaternion.y = control.camera.instance.quaternion.y; + control.camera.quaternion.z = control.camera.instance.quaternion.z; + control.camera.quaternion.w = control.camera.instance.quaternion.w; + } + ); + +}; + +/** + * Update the camera position etc. after mouse up + * @returns {Function} + * @param event + */ +R3.System.Input.prototype.onMouseUpEdit = function(event) { + +}; + +/** + * Update our camera position after moving the mouse wheel + * @returns {Function} + * @param event + */ +R3.System.Input.prototype.onMouseWheelEdit = function(event) { + + R3.EntityManager.Instance.queryComponentsByConstructor(R3.Controls.D3).map( + function(control) { + + control.camera.position.x = control.camera.instance.position.x; + control.camera.position.y = control.camera.instance.position.y; + control.camera.position.z = control.camera.instance.position.z; + } + ); + +}; + +R3.System.Input.prototype.selectFace = function(mesh, face) { + + /** + * If mesh is already selected, do nothing + */ + if (face.selected === true) { + return; + } + + /** + * Notify our component as being 'selected' + * @type {boolean} + */ + face.selected = true; + + face.createHelper(mesh); + + R3.Event.Emit( + R3.Event.MESH_FACE_SELECTED, + { + mesh : mesh, + face : face + } + ); +}; + +R3.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(); + + this.orbitControls.map( + function(controls){ + controls.target = mesh; + controls.updateInstance('target'); + } + ); + + R3.Event.Emit( + R3.Event.MESH_SELECTED, + { + mesh : mesh + } + ); +}; + +R3.System.Input.prototype.deselectFace = function(mesh, face) { + + face.selected = false; + + face.removeHelper(mesh); + + R3.Event.Emit( + R3.Event.MESH_FACE_DESELECTED, + { + mesh : mesh, + face : face + } + ); +}; + +R3.System.Input.prototype.deselectMesh = function(mesh) { + + mesh.selected = false; + + mesh.removeHelper(); + + this.orbitControls.map( + function(controls){ + controls.target = null; + controls.updateInstance('target'); + } + ); + + R3.Event.Emit( + R3.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'); +// } +// } +// }; + +// R3.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(R3.Component.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} +// */ +// R3.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 +// */ +// R3.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 +// */ +// R3.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(); +// } +// } +// } +// }; + diff --git a/src/r3-system-linking.js b/src/r3-system-linking.js new file mode 100644 index 0000000..ddd5495 --- /dev/null +++ b/src/r3-system-linking.js @@ -0,0 +1,930 @@ +/** + * 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 R3.API.System + * @constructor + */ +R3.System.Linking = function( + apiSystem +) { + R3.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.componentUpdateSubcription = null; + this.componentClonedSubscription = null; + this.registerDependenciesSubscription = null; + this.componentRemoveSubscription = null; + this.resolveDependenciesSubscription = null; + this.replaceComponentSubscription = null; //render system does this + + /** + * Parents + */ + this.parentSceneChangeSubscription = null; + this.parentPhysicsWorldChangeSubscription = null; + + /** + * Instances + */ + this.instanceCreatedSubscription = null; + this.instanceClonedSubscription = null; + + /** + * Meshes + */ + this.removeMeshSubscription = null; + + /** + * Materials + */ + this.materialTypeChangedSubscription = null; + + /** + * Arrays + */ + this.arrayItemAddedSubscription = null; + +}; + +R3.System.Linking.prototype = Object.create(R3.System.prototype); +R3.System.Linking.prototype.constructor = R3.System.Linking; + +R3.System.Linking.prototype.start = function() { + + R3.System.prototype.start.call(this); + + /** + * Components + */ + this.componentCreatedSubscription = this.subscribe( + R3.Event.COMPONENT_CREATED, + this.componentCreated.bind(this) + ); + + this.componentUpdateSubcription = this.subscribe( + R3.Event.COMPONENT_UPDATE, + this.componentUpdate.bind(this) + ); + + this.componentClonedSubscription = this.subscribe( + R3.Event.COMPONENT_CLONED, + this.componentCloned.bind(this) + ); + + this.registerDependenciesSubscription = this.subscribe( + R3.Event.REGISTER_DEPENDENCIES, + this.registerDependenciesDirect + ); + + this.componentRemoveSubscription = this.subscribe( + R3.Event.REMOVE_COMPONENT, + this.removeComponent + ); + + this.resolveDependenciesSubscription = this.subscribe( + R3.Event.RESOLVE_DEPENDENCIES, + this.resolveDependencies + ); + + this.replaceComponentSubscription = this.subscribe( + R3.Event.REPLACE_COMPONENT, + this.replaceComponent + ); + + /** + * Parents + */ + this.parentSceneChangeSubscription = this.subscribe( + R3.Event.PARENT_SCENE_CHANGE, + this.onParentSceneChange + ); + + this.parentPhysicsWorldChangeSubscription = this.subscribe( + R3.Event.PARENT_WORLD_CHANGE, + this.onParentWorldChange + ); + + /** + * Instances + */ + this.instanceCreatedSubscription = this.subscribe( + R3.Event.INSTANCE_CREATED, + this.instanceCreated + ); + + this.instanceClonedSubscription = this.subscribe( + R3.Event.INSTANCE_CLONED, + this.instanceCloned + ); + + /** + * Meshes + */ + this.removeMeshSubscription = this.subscribe( + R3.Event.REMOVE_MESH, + this.removeMesh + ); + + /** + * Materials + */ + this.materialTypeChangedSubscription = this.subscribe( + R3.Event.MATERIAL_TYPE_CHANGED, + this.materialTypeChanged + ); + + /** + * Arrays + */ + this.arrayItemAddedSubscription = this.subscribe( + R3.Event.ARRAY_ITEM_ADDED, + this.arrayItemAdded + ); + +}; + +R3.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) { + R3.Event.Emit( + R3.Event.COMPONENT_LINKED, + link + ); + }) + + } else { + if (component[property] && + component[property] === data.component.id) { + component[property] = data.component; + + R3.Event.Emit( + R3.Event.COMPONENT_LINKED, + { + parent : component, + property : property, + child : data.component + } + ); + } + } + } + } +}; + +R3.System.Linking.prototype.resolveDependencies = function(data) { + + var component = data.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 (R3.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 + */ + R3.Utils.PushUnique(this.resolved, component); + + /** + * First check if the dependencies have already been met + */ + if ( + R3.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 || + R3.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 + */ + R3.Event.Emit( + R3.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 (R3.Utils.IsEmpty(this.dependencies)) { + + /** + * This also only notifies the Editor - We still have some more work to here + */ + R3.Event.Emit( + R3.Event.COMPONENTS_LINKED, + { + components: this.resolved.map( + function(component) { + return component; + } + ) + } + ); + + this.resolved = []; + + } + +}; + +R3.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 = R3.EntityManager.Instance.findComponentById(id); + + if (processedComponent && processedComponent.loaded) { + + /** + * Link the component + */ + this.link(component, {component: processedComponent}); + + R3.Utils.PushUnique(this.resolved, processedComponent); + + } else { + + /** + * Create a new link if none exists + */ + if (R3.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); + R3.Event.Emit( + R3.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 + */ +R3.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 : component}); + +}; + +/** + * Trigger a component update + * @param data + */ +R3.System.Linking.prototype.componentUpdate = function(data){ + + var component = R3.EntityManager.Instance.findComponentByName(data.name); + + if (R3.Utils.UndefinedOrNull(data.property)) { + console.warn('invalid data format - we expect data.property'); + return; + } + + if (R3.Utils.UndefinedOrNull(data.value)) { + console.warn('invalid data format - we expect data.value'); + return; + } + + if (R3.Utils.UndefinedOrNull(data.subProperty)) { + component[data.property] = data.value; + } else { + component[data.property][data.subProperty] = data.value; + } + + component.updateInstance(data.property); +}; + +R3.System.Linking.prototype.componentCloned = function(data) { + + this.componentCreated(data); + + if (data.component instanceof R3.D3.Mesh) { + + if (!(data.parent instanceof R3.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 + */ +R3.System.Linking.prototype.registerDependenciesDirect = function(data) { + this.registerDependencies(data.component); +}; + +R3.System.Linking.prototype.replaceComponent = function(data) { + + /** + * Link canvases + */ + if ( + data.current instanceof R3.D3.Geometry.Buffer && + data.replacement instanceof R3.D3.Geometry.Buffer + ) { + data.replacement.faces = data.current.faces.map( + function(face) { + return face; + } + ); + + data.replacement.vertices = data.current.vertices.map( + function(vertex) { + return vertex; + } + ); + + data.replacement.updateInstance('faces'); + + /** + * TODO: update both seperately when implemented properly + */ + //data.replacement.updateInstance('vertices'); + + R3.EntityManager.Instance.queryComponents(R3.Component.MESH).map( + function(mesh) { + if (mesh.geometry === data.current) { + mesh.geometry = data.replacement; + mesh.updateInstance('geometry'); + } + } + ) + } + +}; + +R3.System.Linking.prototype.removeComponent = function(data) { + + if (!data.component) { + console.error('no component to remove'); + return; + } + + var component = data.component; + + if (component.parentEntity instanceof R3.Entity) { + component.parentEntity.removeComponent(component); + } + + if (component instanceof R3.D3.Mesh && + component.parentScene instanceof R3.D3.Scene) { + + component.removeHelper(); + + component.parentScene.removeObject(component); + } + + if (component instanceof R3.D3.Light && + component.parentScene instanceof R3.D3.Scene) { + component.parentScene.removeObject(component); + } + + if (component instanceof R3.Entity) { + R3.EntityManager.Instance.removeEntity(component); + } + + // if (component instanceof R3.D3.Particle) { + // // component.mesh.parentScene.removeObject(component.mesh); + // } +}; + +R3.System.Linking.prototype.arrayItemAdded = function(data) { + if ( + data.component instanceof R3.D3.PhysicsWorld && + data.item instanceof R3.D3.RigidBody + ) { + data.component.addRigidBody(data.item); + } + + console.warn('todo: check if this is still necessary to add material to mesh'); + + // if (data.component instanceof R3.D3.Mesh && + // data.item instanceof R3.D3.Material + // ) { + // data.component.updateInstance('materials'); + // } +}; + +R3.System.Linking.prototype.instanceCloned = function(data) { + + // if (data.component instanceof R3.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); + // } + // } + +}; + +R3.System.Linking.prototype.instanceCreated = function(data) { + + if (data.component instanceof R3.Image) { + /** + * Find all textures which use this image + */ + R3.EntityManager.Instance.queryComponents(R3.Component.TEXTURE_IMAGE).map( + function(texture) { + if (texture.instance && texture.image === data.component) { + texture.updateInstance('image'); + } + } + ); + + R3.EntityManager.Instance.queryComponents(R3.Component.TEXTURE_CUBE).map( + function(texture) { + if (texture.instance && texture.images.indexOf(data.component) !== -1) { + texture.updateInstance('images'); + } + } + ); + + } + + /** + * Link all scenes + */ + if (data.component instanceof R3.D3.Scene) { + /** + * Check ALL components for 'parentScenes' - this is expensive so it checks the register directly + */ + + Object.keys(R3.EntityManager.Instance.idRegister).map( + function(componentId) { + if (R3.EntityManager.Instance.idRegister[componentId].parentScene === data.component.id) { + R3.EntityManager.Instance.idRegister[componentId].parentScene = data.component; + } + } + ); + } + + if ( + data.component.parentScene && + typeof data.component.parentScene === 'string' + ) { + R3.EntityManager.Instance.queryComponents(R3.Component.SCENE).map( + function (scene) { + if (data.component.parentScene === scene.id) { + data.component.parentScene = scene; + scene.addObject(data.component); + } + } + ); + } + + + /** + * Link all meshes + */ + if (data.component instanceof R3.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) { + + Object.keys(R3.EntityManager.Instance.idRegister).map( + function(componentId) { + if (R3.EntityManager.Instance.idRegister[componentId].parentMesh === data.component.id) { + R3.EntityManager.Instance.idRegister[componentId].parentMesh = data.component; + R3.EntityManager.Instance.idRegister[componentId].updateInstance('parentMesh'); + } + } + ); + + } + + } + + /** + * Maybe this component has a parent mesh + */ + if ( + data.component.parentMesh && + typeof data.component.parentMesh === 'string' + ) { + R3.EntityManager.Instance.queryComponents(R3.Component.MESH).map( + function (mesh) { + if (data.component.parentMesh === mesh.id) { + data.component.parentMesh = mesh; + data.component.updateInstance('parentMesh'); + } + } + ); + } + + if ( + data.component.parentPhysicsWorld && + typeof data.component.parentPhysicsWorld === 'string' + ) { + R3.EntityManager.Instance.queryComponents(R3.Component.PHYSICS_WORLD).map( + function (world) { + if (data.component.parentPhysicsWorld === world.id) { + data.component.parentPhysicsWorld = world; + + if (typeof data.component.instance.addToWorld === 'function') { + data.component.instance.addToWorld(world.instance); + console.log('instance added to physics world'); + } + } + } + ); + } + +}; + +R3.System.Linking.prototype.materialTypeChanged = function(data) { + + var meshes = R3.EntityManager.Instance.queryComponents(R3.Component.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 + */ +R3.System.Linking.prototype.onParentWorldChange = function(data) { + + if ( + data.object instanceof R3.D3.RigidBody + ) { + + if (data.originalWorld instanceof R3.D3.PhysicsWorld) { + data.originalWorld.removeRigidBody(data.object); + } + + if (data.newWorld instanceof R3.D3.PhysicsWorld) { + data.newWorld.addRigidBody(data.object); + } + } + +}; + +/** + * Defines what should happen when a parent scene changes + * @param data + */ +R3.System.Linking.prototype.onParentSceneChange = function(data) { + + if ( + data.object instanceof R3.D3.Mesh || + data.object instanceof R3.D3.Light + ) { + + /** + * We remove the helper (if any) from the old scene and add it to the new scene + */ + var helper = R3.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); + } + } + +}; + +/** + * 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 + */ +R3.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 = R3.EntityManager.Instance.queryComponents(R3.Component.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(); + } + ); +}; + +R3.System.Linking.prototype.stop = function() { + R3.System.prototype.stop.call(this); + /** + * Components + */ + this.componentCreatedSubscription.remove(); + this.componentUpdateSubcription.remove(); + this.componentClonedSubscription.remove(); + this.registerDependenciesSubscription.remove(); + this.componentRemoveSubscription.remove(); + this.resolveDependenciesSubscription.remove(); + this.replaceComponentSubscription.remove(); + + /** + * Parents + */ + this.parentSceneChangeSubscription.remove(); + this.parentPhysicsWorldChangeSubscription.remove(); + + /** + * Instances + */ + this.instanceCreatedSubscription.remove(); + this.instanceClonedSubscription.remove(); + + /** + * Meshes + */ + this.removeMeshSubscription.remove(); + + /** + * Materials + */ + this.materialTypeChangedSubscription.remove(); + + /** + * Arrays + */ + this.arrayItemAddedSubscription.remove(); +}; + diff --git a/src/r3-system-particle.js b/src/r3-system-particle.js new file mode 100644 index 0000000..0afa659 --- /dev/null +++ b/src/r3-system-particle.js @@ -0,0 +1,325 @@ +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem R3.API.System + * @constructor + */ +R3.System.Particle = function( + apiSystem +) { + R3.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.totalTime = 0; + + this.instanceCreatedSubscription = null; + + this.removeComponentSubscription = null; + + this.beforeRenderSubscription = null; +}; + +R3.System.Particle.prototype = Object.create(R3.System.prototype); +R3.System.Particle.prototype.constructor = R3.System.Particle; + +/** + * Start this system (add all event listeners) + */ +R3.System.Particle.prototype.start = function() { + + R3.System.prototype.start.call(this); + + this.particleEngines = R3.EntityManager.Instance.queryComponents(R3.Component.PARTICLE_ENGINE); + + this.instanceCreatedSubscription = R3.Event.Subscribe( + R3.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + this.removeComponentSubscription = R3.Event.Subscribe( + R3.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + this.beforeRenderSubscription = R3.Event.Subscribe( + R3.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 + */ +R3.System.Particle.prototype.instanceCreated = function(data) { + + /** + * If we loaded a ParticleEngine - store a reference to it for later, also link all particles with this as parent + */ + if (data.component instanceof R3.D3.ParticleEngine) { + this.particleEngines.push(data.component); + + /** + * Link parent particle engines of already loaded particles + */ + R3.EntityManager.Instance.queryComponents(R3.Component.PARTICLE).map( + function(particle){ + if (particle.parentParticleEngine === data.component.id) { + particle.parentParticleEngine = data.component; + } + } + ) + } + + /** + * If we load a Particle, check to see if its engine loaded and link it. + */ + if (data.component instanceof R3.D3.Particle) { + R3.EntityManager.Instance.queryComponents(R3.Component.PARTICLE_ENGINE).map( + function (particleEngine) { + if (data.component.parentParticleEngine === particleEngine.id) { + data.component.parentParticleEngine = particleEngine; + } + } + ); + } +}; + +/** + * Removes a particle engine from this system + * @param data + */ +R3.System.Particle.prototype.removeComponent = function(data) { + + if (data.component instanceof R3.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 + */ +R3.System.Particle.prototype.beforeRender = function(data) { + + this.totalTime += data.delta; + + this.particleEngines.map( + function(particleEngine) { + + if ( + R3.Utils.UndefinedOrNull(particleEngine.templateParticle) || + R3.Utils.UndefinedOrNull(particleEngine.templateParticle.mesh) || + R3.Utils.UndefinedOrNull(particleEngine.templateParticle.mesh.parentScene) || + R3.Utils.UndefinedOrNull(particleEngine.templateParticle.mesh.parentScene.instance) || + !particleEngine.enabled + ) { + return; + } + + particleEngine.elapsed += data.delta; + + particleEngine.particles = particleEngine.particles.reduce( + + function(result, particle){ + + var speed = particle.userData.speed; + + if (particle.userData.speedType === R3.D3.API.Particle.SPEED_TYPE_CONSTANT) { + speed = data.delta * particle.userData.speed; + } + + if (particle.userData.speedType === R3.D3.API.Particle.SPEED_TYPE_LINEAR) { + speed = data.delta * particle.userData.speed; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === R3.D3.API.Particle.SPEED_TYPE_EXPONENTIAL) { + speed = Math.pow(particle.userData.speed, 2) * data.delta; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === R3.D3.API.Particle.SPEED_TYPE_LOGARITHMIC) { + speed = Math.log(particle.userData.speed) * data.delta; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === R3.D3.API.Particle.SPEED_TYPE_ONE_OVER_LOG) { + speed = 1 / Math.log(particle.userData.speed) * data.delta; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === R3.D3.API.Particle.SPEED_TYPE_EXP) { + speed = Math.exp(particle.userData.speed) * data.delta; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === R3.D3.API.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 === R3.D3.API.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 === R3.D3.API.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; + } + + if (particleEngine.camera && particleEngine.camera.instance) { + particle.quaternion.copy(particleEngine.camera.instance.quaternion); + } + + if (particleEngine.templateParticle.opacityType === R3.D3.API.Particle.OPACITY_TYPE_FADE_IN_LINEAR) { + if (particle.userData.elapsed > particleEngine.templateParticle.fadeInAfter) { + particle.material.opacity += particleEngine.templateParticle.fadeInFactor; + } + } + + if (particleEngine.templateParticle.opacityType === R3.D3.API.Particle.OPACITY_TYPE_FADE_OUT_LINEAR) { + if (particle.userData.elapsed > particleEngine.templateParticle.fadeOutAfter) { + particle.material.opacity -= particleEngine.templateParticle.fadeOutFactor; + } + } + + if (particleEngine.templateParticle.opacityType === R3.D3.API.Particle.OPACITY_TYPE_FADE_IN_OUT_LINEAR) { + + if (particle.userData.fadeIn) { + if (particle.userData.elapsed > particleEngine.templateParticle.fadeInAfter) { + particle.material.opacity += particleEngine.templateParticle.fadeInFactor; + } + } else { + if (particle.userData.elapsed > particleEngine.templateParticle.fadeOutAfter) { + particle.material.opacity -= particleEngine.templateParticle.fadeOutFactor; + } + } + + if (particle.material.opacity >= 1) { + particle.userData.fadeIn = false; + } + } + + 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) { + R3.Event.Emit( + R3.Event.REMOVE_PARTICLE_ENGINE, + { + component : particleEngine + } + ) + } + + if (particleEngine.fired && particleEngine.particles.length === 0) { + R3.Event.Emit( + R3.Event.ENGINE_FIRED_PARTICLES_ZERO, + { + 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); + } + + particleEngine.fired = true; + } + + } 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) + */ +R3.System.Particle.prototype.stop = function() { + + R3.System.prototype.stop.call(this); + + this.instanceCreatedSubscription.remove(); + this.removeComponentSubscription.remove(); + this.beforeRenderSubscription.remove(); + +}; diff --git a/src/r3-system-physics.js b/src/r3-system-physics.js new file mode 100644 index 0000000..927659c --- /dev/null +++ b/src/r3-system-physics.js @@ -0,0 +1,151 @@ +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem R3.API.System + * @constructor + */ +R3.System.Physics = function( + apiSystem +) { + + R3.System.call( + this, + apiSystem + ); + + this.worlds = []; + // this.rigidBodies = []; + // this.wheels = []; + // this.vehicles = []; + + // this.worldSubscription = null; + // this.rigidBodySubscription = null; + this.beforeRenderSubscription = null; + this.afterRenderSubscription = null; + + + + +}; + +R3.System.Physics.prototype = Object.create(R3.System.prototype); +R3.System.Physics.prototype.constructor = R3.System.Physics; + +R3.System.Physics.prototype.start = function() { + + R3.System.prototype.start.call(this); + + this.worlds = R3.EntityManager.Instance.queryComponents(R3.Component.PHYSICS_WORLD); + // this.rigidBodies = R3.EntityManager.Instance.queryComponents(R3.Component.RIGID_BODY); + // this.wheels = R3.EntityManager.Instance.queryComponents(R3.Component.RAYCAST_WHEEL); + // this.vehicles = R3.EntityManager.Instance.queryComponents(R3.Component.RAYCAST_VEHICLE); + + + + // 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( + R3.Event.BEFORE_RENDER, + this.beforeRender + ); +}; + +/** + * Update script + */ +R3.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) + ); +}; + + +R3.System.Physics.prototype.stop = function() { + + R3.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(); + } + +}; + diff --git a/src/r3-system-render.js b/src/r3-system-render.js new file mode 100644 index 0000000..f2646ed --- /dev/null +++ b/src/r3-system-render.js @@ -0,0 +1,827 @@ +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem R3.API.System + * @param graphicsRuntime + * @constructor + */ +R3.System.Render = function( + apiSystem, + graphicsRuntime +) { + + R3.System.call( + this, + apiSystem + ); + + this.renderSubscription = null; + + this.replaceComponentSubscription = null; + + this.clock = new R3.Clock(graphicsRuntime); + + this.delta = null; + + this.animationFrameHook = null; + + this.activeRenderConfiguration = null; + + this.excludeFromEnvironmentSubscription = null; + + this.shaderUpdateSubscription = null; + + /** + * Images + */ + this.textureUpdatedSubscription = null; + + this.renderConfigurations = []; + + this.renderers = []; + + this.composers = []; + + this.statistics = []; + + this.cubeCameras = []; +}; + +R3.System.Render.prototype = Object.create(R3.System.prototype); +R3.System.Render.prototype.constructor = R3.System.Render; + +/** + * Start the rendering system + */ +R3.System.Render.prototype.start = function() { + + R3.System.prototype.start.call(this); + + this.renderConfigurations = R3.EntityManager.Instance.queryComponents(R3.Component.RENDER_CONFIGURATION); + + this.renderers = R3.EntityManager.Instance.queryComponentsByConstructor(R3.Renderer); + + this.composers = R3.EntityManager.Instance.queryComponents(R3.Component.COMPOSER); + + this.statistics = R3.EntityManager.Instance.queryComponents(R3.Component.STATS); + + this.cubeCameras = R3.EntityManager.Instance.queryComponents(R3.Component.CAMERA_CUBE); + + this.excludedFromEnvironment = []; + + R3.EntityManager.Instance.queryComponentsByConstructor(R3.D3.Mesh).map( + function(mesh) { + if (mesh.excludeFromEnvironment) { + this.excludedFromEnvironment.push(mesh); + } + }.bind(this) + ); + + this.excludeFromEnvironmentSubscription = this.subscribe( + R3.Event.EXCLUDE_FROM_ENVIRONMENT, + this.excludeFromEnvironmentUpdate + ); + + this.instanceCreatedSubscription = R3.Event.Subscribe( + R3.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + this.removeComponentSubscription = R3.Event.Subscribe( + R3.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + this.replaceComponentSubscription = R3.Event.Subscribe( + R3.Event.REPLACE_COMPONENT, + this.replaceComponent.bind(this) + ); + + this.renderSubscription = this.subscribe( + R3.Event.RENDER, + this.render + ); + + this.windowResizeSubscription = this.subscribe( + R3.Event.WINDOW_RESIZE, + this.windowResize + ); + + this.textureUpdatedSubscription = this.subscribe( + R3.Event.TEXTURE_INSTANCE_UPDATED, + this.textureUpdated + ); + + this.getRenderConfigurationSubscription = this.subscribe( + R3.Event.GET_RENDER_CONFIGURATION, + this.getRenderConfiguration + ); + + this.setActiveRenderConfigurationSubscription = this.subscribe( + R3.Event.SET_ACTIVE_RENDER_CONFIGURATION, + this.setActiveRenderConfiguration + ); + + this.shaderUpdateSubscription = R3.Event.Subscribe( + R3.Event.SHADER_UPDATE, + this.shaderUpdate.bind(this) + ); + + // this.delayedInstanceEncounteredSubscription = R3.Event.Subscribe( + // R3.Event.DELAYED_INSTANCE_ENCOUNTERED, + // this.delayedInstanceEncountered.bind(this) + // ); + + // window.addEventListener( + // 'resize', + // this.nativeWindowResize, + // false + // ); + + // window.addEventListener( + // "orientationchangeend", + // this.nativeWindowResize, + // false + // ); + + // R3.Event.Emit( + // R3.Event.WINDOW_RESIZE, + // { + // width : window.screen.availWidth, + // height : window.screen.availHeight + // } + // ); + + this.run(); + +}; +// +// R3.System.Render.prototype.delayedInstanceEncountered = function() { +// +// +// }; + +R3.System.Render.prototype.run = function() { + + this.animationFrameHook = requestAnimationFrame( this.run.bind(this) ); + + this.delta = this.clock.getDelta(); + + R3.Event.Emit( + R3.Event.RENDER, + { + delta : this.delta + } + ); + +}; + +// R3.System.Render.prototype.nativeWindowResize = function() { +// R3.Event.Emit( +// R3.Event.WINDOW_RESIZE, +// { +// width : window.screen.availWidth, +// height : window.screen.availHeight +// } +// ); +// }; + +R3.System.Render.prototype.getRenderConfiguration = function (data, callback) { + callback(this.activeRenderConfiguration); +}; + +R3.System.Render.prototype.excludeFromEnvironmentUpdate = function (data) { + + if (data.component.excludeFromEnvironment) { + console.log('excluding ' + data.component.name + ' from environment'); + R3.Utils.PushUnique(this.excludedFromEnvironment, data.component); + } else { + var index = this.excludedFromEnvironment.indexOf(data.component); + if (index !== -1) { + this.excludedFromEnvironment.splice(index,1); + } + console.log('including ' + data.component.name + ' in environment'); + } +}; + +R3.System.Render.prototype.setActiveRenderConfiguration = function (data) { + + if (this.renderConfigurations.indexOf(data.renderConfiguration) !== -1) { + this.activeRenderConfiguration = data.renderConfiguration; + } else { + console.warn('active render configuration not found in render system'); + } + +}; + +R3.System.Render.prototype.getOffset = function (el) { + var rect = el.getBoundingClientRect(), + scrollLeft = window.pageXOffset || document.documentElement.scrollLeft, + scrollTop = window.pageYOffset || document.documentElement.scrollTop; + return { top: rect.top + scrollTop, left: rect.left + scrollLeft } +}; + +R3.System.Render.prototype.windowResize = function(data) { + + R3.Event.Emit( + R3.Event.BEFORE_WINDOW_RESIZE, + data + ); + + R3.EntityManager.Instance.queryComponentsByConstructor(R3.D3.RenderTarget).map( + function(renderTarget) { + if (renderTarget.autoUpdateSize) { + renderTarget.updateInstance('autoUpdateSize'); + } + } + ); + + R3.EntityManager.Instance.queryComponentsByConstructor(R3.Renderer).map( + function(renderer) { + renderer.setSize(data.width, data.height); + } + ); + + R3.EntityManager.Instance.queryComponentsByConstructor(R3.D3.Effect).map( + function(effect){ + effect.setSize(data.width, data.height); + } + ); + + R3.EntityManager.Instance.queryComponentsByConstructor(R3.Canvas).map( + function(canvas) { + canvas.updateInstance('autoUpdateSize'); + } + ); + + R3.EntityManager.Instance.queryComponentsByConstructor(R3.D3.Camera).map( + function(camera){ + if ( + camera instanceof R3.D3.Camera.Orthographic && + camera.aspectRatioMode !== R3.D3.API.Camera.Orthographic.ASPECT_RATIO_MODE_NONE + ) { + camera.updateInstance('aspect'); + } + + if ( + camera instanceof R3.D3.Camera.Perspective || + camera instanceof R3.D3.Camera.Stereo + ) { + camera.aspect = data.width / data.height; + camera.updateInstance('aspect'); + } + } + ); + + R3.EntityManager.Instance.queryComponents(R3.Component.COMPOSER).map( + function(composer){ + + composer.setSize( + data.width, + data.height + ); + + composer.passes.map( + function(pass) { + pass.setSize( + data.width, + data.height + ) + } + ) + } + ); + + R3.Event.Emit( + R3.Event.AFTER_WINDOW_RESIZE, + data + ); + +}; + +R3.System.Render.prototype.shaderUpdate = function(data) { + + this.activeRenderConfiguration.activeScenes.map( + function(scene){ + this.activeRenderConfiguration.activeRenderer.instance.compile( + scene.instance, + this.activeRenderConfiguration.activeCamera.instance + ); + }.bind(this) + ); + +}; + +R3.System.Render.prototype.textureUpdated = function(data) { + + R3.EntityManager.Instance.queryComponentsByConstructor(R3.D3.Material).map( + function(material) { + + material.getTextures().map( + function (object) { + + if (object.texture === data.texture) { + + if (material.loaded) { + material.updateInstance(object.property); + } + + } + + } + ); + + } + ); + +}; + +/** + * From now on we want to track everything about a component, only from the systems that are active + * @param data + */ +R3.System.Render.prototype.instanceCreated = function(data) { + + if (data.component instanceof R3.RenderConfiguration) { + console.log('adding render configuration to render system'); + this.renderConfigurations.push(data.component); + + if (this.renderConfigurations.length === 1) { + this.activeRenderConfiguration = this.renderConfigurations[0]; + } + } + + if (data.component instanceof R3.Renderer) { + console.log('adding renderer to render system'); + this.renderers.push(data.component); + } + + if (data.component instanceof R3.D3.Composer) { + console.log('adding composer to render system'); + this.composers.push(data.component); + } + + if (data.component instanceof R3.Stats) { + this.statistics.push(data.component); + } + + if (data.component instanceof R3.D3.Camera.Cube) { + this.cubeCameras.push(data.component); + } + + if ( + data.component instanceof R3.D3.Mesh && + data.component.excludeFromEnvironment + ) { + R3.Utils.PushUnique(this.excludedFromEnvironment, data.component); + } + + if (data.component instanceof R3.D3.Texture) { + + /** + * Link Parent Textures to Canvas Objects + */ + R3.EntityManager.Instance.queryComponents(R3.Component.CANVAS).map( + function(canvas){ + if (canvas.parentTexture === data.component.id) { + canvas.parentTexture = data.component; + } + } + ); + + /** + * Find all Render Targets and see if their textures need updating + */ + R3.EntityManager.Instance.queryComponents(R3.Component.RENDER_TARGET).map( + function(renderTarget) { + if (renderTarget.texture === data.component) { + /** + * We found a render target which has this component as their texture - their instance + * has been updated + */ + + if (renderTarget.texture.instance !== renderTarget.instance.texture) { + console.log('updating render target texture instance'); + renderTarget.instance.texture = renderTarget.texture.instance; + } + } + } + ) + } + + if (data.component instanceof R3.Canvas) { + R3.EntityManager.Instance.queryComponents(R3.Component.TEXTURE_CANVAS).map( + function(texture){ + if (data.component.parentTexture === texture.id) { + data.component.parentTexture = texture; + } + } + ) + } +}; + +R3.System.Render.prototype.replaceComponent = function(data) { + + if (data.current instanceof R3.D3.Material) { + R3.EntityManager.Instance.queryComponentsByConstructor(R3.D3.Mesh).map( + function(mesh) { + + var index = mesh.materials.indexOf(data.current); + + while (index !== -1) { + + mesh.materials[index] = data.replacement; + mesh.updateInstance('materials'); + + index = mesh.materials.indexOf(data.current); + } + } + ); + } + + if (data.current instanceof R3.D3.Light) { + R3.EntityManager.Instance.queryComponents(R3.Component.SCENE).map( + function(scene) { + + var index = scene.lights.indexOf(data.current); + + if (index !== -1) { + scene.lights[index] = data.replacement; + scene.updateInstance('lights'); + } + + } + ); + } + + if (data.current instanceof R3.D3.Pass) { + R3.EntityManager.Instance.queryComponents(R3.Component.COMPOSER).map( + function(composer) { + + var index = composer.passes.indexOf(data.current); + + if (index !== -1) { + + if (data.current.renderToScreen === true) { + data.replacement.renderToScreen = true; + } + + if (data.replacement.loaded) { + composer.passes[index] = data.replacement; + } else { + composer.passes.splice(index, 1); + } + + composer.updateInstance('passes'); + } + + } + ); + } + + if ( + data.current instanceof R3.Renderer && + data.replacement instanceof R3.Renderer + ) { + data.replacement.canvas.remove(); + data.replacement.canvas = data.current.canvas; + data.current.canvas = null; + + if (this.activeRenderConfiguration.activeRenderer === data.current) { + this.activeRenderConfiguration.activeRenderer = data.replacement; + } + + if (this.activeRenderConfiguration.activeRenderer instanceof R3.Renderer.D2) { + + if (this.activeRenderConfiguration.activeCamera) { + this.activeRenderConfiguration.activeCamera.remove(); + this.activeRenderConfiguration.activeCamera = null; + } + + this.activeRenderConfiguration.activeScenes.map( + function(scene) { + scene.remove(); + } + ); + + this.activeRenderConfiguration.activeScenes = []; + } + + } +}; + +/** + * Removes a particle engine from this system + * @param data + */ +R3.System.Render.prototype.removeComponent = function(data) { + + var index; + + if (data.component instanceof R3.RenderConfiguration) { + + index = this.renderConfigurations.indexOf(data.component); + + if (index !== -1) { + console.log('removing renderer configuration from system'); + + this.renderConfigurations.splice(index, 1); + + } else { + console.log('failed to find the render configuration in the system : ' + data.component.name); + } + + if (this.renderConfigurations.length === 0) { + this.activeRenderConfiguration = null; + } + + if (this.renderConfigurations.length === 1) { + this.activeRenderConfiguration = this.renderConfigurations[0]; + } + } + + if (data.component instanceof R3.Renderer) { + + 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); + } + } + + if (data.component instanceof R3.D3.Composer) { + + index = this.composers.indexOf(data.component); + + if (index !== -1) { + console.log('removing composer from system'); + + this.composers.splice(index, 1); + + } else { + console.log('failed to find the composer in the system : ' + data.component.name); + } + } + + if (data.component instanceof R3.Stats) { + + index = this.statistics.indexOf(data.component); + + if (index !== -1) { + console.log('removing statistics from system'); + + this.statistics.splice(index, 1); + + } else { + console.log('failed to find the statistics in the system : ' + data.component.name); + } + } + + if (data.component instanceof R3.D3.Camera.Cube) { + + index = this.cubeCameras.indexOf(data.component); + + if (index !== -1) { + console.log('removing cube camera from system'); + + this.cubeCameras.splice(index, 1); + + } else { + console.log('failed to find the cube camera in the system : ' + data.component.name); + } + } + + if (data.component instanceof R3.D3.Mesh) { + index = this.excludedFromEnvironment.indexOf(data.component); + if (index !== -1) { + console.log('removing excluded environment mesh from system'); + this.excludedFromEnvironment.splice(index, 1); + } + } +}; + +/** + * Render subscription script + */ +R3.System.Render.prototype.render = function(data) { + + if (this.statistics) { + this.statistics.map( + function (statistics) { + statistics.start(); + } + ); + } + + R3.Event.Emit( + R3.Event.BEFORE_RENDER, + data + ); + + var configuration = this.activeRenderConfiguration; + + if (!configuration) { + return; + } + + var renderer = configuration.activeRenderer; + + if (renderer instanceof R3.Renderer.D2) { + return; + } + + var scenes = configuration.activeScenes; + + var camera = configuration.activeCamera; + + var effect = configuration.activeEffect; + + var composer = configuration.activeComposer; + + if ( + configuration.enableEffect && + (!effect || !effect.instance) + ) { + renderer.clear(); + return; + } + + if ( + configuration.enableComposer && + (!composer || !composer.instance || composer.passes.length === 0) + ) { + renderer.clear(); + return; + } + + if ( + renderer.renderMode === R3.API.Renderer.MODE_TARGET || + renderer.renderMode === R3.API.Renderer.MODE_CANVAS_AND_TARGET + ) { + if (!renderer.renderTarget) { + console.warn('no render renderTarget'); + return; + } + } + + var size = renderer.getSize(); + + renderer.viewports.map( + + function(viewport) { + + renderer.setViewport( + viewport.x * size.width, + viewport.y * size.height, + viewport.width * size.width, + viewport.height * size.height + ); + + /** + * Update any cube camera's based on the scene + */ + this.cubeCameras.map( + function(cubeCamera) { + + this.excludedFromEnvironment.map( + function(mesh){ + mesh.visible = false; + mesh.updateInstance('visible'); + } + ); + + scenes.map( + function(scene) { + cubeCamera.update(renderer, scene); + } + ); + + this.excludedFromEnvironment.map( + function(mesh){ + mesh.visible = true; + mesh.updateInstance('visible'); + } + ); + + }.bind(this) + ); + + if (configuration.enableComposer) { + composer.render(); + return; + } + + scenes.map( + + function (scene) { + + if (renderer.renderMode === R3.API.Renderer.MODE_TARGET || + renderer.renderMode === R3.API.Renderer.MODE_CANVAS_AND_TARGET) { + + renderer.renderToTarget( + scene, + camera + ) + + } + + if (renderer.renderMode === R3.API.Renderer.MODE_CANVAS || + renderer.renderMode === R3.API.Renderer.MODE_CANVAS_AND_TARGET) { + + if (configuration.enableEffect) { + effect.render(scene, camera); + return; + } + + renderer.render(scene, camera); + } + + }.bind(this) + ); + }.bind(this) + ); + + R3.Event.Emit( + R3.Event.AFTER_RENDER, + data + ); + + if (this.statistics) { + this.statistics.map( + function (statistics) { + statistics.end(); + } + ); + } +}; + +/** + * Stop the rendering system + */ +R3.System.Render.prototype.stop = function() { + + R3.System.prototype.stop.call(this); + + cancelAnimationFrame(this.animationFrameHook); + + this.instanceCreatedSubscription.remove(); + + this.removeComponentSubscription.remove(); + + this.replaceComponentSubscription.remove(); + + this.renderSubscription.remove(); + + this.getRenderConfigurationSubscription.remove(); + + this.setActiveRenderConfigurationSubscription.remove(); + + this.excludeFromEnvironmentSubscription.remove(); + + /** + * Images + */ + this.textureUpdatedSubscription.remove(); + + this.shaderUpdateSubscription.remove(); + + // this.delayedInstanceEncounteredSubscription.remove(); + + // window.removeEventListener( + // 'resize', + // this.nativeWindowResize, + // false + // ); + + // window.removeEventListener( + // 'orientationchangeend', + // this.nativeWindowResize, + // false + // ); + + this.windowResizeSubscription.remove(); + + this.renderers.map( + function(renderer) { + if (renderer.statistics) { + renderer.statistics.resize(); + renderer.canvas.instance.parentElement.removeChild(renderer.statistics.instance.dom); + } + } + ); + + this.renderConfigurations = []; + + this.renderers = []; + + this.composers = []; + + this.statistics = []; + + this.cubeCameras = []; +}; + diff --git a/src/r3-system-socket.js b/src/r3-system-socket.js new file mode 100644 index 0000000..1381cc9 --- /dev/null +++ b/src/r3-system-socket.js @@ -0,0 +1,176 @@ +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem R3.API.System + * @constructor + */ +R3.System.Socket = function( + apiSystem +) { + R3.System.call( + this, + apiSystem + ); + + this.totalTime = 0; + + this.castComponents = []; + + this.receiveComponents = []; + + this.servers = []; + + this.instanceCreatedSubscription = null; + + this.removeComponentSubscription = null; + + this.beforeRenderSubscription = null; +}; + +R3.System.Socket.prototype = Object.create(R3.System.prototype); +R3.System.Socket.prototype.constructor = R3.System.Socket; + +/** + * Start this system (add all event listeners) + */ +R3.System.Socket.prototype.start = function() { + + R3.System.prototype.start.call(this); + + this.castComponents = R3.EntityManager.Instance.queryComponents(R3.Component.SOCKET_CAST); + this.receiveComponents = R3.EntityManager.Instance.queryComponents(R3.Component.SOCKET_RECEIVE); + this.servers = R3.EntityManager.Instance.queryComponents(R3.Component.SERVER); + + this.instanceCreatedSubscription = R3.Event.Subscribe( + R3.Event.INSTANCE_CREATED, + this.instanceCreated.bind(this) + ); + + this.removeComponentSubscription = R3.Event.Subscribe( + R3.Event.REMOVE_COMPONENT, + this.removeComponent.bind(this) + ); + + this.beforeRenderSubscription = R3.Event.Subscribe( + R3.Event.BEFORE_RENDER, + this.beforeRender.bind(this) + ); + +}; + +/** + * Connect to the socket server + * @param socketComponent + */ +R3.System.Socket.prototype.connect = function(socketComponent) { + console.log(socketComponent.name + ' is connecting to the server ' + socketComponent.serverIp); +}; + +/** + * Disconnect from the socket server + * @param socketComponent + */ +R3.System.Socket.prototype.disconnect = function(socketComponent) { + console.log(socketComponent.name + ' is disconnecting from server ' + socketComponent.serverIp); +}; + + +/** + * From now on we want to track everything about a component, only from the systems that are active + * @param data + */ +R3.System.Socket.prototype.instanceCreated = function(data) { + + if (data.component instanceof R3.Socket.Cast) { + R3.Utils.PushUnique(this.castComponents, data.component); + } + + if (data.component instanceof R3.Socket.Receive) { + R3.Utils.PushUnique(this.receiveComponents, data.component); + } + + if (data.component instanceof R3.Server) { + R3.Utils.PushUnique(this.servers, data.component); + } +}; + +/** + * Removes a cast or receive component from this system + * @param data + */ +R3.System.Socket.prototype.removeComponent = function(data) { + + var index; + + if (data.component instanceof R3.Socket.Cast) { + + index = this.castComponents.indexOf(data.component); + + if (index !== -1) { + this.castComponents.splice(index, 1); + } else { + console.log('Socket System out of Cast Component sync') + } + } + + if (data.component instanceof R3.Socket.Receive) { + + index = this.receiveComponents.indexOf(data.component); + + if (index !== -1) { + this.receiveComponents.splice(index, 1); + } else { + console.log('Socket System out of Receive Component sync') + } + } + + + if (data.component instanceof R3.Server) { + + index = this.servers.indexOf(data.component); + + if (index !== -1) { + this.servers.splice(index, 1); + } else { + console.log('Socket System out of Server Component sync') + } + } + +}; + +/** + * @param data + */ +R3.System.Socket.prototype.beforeRender = function(data) { + + this.totalTime += data.delta; + +}; + + +/** + * Stop this system (remove all event listeners) + */ +R3.System.Socket.prototype.stop = function() { + + R3.System.prototype.stop.call(this); + + this.instanceCreatedSubscription.remove(); + this.removeComponentSubscription.remove(); + this.beforeRenderSubscription.remove(); + + this.servers = this.servers.reduce( + function(result, serverComponent) { + + if (!serverComponent.disconnect()) { + result.push(serverComponent); + } + + }.bind(this), + [] + ); + + if (this.servers.length !== 0) { + console.warn(this.servers.length + ' connections still open after socket system stopped'); + } + +}; diff --git a/src/r3-system-storage.js b/src/r3-system-storage.js new file mode 100644 index 0000000..0e08da9 --- /dev/null +++ b/src/r3-system-storage.js @@ -0,0 +1,996 @@ +/** + * Storage System takes care loading and linking components and dependencies + * @param apiSystem R3.API.System + * @param token + * @param apiUploadUrl + * @param onImageLoaded + * @param onImageProgress + * @param onImageError + * @constructor + */ +R3.System.Storage = function( + apiSystem, + token, + apiUploadUrl, + onImageLoaded, + onImageProgress, + onImageError +) { + R3.System.call( + this, + apiSystem + ); + + if (R3.Utils.UndefinedOrNull(token)) { + token = null; + } + this.token = token; + + if (R3.Utils.UndefinedOrNull(apiUploadUrl)) { + console.warn('Need an API Upload URL for a storage system'); + apiUploadUrl = ''; + } + this.apiUploadUrl = apiUploadUrl; + + if (R3.Utils.UndefinedOrNull(onImageLoaded)) { + onImageLoaded = null; + } + this.onImageLoaded = onImageLoaded; + + if (R3.Utils.UndefinedOrNull(onImageProgress)) { + onImageProgress = null; + } + this.onImageProgress = onImageProgress; + + if (R3.Utils.UndefinedOrNull(onImageError)) { + onImageError = null; + } + this.onImageError = onImageError; + + 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; +}; + +R3.System.Storage.prototype = Object.create(R3.System.prototype); +R3.System.Storage.prototype.constructor = R3.System.Storage; + +R3.System.Storage.prototype.start = function() { + + R3.System.prototype.start.call(this); + + this.loginSubscription = this.subscribe( + R3.Event.LOGGED_IN, + function(data) { + this.token = data.token; + } + ); + + this.saveSubscription = this.subscribe( + R3.Event.SAVE_COMPONENT, + this.save + ); + + this.loadSubscription = this.subscribe( + R3.Event.LOAD_COMPONENT, + this.load + ); + + this.deleteSubscription = this.subscribe( + R3.Event.DELETE_COMPONENT, + this.delete + ); + + this.loadImageSubscription = this.subscribe( + R3.Event.LOAD_IMAGE, + this.loadImage + ); + + this.loadFontSubscription = this.subscribe( + R3.Event.LOAD_FONT, + this.loadFont + ); + + this.blenderDataSubscription = this.subscribe( + R3.Event.BLENDER_DATA_RECEIVED, + this.processBlenderData + ); + + this.imageUploadCompleteSubscription = this.subscribe( + R3.Event.IMAGE_UPLOAD_COMPLETE, + this.imageUploadComplete + ); + + this.fetchComponentTypesSubscription = this.subscribe( + R3.Event.FETCH_COMPONENT_TYPES, + this.fetchComponentTypes + ); + + this.fetchComponentsSubscription = this.subscribe( + R3.Event.FETCH_COMPONENTS, + this.fetchComponents + ); + +}; + + +R3.System.Storage.prototype.delete = function(data) { + + this.publish( + R3.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) { + R3.Event.Emit( + R3.Event.DELETE_COMPONENT_ERROR, + { + message: this.responseText + } + ) + } + + if (response.result === 'success') { + R3.Event.Emit( + R3.Event.COMPONENT_DELETED, + { + message: response.message || 'Successfully saved the component' + } + ) + } else { + R3.Event.Emit( + R3.Event.DELETE_COMPONENT_ERROR, + { + message: response.message || 'The server responded but failed to save the component' + } + ) + } + } + }; + + xhr.send(JSON.stringify({ + session : this.token, + includeDependencies : data.includeDependencies + })); + + }.bind(this)); + }.bind(this), + function(error) { + console.error(error.message); + throw new Error(error.message); + } + ); + + +}; + +/** + * 'Saves' data to somewhere + */ +R3.System.Storage.prototype.save = function(data) { + + var event = R3.Event.GET_API_URL; + + if (data.remote) { + event = R3.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) { + R3.Event.Emit( + R3.Event.SAVE_COMPONENT_ERROR, + { + message: this.responseText, + component : data.apiObject + } + ) + } + + if (response.result === 'success') { + R3.Event.Emit( + R3.Event.COMPONENT_SAVED, + { + message: response.message || 'Successfully saved the component', + component : data.apiObject + } + ) + } else { + R3.Event.Emit( + R3.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 + })); + }, + function error(error){ + console.error(error); + } + ); + +}; + +R3.System.Storage.prototype.createRuntimeObject = function(responseText, clientErrorCallback) { + + try { + var object = JSON.parse(responseText); + } catch (errorObject) { + + if (clientErrorCallback) { + clientErrorCallback({ + message : errorObject.message || 'JSON parse error' + }) + } + + R3.Event.Emit( + R3.Event.LOAD_COMPONENT_ERROR, + {error: errorObject} + ); + + return null; + } + + if (object.result !== 'success') { + + if (clientErrorCallback) { + clientErrorCallback({ + message : object.message || 'Server load error' + }) + } + + R3.Event.Emit( + R3.Event.LOAD_COMPONENT_ERROR, + {error : object} + ); + + return 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 runtimeComponent = R3.Component.ConstructFromObject(object.component[0]); + + if (!runtimeComponent) { + if (clientErrorCallback) { + clientErrorCallback({ + result: 'failure', + message: 'Could not create a runtime component: ' + object.component[0].name + }); + } + } + + return runtimeComponent; +}; + +R3.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) { + + R3.Utils.PushUnique(this.loading, id); + + var component = R3.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' + ) { + R3.EntityManager.Instance.queryComponents(R3.Component.ENTITY).map( + function (entity) { + if (runtimeComponent.parentEntity === entity.id) { + runtimeComponent.parentEntity = entity; + } + } + ); + } + + R3.Event.Emit( + R3.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) { + R3.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 (R3.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) { + R3.Utils.PushUnique(__system.loading, dependency); + } + ); + + __system.loadComponent(apiUrl, dependencies, includeDependencies, clientCallback, clientErrorCallback); + + } + + // R3.Event.Emit( + // R3.Event.COMPONENT_DOWNLOAD_COMPLETE, + // { + // loaded: __system.loaded + // } + // ); + + R3.Event.Emit( + R3.Event.LOAD_PROGRESS, + { + loading : __system.loading.length, + loaded : __system.loaded.length + } + ); + + if (__system.loading.length === __system.loaded.length) { + + console.log('loaded ' + __system.loaded.length + ' components'); + + if (clientCallback) { + clientCallback({ + components : __system.loaded + }) + } + + __system.otherDependencies = []; + __system.loaded = []; + } + + + + } + + }(this); + + xhr.onerror = function(__id) { + return function (error) { + console.warn('component load failed for component ID ' + __id); + + if (clientErrorCallback) { + clientErrorCallback(error || {message:'xhr failure'}) + } + }.bind(this); + }(id); + + xhr.open( + 'GET', + apiUrl + '/component/load/' + id + ); + + + xhr.send(); + + }.bind(this) + + ); + + +}; + +/** + * 'Loads' data from a url + */ +R3.System.Storage.prototype.load = function(data, clientCallback, clientErrorCallback) { + + this.publish( + R3.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); + } + ); + +}; + +R3.System.Storage.prototype.xhrLoad = function( + url, + callback, + errorCallback +) { + + if (typeof XMLHttpRequest === 'undefined') { + console.log('Implement server side load here'); + return; + } + + console.log('Loading from ' + url); + + 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 + */ +R3.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 + */ +R3.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 + */ +R3.System.Storage.prototype.imageUploadComplete = function(data) { + + /** + * Process all images - we have to load them in addition to creating their runtime components + */ + data.images.map(function(rawImage){ + + var image = R3.EntityManager.Instance.findComponentById(rawImage.id); + + if (image) { + /** + * We are updating an existing image + */ + image.updateFromRawObject(rawImage); + + /** + * Our symbolic path has changed server side, even though it looks the same + */ + image.updateInstance('path'); + + } else { + /** + * We are creating a new image + */ + R3.Component.ConstructFromObject(rawImage); + } + + }.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 + */ +R3.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(rawImageObject) { + var image = R3.Component.ConstructFromObject(rawImageObject); + R3.Event.Emit( + R3.Event.COMPONENT_CREATED, + { + component: image + } + ); + }.bind(this) + ); + + /** + * Process all textures + */ + data.textures.map(function(rawTextureObject){ + var texture = R3.Component.ConstructFromObject(rawTextureObject); + R3.Event.Emit( + R3.Event.COMPONENT_CREATED, + { + component: texture + } + ); + }.bind(this)); + + /** + * Process all materials + */ + data.materials.map(function(rawMaterialObject){ + var material = R3.Component.ConstructFromObject(rawMaterialObject); + R3.Event.Emit( + R3.Event.COMPONENT_CREATED, + { + component: material + } + ); + }.bind(this)); + + /** + * Now process all meshes + */ + data.meshes.map(function(rawMeshObject){ + var mesh = R3.Component.ConstructFromObject(rawMeshObject); + R3.Event.Emit( + R3.Event.COMPONENT_CREATED, + { + component: mesh + } + ); + }.bind(this)); + + /** + * And that should be it... + */ +}; + +R3.System.Storage.prototype.loadFont = function(data, callback, errorCallback) { + + console.log('loading font : ' + data.font.name); + + this.publish( + R3.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 (R3.Utils.IsEmpty(font.data)) { + + errorCallback({message:'font is empty'}); + + } else { + + callback(font); + + } + } + ); + + }.bind(this), + function(error) { + errorCallback(error); + } + ); + + +}; + +R3.System.Storage.prototype.loadImage = function(data, callback, errorCallback) { + + console.log('loading image : ' + data.image.name); + + this.publish( + R3.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() { + + window.URL = window.URL || window.webkitURL; + + // + // console.log(image.name + ' - response type : ' + this.response.type); + + var url; + + if (this.response.type.indexOf('application/json') !== -1) { + + var base64 = 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gIPDBcYqg62uwAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAaSURBVCjPY/z//z8DKYCJgUQwqmFUw9DRAABVbQMdny4VogAAAABJRU5ErkJggg=='; + + function fixBinary (bin) { + var length = bin.length; + var buf = new ArrayBuffer(length); + var arr = new Uint8Array(buf); + for (var i = 0; i < length; i++) { + arr[i] = bin.charCodeAt(i); + } + return buf; + } + + var binary = fixBinary(atob(base64)); + var blob = new Blob([binary], {type: 'image/png'}); + try { + url = window.URL.createObjectURL(blob); + } + catch (error) { + if (errorCallback) { + errorCallback({ + result: 'failure', + message: 'invalid server response trying to download image ' + data.image.name + }); + } + } + console.log('creating url : ' + url); + + + } else { + try { + url = window.URL.createObjectURL(this.response); + } catch (error) { + if (errorCallback) { + errorCallback({ + result: 'failure', + message: 'invalid server response trying to download image ' + data.image.name + }); + } + } + } + + var img = new Image(); + + img.onload = function() { + + window.URL.revokeObjectURL(url); + + if (callback) { + callback(img); + } + + 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 (errorCallback) { + errorCallback(error); + } + + if (onError) { + onError(image, error) + } + }; + + xhr.send(); + }; + + preflight.onerror = function(error) { + console.warn('image pre-flight request failed for image ' + image.name); + + if (errorCallback) { + errorCallback(error); + } + + if (onError) { + onError(image, error); + } + }; + + preflight.send(); + }.bind(this), + function(error) { + console.error(error.message); + throw new Error(error.message); + } + ); + + +}; + +R3.System.Storage.prototype.stop = function() { + + R3.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(); +}; + diff --git a/src/r3-system-visualization.js b/src/r3-system-visualization.js new file mode 100644 index 0000000..5e03c0c --- /dev/null +++ b/src/r3-system-visualization.js @@ -0,0 +1,148 @@ +/** + * 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 R3.API.System + * @param graphics + * @param physics + * @constructor + */ +R3.System.Visualization = function( + apiSystem, + graphics, + physics +) { + + R3.System.call( + this, + apiSystem + ); + + if (R3.Utils.UndefinedOrNull(graphics)){ + R3.Event.Emit( + R3.Event.GET_GRAPHICS_RUNTIME, + null, + function(graphicsRuntime) { + graphics = graphicsRuntime; + }.bind(this), + function() { + graphics = null; + }.bind(this) + ); + } + this.graphics = graphics; + + if (R3.Utils.UndefinedOrNull(physics)){ + R3.Event.Emit( + R3.Event.GET_PHYSICS_RUNTIME, + null, + function(physicsRuntime) { + physics = physicsRuntime; + }.bind(this), + function() { + physics = null; + }.bind(this) + ); + } + this.physics = physics; + + this.visualizationSubscription = null; + this.stopVisualizationSubscription = null; + +}; + +R3.System.Visualization.prototype = Object.create(R3.System.prototype); +R3.System.Visualization.prototype.constructor = R3.System.Visualization; + +R3.System.Visualization.prototype.start = function() { + + R3.System.prototype.start.call(this); + + this.visualizationSubscription = this.subscribe( + R3.Event.VISUALIZE, + this.visualize + ); + + this.stopVisualizationSubscription = this.subscribe( + R3.Event.STOP_VISUALIZE, + this.stopVisualize + ) +}; + + +R3.System.Visualization.prototype.visualize = function(data) { + + var shape = data.shape; + + var parentMesh = shape.parentMesh; + + shape.setFromMesh(); + + var apiMesh = new R3.D3.API.Mesh(); + + apiMesh.name = 'Visualization Mesh for Shape ' + shape.name; + + if (shape instanceof R3.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 R3.D3.API.Vertex( + new R3.API.Vector3(v0.x, v0.y, v0.z) + ), + new R3.D3.API.Vertex( + new R3.API.Vector3(v1.x, v1.y, v1.z) + ), + new R3.D3.API.Vertex( + new R3.API.Vector3(v2.x, v2.y, v2.z) + ) + ); + var i = apiMesh.vertices.length - 3; + apiMesh.faces.push( + new R3.D3.API.Face( + null, + null, + i, + i+1, + i+2 + ) + ); + } + } + } + } + + new R3.D3.Mesh( + this.graphics, + apiMesh + ); + +}; + +R3.System.Visualization.prototype.stopVisualize = function(data) { +}; + +R3.System.Visualization.prototype.stop = function() { + + R3.System.prototype.stop.call(this); + + if (this.visualizationSubscription) { + this.visualizationSubscription.remove(); + } + + if (this.stopVisualizationSubscription) { + this.stopVisualizationSubscription.remove(); + } + +}; + diff --git a/src/r3-vector2.js b/src/r3-vector2.js new file mode 100644 index 0000000..ca0a6e8 --- /dev/null +++ b/src/r3-vector2.js @@ -0,0 +1,291 @@ +/** + * Runtime vector2 for updating instance objects + * @param graphics R3.GraphicsRuntime + * @param parentObject R3.D3.* + * @param apiVector2 R3.API.Vector2 + * @param grain Number + * @constructor + */ +R3.Vector2 = function ( + graphics, + apiVector2, + parentObject, + grain +) { + this.graphics = graphics; + + if (R3.Utils.UndefinedOrNull(apiVector2)) { + apiVector2 = {}; + } + + R3.API.Vector2.call( + this, + apiVector2.x, + apiVector2.y + ); + + if (R3.Utils.UndefinedOrNull(parentObject)) { + parentObject = null; + } + this.parentObject = parentObject; + + if (R3.Utils.UndefinedOrNull(grain)) { + grain = 0.001; + } + this.grain = grain; + + this.createInstance(); +}; + +R3.Vector2.prototype = Object.create(R3.API.Vector2.prototype); +R3.Vector2.prototype.constructor = R3.Vector2; + + +/** + * Creates an instance vector2 + * @returns {*} + */ +R3.Vector2.prototype.createInstance = function() { + + if (this.graphics && this.graphics.isThree()) { + this.instance = new THREE.Vector2(this.x, this.y); + } else { + this.instance = this; + } + +}; + +/** + * Updates the instance vector, calls updateInstance on the parent object + */ +R3.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 {R3.API.Vector2} + */ +R3.Vector2.prototype.toApiObject = function() { + return new R3.API.Vector2( + this.x, + this.y + ); +}; + +/** + * Copy + * TODO: Test + * @param v optional + * @returns {R3.Vector2} + */ +R3.Vector2.prototype.copy = function (v) { + + if (R3.Utils.UndefinedOrNull(v)) { + + return new R3.Vector2( + this.graphics, + new R3.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} + */ +R3.Vector2.prototype.equals = function(v) { + + if ((this.x == v.x) && + (this.y == v.y)) { + return true; + } else { + return false; + } + +}; + +/** + * Add + * TODO: Test + * @param v + */ +R3.Vector2.prototype.add = function(v) { + + if ( + v instanceof R3.API.Vector2 || + v instanceof R3.API.Vector3 || + v instanceof R3.API.Vector4 || + v instanceof R3.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 + */ +R3.Vector2.prototype.subtract = function(v) { + + if ( + v instanceof R3.API.Vector2 || + v instanceof R3.API.Vector3 || + v instanceof R3.API.Vector4 || + v instanceof R3.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 + */ +R3.Vector2.prototype.multiply = function(v) { + + if ( + v instanceof R3.API.Vector2 || + v instanceof R3.API.Vector3 || + v instanceof R3.API.Vector4 || + v instanceof R3.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 + */ +R3.Vector2.prototype.divide = function(v) { + + if ( + v instanceof R3.API.Vector2 || + v instanceof R3.API.Vector3 || + v instanceof R3.API.Vector4 || + v instanceof R3.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 R3.API.Vector2 + * @param max R3.API.Vector2 + * @returns {R3.Vector2} + */ +R3.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} + */ +R3.Vector2.prototype.length = function() { + return Math.sqrt( + this.x * this.x + this.y * this.y + ); +}; + +/** + * Dot product + * TODO: Test + * @param v + * @returns {number} + */ +R3.Vector2.prototype.dot = function(v) { + return this.x * v.x + this.y * v.y; +}; + +/** + * Normalize + * TODO: Test + */ +R3.Vector2.prototype.normalize = function() { + return this.multiply(1.0 / this.length()); +}; + +/** + * TODO: Test + * Angle between this vector and origin + * @returns {number} + */ +R3.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 {R3.Vector2} + */ +R3.Vector2.prototype.lerp = function ( v, alpha ) { + return new R3.Vector2( + this.x + ( v.x - this.x ) * alpha, + this.y + ( v.y - this.y ) * alpha + ); +}; \ No newline at end of file diff --git a/src/r3-vector3.js b/src/r3-vector3.js new file mode 100644 index 0000000..cdff564 --- /dev/null +++ b/src/r3-vector3.js @@ -0,0 +1,193 @@ +/** + * Runtime apiVector3 for updating instance objects + * @param implementation R3.GraphicsRuntime + * @param apiVector3 R3.API.Vector3 + * @param parentObject R3.* + * @param grain Number + * @param min + * @param max + * @constructor + */ +R3.Vector3 = function ( + implementation, + apiVector3, + parentObject, + grain, + min, + max +) { + + this.implementation = implementation; + + if (implementation instanceof R3.GraphicsRuntime) { + this.physics = null; + this.graphics = implementation; + this.graphics.isNotThreeThrow(); + } else if (implementation instanceof R3.PhysicsRuntime) { + this.graphics = null; + this.physics = implementation; + this.physics.isNotCannonThrow(); + } else { + throw new Error('Unhandled implementation : ' + implementation); + } + + if (R3.Utils.UndefinedOrNull(apiVector3)) { + apiVector3 = {}; + } + + R3.API.Vector3.call( + this, + apiVector3.x, + apiVector3.y, + apiVector3.z + ); + + if (R3.Utils.UndefinedOrNull(parentObject)) { + parentObject = this; + } + this.parentObject = parentObject; + + if (R3.Utils.UndefinedOrNull(grain)) { + grain = 0.001; + } + this.grain = grain; + + if (R3.Utils.UndefinedOrNull(min)) { + min = 0; + } + this.min = min; + + if (R3.Utils.UndefinedOrNull(max)) { + max = 1; + } + this.max = max; + + + this.createInstance(); +}; + +R3.Vector3.prototype = Object.create(R3.API.Vector3.prototype); +R3.Vector3.prototype.constructor = R3.Vector3; + +/** + * Creates an instance vector3 + * @returns {*} + */ +R3.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 + */ +R3.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 + */ +R3.Vector3.prototype.toApiObject = function() { + return new R3.API.Vector3( + this.x, + this.y, + this.z + ); +}; + +/** + * Creates a new copy of this Vector3 + */ +R3.Vector3.prototype.copy = function() { + return new R3.Vector3( + this.implementation, + new R3.API.Vector3( + this.x, + this.y, + this.z + ), + this.parentObject, + this.grain + ) +}; + +R3.Vector3.prototype.clone = function() { + return new R3.Vector3( + this.implementation, + new R3.API.Vector3( + this.x, + this.y, + this.z + ), + this.parentObject, + this.grain + ) +}; + +/** + * Create a negative version of this vector + * @returns {R3.Vector3} + */ +R3.Vector3.prototype.negativeCopy = function() { + return new R3.Vector3( + this.implementation, + new R3.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 + */ +R3.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; +}; + +R3.Vector3.prototype.setFrom = function(vector3) { + this.x = vector3.x; + this.y = vector3.y; + this.z = vector3.z; +}; diff --git a/src/r3-vector4.js b/src/r3-vector4.js new file mode 100644 index 0000000..36e319a --- /dev/null +++ b/src/r3-vector4.js @@ -0,0 +1,86 @@ +/** + * Runtime apiVector4 for updating instance objects + * @param graphics R3.GraphicsRuntime + * @param apiVector4 R3.API.Vector4 + * @param parentObject R3.* + * @param grain Number + * @constructor + */ +R3.Vector4 = function ( + graphics, + apiVector4, + parentObject, + grain +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (R3.Utils.UndefinedOrNull(apiVector4)) { + apiVector4 = {}; + } + + R3.API.Vector4.call( + this, + apiVector4.x, + apiVector4.y, + apiVector4.z, + apiVector4.w + ); + + if (R3.Utils.UndefinedOrNull(parentObject)) { + parentObject = null; + } + this.parentObject = parentObject; + + if (R3.Utils.UndefinedOrNull(grain)) { + grain = 0.001; + } + this.grain = grain; + + this.createInstance(); +}; + +R3.Vector4.prototype = Object.create(R3.API.Vector4.prototype); +R3.Vector4.prototype.constructor = R3.Vector4; + +/** + * Creates an instance vector4 + * @returns {*} + */ +R3.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 + */ +R3.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 + */ +R3.Vector4.prototype.toApiObject = function() { + return new R3.API.Vector4( + this.x, + this.y, + this.z, + this.w + ); +}; diff --git a/src/r3-z.js b/src/r3-z.js new file mode 100644 index 0000000..3c359cb --- /dev/null +++ b/src/r3-z.js @@ -0,0 +1,10 @@ + +R3.EntityManager.Instance = new R3.EntityManager(); + +if (typeof window !== 'undefined') { + window.R3 = R3; +} + +if (typeof module !== 'undefined') { + module.exports = R3; +} \ No newline at end of file