Initial commit
This commit is contained in:
11
C#/TSEngine/Core/Assets/IAsset.ts
Normal file
11
C#/TSEngine/Core/Assets/IAsset.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace TSE {
|
||||
|
||||
export interface IAsset {
|
||||
|
||||
readonly name: string;
|
||||
|
||||
readonly data: any;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
11
C#/TSEngine/Core/Assets/IAssetLoader.ts
Normal file
11
C#/TSEngine/Core/Assets/IAssetLoader.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace TSE {
|
||||
|
||||
export interface IAssetLoader {
|
||||
|
||||
readonly supportedExtensions: string[];
|
||||
|
||||
loadAsset(assetName: string): void;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
54
C#/TSEngine/Core/Assets/assetManager.ts
Normal file
54
C#/TSEngine/Core/Assets/assetManager.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
namespace TSE {
|
||||
|
||||
export const MESSAGE_ASSET_LOADER_ASSET_LOADED = "MESSAGE_ASSET_LOADER_ASSET_LOADED::";
|
||||
|
||||
export class AssetManager {
|
||||
|
||||
private static _loaders: IAssetLoader[] = [];
|
||||
private static _loadedAssets: { [name: string]: IAsset } = {};
|
||||
|
||||
private constructor() {}
|
||||
|
||||
public static initialize(): void {
|
||||
this.registerLoader(new ImageAssetLoader());
|
||||
this.registerLoader(new JsonAssetLoader());
|
||||
}
|
||||
|
||||
public static registerLoader(loader: IAssetLoader): void {
|
||||
AssetManager._loaders.push(loader);
|
||||
}
|
||||
|
||||
public static onAssetLoaded(asset: IAsset): void {
|
||||
AssetManager._loadedAssets[asset.name] = asset;
|
||||
Message.send(MESSAGE_ASSET_LOADER_ASSET_LOADED + asset.name, this, asset);
|
||||
}
|
||||
|
||||
public static loadAsset(assetName: string): void {
|
||||
let extention = assetName.split('.').pop().toLowerCase();
|
||||
for (let loader of AssetManager._loaders) {
|
||||
if (loader.supportedExtensions.indexOf(extention) !== -1) {
|
||||
loader.loadAsset(assetName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
console.warn("Unable to load asset with extention: '" + extention + "'. no loader was found.");
|
||||
}
|
||||
|
||||
public static isAssetLoaded(assetName: string): boolean {
|
||||
return AssetManager._loadedAssets[assetName] !== undefined;
|
||||
}
|
||||
|
||||
public static getAsset(assetName: string): IAsset {
|
||||
if (AssetManager.isAssetLoaded(assetName)) {
|
||||
return AssetManager._loadedAssets[assetName];
|
||||
} else {
|
||||
AssetManager.loadAsset(assetName);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
42
C#/TSEngine/Core/Assets/imageAssetLoader.ts
Normal file
42
C#/TSEngine/Core/Assets/imageAssetLoader.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
namespace TSE {
|
||||
|
||||
export class ImageAsset implements IAsset {
|
||||
|
||||
public readonly name: string;
|
||||
|
||||
public readonly data: HTMLImageElement;
|
||||
|
||||
public constructor(name: string, data: HTMLImageElement) {
|
||||
this.name = name;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public get width(): number {
|
||||
return this.data.width;
|
||||
}
|
||||
|
||||
public get height(): number {
|
||||
return this.data.height;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ImageAssetLoader implements IAssetLoader {
|
||||
|
||||
public get supportedExtensions(): string[] { return ["png", "gif", "jpg", "jpeg"] }
|
||||
|
||||
public loadAsset(assetName: string): void {
|
||||
let image: HTMLImageElement = new Image();
|
||||
image.onload = this.onImageLoaded.bind(this, assetName, image);
|
||||
image.src = assetName;
|
||||
}
|
||||
|
||||
private onImageLoaded(assetName: string, image: HTMLImageElement): void {
|
||||
console.log("onImageLoaded: assetName/image", assetName, image);
|
||||
let asset = new ImageAsset(assetName, image);
|
||||
AssetManager.onAssetLoaded(asset);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
39
C#/TSEngine/Core/Assets/jsonAssetLoader.ts
Normal file
39
C#/TSEngine/Core/Assets/jsonAssetLoader.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
namespace TSE {
|
||||
|
||||
export class JsonAsset implements IAsset {
|
||||
|
||||
public readonly name: string;
|
||||
|
||||
public readonly data: any;
|
||||
|
||||
public constructor(name: string, data: any) {
|
||||
this.name = name;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class JsonAssetLoader implements IAssetLoader {
|
||||
|
||||
public get supportedExtensions(): string[] { return ["json"] }
|
||||
|
||||
public loadAsset(assetName: string): void {
|
||||
let request: XMLHttpRequest = new XMLHttpRequest();
|
||||
request.open("GET", assetName);
|
||||
request.addEventListener("load", this.onJsonLoaded.bind(this, assetName, request));
|
||||
request.send();
|
||||
}
|
||||
|
||||
private onJsonLoaded(assetName: string, request: XMLHttpRequest): void {
|
||||
console.log("onJsonLoaded: assetName/request", assetName, request);
|
||||
|
||||
if (request.readyState === request.DONE) {
|
||||
let json = JSON.parse(request.responseText);
|
||||
let asset = new JsonAsset(assetName, json);
|
||||
AssetManager.onAssetLoaded(asset);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
45
C#/TSEngine/Core/Behaviors/behavior.ts
Normal file
45
C#/TSEngine/Core/Behaviors/behavior.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
namespace TSE {
|
||||
|
||||
export class BaseBehavior {
|
||||
public name: string;
|
||||
protected _data: IBehaviorData;
|
||||
protected _owner: SimObject;
|
||||
|
||||
public constructor(data: IBehaviorData) {
|
||||
this._data = data;
|
||||
this.name = data.name;
|
||||
}
|
||||
|
||||
public set owner(value: SimObject) { this._owner = value; }
|
||||
|
||||
public update(time: number): void {}
|
||||
public apply(userData: any): void {}
|
||||
|
||||
}
|
||||
|
||||
export interface IBehaviorBuilder {
|
||||
get type(): string;
|
||||
buildFromJson(json: any): BaseBehavior;
|
||||
}
|
||||
|
||||
export interface IBehaviorData {
|
||||
name: string;
|
||||
setFromJson(json: any): void;
|
||||
}
|
||||
|
||||
export class BehaviorManager {
|
||||
|
||||
private static _registeredBuilders: {[type: string]: IBehaviorBuilder} = {};
|
||||
|
||||
public static registerBuilder(builder: IBehaviorBuilder): void {
|
||||
BehaviorManager._registeredBuilders[builder.type] = builder;
|
||||
}
|
||||
|
||||
public static extractComponent(json: any): BaseBehavior {
|
||||
if (BehaviorManager._registeredBuilders[json?.type] === undefined) return undefined;
|
||||
return BehaviorManager._registeredBuilders[json.type].buildFromJson(json);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
46
C#/TSEngine/Core/Behaviors/rotationBehavior.ts
Normal file
46
C#/TSEngine/Core/Behaviors/rotationBehavior.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
///<reference path="behavior.ts"/>
|
||||
|
||||
namespace TSE {
|
||||
|
||||
export class RotationBehaviorData implements IBehaviorData {
|
||||
public name: string;
|
||||
public rotation: Vector3 = Vector3.zero;
|
||||
|
||||
public setFromJson(json: any): void {
|
||||
if (json?.name === undefined) return;
|
||||
this.name = String(json.name);
|
||||
this.rotation.setFromJson(json.rotation);
|
||||
}
|
||||
}
|
||||
|
||||
export class RotationBehaviorBuilder implements IBehaviorBuilder {
|
||||
public buildFromJson(json: any): TSE.BaseBehavior {
|
||||
let data = new RotationBehaviorData();
|
||||
data.setFromJson(json);
|
||||
return new RotationBehavior(data);
|
||||
}
|
||||
|
||||
public get type(): string { return "rotation"; }
|
||||
}
|
||||
|
||||
export class RotationBehavior extends BaseBehavior{
|
||||
|
||||
private _rotation: Vector3;
|
||||
|
||||
public constructor(data: RotationBehaviorData) {
|
||||
super(data);
|
||||
|
||||
this._rotation = data.rotation;
|
||||
}
|
||||
|
||||
public update(time: number) {
|
||||
this._owner.transform.rotation.add(this._rotation);
|
||||
|
||||
super.update(time);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BehaviorManager.registerBuilder(new RotationBehaviorBuilder());
|
||||
|
||||
}
|
||||
35
C#/TSEngine/Core/Components/baseComponent.ts
Normal file
35
C#/TSEngine/Core/Components/baseComponent.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace TSE {
|
||||
|
||||
export abstract class BaseComponent {
|
||||
|
||||
public name: string;
|
||||
protected _owner: SimObject;
|
||||
protected _data: IComponentData;
|
||||
|
||||
public constructor(data: IComponentData) {
|
||||
this._data = data;
|
||||
this.name = data.name;
|
||||
}
|
||||
|
||||
public get owner(): SimObject { return this._owner; }
|
||||
public set owner(value: SimObject) { this._owner = value; }
|
||||
|
||||
public load(): void { }
|
||||
public update(time: number): void { }
|
||||
public render(shader: Shader): void { }
|
||||
|
||||
}
|
||||
|
||||
export interface IComponentData {
|
||||
name: string;
|
||||
|
||||
setFromJson(json: any): void;
|
||||
}
|
||||
|
||||
export interface IComponentBuilder {
|
||||
get type(): string;
|
||||
|
||||
buildFromJson(json: any): BaseComponent;
|
||||
}
|
||||
|
||||
}
|
||||
18
C#/TSEngine/Core/Components/componentManager.ts
Normal file
18
C#/TSEngine/Core/Components/componentManager.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace TSE {
|
||||
|
||||
export class ComponentManager {
|
||||
|
||||
private static _registeredBuilders: {[type: string]: IComponentBuilder} = {};
|
||||
|
||||
public static registerBuilder(builder: IComponentBuilder): void {
|
||||
ComponentManager._registeredBuilders[builder.type] = builder;
|
||||
}
|
||||
|
||||
public static extractComponent(json: any): BaseComponent {
|
||||
if (ComponentManager._registeredBuilders[json?.type] === undefined) return undefined;
|
||||
return ComponentManager._registeredBuilders[json.type].buildFromJson(json);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
94
C#/TSEngine/Core/Components/spriteComponent.ts
Normal file
94
C#/TSEngine/Core/Components/spriteComponent.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
///<reference path="componentManager.ts"/>
|
||||
|
||||
namespace TSE {
|
||||
|
||||
export class SpriteComponentData implements IComponentData {
|
||||
public name: string;
|
||||
public materialName: string;
|
||||
|
||||
public setFromJson(json: any): void {
|
||||
this.name = json.name !== undefined ? String(json.name) : undefined;
|
||||
this.materialName = json.materialName !== undefined ? String(json.materialName) : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class SpriteComponentBuilder implements IComponentBuilder {
|
||||
public get type(): string { return "sprite"; }
|
||||
|
||||
public buildFromJson(json: any): BaseComponent {
|
||||
let data = new SpriteComponentData();
|
||||
data.setFromJson(json);
|
||||
return new SpriteComponent(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class SpriteComponent extends BaseComponent {
|
||||
|
||||
protected _sprite: Sprite;
|
||||
|
||||
public constructor(data: SpriteComponentData) {
|
||||
super(data);
|
||||
|
||||
this._sprite = new Sprite(data.name, data.materialName);
|
||||
}
|
||||
|
||||
public load(): void {
|
||||
this._sprite.load();
|
||||
}
|
||||
|
||||
public render(shader: Shader): void {
|
||||
this._sprite.draw(shader, this.owner.worldMatrix);
|
||||
|
||||
super.render(shader);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
export class AnimatedSpriteComponentData extends SpriteComponentData {
|
||||
public frameWidth: number;
|
||||
public frameHeight: number;
|
||||
public frameCount: number;
|
||||
public frameSequence: number[];
|
||||
|
||||
public setFromJson(json: any): void {
|
||||
super.setFromJson(json);
|
||||
|
||||
this.frameWidth = Number(json.frameWidth);
|
||||
this.frameHeight = Number(json.frameHeight);
|
||||
this.frameCount = Number(json.frameCount);
|
||||
this.frameSequence = json.frameSequence;
|
||||
}
|
||||
}
|
||||
|
||||
export class AnimatedSpriteComponentBuilder extends SpriteComponentBuilder {
|
||||
public get type(): string { return "animated_sprite"; }
|
||||
|
||||
public buildFromJson(json: any): BaseComponent {
|
||||
let data = new AnimatedSpriteComponentData();
|
||||
data.setFromJson(json);
|
||||
return new AnimatedSpriteComponent(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AnimatedSpriteComponent extends SpriteComponent {
|
||||
|
||||
public constructor(data: AnimatedSpriteComponentData) {
|
||||
super(data);
|
||||
this._sprite = new AnimatedSprite(this.name, data.materialName, data.frameWidth, data.frameHeight, data.frameCount, data.frameSequence);
|
||||
}
|
||||
|
||||
public update(time: number) {
|
||||
this._sprite.update(time);
|
||||
super.update(time);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ComponentManager.registerBuilder(new SpriteComponentBuilder());
|
||||
ComponentManager.registerBuilder(new AnimatedSpriteComponentBuilder());
|
||||
|
||||
}
|
||||
32
C#/TSEngine/Core/GL/gl.ts
Normal file
32
C#/TSEngine/Core/GL/gl.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace TSE {
|
||||
/** The WebGL rendering context. */
|
||||
export var gl: WebGLRenderingContext;
|
||||
|
||||
/**
|
||||
* Responsible for setting up a WebGL rendering context.
|
||||
* */
|
||||
export class GLUtilities {
|
||||
|
||||
/**
|
||||
* Initialize WebGL
|
||||
* @param elementId The id of the canvas element for rendering the game output.
|
||||
*/
|
||||
public static initialize(elementId?: string): HTMLCanvasElement {
|
||||
let canvas: HTMLCanvasElement;
|
||||
|
||||
if (elementId !== undefined)
|
||||
canvas = document.getElementById(elementId) as HTMLCanvasElement;
|
||||
if (elementId === undefined) {
|
||||
canvas = document.createElement("canvas") as HTMLCanvasElement;
|
||||
document.body.appendChild(canvas);
|
||||
}
|
||||
|
||||
gl = canvas.getContext("webgl");
|
||||
if (gl === undefined)
|
||||
throw new Error("Unable to initialize WebGL");
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
188
C#/TSEngine/Core/GL/glBuffer.ts
Normal file
188
C#/TSEngine/Core/GL/glBuffer.ts
Normal file
@@ -0,0 +1,188 @@
|
||||
///<reference path="gl.ts"/>
|
||||
|
||||
namespace TSE {
|
||||
|
||||
/** Represents the Information needed for a GLBuffer Attribute. */
|
||||
export class AttributeInfo {
|
||||
/** The location of this Attribute */
|
||||
public location: number;
|
||||
|
||||
/** The size (number of elements) in this Attribute (i.e Vector3 = 3). */
|
||||
public size: number;
|
||||
|
||||
/** The number of Elements from the beginning of the Buffer. */
|
||||
public offset: number;
|
||||
|
||||
public constructor(location: number, size: number) {
|
||||
this.location = location;
|
||||
this.size = size;
|
||||
this.offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents a WebGLBuffer */
|
||||
export class GLBuffer {
|
||||
|
||||
private _hasAttributeLocation: boolean = false;
|
||||
private _elementSize: number;
|
||||
private _stride: number;
|
||||
private _buffer: WebGLBuffer;
|
||||
|
||||
private _targetBufferType: number;
|
||||
private _dataType: number;
|
||||
private _mode: number;
|
||||
private _typeSize: number;
|
||||
|
||||
private _data: number[] = [];
|
||||
private _attributes: AttributeInfo[] = [];
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new GLBuffer.
|
||||
* @param elementSize The size of each Element in this Buffer.
|
||||
* @param dataType The data type of this Buffer. Default: FLOAT
|
||||
* @param targetBufferType The Buffer target type. ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER. Default: ARRAY_BUFFER
|
||||
* @param mode The drawing mode of this Buffer. TRIANGLES, LINES. Default: TRIANGLES
|
||||
*/
|
||||
public constructor(dataType: number = gl.FLOAT, targetBufferType: number = gl.ARRAY_BUFFER, mode: number = gl.TRIANGLES) {
|
||||
this._elementSize = 0;
|
||||
this._dataType = dataType;
|
||||
this._targetBufferType = targetBufferType;
|
||||
this._mode = mode;
|
||||
|
||||
// Determine Byte size
|
||||
switch (this._dataType) {
|
||||
case gl.FLOAT:
|
||||
case gl.INT:
|
||||
case gl.UNSIGNED_INT:
|
||||
this._typeSize = 4;
|
||||
break;
|
||||
|
||||
case gl.SHORT:
|
||||
case gl.UNSIGNED_SHORT:
|
||||
this._typeSize = 2;
|
||||
break;
|
||||
|
||||
case gl.BYTE:
|
||||
case gl.UNSIGNED_BYTE:
|
||||
this._typeSize = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("Unrecognized data type: " + dataType.toString());
|
||||
}
|
||||
|
||||
this._buffer = gl.createBuffer();
|
||||
}
|
||||
|
||||
/** Destroys this Buffer. */
|
||||
public destroy(): void {
|
||||
gl.deleteBuffer(this._buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds this Buffer.
|
||||
* @param normalized Indecates if the BufferData should be normalized. Default: false
|
||||
*/
|
||||
public bind(normalized: boolean = false): void {
|
||||
gl.bindBuffer(this._targetBufferType, this._buffer);
|
||||
|
||||
if (this._hasAttributeLocation) {
|
||||
for (let it of this._attributes) {
|
||||
gl.vertexAttribPointer(it.location, it.size, this._dataType, normalized, this._stride, it.offset * this._typeSize);
|
||||
gl.enableVertexAttribArray(it.location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Unbinds this Buffer. */
|
||||
public unbind(): void {
|
||||
if (this._hasAttributeLocation) {
|
||||
for (let it of this._attributes) {
|
||||
gl.disableVertexAttribArray(it.location);
|
||||
}
|
||||
}
|
||||
|
||||
gl.bindBuffer(this._targetBufferType, undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an Attribute with the provided info to this Buffer.
|
||||
* @param info The Attribute Information.
|
||||
*/
|
||||
public addAttributeLocation(info: AttributeInfo): void {
|
||||
this._hasAttributeLocation = true;
|
||||
info.offset = this._elementSize;
|
||||
this._attributes.push(info);
|
||||
this._elementSize += info.size;
|
||||
this._stride = this._elementSize * this._typeSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds Data to this Buffer.
|
||||
* @param data The Data for this Buffer.
|
||||
*/
|
||||
public pushBackData(data: number[]): void {
|
||||
for (let d of data)
|
||||
this._data.push(d);
|
||||
}
|
||||
|
||||
public clearData(): void {
|
||||
this._data.length = 0;
|
||||
}
|
||||
|
||||
public setData(data: number[]): void {
|
||||
this.clearData();
|
||||
this.pushBackData(data);
|
||||
}
|
||||
|
||||
/** Upload the BufferData to the GPU */
|
||||
public upload(): void {
|
||||
gl.bindBuffer(this._targetBufferType, this._buffer);
|
||||
|
||||
let bufferData: ArrayBuffer;
|
||||
switch (this._dataType) {
|
||||
case gl.FLOAT:
|
||||
bufferData = new Float32Array(this._data);
|
||||
break;
|
||||
|
||||
case gl.INT:
|
||||
bufferData = new Int32Array(this._data);
|
||||
break;
|
||||
|
||||
case gl.UNSIGNED_INT:
|
||||
bufferData = new Uint32Array(this._data);
|
||||
break;
|
||||
|
||||
case gl.SHORT:
|
||||
bufferData = new Int16Array(this._data);
|
||||
break;
|
||||
|
||||
case gl.UNSIGNED_SHORT:
|
||||
bufferData = new Uint16Array(this._data);
|
||||
break;
|
||||
|
||||
case gl.BYTE:
|
||||
bufferData = new Int8Array(this._data);
|
||||
break;
|
||||
|
||||
case gl.UNSIGNED_BYTE:
|
||||
bufferData = new Uint8Array(this._data);
|
||||
break;
|
||||
}
|
||||
|
||||
gl.bufferData(this._targetBufferType, bufferData, gl.STATIC_DRAW);
|
||||
}
|
||||
|
||||
/** Draws this Buffer. */
|
||||
public draw(): void {
|
||||
if (this._targetBufferType === gl.ARRAY_BUFFER)
|
||||
gl.drawArrays(this._mode, 0, this._data.length / this._elementSize);
|
||||
|
||||
if (this._targetBufferType === gl.ELEMENT_ARRAY_BUFFER)
|
||||
gl.drawElements(this._mode, this._data.length, this._dataType, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
106
C#/TSEngine/Core/GL/shader.ts
Normal file
106
C#/TSEngine/Core/GL/shader.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
namespace TSE {
|
||||
|
||||
export abstract class Shader {
|
||||
private _name: string;
|
||||
private _program: WebGLProgram;
|
||||
private _attributes: { [name: string]: number } = {};
|
||||
private _uniforms: { [name: string]: WebGLUniformLocation } = {};
|
||||
|
||||
/**
|
||||
* Create a new Shader.
|
||||
* @param name The name of the Shader.
|
||||
* @param vertexSource The source of the VertexShader
|
||||
* @param fragementSource The source of the FragmentShader
|
||||
*/
|
||||
public constructor(name: string) {
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
protected setSource(vertexSource: string, fragementSource: string): void {
|
||||
let vertexShader = this.loadShader(vertexSource, gl.VERTEX_SHADER);
|
||||
let fragmentShader = this.loadShader(fragementSource, gl.FRAGMENT_SHADER);
|
||||
this.createProgram(vertexShader, fragmentShader);
|
||||
|
||||
this.detectAtrributes();
|
||||
this.detectUniforms();
|
||||
}
|
||||
|
||||
/** Use this Shader. */
|
||||
public use(): void {
|
||||
gl.useProgram(this._program);
|
||||
}
|
||||
|
||||
private loadShader(source: string, shaderType: number): WebGLShader {
|
||||
let shader: WebGLShader = gl.createShader(shaderType);
|
||||
|
||||
gl.shaderSource(shader, source);
|
||||
gl.compileShader(shader);
|
||||
|
||||
const error = gl.getShaderInfoLog(shader);
|
||||
if (error != "")
|
||||
throw new Error("Error compiling shader '" + this._name + "': " + error);
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
/** The name of this Shader. */
|
||||
public get name(): string { return this._name; }
|
||||
|
||||
/**
|
||||
* Get the Location of an Attribute with the provided Name.
|
||||
* @param name The name of the Attribute.
|
||||
*/
|
||||
public getAttributeLocation(name: string): number {
|
||||
if (this._attributes[name] === undefined) throw new Error(`Unable to find Attribute '${name}' in shader '${this._name}'`);
|
||||
|
||||
return this._attributes[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Location of an Uniform with the provided Name.
|
||||
* @param name The name of the Uniform.
|
||||
*/
|
||||
public getUniformLocation(name: string): WebGLUniformLocation {
|
||||
if (this._uniforms[name] === undefined) throw new Error(`Unable to find Uniform '${name}' in shader '${this._name}'`);
|
||||
|
||||
return this._uniforms[name];
|
||||
}
|
||||
|
||||
private createProgram(vertexShader: WebGLShader, fragmentShader: WebGLShader): void {
|
||||
this._program = gl.createProgram();
|
||||
|
||||
gl.attachShader(this._program, vertexShader);
|
||||
gl.attachShader(this._program, fragmentShader);
|
||||
|
||||
gl.linkProgram(this._program);
|
||||
|
||||
const error = gl.getProgramInfoLog(this._program);
|
||||
if (error != "")
|
||||
throw new Error("Error linking shader '" + this._name + "': " + error);
|
||||
}
|
||||
|
||||
private detectAtrributes(): void {
|
||||
let attributeCount = gl.getProgramParameter(this._program, gl.ACTIVE_ATTRIBUTES);
|
||||
|
||||
for (let i = 0; i < attributeCount; i++) {
|
||||
let attributeInfo: WebGLActiveInfo = gl.getActiveAttrib(this._program, i);
|
||||
if (!attributeInfo) break;
|
||||
|
||||
this._attributes[attributeInfo.name] = gl.getAttribLocation(this._program, attributeInfo.name);
|
||||
}
|
||||
}
|
||||
|
||||
private detectUniforms(): void {
|
||||
let uniformCount = gl.getProgramParameter(this._program, gl.ACTIVE_UNIFORMS);
|
||||
|
||||
for (let i = 0; i < uniformCount; i++) {
|
||||
let uniformInfo: WebGLActiveInfo = gl.getActiveUniform(this._program, i);
|
||||
if (!uniformInfo) break;
|
||||
|
||||
this._uniforms[uniformInfo.name] = gl.getUniformLocation(this._program, uniformInfo.name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
37
C#/TSEngine/Core/Graphics/color.ts
Normal file
37
C#/TSEngine/Core/Graphics/color.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
namespace TSE {
|
||||
|
||||
export class Color {
|
||||
public static get white(): Color { return new Color(255, 255, 255, 255); }
|
||||
public static get black(): Color { return new Color(0, 0, 0, 255) };
|
||||
public static get red(): Color { return new Color(255, 0, 0, 255) };
|
||||
public static get green(): Color { return new Color(0, 255, 0, 255) };
|
||||
public static get blue(): Color { return new Color(0, 0, 255, 255) };
|
||||
|
||||
private _red;
|
||||
private _green;
|
||||
private _blue;
|
||||
private _alpha;
|
||||
|
||||
public constructor(red: number = 255, green: number = 255, blue: number = 255, alpha: number = 255) {
|
||||
this._red = red;
|
||||
this._green = green;
|
||||
this._blue = blue;
|
||||
this._alpha = alpha;
|
||||
}
|
||||
|
||||
public get red(): number { return this._red; }
|
||||
public get green(): number { return this._green; }
|
||||
public get blue(): number { return this._blue; }
|
||||
public get alpha(): number { return this._alpha; }
|
||||
|
||||
public get redFload(): number { return this._red / 255; }
|
||||
public get greenFload(): number { return this._green / 255; }
|
||||
public get blueFload(): number { return this._blue / 255; }
|
||||
public get alphaFload(): number { return this._alpha / 255; }
|
||||
|
||||
public toArray(): number[] { return [this._red, this._green, this._blue, this._alpha] }
|
||||
public toFloatArray(): number[] { return [this.redFload, this.greenFload, this.blueFload, this.alphaFload]; }
|
||||
public toFloat32Array(): Float32Array { return new Float32Array(this.toFloatArray()); }
|
||||
}
|
||||
|
||||
}
|
||||
41
C#/TSEngine/Core/Graphics/material.ts
Normal file
41
C#/TSEngine/Core/Graphics/material.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
namespace TSE {
|
||||
|
||||
export class Material {
|
||||
|
||||
private _name: string;
|
||||
private _diffuseTextureName: string;
|
||||
|
||||
private _diffuseTexture: Texture;
|
||||
private _tint: Color;
|
||||
|
||||
public constructor(name: string, diffuseTextureName: string, tint: Color = Color.white) {
|
||||
this._name = name;
|
||||
this._diffuseTextureName = diffuseTextureName;
|
||||
this._tint = tint;
|
||||
|
||||
if (this._diffuseTextureName !== undefined)
|
||||
this._diffuseTexture = TextureManager.getTexture(this._diffuseTextureName);
|
||||
}
|
||||
|
||||
public get name(): string { return this._name; }
|
||||
public get diffuseTextureName(): string { return this._diffuseTextureName; }
|
||||
public get diffuseTexture(): Texture { return this._diffuseTexture; }
|
||||
public get tint(): Color { return this._tint; }
|
||||
|
||||
public set diffuseTextureName(value: string) {
|
||||
if (this._diffuseTexture !== undefined)
|
||||
TextureManager.releaseTexture(this._diffuseTextureName);
|
||||
|
||||
if (value === undefined) return;
|
||||
this.diffuseTextureName = value;
|
||||
this._diffuseTexture = TextureManager.getTexture(this._diffuseTextureName);
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
TextureManager.releaseTexture(this._diffuseTextureName);
|
||||
this._diffuseTexture = undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
45
C#/TSEngine/Core/Graphics/materialManager.ts
Normal file
45
C#/TSEngine/Core/Graphics/materialManager.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
namespace TSE {
|
||||
|
||||
class MaterialReferenceNode {
|
||||
|
||||
public material: Material;
|
||||
public referenceCount: number = 1;
|
||||
|
||||
public constructor(material: Material) {
|
||||
this.material = material;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class MaterialManager {
|
||||
|
||||
private static _materials: { [name: string]: MaterialReferenceNode } = {};
|
||||
|
||||
private constructor() { }
|
||||
|
||||
public static registerMaterial(material: Material): void {
|
||||
if (MaterialManager._materials[material.name] === undefined)
|
||||
MaterialManager._materials[material.name] = new MaterialReferenceNode(material);
|
||||
}
|
||||
|
||||
public static getMaterial(materialName: string): Material {
|
||||
if (MaterialManager._materials[materialName] === undefined) return undefined;
|
||||
|
||||
MaterialManager._materials[materialName].referenceCount++;
|
||||
return MaterialManager._materials[materialName].material;
|
||||
}
|
||||
|
||||
public static releaseMaterial(materialName: string): void {
|
||||
if (MaterialManager._materials[materialName] === undefined) console.warn("Cannot release an undefined Material!");
|
||||
else {
|
||||
MaterialManager._materials[materialName].referenceCount--;
|
||||
if (MaterialManager._materials[materialName].referenceCount < 1) {
|
||||
MaterialManager._materials[materialName].material.destroy();
|
||||
delete MaterialManager._materials[materialName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
151
C#/TSEngine/Core/Graphics/sprite.ts
Normal file
151
C#/TSEngine/Core/Graphics/sprite.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
namespace TSE {
|
||||
|
||||
export class Sprite {
|
||||
protected _buffer: GLBuffer;
|
||||
|
||||
protected _width: number;
|
||||
protected _height: number;
|
||||
protected _name: string;
|
||||
|
||||
protected _material: Material;
|
||||
protected _vertices: Vertex[] = [];
|
||||
|
||||
public constructor(name: string, materialName: string, width: number = 100, height: number = 100) {
|
||||
this._name = name;
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
this._material = MaterialManager.getMaterial(materialName);
|
||||
}
|
||||
|
||||
public load(): void {
|
||||
this._buffer = new GLBuffer();
|
||||
|
||||
this._buffer.addAttributeLocation(new AttributeInfo(0, 3)); //Position
|
||||
this._buffer.addAttributeLocation(new AttributeInfo(1, 2)); //UVs
|
||||
|
||||
this._vertices = [
|
||||
new Vertex(0, 0, 0, 0, 0),
|
||||
new Vertex(0, this._height, 0, 0, 1.0),
|
||||
new Vertex(this._width, this._height, 0, 1.0, 1.0),
|
||||
|
||||
new Vertex(this._width, this._height, 0, 1.0, 1.0),
|
||||
new Vertex(this._width, 0, 0, 1.0, 0),
|
||||
new Vertex(0, 0, 0, 0, 0)
|
||||
];
|
||||
|
||||
this._buffer.pushBackData(Vertex.vertexArray(this._vertices));
|
||||
this._buffer.upload();
|
||||
this._buffer.unbind();
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
this._buffer.destroy();
|
||||
MaterialManager.releaseMaterial(this._material.name);
|
||||
delete this._material;
|
||||
}
|
||||
|
||||
public update(time: number): void {
|
||||
|
||||
}
|
||||
|
||||
public draw(shader: Shader, model: Matrix4x4): void {
|
||||
let modelLocation = shader.getUniformLocation("u_model");
|
||||
gl.uniformMatrix4fv(modelLocation, false, model.toFloat32Array());
|
||||
|
||||
let colorLocation = shader.getUniformLocation("u_tint");
|
||||
gl.uniform4fv(colorLocation, this._material.tint.toFloat32Array());
|
||||
|
||||
if (this._material.diffuseTexture !== undefined) {
|
||||
this._material.diffuseTexture.activateAndBind(0);
|
||||
let diffuseLocation = shader.getUniformLocation("u_diffuse");
|
||||
gl.uniform1i(diffuseLocation, 0);
|
||||
}
|
||||
|
||||
this._buffer.bind();
|
||||
this._buffer.draw();
|
||||
}
|
||||
|
||||
public get name(): string { return this._name; }
|
||||
|
||||
}
|
||||
|
||||
export class AnimatedSprite extends Sprite {
|
||||
|
||||
private _frameHeight: number;
|
||||
private _frameWidth: number;
|
||||
private _frameCount: number;
|
||||
private _frameSequence: number[];
|
||||
|
||||
private _currentFrame: number = 0;
|
||||
private currentTime: number = 0;
|
||||
private _frameTime: number = 300;
|
||||
private _frameUVs: Vector2[][];
|
||||
private _loaded: boolean = false;
|
||||
|
||||
public constructor(name: string, materialName: string, frameWidth: number = 10, frameHeight: number = 10, frameCount: number = 1, frameSequence: number[] = []) {
|
||||
super(name, materialName, frameWidth, frameHeight);
|
||||
this._frameWidth = frameWidth;
|
||||
this._frameHeight = frameHeight;
|
||||
this._frameCount = frameCount;
|
||||
this._frameSequence = frameSequence;
|
||||
}
|
||||
|
||||
public load() {
|
||||
super.load();
|
||||
this.calculateUVs();
|
||||
}
|
||||
|
||||
private calculateUVs(): void {
|
||||
setTimeout(() => {
|
||||
this._frameUVs = [];
|
||||
|
||||
let totalWidth: number = 0;
|
||||
let totalHeight: number = 0;
|
||||
for (let i = 0; i < this._frameCount; i++) {
|
||||
totalWidth += this._frameWidth;
|
||||
if (totalWidth > this._material.diffuseTexture.width) {
|
||||
totalWidth = 0;
|
||||
totalHeight++;
|
||||
}
|
||||
|
||||
const u = (i * this._frameWidth) / this._material.diffuseTexture.width;
|
||||
const v = (totalHeight * this._frameHeight) / this._material.diffuseTexture.height;
|
||||
const um = ((i * this._frameWidth) + this._frameWidth) / this._material.diffuseTexture.width;
|
||||
const vm = ((totalHeight * this._frameHeight) + this._frameHeight) / this._material.diffuseTexture.height;
|
||||
this._frameUVs.push([new Vector2(u, v), new Vector2(um, vm)]);
|
||||
}
|
||||
this._loaded = true;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
public update(time: number) {
|
||||
if (!this._loaded) return;
|
||||
this.currentTime += time;
|
||||
if (this.currentTime > this._frameTime) {
|
||||
this._currentFrame++;
|
||||
this.currentTime = 0;
|
||||
|
||||
if (this._currentFrame >= this._frameSequence.length)
|
||||
this._currentFrame = 0;
|
||||
|
||||
const frameUVs = this._frameUVs[this._frameSequence[this._currentFrame]];
|
||||
|
||||
this._vertices[0].texCoords.copyFrom(frameUVs[0]);
|
||||
this._vertices[1].texCoords = new Vector2(frameUVs[0].x, frameUVs[1].y);
|
||||
this._vertices[2].texCoords.copyFrom(frameUVs[1]);
|
||||
|
||||
this._vertices[3].texCoords.copyFrom(frameUVs[1]);
|
||||
this._vertices[4].texCoords = new Vector2(frameUVs[1].x, frameUVs[0].y);
|
||||
this._vertices[5].texCoords.copyFrom(frameUVs[0]);
|
||||
|
||||
this._buffer.setData(Vertex.vertexArray(this._vertices));
|
||||
this._buffer.upload();
|
||||
this._buffer.unbind();
|
||||
}
|
||||
|
||||
super.update(time);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
94
C#/TSEngine/Core/Graphics/texture.ts
Normal file
94
C#/TSEngine/Core/Graphics/texture.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
namespace TSE {
|
||||
|
||||
const LEVEL: number = 0;
|
||||
const BORDER: number = 0;
|
||||
const TEMP_IMAGE_DATA: Uint8Array = new Uint8Array([255, 255, 255, 255]);
|
||||
|
||||
export class Texture implements IMessageHanlder {
|
||||
|
||||
private _name: string;
|
||||
private _handle: WebGLTexture;
|
||||
private _isLoaded: boolean = false;
|
||||
private _width: number;
|
||||
private _height: number;
|
||||
|
||||
public constructor(name: string, width: number = 1, height: number = 1) {
|
||||
this._name = name;
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
|
||||
this._handle = gl.createTexture();
|
||||
|
||||
Message.subscribe(MESSAGE_ASSET_LOADER_ASSET_LOADED + this._name, this);
|
||||
|
||||
this.bind();
|
||||
|
||||
gl.texImage2D(gl.TEXTURE_2D, LEVEL, gl.RGBA, 1, 1, BORDER, gl.RGBA, gl.UNSIGNED_BYTE, TEMP_IMAGE_DATA);
|
||||
|
||||
let asset = AssetManager.getAsset(this._name) as ImageAsset;
|
||||
if (asset !== undefined) {
|
||||
this.loadTextureFromAsset(asset);
|
||||
}
|
||||
}
|
||||
|
||||
public onMessage(message: Message): void {
|
||||
if (message.code === MESSAGE_ASSET_LOADER_ASSET_LOADED + this._name) {
|
||||
this.loadTextureFromAsset(message.context as ImageAsset);
|
||||
}
|
||||
}
|
||||
|
||||
public get name(): string { return this._name; }
|
||||
public get isLoaded(): boolean { return this._isLoaded; }
|
||||
public get width(): number { return this._width; }
|
||||
public get height(): number { return this._height; }
|
||||
|
||||
public activateAndBind(textureUnit: number = 0): void {
|
||||
gl.activeTexture(gl.TEXTURE0 + textureUnit);
|
||||
|
||||
this.bind();
|
||||
}
|
||||
|
||||
public bind(): void {
|
||||
gl.bindTexture(gl.TEXTURE_2D, this._handle);
|
||||
}
|
||||
|
||||
public unbind(): void {
|
||||
gl.bindTexture(gl.TEXTURE_2D, undefined);
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
gl.deleteTexture(this._handle);
|
||||
}
|
||||
|
||||
private loadTextureFromAsset(asset: ImageAsset): void {
|
||||
this._width = asset.width;
|
||||
this._height = asset.height;
|
||||
|
||||
this.bind();
|
||||
|
||||
gl.texImage2D(gl.TEXTURE_2D, LEVEL, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, asset.data);
|
||||
|
||||
if (this.isPowerOf2()) {
|
||||
gl.generateMipmap(gl.TEXTURE_2D);
|
||||
} else {
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||
|
||||
this._isLoaded = true;
|
||||
}
|
||||
|
||||
private isPowerOf2(): boolean {
|
||||
return (this.isValuePowerOf2(this.width) && this.isValuePowerOf2(this.height));
|
||||
}
|
||||
|
||||
private isValuePowerOf2(value: number): boolean {
|
||||
return (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
44
C#/TSEngine/Core/Graphics/textureManager.ts
Normal file
44
C#/TSEngine/Core/Graphics/textureManager.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
namespace TSE {
|
||||
|
||||
class TextureReferenceNode {
|
||||
|
||||
public texture: Texture;
|
||||
public referenceCount: number = 1;
|
||||
|
||||
public constructor(texture: Texture) {
|
||||
this.texture = texture;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class TextureManager {
|
||||
|
||||
private static _textures: { [name: string]: TextureReferenceNode } = {};
|
||||
|
||||
private constructor() { }
|
||||
|
||||
public static getTexture(textureName: string): Texture {
|
||||
if (TextureManager._textures[textureName] === undefined)
|
||||
TextureManager._textures[textureName] = new TextureReferenceNode(new Texture(textureName));
|
||||
else
|
||||
TextureManager._textures[textureName].referenceCount++;
|
||||
|
||||
return TextureManager._textures[textureName].texture;
|
||||
}
|
||||
|
||||
public static releaseTexture(textureName: string): void {
|
||||
if (TextureManager._textures[textureName] === undefined) {
|
||||
console.warn(`A Texture named ${textureName} does not exist and cannot be released!`);
|
||||
} else {
|
||||
TextureManager._textures[textureName].referenceCount--;
|
||||
if (TextureManager._textures[textureName].referenceCount < 1) {
|
||||
TextureManager._textures[textureName].texture.destroy();
|
||||
TextureManager._textures[textureName] = undefined;
|
||||
delete TextureManager._textures[textureName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
30
C#/TSEngine/Core/Graphics/vertex.ts
Normal file
30
C#/TSEngine/Core/Graphics/vertex.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace TSE {
|
||||
|
||||
export class Vertex {
|
||||
|
||||
public static vertexArray(vertices: Vertex[]): number[] {
|
||||
let array: number[] = [];
|
||||
for (let vertex of vertices)
|
||||
array = array.concat(vertex.toArray());
|
||||
return array;
|
||||
}
|
||||
|
||||
public position: Vector3;
|
||||
public texCoords: Vector2;
|
||||
|
||||
public constructor(x: number = 0, y: number = 0, z: number = 0, u: number = 0, v: number = 0) {
|
||||
this.position = new Vector3(x, y, z);
|
||||
this.texCoords = new Vector2(u, v);
|
||||
}
|
||||
|
||||
public toArray(): number[] {
|
||||
let array: number[] = [];
|
||||
array = array.concat(this.position.toArray(), this.texCoords.toArray());
|
||||
return array;
|
||||
}
|
||||
|
||||
public toFloat32Array(): Float32Array { return new Float32Array(this.toArray()); }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
177
C#/TSEngine/Core/Math/matrix4x4.ts
Normal file
177
C#/TSEngine/Core/Math/matrix4x4.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
namespace TSE {
|
||||
|
||||
export class Matrix4x4 {
|
||||
|
||||
private _data: number[] = [];
|
||||
|
||||
private constructor() {
|
||||
this._data = [
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1
|
||||
];
|
||||
}
|
||||
|
||||
public get data(): number[] {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
public static identity(): Matrix4x4 {
|
||||
return new Matrix4x4();
|
||||
}
|
||||
|
||||
public static orthographic(left: number, right: number, bottom: number, top: number, nearClip: number, farClip: number): Matrix4x4 {
|
||||
let matrix = new Matrix4x4();
|
||||
|
||||
let lr: number = 1.0 / (left - right);
|
||||
let bt: number = 1.0 / (bottom - top);
|
||||
let nf: number = 1.0 / (nearClip - farClip);
|
||||
|
||||
matrix._data[0] = -2.0 * lr;
|
||||
matrix._data[5] = -2.0 * bt;
|
||||
matrix._data[10] = 2.0 * nf;
|
||||
|
||||
matrix._data[12] = (left + right) * lr;
|
||||
matrix._data[13] = (top + bottom) * bt;
|
||||
matrix._data[14] = (farClip + nearClip) * nf;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
public static translation(position: Vector3): Matrix4x4 {
|
||||
let matrix = new Matrix4x4();
|
||||
|
||||
matrix._data[12] = position.x;
|
||||
matrix._data[13] = position.y;
|
||||
matrix._data[14] = position.z;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
public static rotationX(angle: number): Matrix4x4 {
|
||||
let matrix = new Matrix4x4();
|
||||
|
||||
let c = Math.cos(angle);
|
||||
let s = Math.sin(angle);
|
||||
|
||||
matrix._data[5] = c;
|
||||
matrix._data[6] = s;
|
||||
matrix._data[9] = -s;
|
||||
matrix._data[10] = c;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
public static rotationY(angle: number): Matrix4x4 {
|
||||
let matrix = new Matrix4x4();
|
||||
|
||||
let c = Math.cos(angle);
|
||||
let s = Math.sin(angle);
|
||||
|
||||
matrix._data[0] = c;
|
||||
matrix._data[2] = -s;
|
||||
matrix._data[8] = s;
|
||||
matrix._data[10] = c;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
public static rotationZ(angle: number): Matrix4x4 {
|
||||
let matrix = new Matrix4x4();
|
||||
|
||||
let c = Math.cos(angle);
|
||||
let s = Math.sin(angle);
|
||||
|
||||
matrix._data[0] = c;
|
||||
matrix._data[1] = s;
|
||||
matrix._data[4] = -s;
|
||||
matrix._data[5] = c;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
public static rotationXYZ(x: number, y: number, z: number): Matrix4x4 {
|
||||
return Matrix4x4.multiply3(Matrix4x4.rotationZ(z), Matrix4x4.rotationY(y), Matrix4x4.rotationX(x));
|
||||
}
|
||||
|
||||
public static scale(scale: Vector3): Matrix4x4 {
|
||||
let matrix = new Matrix4x4();
|
||||
|
||||
matrix._data[0] = scale.x;
|
||||
matrix._data[5] = scale.y;
|
||||
matrix._data[10] = scale.z;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
public static multiply(a: Matrix4x4, b: Matrix4x4): Matrix4x4 {
|
||||
let matrix = new Matrix4x4();
|
||||
|
||||
let b00 = b._data[0 * 4 + 0];
|
||||
let b01 = b._data[0 * 4 + 1];
|
||||
let b02 = b._data[0 * 4 + 2];
|
||||
let b03 = b._data[0 * 4 + 3];
|
||||
let b10 = b._data[1 * 4 + 0];
|
||||
let b11 = b._data[1 * 4 + 1];
|
||||
let b12 = b._data[1 * 4 + 2];
|
||||
let b13 = b._data[1 * 4 + 3];
|
||||
let b20 = b._data[2 * 4 + 0];
|
||||
let b21 = b._data[2 * 4 + 1];
|
||||
let b22 = b._data[2 * 4 + 2];
|
||||
let b23 = b._data[2 * 4 + 3];
|
||||
let b30 = b._data[3 * 4 + 0];
|
||||
let b31 = b._data[3 * 4 + 1];
|
||||
let b32 = b._data[3 * 4 + 2];
|
||||
let b33 = b._data[3 * 4 + 3];
|
||||
let a00 = a._data[0 * 4 + 0];
|
||||
let a01 = a._data[0 * 4 + 1];
|
||||
let a02 = a._data[0 * 4 + 2];
|
||||
let a03 = a._data[0 * 4 + 3];
|
||||
let a10 = a._data[1 * 4 + 0];
|
||||
let a11 = a._data[1 * 4 + 1];
|
||||
let a12 = a._data[1 * 4 + 2];
|
||||
let a13 = a._data[1 * 4 + 3];
|
||||
let a20 = a._data[2 * 4 + 0];
|
||||
let a21 = a._data[2 * 4 + 1];
|
||||
let a22 = a._data[2 * 4 + 2];
|
||||
let a23 = a._data[2 * 4 + 3];
|
||||
let a30 = a._data[3 * 4 + 0];
|
||||
let a31 = a._data[3 * 4 + 1];
|
||||
let a32 = a._data[3 * 4 + 2];
|
||||
let a33 = a._data[3 * 4 + 3];
|
||||
|
||||
matrix._data[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30;
|
||||
matrix._data[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31;
|
||||
matrix._data[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32;
|
||||
matrix._data[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33;
|
||||
matrix._data[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30;
|
||||
matrix._data[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31;
|
||||
matrix._data[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32;
|
||||
matrix._data[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33;
|
||||
matrix._data[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30;
|
||||
matrix._data[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31;
|
||||
matrix._data[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32;
|
||||
matrix._data[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33;
|
||||
matrix._data[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30;
|
||||
matrix._data[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31;
|
||||
matrix._data[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32;
|
||||
matrix._data[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
public static multiply3(a: Matrix4x4, b: Matrix4x4, c: Matrix4x4): Matrix4x4 {
|
||||
return Matrix4x4.multiply(Matrix4x4.multiply(a, b), c);
|
||||
}
|
||||
|
||||
public toFloat32Array(): Float32Array { return new Float32Array(this._data); }
|
||||
|
||||
public copyFrom(matrix: Matrix4x4): void {
|
||||
for (let i = 0; i < this._data.length; i++) {
|
||||
this._data[i] = matrix._data[i];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
31
C#/TSEngine/Core/Math/transform.ts
Normal file
31
C#/TSEngine/Core/Math/transform.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
namespace TSE {
|
||||
|
||||
export class Transform {
|
||||
|
||||
public position: Vector3 = Vector3.zero;
|
||||
public rotation: Vector3 = Vector3.zero;
|
||||
public scale: Vector3 = Vector3.one;
|
||||
|
||||
public copyFrom(transform: Transform): void {
|
||||
this.position.copyFrom(transform.position);
|
||||
this.rotation.copyFrom(transform.rotation);
|
||||
this.scale.copyFrom(transform.scale);
|
||||
}
|
||||
|
||||
public get transformationMatrix(): Matrix4x4 {
|
||||
let translation = Matrix4x4.translation(this.position);
|
||||
let rotation = Matrix4x4.rotationXYZ(this.rotation.x, this.rotation.y, this.rotation.z);
|
||||
let scale = Matrix4x4.scale(this.scale);
|
||||
|
||||
return Matrix4x4.multiply3(translation, rotation, scale);
|
||||
}
|
||||
|
||||
public setFromJson(json: any): void {
|
||||
if (json.position !== undefined) this.position.setFromJson(json.position);
|
||||
if (json.rotation !== undefined) this.rotation.setFromJson(json.rotation);
|
||||
if (json.scale !== undefined) this.scale.setFromJson(json.scale);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
34
C#/TSEngine/Core/Math/vector2.ts
Normal file
34
C#/TSEngine/Core/Math/vector2.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
namespace TSE {
|
||||
|
||||
export class Vector2 {
|
||||
protected _x: number;
|
||||
protected _y: number;
|
||||
|
||||
public constructor(x: number = 0, y: number = 0) {
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
|
||||
public get x() { return this._x; }
|
||||
public set x(value: number) { this._x = value; }
|
||||
|
||||
public get y() { return this._y; }
|
||||
public set y(value: number) { this._y = value; }
|
||||
|
||||
public toArray(): number[] { return [this._x, this._y]; }
|
||||
public toFloat32Array(): Float32Array { return new Float32Array(this.toArray()); }
|
||||
|
||||
public setFromJson(json: any): void {
|
||||
this._x = json.x !== undefined ? Number(json.x) : 0;
|
||||
this._y = json.y !== undefined ? Number(json.y) : 0;
|
||||
}
|
||||
|
||||
public copyFrom(vector: Vector2): Vector2 {
|
||||
this._x = vector._x;
|
||||
this._y = vector._y;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
68
C#/TSEngine/Core/Math/vector3.ts
Normal file
68
C#/TSEngine/Core/Math/vector3.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
namespace TSE {
|
||||
|
||||
export class Vector3 {
|
||||
public static get zero(): Vector3 { return new Vector3(0, 0, 0); }
|
||||
public static get one(): Vector3 { return new Vector3(1, 1, 1); }
|
||||
|
||||
protected _x: number;
|
||||
protected _y: number;
|
||||
protected _z: number;
|
||||
|
||||
public constructor(x: number = 0, y: number = 0, z: number = 0) {
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._z = z;
|
||||
}
|
||||
|
||||
public get x() { return this._x; }
|
||||
public set x(value: number) { this._x = value; }
|
||||
|
||||
public get y() { return this._y; }
|
||||
public set y(value: number) { this._y = value; }
|
||||
|
||||
public get z() { return this._z; }
|
||||
public set z(value: number) { this._z = value; }
|
||||
|
||||
public toArray(): number[] { return [this._x, this._y, this._z]; }
|
||||
public toFloat32Array(): Float32Array { return new Float32Array(this.toArray()); }
|
||||
|
||||
public copyFrom(vector: Vector3): void {
|
||||
this._x = vector._x;
|
||||
this._y = vector._y;
|
||||
this._z = vector._z;
|
||||
}
|
||||
|
||||
public setFromJson(json: any): void {
|
||||
this._x = json.x !== undefined ? Number(json.x) : 0;
|
||||
this._y = json.y !== undefined ? Number(json.y) : 0;
|
||||
this._z = json.z !== undefined ? Number(json.z) : 0;
|
||||
}
|
||||
|
||||
public add(vector: Vector3): Vector3 {
|
||||
this._x += vector._x;
|
||||
this._y += vector._y;
|
||||
this._z += vector._z;
|
||||
return this;
|
||||
}
|
||||
public subtract(vector: Vector3): Vector3 {
|
||||
this._x -= vector._x;
|
||||
this._y -= vector._y;
|
||||
this._z -= vector._z;
|
||||
return this;
|
||||
}
|
||||
public multiply(vector: Vector3): Vector3 {
|
||||
this._x *= vector._x;
|
||||
this._y *= vector._y;
|
||||
this._z *= vector._z;
|
||||
return this;
|
||||
}
|
||||
public divide(vector: Vector3): Vector3 {
|
||||
this._x /= vector._x;
|
||||
this._y /= vector._y;
|
||||
this._z /= vector._z;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
9
C#/TSEngine/Core/Message/IMessageHandler.ts
Normal file
9
C#/TSEngine/Core/Message/IMessageHandler.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace TSE {
|
||||
|
||||
export interface IMessageHanlder {
|
||||
|
||||
onMessage(message: Message): void;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
40
C#/TSEngine/Core/Message/message.ts
Normal file
40
C#/TSEngine/Core/Message/message.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
namespace TSE {
|
||||
|
||||
export enum MessagePriority {
|
||||
NORMAL,
|
||||
HIGH
|
||||
}
|
||||
|
||||
export class Message {
|
||||
|
||||
public code: string;
|
||||
public context: any;
|
||||
public sender: any;
|
||||
public priority: MessagePriority;
|
||||
|
||||
public constructor(code: string, sender: any, context?: any, priority: MessagePriority = MessagePriority.NORMAL) {
|
||||
this.code = code;
|
||||
this.context = context;
|
||||
this.sender = sender;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public static send(code: string, sender: any, context?: any): void {
|
||||
MessageBus.post(new Message(code, sender, context));
|
||||
}
|
||||
|
||||
public static sendPriority(code: string, sender: any, context?: any): void {
|
||||
MessageBus.post(new Message(code, sender, context, MessagePriority.HIGH));
|
||||
}
|
||||
|
||||
public static subscribe(code: string, handler: IMessageHanlder): void {
|
||||
MessageBus.addSubscription(code, handler);
|
||||
}
|
||||
|
||||
public static unsubscribe(code: string, handler: IMessageHanlder): void {
|
||||
MessageBus.removeSubscription(code, handler);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
56
C#/TSEngine/Core/Message/messageBus.ts
Normal file
56
C#/TSEngine/Core/Message/messageBus.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
namespace TSE {
|
||||
|
||||
export class MessageBus {
|
||||
|
||||
private static _subscriptions: { [code: string]: IMessageHanlder[] } = {};
|
||||
|
||||
private static _normalQueueMessagePerUpdate: number = 10;
|
||||
private static _normalMessageQueue: MessageSubscriptionNode[] = [];
|
||||
|
||||
private constructor() { }
|
||||
|
||||
public static addSubscription(code: string, handler: IMessageHanlder): void {
|
||||
if (MessageBus._subscriptions[code] === undefined)
|
||||
MessageBus._subscriptions[code] = [];
|
||||
|
||||
if (MessageBus._subscriptions[code].indexOf(handler) !== -1)
|
||||
console.warn("Attempting to add a duplicate hanlder to code: '" + code + "'. Subscription not added.");
|
||||
else
|
||||
MessageBus._subscriptions[code].push(handler);
|
||||
}
|
||||
|
||||
public static removeSubscription(code: string, handler: IMessageHanlder): void {
|
||||
if (MessageBus._subscriptions[code] === undefined) {
|
||||
console.warn("Cannot unsubscribe handler from code: '" + code + "'. Because that code is not subscribed to.");
|
||||
return;
|
||||
}
|
||||
|
||||
let nodeIndex = MessageBus._subscriptions[code].indexOf(handler);
|
||||
if (nodeIndex !== -1)
|
||||
MessageBus._subscriptions[code].splice(nodeIndex, 1);
|
||||
}
|
||||
|
||||
public static post(message: Message): void {
|
||||
console.log("Message posted:", message);
|
||||
let handlers = MessageBus._subscriptions[message.code];
|
||||
if (handlers === undefined) return;
|
||||
|
||||
for (let handler of handlers) {
|
||||
if (message.priority === MessagePriority.HIGH) handler.onMessage(message);
|
||||
else MessageBus._normalMessageQueue.push(new MessageSubscriptionNode(message, handler));
|
||||
}
|
||||
}
|
||||
|
||||
public static update(time: number): void {
|
||||
if (MessageBus._normalMessageQueue.length === 0) return;
|
||||
|
||||
let limit = Math.min(MessageBus._normalQueueMessagePerUpdate, MessageBus._normalMessageQueue.length);
|
||||
for (let i = 0; i < limit; i++) {
|
||||
let node = MessageBus._normalMessageQueue.pop();
|
||||
node.handler.onMessage(node.message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
15
C#/TSEngine/Core/Message/messageSubscriptionNode.ts
Normal file
15
C#/TSEngine/Core/Message/messageSubscriptionNode.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace TSE {
|
||||
|
||||
export class MessageSubscriptionNode {
|
||||
|
||||
public message: Message;
|
||||
public handler: IMessageHanlder;
|
||||
|
||||
public constructor(message: Message, handler: IMessageHanlder) {
|
||||
this.message = message;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
47
C#/TSEngine/Core/Shaders/basicShader.ts
Normal file
47
C#/TSEngine/Core/Shaders/basicShader.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
///<reference path="../GL/shader.ts"/>
|
||||
|
||||
namespace TSE {
|
||||
|
||||
export class BasicShader extends Shader {
|
||||
|
||||
public constructor() {
|
||||
super("basic");
|
||||
|
||||
this.setSource(this.getVertexSource(), this.getFragmentSource());
|
||||
}
|
||||
|
||||
private getVertexSource(): string {
|
||||
return `
|
||||
attribute vec3 a_position;
|
||||
attribute vec2 a_texCoord;
|
||||
|
||||
uniform mat4 u_projection;
|
||||
uniform mat4 u_model;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_model * vec4(a_position, 1.0);
|
||||
v_texCoord = a_texCoord;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
private getFragmentSource(): string {
|
||||
return `
|
||||
precision mediump float;
|
||||
|
||||
uniform vec4 u_tint;
|
||||
uniform sampler2D u_diffuse;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = u_tint * texture2D(u_diffuse, v_texCoord);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
23
C#/TSEngine/Core/World/scene.ts
Normal file
23
C#/TSEngine/Core/World/scene.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace TSE {
|
||||
|
||||
export class Scene {
|
||||
|
||||
private _root: SimObject;
|
||||
|
||||
public constructor() {
|
||||
this._root = new SimObject(0, "__ROOT__", this);
|
||||
}
|
||||
|
||||
public get root(): SimObject { return this._root; }
|
||||
public get isLoaded(): boolean { return this._root.isLoaded; }
|
||||
|
||||
public addObject(object: SimObject): void { this._root.addChild(object); }
|
||||
public getObjectByName(name: string): SimObject { return this._root.getObjectByName(name); }
|
||||
|
||||
public load(): void { this._root.load(); }
|
||||
public update(time: number): void { this._root.update(time); }
|
||||
public render(shader: Shader): void { this._root.render(shader); }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
107
C#/TSEngine/Core/World/simObject.ts
Normal file
107
C#/TSEngine/Core/World/simObject.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
namespace TSE {
|
||||
|
||||
export class SimObject {
|
||||
public name: string;
|
||||
public transform: Transform = new Transform();
|
||||
|
||||
private _id: number;
|
||||
private _children: SimObject[] = [];
|
||||
private _parent: SimObject;
|
||||
private _scene: Scene;
|
||||
private _isLoaded: boolean = false;
|
||||
private _components: BaseComponent[] = [];
|
||||
private _behaviors: BaseBehavior[] = [];
|
||||
|
||||
private _localMatrix: Matrix4x4 = Matrix4x4.identity();
|
||||
private _worldMatrix: Matrix4x4 = Matrix4x4.identity();
|
||||
|
||||
public constructor(id: number, name: string, scene?: Scene) {
|
||||
this._id = id;
|
||||
this.name = name;
|
||||
this._scene = scene;
|
||||
}
|
||||
|
||||
public get id(): number { return this._id; }
|
||||
public get parent(): SimObject { return this._parent; }
|
||||
public get worldMatrix(): Matrix4x4 { return this._worldMatrix; }
|
||||
public get isLoaded(): boolean { return this._isLoaded; }
|
||||
|
||||
public addChild(child: SimObject): void {
|
||||
child._parent = this;
|
||||
this._children.push(child);
|
||||
child.load();
|
||||
child.onAdded(this._scene);
|
||||
}
|
||||
|
||||
public removeChild(child: SimObject): void {
|
||||
const index = this._children.indexOf(child);
|
||||
if (index == -1) return;
|
||||
child._parent = undefined;
|
||||
this._children.splice(index, 1);
|
||||
}
|
||||
|
||||
public getObjectByName(name: string): SimObject {
|
||||
if (this.name === name) return this;
|
||||
|
||||
for (let child of this._children) {
|
||||
let result = child.getObjectByName(name);
|
||||
if (result !== undefined) return result;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public addComponent(component: BaseComponent): void {
|
||||
this._components.push(component);
|
||||
component.owner = this;
|
||||
}
|
||||
|
||||
public addBehavior(behavior: BaseBehavior): void {
|
||||
this._behaviors.push(behavior);
|
||||
behavior.owner = this;
|
||||
}
|
||||
|
||||
public load(): void {
|
||||
this._isLoaded = true;
|
||||
|
||||
for (let c of this._components)
|
||||
c.load();
|
||||
|
||||
for (let child of this._children)
|
||||
child.load();
|
||||
}
|
||||
public update(time: number): void {
|
||||
this._localMatrix = this.transform.transformationMatrix;
|
||||
this.updateWorldMatrix(this._parent?._worldMatrix);
|
||||
|
||||
for (let c of this._components)
|
||||
c.update(time);
|
||||
|
||||
for (let c of this._behaviors)
|
||||
c.update(time);
|
||||
|
||||
for (let child of this._children)
|
||||
child.update(time);
|
||||
}
|
||||
public render(shader: Shader): void {
|
||||
for (let c of this._components)
|
||||
c.render(shader);
|
||||
|
||||
for (let child of this._children)
|
||||
child.render(shader);
|
||||
}
|
||||
|
||||
protected onAdded(scene: Scene): void {
|
||||
this._scene = scene;
|
||||
}
|
||||
|
||||
private updateWorldMatrix(parentWorldMatrix: Matrix4x4): void {
|
||||
if (parentWorldMatrix !== undefined)
|
||||
this._worldMatrix = Matrix4x4.multiply(parentWorldMatrix, this._localMatrix);
|
||||
else
|
||||
this._worldMatrix.copyFrom(this._localMatrix);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
86
C#/TSEngine/Core/World/zone.ts
Normal file
86
C#/TSEngine/Core/World/zone.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
namespace TSE {
|
||||
|
||||
export enum ZoneState {
|
||||
UNINITIALIZED,
|
||||
LOADING,
|
||||
UPDATING
|
||||
}
|
||||
|
||||
export class Zone {
|
||||
|
||||
private _name: string;
|
||||
private _description: string;
|
||||
private _id: number;
|
||||
private _scene: Scene;
|
||||
private _state: ZoneState = ZoneState.UNINITIALIZED;
|
||||
private _globalId: number = -1;
|
||||
|
||||
public constructor(id: number, name: string, descripton?: string) {
|
||||
this._id = id;
|
||||
this._name = name;
|
||||
this._description = descripton;
|
||||
this._scene = new Scene();
|
||||
}
|
||||
|
||||
public get id(): number { return this._id; }
|
||||
public get name(): string { return this._name; }
|
||||
public get description(): string { return this._description; }
|
||||
public get scene(): Scene { return this._scene; }
|
||||
public get state(): ZoneState { return this._state; }
|
||||
|
||||
public initialize(zoneData: any): void {
|
||||
if (zoneData.objects === undefined) return;
|
||||
|
||||
for (let object of zoneData.objects) this.loadSimObject(object, this._scene.root);
|
||||
}
|
||||
|
||||
public load(): void {
|
||||
if (this._state !== ZoneState.UNINITIALIZED) return;
|
||||
this._state = ZoneState.LOADING;
|
||||
this._scene.load();
|
||||
this._state = ZoneState.UPDATING;
|
||||
}
|
||||
public unload(): void {
|
||||
if (this._state === ZoneState.UNINITIALIZED) return;
|
||||
this._state = ZoneState.UNINITIALIZED;
|
||||
}
|
||||
public update(time: number): void {
|
||||
if (this._state === ZoneState.UPDATING)
|
||||
this._scene.update(time);
|
||||
}
|
||||
public render(shader: Shader): void {
|
||||
if (this._state === ZoneState.UPDATING)
|
||||
this._scene.render(shader);
|
||||
}
|
||||
|
||||
public onActivated(): void { }
|
||||
public onDeactivated(): void { }
|
||||
|
||||
private loadSimObject(dataSection: any, parent: SimObject): void {
|
||||
if (dataSection.name === undefined) throw new Error("Invalid Object data!");
|
||||
let name: string = String(dataSection.name);
|
||||
|
||||
this._globalId++;
|
||||
let simObject = new SimObject(this._globalId, name, this._scene);
|
||||
|
||||
if (dataSection.transform !== undefined) simObject.transform.setFromJson(dataSection.transform);
|
||||
|
||||
if (dataSection.components !== undefined) {
|
||||
for (let component of dataSection.components)
|
||||
simObject.addComponent(ComponentManager.extractComponent(component));
|
||||
}
|
||||
|
||||
if (dataSection.behaviors !== undefined) {
|
||||
for (let behavior of dataSection.behaviors)
|
||||
simObject.addBehavior(BehaviorManager.extractComponent(behavior));
|
||||
}
|
||||
|
||||
if (dataSection.children !== undefined) {
|
||||
for (let object of dataSection.children) this.loadSimObject(object, simObject);
|
||||
}
|
||||
|
||||
parent.addChild(simObject);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
69
C#/TSEngine/Core/World/zoneManager.ts
Normal file
69
C#/TSEngine/Core/World/zoneManager.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
namespace TSE {
|
||||
|
||||
export class ZoneManager implements IMessageHanlder{
|
||||
|
||||
private static _globalZoneId: number = -1;
|
||||
//private static _zones: { [id: number]: Zone } = {};
|
||||
private static _registeredZones: {[id: number]: string} = {};
|
||||
private static _activeZone: Zone;
|
||||
private static _instance: ZoneManager;
|
||||
|
||||
private constructor() { }
|
||||
|
||||
public static initialize(): void {
|
||||
ZoneManager._instance = new ZoneManager();
|
||||
|
||||
ZoneManager._registeredZones[0] = "assets/zones/testZone.json";
|
||||
}
|
||||
|
||||
public static changeZone(id: number): void {
|
||||
if (ZoneManager._activeZone !== undefined) {
|
||||
ZoneManager._activeZone.onDeactivated();
|
||||
ZoneManager._activeZone.unload();
|
||||
delete ZoneManager._activeZone;
|
||||
}
|
||||
let zonePath = ZoneManager._registeredZones[id];
|
||||
if (zonePath === undefined) throw new Error("Zone Id does not exist!");
|
||||
|
||||
if (AssetManager.isAssetLoaded(zonePath)) ZoneManager.loadZone(AssetManager.getAsset(zonePath));
|
||||
else {
|
||||
Message.subscribe(MESSAGE_ASSET_LOADER_ASSET_LOADED + zonePath, ZoneManager._instance);
|
||||
AssetManager.loadAsset(zonePath);
|
||||
}
|
||||
}
|
||||
|
||||
public static update(time: number): void {
|
||||
if (ZoneManager._activeZone === undefined) return;
|
||||
ZoneManager._activeZone.update(time);
|
||||
}
|
||||
public static render(shader: Shader): void {
|
||||
if (ZoneManager._activeZone === undefined) return;
|
||||
ZoneManager._activeZone.render(shader);
|
||||
}
|
||||
|
||||
private static loadZone(asset: JsonAsset): void {
|
||||
let zoneData = asset.data;
|
||||
if (zoneData.id === undefined) throw new Error("Zone file format exception: Zone id not present.")
|
||||
let zoneId: number = Number(zoneData.id);
|
||||
let zoneName: string = String(zoneData.name);
|
||||
let zoneDescription: string = String(zoneData.description);
|
||||
|
||||
let zone = new Zone(zoneId, zoneName, zoneDescription);
|
||||
zone.initialize(zoneData);
|
||||
ZoneManager._activeZone = zone;
|
||||
zone.load();
|
||||
zone.onActivated();
|
||||
}
|
||||
|
||||
public onMessage(message: Message): void {
|
||||
if (message.code.indexOf(MESSAGE_ASSET_LOADER_ASSET_LOADED) !== -1) {
|
||||
let asset = message.context as JsonAsset;
|
||||
ZoneManager.loadZone(asset);
|
||||
}
|
||||
}
|
||||
|
||||
public static get zone(): Zone { return this._activeZone; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
71
C#/TSEngine/Core/engine.ts
Normal file
71
C#/TSEngine/Core/engine.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
namespace TSE {
|
||||
|
||||
/**
|
||||
* The main GameEngine class.
|
||||
* */
|
||||
export class Engine {
|
||||
private _canvas: HTMLCanvasElement;
|
||||
private _shader: Shader;
|
||||
private _projection: Matrix4x4;
|
||||
private _previousTime: number = 0;
|
||||
|
||||
/**
|
||||
* Creates a new Engine.
|
||||
* */
|
||||
public constructor(canvasId: string) {
|
||||
this._canvas = GLUtilities.initialize(canvasId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts this Engine.
|
||||
* */
|
||||
public start(): void {
|
||||
AssetManager.initialize();
|
||||
ZoneManager.initialize();
|
||||
|
||||
gl.clearColor(0, 0, 0, 1);
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
//LoadMaterials
|
||||
MaterialManager.registerMaterial(new Material("crate", "/assets/textures/crate.jpg"));
|
||||
MaterialManager.registerMaterial(new Material("goblin", "/assets/textures/goblin.png"));
|
||||
|
||||
//Load Shader
|
||||
this._shader = new BasicShader();
|
||||
this._shader.use();
|
||||
|
||||
//Load
|
||||
this._projection = Matrix4x4.orthographic(0, this._canvas.width, this._canvas.height, 0, -100.0, 100.0);
|
||||
ZoneManager.changeZone(0);
|
||||
|
||||
this.loop();
|
||||
}
|
||||
|
||||
private loop(): void {
|
||||
let delta = performance.now() - this._previousTime;
|
||||
|
||||
MessageBus.update(delta);
|
||||
ZoneManager.update(delta);
|
||||
|
||||
this._previousTime = performance.now();
|
||||
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
ZoneManager.render(this._shader);
|
||||
|
||||
//Set Uniforms
|
||||
let projectionPosition = this._shader.getUniformLocation("u_projection");
|
||||
gl.uniformMatrix4fv(projectionPosition, false, new Float32Array(this._projection.data));
|
||||
|
||||
requestAnimationFrame(this.loop.bind(this));
|
||||
}
|
||||
|
||||
public resize(): void {
|
||||
this._projection = Matrix4x4.orthographic(0, this._canvas.width, this._canvas.height, 0, -100.0, 100.0);
|
||||
gl.viewport(0, 0, this._canvas.width, this._canvas.height);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user