main/service/RenderService.js
import { Graphic } from 'model/component/Graphic';
import { Sprite } from 'model/component/Sprite';
import { Canvas } from 'model/component/Canvas';
import { Camera2D } from 'model/core/Camera2D';
import { Three } from 'link/Three';
import { Logger } from 'commons/Logger';
import { GameState } from 'GameState';
const cameras = new Map();
const scenes = new Map();
export class RenderService {
static get DEFAULT_SCENE_ID() {
return 'default_scene_id';
}
static get DEFAULT_CAMERA_ID() {
return 'default_camera_id';
}
constructor(width, height, targetWidth, targetHeight) {
this._logger = new Logger(RenderService.name);
GameState.width = width;
GameState.height = height;
var canvas = document.createElement("canvas");
this._renderer = (canvas.getContext('webgl') || canvas.getContext('experimental-webgl'))
? new Three.WebGLRenderer({ antialias: true })
: new Three.CanvasRenderer();
this._renderer.setClearColor(0x000000, 1);
this.createScene(RenderService.DEFAULT_SCENE_ID);
this.createCamera(RenderService.DEFAULT_CAMERA_ID);
}
get domElement() {
return this._renderer.domElement;
}
createScene(sceneId) {
scenes.set(sceneId, new Three.Scene());
}
createCamera(cameraId, { width = GameState.width, height = GameState.height, sceneId = RenderService.DEFAULT_SCENE_ID } = {}) {
if (scenes.has(sceneId)) {
var camera = new Camera2D(cameraId, width / -2, width / 2, height / -2, height / 2, Math.max(width, height) / -2, Math.max(width, height) / 2);
camera.sceneIds.add(sceneId);
cameras.set(cameraId, camera);
} else {
throw Error("Invalid scene " + sceneId);
}
}
update(component, position, rotation, scale) {
if (component instanceof Sprite) {
if (component.state === Graphic.STATE.REGISTERED) {
component.mesh.position.set(position.x, position.y, position.z);
component.mesh.rotation.set(rotation.x, rotation.y, rotation.z);
component.mesh.scale.set(-scale.x, scale.y, scale.z);
} else if (component.state === Graphic.STATE.LOADED) {
scenes.get(component.sceneId).add(component.mesh);
component.state = Graphic.STATE.REGISTERED;
} else if (component.state === Graphic.STATE.CREATED) {
component.sceneId = component.sceneId ? component.sceneId : RenderService.DEFAULT_SCENE_ID;
component.state = Graphic.STATE.BUFFERING;
new Three.TextureLoader().load(
component.source,
function (texture) { // load callback
component.texture = texture;
component.texture.wrapS = component.texture.wrapT = Three.ClampToEdgeWrapping;
component.texture.flipY = true;
component.texture.minFilter = Three.NearestFilter;
component.texture.offset.x = component.row / component.cols;
component.texture.offset.y = component.col / component.rows;
component.texture.repeat.set(1 / component.cols, 1 / component.rows);
component.material = new Three.MeshBasicMaterial({ map: component.texture, side: Three.FrontSide });
component.material.transparent = true;
component.geometry = new Three.PlaneBufferGeometry(component.w, component.h, 1, 1);
component.mesh = new Three.Mesh(component.geometry, component.material);
component.state = Graphic.STATE.LOADED;
this._logger.debug("texture loaded", component.source);
}.bind(this),
function (xhr) { // download callback
this._logger.debug("texture " + (xhr.loaded / xhr.total * 100) + "% loaded", component);
}.bind(this),
function (xhr) { // error callback
component.state = Graphic.STATE.FAILED;
this._logger.error("error while loading texture", component.source, xhr);
}.bind(this)
);
} else if (component.state === Graphic.STATE.FAILED) {
throw Error("Sprite failed to load with source " + component.source);
}
} else if (component instanceof Canvas) {
if (component.state === Graphic.STATE.REGISTERED) {
component.context.imageSmoothingEnabled = false;
component.context.webkitImageSmoothingEnabled = false;
component.context.mozImageSmoothingEnabled = false;
component.clear();
component.draw();
// This makes the textures created during execution to work properly
//component.texture.needsUpdate = true;
component.texture.image = component.canvas;
} else if (component.state === Graphic.STATE.CREATED) {
component.canvas = document.createElement('canvas');
component.canvas.width = component.width;
component.canvas.height = component.height;
component.context = component.canvas.getContext("2d");
component.texture = new Three.Texture(this.canvas);
component.texture.flipY = true;
component.texture.wrapS = component.texture.wrapT = Three.ClampToEdgeWrapping;
component.texture.minFilter = Three.NearestFilter;
component.material = new Three.MeshBasicMaterial({
map: component.texture,
side: Three.FrontSide
});
component.material.transparent = true;
component.geometry = new Three.PlaneBufferGeometry(component.width, component.height, 1, 1);
component.mesh = new Three.Mesh(component.geometry, component.material);
scenes.get(RenderService.DEFAULT_SCENE_ID).add(component.mesh);
component.state = Graphic.STATE.REGISTERED;
}
}
}
render() {
this._renderer.setSize(GameState.width * GameState.ratio, GameState.height * GameState.ratio);
cameras.forEach(camera => {
camera.sceneIds.forEach(sceneId => {
this._renderer.render(scenes.get(sceneId), camera.cam);
});
});
}
}