Refactor rendering
This commit is contained in:
parent
edca93fcfe
commit
76282a4cf7
25 changed files with 239 additions and 213 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"trailingComma": "es5",
|
"trailingComma": "es5",
|
||||||
|
"printWidth": 120,
|
||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"endOfLine": "lf"
|
"endOfLine": "lf"
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { IDrawable } from './i-drawable';
|
||||||
import { IDrawableDescriptor } from './i-drawable-descriptor';
|
import { IDrawableDescriptor } from './i-drawable-descriptor';
|
||||||
import { settings } from '../settings';
|
import { settings } from '../settings';
|
||||||
import { Blob } from '../../shapes/types/blob';
|
import { Blob } from '../../shapes/types/blob';
|
||||||
|
import { vec2, mat2d } from 'gl-matrix';
|
||||||
|
|
||||||
export class DrawableBlob extends Blob implements IDrawable {
|
export class DrawableBlob extends Blob implements IDrawable {
|
||||||
public static descriptor: IDrawableDescriptor = {
|
public static descriptor: IDrawableDescriptor = {
|
||||||
|
|
@ -10,17 +11,37 @@ export class DrawableBlob extends Blob implements IDrawable {
|
||||||
shaderCombinationSteps: settings.shaderCombinations.blobSteps,
|
shaderCombinationSteps: settings.shaderCombinations.blobSteps,
|
||||||
};
|
};
|
||||||
|
|
||||||
public serializeToUniforms(uniforms: any): void {
|
public serializeToUniforms(
|
||||||
|
uniforms: any,
|
||||||
|
scale: number,
|
||||||
|
transform: mat2d
|
||||||
|
): void {
|
||||||
const uniformName = DrawableBlob.descriptor.uniformName;
|
const uniformName = DrawableBlob.descriptor.uniformName;
|
||||||
if (!uniforms.hasOwnProperty(uniformName)) {
|
if (!uniforms.hasOwnProperty(uniformName)) {
|
||||||
uniforms[uniformName] = [];
|
uniforms[uniformName] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
uniforms[uniformName].push({
|
uniforms[uniformName].push({
|
||||||
headCenter: this.head.center,
|
headCenter: vec2.transformMat2d(
|
||||||
torsoCenter: this.torso.center,
|
vec2.create(),
|
||||||
leftFootCenter: this.leftFoot.center,
|
this.head.center,
|
||||||
rightFootCenter: this.rightFoot.center,
|
transform
|
||||||
|
),
|
||||||
|
torsoCenter: vec2.transformMat2d(
|
||||||
|
vec2.create(),
|
||||||
|
this.torso.center,
|
||||||
|
transform
|
||||||
|
),
|
||||||
|
leftFootCenter: vec2.transformMat2d(
|
||||||
|
vec2.create(),
|
||||||
|
this.leftFoot.center,
|
||||||
|
transform
|
||||||
|
),
|
||||||
|
rightFootCenter: vec2.transformMat2d(
|
||||||
|
vec2.create(),
|
||||||
|
this.rightFoot.center,
|
||||||
|
transform
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { IDrawable } from './i-drawable';
|
||||||
import { TunnelShape } from '../../shapes/types/tunnel-shape';
|
import { TunnelShape } from '../../shapes/types/tunnel-shape';
|
||||||
import { IDrawableDescriptor } from './i-drawable-descriptor';
|
import { IDrawableDescriptor } from './i-drawable-descriptor';
|
||||||
import { settings } from '../settings';
|
import { settings } from '../settings';
|
||||||
|
import { mat2d, vec2 } from 'gl-matrix';
|
||||||
|
|
||||||
export class DrawableTunnel extends TunnelShape implements IDrawable {
|
export class DrawableTunnel extends TunnelShape implements IDrawable {
|
||||||
public static descriptor: IDrawableDescriptor = {
|
public static descriptor: IDrawableDescriptor = {
|
||||||
|
|
@ -10,17 +11,25 @@ export class DrawableTunnel extends TunnelShape implements IDrawable {
|
||||||
shaderCombinationSteps: settings.shaderCombinations.lineSteps,
|
shaderCombinationSteps: settings.shaderCombinations.lineSteps,
|
||||||
};
|
};
|
||||||
|
|
||||||
public serializeToUniforms(uniforms: any): void {
|
public serializeToUniforms(
|
||||||
|
uniforms: any,
|
||||||
|
scale: number,
|
||||||
|
transform: mat2d
|
||||||
|
): void {
|
||||||
const uniformName = DrawableTunnel.descriptor.uniformName;
|
const uniformName = DrawableTunnel.descriptor.uniformName;
|
||||||
if (!uniforms.hasOwnProperty(uniformName)) {
|
if (!uniforms.hasOwnProperty(uniformName)) {
|
||||||
uniforms[uniformName] = [];
|
uniforms[uniformName] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
uniforms[uniformName].push({
|
uniforms[uniformName].push({
|
||||||
from: this.from,
|
from: vec2.transformMat2d(vec2.create(), this.from, transform),
|
||||||
toFromDelta: this.toFromDelta,
|
toFromDelta: vec2.transformMat2d(
|
||||||
fromRadius: this.fromRadius,
|
vec2.create(),
|
||||||
toRadius: this.toRadius,
|
this.toFromDelta,
|
||||||
|
transform
|
||||||
|
),
|
||||||
|
fromRadius: this.fromRadius * scale,
|
||||||
|
toRadius: this.toRadius * scale,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2, mat2d } from 'gl-matrix';
|
||||||
|
|
||||||
export interface IDrawable {
|
export interface IDrawable {
|
||||||
distance(target: vec2): number;
|
distance(target: vec2): number;
|
||||||
serializeToUniforms(uniforms: any): void;
|
serializeToUniforms(uniforms: any, scale: number, transform: mat2d): void;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { vec2, vec3 } from 'gl-matrix';
|
import { vec2, vec3, mat2d } from 'gl-matrix';
|
||||||
import { GameObject } from '../../../objects/game-object';
|
import { GameObject } from '../../../objects/game-object';
|
||||||
import { settings } from '../../settings';
|
import { settings } from '../../settings';
|
||||||
import { IDrawableDescriptor } from '../i-drawable-descriptor';
|
import { IDrawableDescriptor } from '../i-drawable-descriptor';
|
||||||
|
|
@ -12,7 +12,6 @@ export class CircleLight implements ILight {
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public readonly owner: GameObject,
|
|
||||||
public center: vec2,
|
public center: vec2,
|
||||||
public radius: number,
|
public radius: number,
|
||||||
public color: vec3,
|
public color: vec3,
|
||||||
|
|
@ -23,7 +22,11 @@ export class CircleLight implements ILight {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public serializeToUniforms(uniforms: any): void {
|
public serializeToUniforms(
|
||||||
|
uniforms: any,
|
||||||
|
scale: number,
|
||||||
|
transform: mat2d
|
||||||
|
): void {
|
||||||
const uniformName = CircleLight.descriptor.uniformName;
|
const uniformName = CircleLight.descriptor.uniformName;
|
||||||
|
|
||||||
if (!uniforms.hasOwnProperty(uniformName)) {
|
if (!uniforms.hasOwnProperty(uniformName)) {
|
||||||
|
|
@ -31,8 +34,8 @@ export class CircleLight implements ILight {
|
||||||
}
|
}
|
||||||
|
|
||||||
uniforms[uniformName].push({
|
uniforms[uniformName].push({
|
||||||
center: this.center,
|
center: vec2.transformMat2d(vec2.create(), this.center, transform),
|
||||||
radius: this.radius,
|
radius: this.radius * scale,
|
||||||
value: this.value,
|
value: this.value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { ILight } from './i-light';
|
import { ILight } from './i-light';
|
||||||
import { vec2, vec3 } from 'gl-matrix';
|
import { vec2, vec3, mat2d } from 'gl-matrix';
|
||||||
import { IDrawableDescriptor } from '../i-drawable-descriptor';
|
import { IDrawableDescriptor } from '../i-drawable-descriptor';
|
||||||
import { settings } from '../../settings';
|
import { settings } from '../../settings';
|
||||||
import { GameObject } from '../../../objects/game-object';
|
import { GameObject } from '../../../objects/game-object';
|
||||||
|
|
@ -12,7 +12,6 @@ export class PointLight implements ILight {
|
||||||
};
|
};
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
public readonly owner: GameObject,
|
|
||||||
public center: vec2,
|
public center: vec2,
|
||||||
public radius: number,
|
public radius: number,
|
||||||
public color: vec3,
|
public color: vec3,
|
||||||
|
|
@ -23,7 +22,11 @@ export class PointLight implements ILight {
|
||||||
return vec2.distance(this.center, target) - this.radius;
|
return vec2.distance(this.center, target) - this.radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
public serializeToUniforms(uniforms: any): void {
|
public serializeToUniforms(
|
||||||
|
uniforms: any,
|
||||||
|
scale: number,
|
||||||
|
transform: mat2d
|
||||||
|
): void {
|
||||||
const listName = PointLight.descriptor.uniformName;
|
const listName = PointLight.descriptor.uniformName;
|
||||||
|
|
||||||
if (!uniforms.hasOwnProperty(listName)) {
|
if (!uniforms.hasOwnProperty(listName)) {
|
||||||
|
|
@ -31,8 +34,8 @@ export class PointLight implements ILight {
|
||||||
}
|
}
|
||||||
|
|
||||||
uniforms[listName].push({
|
uniforms[listName].push({
|
||||||
center: this.center,
|
center: vec2.transformMat2d(vec2.create(), this.center, transform),
|
||||||
radius: this.radius,
|
radius: this.radius * scale,
|
||||||
value: this.value,
|
value: this.value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2 } from 'gl-matrix';
|
||||||
import { ILight } from './drawables/lights/i-light';
|
import { ILight } from './drawables/lights/i-light';
|
||||||
import { IDrawable } from './drawables/i-drawable';
|
import { IDrawable } from './drawables/i-drawable';
|
||||||
|
import { BoundingBoxBase } from '../shapes/bounding-box-base';
|
||||||
|
|
||||||
export interface IRenderer {
|
export interface IRenderer {
|
||||||
startFrame(deltaTime: DOMHighResTimeStamp): void;
|
startFrame(deltaTime: DOMHighResTimeStamp): void;
|
||||||
|
|
@ -10,7 +11,7 @@ export interface IRenderer {
|
||||||
drawLight(light: ILight): void;
|
drawLight(light: ILight): void;
|
||||||
drawInfoText(text: string): void;
|
drawInfoText(text: string): void;
|
||||||
|
|
||||||
setCameraPosition(position: vec2): void;
|
readonly canvasSize: vec2;
|
||||||
|
setViewArea(viewArea: BoundingBoxBase): void;
|
||||||
setCursorPosition(position: vec2): void;
|
setCursorPosition(position: vec2): void;
|
||||||
setInViewArea(size: number): vec2;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2, mat2d } from 'gl-matrix';
|
||||||
import { InfoText } from '../../objects/types/info-text';
|
import { InfoText } from '../../objects/types/info-text';
|
||||||
import { IDrawable } from '../drawables/i-drawable';
|
import { IDrawable } from '../drawables/i-drawable';
|
||||||
import { IDrawableDescriptor } from '../drawables/i-drawable-descriptor';
|
import { IDrawableDescriptor } from '../drawables/i-drawable-descriptor';
|
||||||
|
|
@ -27,20 +27,11 @@ export class RenderingPass {
|
||||||
this.drawables.push(drawable);
|
this.drawables.push(drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(
|
public render(commonUniforms: any, inputTexture?: WebGLTexture) {
|
||||||
commonUniforms: any,
|
|
||||||
viewBoxCenter: vec2,
|
|
||||||
viewBoxRadius: number,
|
|
||||||
inputTexture?: WebGLTexture
|
|
||||||
) {
|
|
||||||
this.frame.bindAndClear(inputTexture);
|
this.frame.bindAndClear(inputTexture);
|
||||||
const q = 1 / settings.tileMultiplier;
|
const q = 1 / settings.tileMultiplier;
|
||||||
const tileUvSize = vec2.fromValues(q, q);
|
const tileUvSize = vec2.fromValues(q, q);
|
||||||
|
|
||||||
const possiblyOnScreenDrawables = this.drawables.filter(
|
|
||||||
(p) => p.distance(viewBoxCenter) < viewBoxRadius
|
|
||||||
);
|
|
||||||
|
|
||||||
const origin = vec2.transformMat2d(
|
const origin = vec2.transformMat2d(
|
||||||
vec2.create(),
|
vec2.create(),
|
||||||
vec2.fromValues(0, 0),
|
vec2.fromValues(0, 0),
|
||||||
|
|
@ -59,6 +50,9 @@ export class RenderingPass {
|
||||||
|
|
||||||
let sumLineCount = 0;
|
let sumLineCount = 0;
|
||||||
|
|
||||||
|
const scale = 1;
|
||||||
|
const transform = mat2d.create();
|
||||||
|
|
||||||
for (let x = 0; x < 1; x += q) {
|
for (let x = 0; x < 1; x += q) {
|
||||||
for (let y = 0; y < 1; y += q) {
|
for (let y = 0; y < 1; y += q) {
|
||||||
const uniforms = { ...commonUniforms };
|
const uniforms = { ...commonUniforms };
|
||||||
|
|
@ -73,24 +67,24 @@ export class RenderingPass {
|
||||||
uniforms.uvToWorld
|
uniforms.uvToWorld
|
||||||
);
|
);
|
||||||
|
|
||||||
const primitivesNearTile = possiblyOnScreenDrawables.filter(
|
const primitivesNearTile = this.drawables.filter(
|
||||||
(p) => p.distance(tileCenterWorldCoordinates) < 2 * worldR
|
(p) => p.distance(tileCenterWorldCoordinates) < 2 * worldR
|
||||||
);
|
);
|
||||||
|
|
||||||
sumLineCount += primitivesNearTile.length;
|
sumLineCount += primitivesNearTile.length;
|
||||||
|
|
||||||
primitivesNearTile.forEach((p) => p.serializeToUniforms(uniforms));
|
primitivesNearTile.forEach((p) =>
|
||||||
|
p.serializeToUniforms(uniforms, scale, transform)
|
||||||
|
);
|
||||||
|
|
||||||
this.program.bindAndSetUniforms(uniforms);
|
this.program.bindAndSetUniforms(uniforms);
|
||||||
this.program.draw();
|
this.program.draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.drawables = [];
|
|
||||||
|
|
||||||
InfoText.modifyRecord(
|
InfoText.modifyRecord(
|
||||||
'nearby ' + this.drawableDescriptors[0].countMacroName,
|
'nearby ' + this.drawableDescriptors[0].countMacroName,
|
||||||
possiblyOnScreenDrawables.length.toFixed(2)
|
this.drawables.length.toFixed(2)
|
||||||
);
|
);
|
||||||
|
|
||||||
InfoText.modifyRecord(
|
InfoText.modifyRecord(
|
||||||
|
|
@ -101,5 +95,7 @@ export class RenderingPass {
|
||||||
settings.tileMultiplier
|
settings.tileMultiplier
|
||||||
).toFixed(2)
|
).toFixed(2)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.drawables = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,13 @@ import { IDrawable } from '../drawables/i-drawable';
|
||||||
import { DrawableTunnel } from '../drawables/drawable-tunnel';
|
import { DrawableTunnel } from '../drawables/drawable-tunnel';
|
||||||
import { enableExtension } from '../graphics-library/helper/enable-extension';
|
import { enableExtension } from '../graphics-library/helper/enable-extension';
|
||||||
import { DrawableBlob } from '../drawables/drawable-blob';
|
import { DrawableBlob } from '../drawables/drawable-blob';
|
||||||
|
import { BoundingBoxBase } from '../../shapes/bounding-box-base';
|
||||||
|
|
||||||
export class WebGl2Renderer implements IRenderer {
|
export class WebGl2Renderer implements IRenderer {
|
||||||
private gl: WebGL2RenderingContext;
|
private gl: WebGL2RenderingContext;
|
||||||
private stopwatch?: WebGlStopwatch;
|
private stopwatch?: WebGlStopwatch;
|
||||||
|
|
||||||
private viewBoxBottomLeft = vec2.create();
|
private viewBoxBottomLeft = vec2.create();
|
||||||
private cameraPosition = vec2.create();
|
|
||||||
private viewBoxSize = vec2.create();
|
private viewBoxSize = vec2.create();
|
||||||
private cursorPosition = vec2.create();
|
private cursorPosition = vec2.create();
|
||||||
|
|
||||||
|
|
@ -92,16 +92,10 @@ export class WebGl2Renderer implements IRenderer {
|
||||||
public finishFrame() {
|
public finishFrame() {
|
||||||
this.calculateMatrices();
|
this.calculateMatrices();
|
||||||
|
|
||||||
const viewBoxRadius = vec2.length(
|
this.distancePass.render(this.uniforms);
|
||||||
vec2.scale(vec2.create(), this.viewBoxSize, 0.5)
|
|
||||||
);
|
|
||||||
|
|
||||||
this.distancePass.render(this.uniforms, this.cameraPosition, viewBoxRadius);
|
|
||||||
|
|
||||||
this.lightingPass.render(
|
this.lightingPass.render(
|
||||||
this.uniforms,
|
this.uniforms,
|
||||||
this.cameraPosition,
|
|
||||||
viewBoxRadius,
|
|
||||||
this.distanceFieldFrameBuffer.colorTexture
|
this.distanceFieldFrameBuffer.colorTexture
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -164,11 +158,16 @@ export class WebGl2Renderer implements IRenderer {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setCameraPosition(position: vec2) {
|
public get canvasSize(): vec2 {
|
||||||
this.cameraPosition = position;
|
return vec2.fromValues(this.canvas.clientWidth, this.canvas.clientHeight);
|
||||||
this.viewBoxBottomLeft = vec2.fromValues(
|
}
|
||||||
this.cameraPosition.x - this.viewBoxSize.x / 2,
|
|
||||||
this.cameraPosition.y - this.viewBoxSize.y / 2
|
public setViewArea(viewArea: BoundingBoxBase) {
|
||||||
|
this.viewBoxSize = viewArea.size;
|
||||||
|
this.viewBoxBottomLeft = vec2.add(
|
||||||
|
vec2.create(),
|
||||||
|
viewArea.topLeft,
|
||||||
|
vec2.fromValues(0, -viewArea.size.y)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,16 +175,6 @@ export class WebGl2Renderer implements IRenderer {
|
||||||
this.cursorPosition = position;
|
this.cursorPosition = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setInViewArea(size: number): vec2 {
|
|
||||||
const canvasAspectRatio =
|
|
||||||
this.canvas.clientWidth / this.canvas.clientHeight;
|
|
||||||
|
|
||||||
return (this.viewBoxSize = vec2.fromValues(
|
|
||||||
Math.sqrt(size * canvasAspectRatio),
|
|
||||||
Math.sqrt(size / canvasAspectRatio)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
public drawInfoText(text: string) {
|
public drawInfoText(text: string) {
|
||||||
if (this.overlay.innerText != text) {
|
if (this.overlay.innerText != text) {
|
||||||
this.overlay.innerText = text;
|
this.overlay.innerText = text;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ export const settings = {
|
||||||
scaleTargets: [
|
scaleTargets: [
|
||||||
[0.2, 0.1],
|
[0.2, 0.1],
|
||||||
[0.6, 0.1],
|
[0.6, 0.1],
|
||||||
[1, 0.3],
|
[1, 1],
|
||||||
/*[1.25, 0.75],
|
/*[1.25, 0.75],
|
||||||
[1.5, 1],
|
[1.5, 1],
|
||||||
[1.75, 1.25],
|
[1.75, 1.25],
|
||||||
|
|
@ -20,12 +20,12 @@ export const settings = {
|
||||||
multiplicativeDecrease: 1.15,
|
multiplicativeDecrease: 1.15,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tileMultiplier: 5,
|
tileMultiplier: 8,
|
||||||
shaderMacros: {
|
shaderMacros: {
|
||||||
edgeSmoothing: 10,
|
edgeSmoothing: 10,
|
||||||
headRadius: 5,
|
headRadius: 5,
|
||||||
torsoRadius: 10,
|
torsoRadius: 8,
|
||||||
footRadius: 4,
|
footRadius: 2,
|
||||||
},
|
},
|
||||||
shaderCombinations: {
|
shaderCombinations: {
|
||||||
lineSteps: [0, 1, 2, 4, 8, 16, 128],
|
lineSteps: [0, 1, 2, 4, 8, 16, 128],
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,6 @@ uniform float maxMinDistance;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
in vec2 worldCoordinates;
|
in vec2 worldCoordinates;
|
||||||
out vec2 fragmentColor;
|
out vec2 fragmentColor;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,40 +61,41 @@ void main() {
|
||||||
|
|
||||||
#if CIRCLE_LIGHT_COUNT > 0
|
#if CIRCLE_LIGHT_COUNT > 0
|
||||||
for (int i = 0; i < CIRCLE_LIGHT_COUNT; i++) {
|
for (int i = 0; i < CIRCLE_LIGHT_COUNT; i++) {
|
||||||
float lightCenterDistance = distance(circleLights[i].center, worldCoordinates);
|
float lightCenterDistance = distance(
|
||||||
|
circleLights[i].center,
|
||||||
|
worldCoordinates
|
||||||
|
);
|
||||||
|
float lightDistance = lightCenterDistance - circleLights[i].radius;
|
||||||
|
|
||||||
|
/*if (lightDistance < 0.0) {
|
||||||
|
lighting = vec3(1.0, 1.0, 0.0);
|
||||||
|
}*/
|
||||||
|
|
||||||
vec3 lightColorAtPosition = circleLights[i].value / pow(
|
vec3 lightColorAtPosition = circleLights[i].value / pow(
|
||||||
lightCenterDistance / LIGHT_DROP + 1.0, 2.0
|
lightDistance / LIGHT_DROP + 1.0, 2.0
|
||||||
);
|
);
|
||||||
|
|
||||||
float q = INFINITY;
|
float q = INFINITY;
|
||||||
float rayLength = startingDistance;
|
float rayLength = startingDistance;
|
||||||
float exponentialDecayDistance = rayLength;
|
|
||||||
vec2 direction = normalize(circleLightDirections[i]) / viewBoxSize;
|
vec2 direction = normalize(circleLightDirections[i]) / viewBoxSize;
|
||||||
|
|
||||||
for (int j = 0; j < 48; j++) {
|
for (int j = 0; j < 48; j++) {
|
||||||
if (rayLength > lightCenterDistance - circleLights[i].radius) {
|
if (rayLength >= lightDistance) {
|
||||||
rayLength = lightCenterDistance - circleLights[i].radius;
|
|
||||||
float minDistance = getDistance(uvCoordinates + direction * rayLength);
|
|
||||||
exponentialDecayDistance = (exponentialDecayDistance + minDistance) / 2.0;
|
|
||||||
q = min(q, minDistance / rayLength);
|
|
||||||
|
|
||||||
lighting += lightColorAtPosition * clamp(
|
lighting += lightColorAtPosition * clamp(
|
||||||
q / circleLights[i].radius * (lightCenterDistance + 1.0), 0.0, 1.0
|
q / circleLights[i].radius * lightCenterDistance, 0.0, 1.0
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
float minDistance = getDistance(uvCoordinates + direction * rayLength);
|
float minDistance = getDistance(uvCoordinates + direction * rayLength);
|
||||||
exponentialDecayDistance = (exponentialDecayDistance + minDistance) / 2.0;
|
q = min(q, minDistance / rayLength);
|
||||||
q = min(q, exponentialDecayDistance / rayLength);
|
|
||||||
rayLength += minDistance;
|
rayLength += minDistance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if POINT_LIGHT_COUNT > 0
|
#if POINT_LIGHT_COUNT > 0
|
||||||
for (int i = 0; i < POINT_LIGHT_COUNT; i++) {
|
/*for (int i = 0; i < POINT_LIGHT_COUNT; i++) {
|
||||||
float lightDistance = distance(pointLights[i].center, worldCoordinates);
|
float lightDistance = distance(pointLights[i].center, worldCoordinates);
|
||||||
|
|
||||||
vec3 lightColorAtPosition = mix(
|
vec3 lightColorAtPosition = mix(
|
||||||
|
|
@ -120,8 +121,11 @@ void main() {
|
||||||
q = min(q, exponentialDecayDistance);
|
q = min(q, exponentialDecayDistance);
|
||||||
rayLength += minDistance;
|
rayLength += minDistance;
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fragmentColor = vec4(colorAtPosition * lighting * step(0.0, startingDistance), 1.0);
|
fragmentColor = vec4(
|
||||||
|
colorAtPosition * lighting * step(0.0, startingDistance),
|
||||||
|
1.0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
#version 300 es
|
|
||||||
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
vec3 rainbow(float level) {
|
|
||||||
float r = float(level <= 2.0) + float(level > 4.0) * 0.5;
|
|
||||||
float g = max(1.0 - abs(level - 2.0) * 0.5, 0.0);
|
|
||||||
float b = (1.0 - (level - 4.0) * 0.5) * float(level >= 4.0);
|
|
||||||
return vec3(r, g, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 smoothRainbow(float x) {
|
|
||||||
float level1 = floor(x*6.0);
|
|
||||||
float level2 = min(6.0, floor(x*6.0) + 1.0);
|
|
||||||
|
|
||||||
vec3 a = rainbow(level1);
|
|
||||||
vec3 b = rainbow(level2);
|
|
||||||
|
|
||||||
return vec4(mix(a, b, fract(x*6.0)), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uniform sampler2D distanceTexture;
|
|
||||||
uniform mat3 worldToDistanceUV;
|
|
||||||
uniform mat3 lightingScreenToWorld;
|
|
||||||
out vec4 fragmentColor;
|
|
||||||
uniform vec2 cursorPosition;
|
|
||||||
|
|
||||||
|
|
||||||
float getDistance(in vec2 targetUV, out vec3 color) {
|
|
||||||
vec4 values = texture(distanceTexture, targetUV);
|
|
||||||
color = values.rgb;
|
|
||||||
return values.a;
|
|
||||||
}
|
|
||||||
|
|
||||||
in vec2 worldCoordinates;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec2 targetUV = (vec3(worldCoordinates.xy, 1.0) * worldToDistanceUV).xy;
|
|
||||||
|
|
||||||
vec4 previous = texture(distanceTexture, targetUV);
|
|
||||||
|
|
||||||
//fragmentColor = smoothRainbow(previous.a);
|
|
||||||
fragmentColor = previous.a > 0.5 ? vec4(1.0, 1.0, 1.0, 1.0) : vec4(0.0, 0.0, 0.0, 1.0);
|
|
||||||
|
|
||||||
if (distance(worldCoordinates, cursorPosition) < 10.0) {
|
|
||||||
fragmentColor = vec4(1.0, 1.0, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -8,22 +8,33 @@ import { MouseListener } from './input/mouse-listener';
|
||||||
import { TouchListener } from './input/touch-listener';
|
import { TouchListener } from './input/touch-listener';
|
||||||
import { Objects } from './objects/objects';
|
import { Objects } from './objects/objects';
|
||||||
import { InfoText } from './objects/types/info-text';
|
import { InfoText } from './objects/types/info-text';
|
||||||
import { createCharacter } from './objects/world/create-character';
|
|
||||||
import { createDungeon } from './objects/world/create-dungeon';
|
import { createDungeon } from './objects/world/create-dungeon';
|
||||||
import { RenderCommand } from './drawing/commands/render';
|
import { RenderCommand } from './drawing/commands/render';
|
||||||
import { Physics } from './physics/physics';
|
import { Physics } from './physics/physics';
|
||||||
import { TeleportToCommand } from './physics/commands/teleport-to';
|
import { TeleportToCommand } from './physics/commands/teleport-to';
|
||||||
import { IRenderer } from './drawing/i-renderer';
|
import { IRenderer } from './drawing/i-renderer';
|
||||||
import { Random } from './helper/random';
|
import { Random } from './helper/random';
|
||||||
|
import { Camera } from './objects/types/camera';
|
||||||
|
import { Character } from './objects/types/character';
|
||||||
|
import { IGame } from './i-game';
|
||||||
|
import { GameObject } from './objects/game-object';
|
||||||
|
import { vec2 } from 'gl-matrix';
|
||||||
|
import { BoundingBoxBase } from './shapes/bounding-box-base';
|
||||||
|
import { MoveToCommand } from './physics/commands/move-to';
|
||||||
|
import { BoundingBox } from './shapes/bounding-box';
|
||||||
|
|
||||||
|
export class Game implements IGame {
|
||||||
|
public readonly objects = new Objects();
|
||||||
|
public readonly physics = new Physics();
|
||||||
|
public readonly camera = new Camera();
|
||||||
|
|
||||||
export class Game {
|
|
||||||
private previousTime?: DOMHighResTimeStamp = null;
|
private previousTime?: DOMHighResTimeStamp = null;
|
||||||
private objects = new Objects();
|
|
||||||
private physics = new Physics();
|
|
||||||
|
|
||||||
private renderer: IRenderer;
|
|
||||||
private previousFpsValues: Array<number> = [];
|
private previousFpsValues: Array<number> = [];
|
||||||
|
|
||||||
|
private infoText = new InfoText();
|
||||||
|
private character: Character;
|
||||||
|
private renderer: IRenderer;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const canvas: HTMLCanvasElement = document.querySelector('canvas#main');
|
const canvas: HTMLCanvasElement = document.querySelector('canvas#main');
|
||||||
const overlay: HTMLElement = document.querySelector('#overlay');
|
const overlay: HTMLElement = document.querySelector('#overlay');
|
||||||
|
|
@ -52,13 +63,29 @@ export class Game {
|
||||||
requestAnimationFrame(this.gameLoop.bind(this));
|
requestAnimationFrame(this.gameLoop.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addObject(o: GameObject) {
|
||||||
|
this.objects.addObject(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get viewArea(): BoundingBoxBase {
|
||||||
|
return this.camera.viewArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
public findIntersecting(box: BoundingBoxBase): Array<BoundingBoxBase> {
|
||||||
|
return this.physics.findIntersecting(box);
|
||||||
|
}
|
||||||
|
|
||||||
private initializeScene() {
|
private initializeScene() {
|
||||||
this.objects.addObject(new InfoText());
|
this.objects.addObject(this.infoText);
|
||||||
|
|
||||||
const start = createDungeon(this.objects, this.physics);
|
const start = createDungeon(this.objects, this.physics);
|
||||||
createDungeon(this.objects, this.physics);
|
createDungeon(this.objects, this.physics);
|
||||||
const character = createCharacter(this.objects, this.physics);
|
|
||||||
console.log('start', start.from);
|
this.character = new Character(this);
|
||||||
character.sendCommand(new TeleportToCommand(start.from));
|
//this.physics.addDynamicBoundingBox(this.character.boundingBox);
|
||||||
|
this.addObject(this.character);
|
||||||
|
this.addObject(this.camera);
|
||||||
|
this.character.sendCommand(new TeleportToCommand(start.from));
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleVisibilityChange() {
|
private handleVisibilityChange() {
|
||||||
|
|
@ -78,10 +105,23 @@ export class Game {
|
||||||
this.calculateFps(deltaTime);
|
this.calculateFps(deltaTime);
|
||||||
|
|
||||||
this.objects.sendCommand(new StepCommand(deltaTime));
|
this.objects.sendCommand(new StepCommand(deltaTime));
|
||||||
|
this.camera.sendCommand(new MoveToCommand(this.character.position));
|
||||||
|
|
||||||
this.renderer.startFrame(deltaTime);
|
this.renderer.startFrame(deltaTime);
|
||||||
this.objects.sendCommand(new BeforeRenderCommand(this.renderer));
|
|
||||||
this.objects.sendCommand(new RenderCommand(this.renderer));
|
this.camera.sendCommand(new BeforeRenderCommand(this.renderer));
|
||||||
|
|
||||||
|
const shouldBeDrawn = this.physics
|
||||||
|
.findIntersecting(this.camera.viewArea)
|
||||||
|
.map((b) => b.shape?.gameObject);
|
||||||
|
|
||||||
|
for (let object of shouldBeDrawn) {
|
||||||
|
object?.sendCommand(new BeforeRenderCommand(this.renderer));
|
||||||
|
object?.sendCommand(new RenderCommand(this.renderer));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.character.sendCommand(new RenderCommand(this.renderer));
|
||||||
|
this.infoText.sendCommand(new RenderCommand(this.renderer));
|
||||||
this.renderer.finishFrame();
|
this.renderer.finishFrame();
|
||||||
|
|
||||||
window.requestAnimationFrame(this.gameLoop.bind(this));
|
window.requestAnimationFrame(this.gameLoop.bind(this));
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
import { InfoText } from '../objects/types/info-text';
|
import { InfoText } from '../objects/types/info-text';
|
||||||
|
import { last } from './last';
|
||||||
|
|
||||||
export function timeIt(interval = 60) {
|
export function timeIt(interval = 60) {
|
||||||
return function (
|
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
||||||
target: any,
|
|
||||||
propertyKey: string,
|
|
||||||
descriptor: PropertyDescriptor
|
|
||||||
) {
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let previousTimes: Array<DOMHighResTimeStamp> = [];
|
let previousTimes: Array<DOMHighResTimeStamp> = [];
|
||||||
|
|
||||||
|
|
@ -19,10 +16,9 @@ export function timeIt(interval = 60) {
|
||||||
previousTimes.push(end - start);
|
previousTimes.push(end - start);
|
||||||
|
|
||||||
if (i++ % interval == 0) {
|
if (i++ % interval == 0) {
|
||||||
previousTimes.sort();
|
previousTimes = previousTimes.sort();
|
||||||
const text = `Max: ${previousTimes[previousTimes.length - 1].toFixed(
|
|
||||||
2
|
const text = `Max: ${last(previousTimes).toFixed(2)} ms\n\tMedian: ${previousTimes[
|
||||||
)} ms\n\tMedian: ${previousTimes[
|
|
||||||
Math.floor(previousTimes.length / 2)
|
Math.floor(previousTimes.length / 2)
|
||||||
].toFixed(2)} ms`;
|
].toFixed(2)} ms`;
|
||||||
|
|
||||||
|
|
|
||||||
9
frontend/src/scripts/i-game.ts
Normal file
9
frontend/src/scripts/i-game.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { GameObject } from './objects/game-object';
|
||||||
|
import { vec2 } from 'gl-matrix';
|
||||||
|
import { BoundingBoxBase } from './shapes/bounding-box-base';
|
||||||
|
|
||||||
|
export interface IGame {
|
||||||
|
addObject(o: GameObject);
|
||||||
|
readonly viewArea: BoundingBoxBase;
|
||||||
|
findIntersecting(box: BoundingBoxBase): Array<BoundingBoxBase>;
|
||||||
|
}
|
||||||
|
|
@ -9,40 +9,46 @@ import { GameObject } from '../game-object';
|
||||||
import { Lamp } from './lamp';
|
import { Lamp } from './lamp';
|
||||||
|
|
||||||
export class Camera extends GameObject {
|
export class Camera extends GameObject {
|
||||||
private inViewArea = 1920 * 1080 * 5;
|
private inViewAreaSize = 1920 * 1080 * 5;
|
||||||
private cursorPosition = vec2.create();
|
private cursorPosition = vec2.create();
|
||||||
private boundingBox: BoundingBox;
|
private _viewArea: BoundingBox;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.boundingBox = new BoundingBox(null);
|
this._viewArea = new BoundingBox(null);
|
||||||
|
|
||||||
this.addCommandExecutor(BeforeRenderCommand, this.draw.bind(this));
|
this.addCommandExecutor(BeforeRenderCommand, this.draw.bind(this));
|
||||||
this.addCommandExecutor(MoveToCommand, this.moveTo.bind(this));
|
this.addCommandExecutor(MoveToCommand, this.moveTo.bind(this));
|
||||||
this.addCommandExecutor(
|
this.addCommandExecutor(CursorMoveCommand, this.setCursorPosition.bind(this));
|
||||||
CursorMoveCommand,
|
|
||||||
this.setCursorPosition.bind(this)
|
|
||||||
);
|
|
||||||
this.addCommandExecutor(ZoomCommand, this.zoom.bind(this));
|
this.addCommandExecutor(ZoomCommand, this.zoom.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public get viewAreaSize(): vec2 {
|
public get viewArea(): BoundingBox {
|
||||||
return this.boundingBox.size;
|
return this._viewArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
private draw(c: BeforeRenderCommand) {
|
private draw(c: BeforeRenderCommand) {
|
||||||
c.renderer.setCameraPosition(this.boundingBox.topLeft);
|
const canvasAspectRatio = c.renderer.canvasSize.x / c.renderer.canvasSize.y;
|
||||||
|
|
||||||
|
this.viewArea.size = vec2.fromValues(
|
||||||
|
Math.sqrt(this.inViewAreaSize * canvasAspectRatio),
|
||||||
|
Math.sqrt(this.inViewAreaSize / canvasAspectRatio)
|
||||||
|
);
|
||||||
|
|
||||||
|
c.renderer.setViewArea(this._viewArea);
|
||||||
c.renderer.setCursorPosition(this.cursorPosition);
|
c.renderer.setCursorPosition(this.cursorPosition);
|
||||||
this.boundingBox.size = c.renderer.setInViewArea(this.inViewArea);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private moveTo(c: MoveToCommand) {
|
private moveTo(c: MoveToCommand) {
|
||||||
this.boundingBox.topLeft = c.position;
|
this._viewArea.topLeft = vec2.fromValues(
|
||||||
|
c.position.x - this._viewArea.size.x / 2,
|
||||||
|
c.position.y + this._viewArea.size.y / 2
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private zoom(c: ZoomCommand) {
|
private zoom(c: ZoomCommand) {
|
||||||
this.inViewArea *= c.factor;
|
this.inViewAreaSize *= c.factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private setCursorPosition(c: CursorMoveCommand) {
|
private setCursorPosition(c: CursorMoveCommand) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2, vec3 } from 'gl-matrix';
|
||||||
import { KeyDownCommand } from '../../input/commands/key-down';
|
import { KeyDownCommand } from '../../input/commands/key-down';
|
||||||
import { KeyUpCommand } from '../../input/commands/key-up';
|
import { KeyUpCommand } from '../../input/commands/key-up';
|
||||||
import { SwipeCommand } from '../../input/commands/swipe';
|
import { SwipeCommand } from '../../input/commands/swipe';
|
||||||
|
|
@ -13,21 +13,25 @@ import { Blob } from '../../shapes/types/blob';
|
||||||
import { RenderCommand } from '../../drawing/commands/render';
|
import { RenderCommand } from '../../drawing/commands/render';
|
||||||
import { DrawableBlob } from '../../drawing/drawables/drawable-blob';
|
import { DrawableBlob } from '../../drawing/drawables/drawable-blob';
|
||||||
import { Lamp } from './lamp';
|
import { Lamp } from './lamp';
|
||||||
|
import { Game } from '../../game';
|
||||||
|
import { IGame } from '../../i-game';
|
||||||
|
|
||||||
export class Character extends GameObject {
|
export class Character extends GameObject {
|
||||||
private keysDown: Set<string> = new Set();
|
private keysDown: Set<string> = new Set();
|
||||||
|
private light = new Lamp(
|
||||||
|
vec2.create(),
|
||||||
|
40,
|
||||||
|
vec3.fromValues(0.67, 0.0, 0.33),
|
||||||
|
2
|
||||||
|
);
|
||||||
|
|
||||||
private shape: DrawableBlob;
|
private shape = new DrawableBlob(vec2.create());
|
||||||
private static speed = 1.5;
|
private static speed = 1.5;
|
||||||
|
|
||||||
constructor(
|
constructor(private game: IGame) {
|
||||||
private physics: Physics,
|
|
||||||
private camera: Camera,
|
|
||||||
private light: Lamp
|
|
||||||
) {
|
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.shape = new DrawableBlob(vec2.create());
|
game.addObject(this.light);
|
||||||
|
|
||||||
this.addCommandExecutor(StepCommand, this.stepHandler.bind(this));
|
this.addCommandExecutor(StepCommand, this.stepHandler.bind(this));
|
||||||
this.addCommandExecutor(RenderCommand, this.draw.bind(this));
|
this.addCommandExecutor(RenderCommand, this.draw.bind(this));
|
||||||
|
|
@ -38,13 +42,18 @@ export class Character extends GameObject {
|
||||||
this.addCommandExecutor(KeyUpCommand, (c) => this.keysDown.delete(c.key));
|
this.addCommandExecutor(KeyUpCommand, (c) => this.keysDown.delete(c.key));
|
||||||
this.addCommandExecutor(SwipeCommand, (c) => {
|
this.addCommandExecutor(SwipeCommand, (c) => {
|
||||||
this.tryMoving(
|
this.tryMoving(
|
||||||
vec2.multiply(vec2.create(), c.delta, this.camera.viewAreaSize)
|
vec2.multiply(vec2.create(), c.delta, this.game.viewArea.size)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get position(): vec2 {
|
||||||
|
return this.shape.center;
|
||||||
|
}
|
||||||
|
|
||||||
private draw(c: RenderCommand) {
|
private draw(c: RenderCommand) {
|
||||||
c.renderer.drawShape(this.shape);
|
c.renderer.drawShape(this.shape);
|
||||||
|
this.light.sendCommand(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
private tryMoving(delta: vec2, isFirstIteration = true) {
|
private tryMoving(delta: vec2, isFirstIteration = true) {
|
||||||
|
|
@ -87,6 +96,9 @@ export class Character extends GameObject {
|
||||||
)
|
)
|
||||||
.sort((e) => Math.abs(e.distance));
|
.sort((e) => Math.abs(e.distance));
|
||||||
|
|
||||||
|
if (intersecting.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const normal = intersecting[0].shape.normal(this.shape.center);
|
const normal = intersecting[0].shape.normal(this.shape.center);
|
||||||
|
|
||||||
const maxDistance = intersecting.reduce((p, c) =>
|
const maxDistance = intersecting.reduce((p, c) =>
|
||||||
|
|
@ -106,7 +118,7 @@ export class Character extends GameObject {
|
||||||
private getNearShapesTo(
|
private getNearShapesTo(
|
||||||
shape: Blob
|
shape: Blob
|
||||||
): Array<{ shape: IShape; distance: number }> {
|
): Array<{ shape: IShape; distance: number }> {
|
||||||
return this.physics
|
return this.game
|
||||||
.findIntersecting(shape.boundingBox)
|
.findIntersecting(shape.boundingBox)
|
||||||
.filter((b) => b.shape)
|
.filter((b) => b.shape)
|
||||||
.map((b) => ({
|
.map((b) => ({
|
||||||
|
|
@ -118,7 +130,6 @@ export class Character extends GameObject {
|
||||||
|
|
||||||
private setPosition(value: vec2) {
|
private setPosition(value: vec2) {
|
||||||
this.shape.position = value;
|
this.shape.position = value;
|
||||||
this.camera.sendCommand(new MoveToCommand(value));
|
|
||||||
vec2.add(value, value, vec2.fromValues(80, 0));
|
vec2.add(value, value, vec2.fromValues(80, 0));
|
||||||
this.light.sendCommand(new MoveToCommand(value));
|
this.light.sendCommand(new MoveToCommand(value));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ export class Lamp extends GameObject {
|
||||||
constructor(center: vec2, radius: number, color: vec3, lightness: number) {
|
constructor(center: vec2, radius: number, color: vec3, lightness: number) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.light = new CircleLight(this, center, radius, color, lightness);
|
this.light = new CircleLight(center, radius, color, lightness);
|
||||||
|
|
||||||
this.addCommandExecutor(RenderCommand, this.draw.bind(this));
|
this.addCommandExecutor(RenderCommand, this.draw.bind(this));
|
||||||
this.addCommandExecutor(MoveToCommand, this.moveTo.bind(this));
|
this.addCommandExecutor(MoveToCommand, this.moveTo.bind(this));
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ export class Tunnel extends GameObject {
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.shape = new DrawableTunnel(from, to, fromRadius, toRadius);
|
this.shape = new DrawableTunnel(from, to, fromRadius, toRadius, this);
|
||||||
physics.addStaticBoundingBox(this.shape.boundingBox);
|
physics.addStaticBoundingBox(this.shape.boundingBox);
|
||||||
this.addCommandExecutor(RenderCommand, this.draw.bind(this));
|
this.addCommandExecutor(RenderCommand, this.draw.bind(this));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
import { vec2, vec3 } from 'gl-matrix';
|
|
||||||
import { Objects } from '../objects';
|
|
||||||
import { Camera } from '../types/camera';
|
|
||||||
import { Character } from '../types/character';
|
|
||||||
import { Lamp } from '../types/lamp';
|
|
||||||
import { Physics } from '../../physics/physics';
|
|
||||||
import { GameObject } from '../game-object';
|
|
||||||
|
|
||||||
export const createCharacter = (
|
|
||||||
objects: Objects,
|
|
||||||
physics: Physics
|
|
||||||
): GameObject => {
|
|
||||||
const light = new Lamp(
|
|
||||||
vec2.create(),
|
|
||||||
40,
|
|
||||||
vec3.fromValues(0.67, 0.0, 0.33),
|
|
||||||
2
|
|
||||||
);
|
|
||||||
|
|
||||||
const camera = new Camera();
|
|
||||||
const character = new Character(physics, camera, light);
|
|
||||||
objects.addObject(light);
|
|
||||||
objects.addObject(camera);
|
|
||||||
objects.addObject(character);
|
|
||||||
|
|
||||||
return character;
|
|
||||||
};
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
import { BoundingBox } from './bounding-box';
|
import { BoundingBox } from './bounding-box';
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2 } from 'gl-matrix';
|
||||||
|
import { GameObject } from '../objects/game-object';
|
||||||
|
|
||||||
export interface IShape {
|
export interface IShape {
|
||||||
readonly isInverted: boolean;
|
readonly isInverted: boolean;
|
||||||
readonly boundingBox: BoundingBox;
|
readonly boundingBox: BoundingBox;
|
||||||
|
|
||||||
|
readonly gameObject?: GameObject;
|
||||||
|
|
||||||
distance(target: vec2): number;
|
distance(target: vec2): number;
|
||||||
normal(from: vec2): vec2;
|
normal(from: vec2): vec2;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { IShape } from '../i-shape';
|
||||||
import { BoundingBox } from '../bounding-box';
|
import { BoundingBox } from '../bounding-box';
|
||||||
import { Circle } from './circle';
|
import { Circle } from './circle';
|
||||||
import { settings } from '../../drawing/settings';
|
import { settings } from '../../drawing/settings';
|
||||||
|
import { GameObject } from '../../objects/game-object';
|
||||||
|
|
||||||
export class Blob implements IShape {
|
export class Blob implements IShape {
|
||||||
private static readonly boundingCircleRadius = 19;
|
private static readonly boundingCircleRadius = 19;
|
||||||
|
|
@ -31,7 +32,10 @@ export class Blob implements IShape {
|
||||||
settings.shaderMacros.footRadius
|
settings.shaderMacros.footRadius
|
||||||
);
|
);
|
||||||
|
|
||||||
public constructor(center: vec2) {
|
public constructor(
|
||||||
|
center: vec2,
|
||||||
|
public readonly gameObject: GameObject = null
|
||||||
|
) {
|
||||||
this.position = center;
|
this.position = center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,6 +72,6 @@ export class Blob implements IShape {
|
||||||
}
|
}
|
||||||
|
|
||||||
public clone(): Blob {
|
public clone(): Blob {
|
||||||
return new Blob(this.boundingCircle.center);
|
return new Blob(this.boundingCircle.center, this.gameObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,16 @@
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2 } from 'gl-matrix';
|
||||||
import { IShape } from '../i-shape';
|
import { IShape } from '../i-shape';
|
||||||
import { BoundingBox } from '../bounding-box';
|
import { BoundingBox } from '../bounding-box';
|
||||||
|
import { GameObject } from '../../objects/game-object';
|
||||||
|
|
||||||
export class Circle implements IShape {
|
export class Circle implements IShape {
|
||||||
public readonly isInverted = false;
|
public readonly isInverted = false;
|
||||||
|
|
||||||
public constructor(public center = vec2.create(), public radius = 0) {}
|
public constructor(
|
||||||
|
public center = vec2.create(),
|
||||||
|
public radius = 0,
|
||||||
|
public readonly gameObject: GameObject = null
|
||||||
|
) {}
|
||||||
|
|
||||||
public distance(target: vec2): number {
|
public distance(target: vec2): number {
|
||||||
return vec2.distance(this.center, target) - this.radius;
|
return vec2.distance(this.center, target) - this.radius;
|
||||||
|
|
@ -36,6 +41,6 @@ export class Circle implements IShape {
|
||||||
}
|
}
|
||||||
|
|
||||||
public clone(): Circle {
|
public clone(): Circle {
|
||||||
return new Circle(vec2.clone(this.center), this.radius);
|
return new Circle(vec2.clone(this.center), this.radius, this.gameObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { clamp01 } from '../../helper/clamp';
|
||||||
import { mix } from '../../helper/mix';
|
import { mix } from '../../helper/mix';
|
||||||
import { IShape } from '../i-shape';
|
import { IShape } from '../i-shape';
|
||||||
import { rotate90Deg } from '../../helper/rotate-90-deg';
|
import { rotate90Deg } from '../../helper/rotate-90-deg';
|
||||||
|
import { GameObject } from '../../objects/game-object';
|
||||||
|
|
||||||
export class TunnelShape implements IShape {
|
export class TunnelShape implements IShape {
|
||||||
public readonly isInverted = true;
|
public readonly isInverted = true;
|
||||||
|
|
@ -14,7 +15,8 @@ export class TunnelShape implements IShape {
|
||||||
public readonly from: vec2,
|
public readonly from: vec2,
|
||||||
public readonly to: vec2,
|
public readonly to: vec2,
|
||||||
public readonly fromRadius: number,
|
public readonly fromRadius: number,
|
||||||
public readonly toRadius: number
|
public readonly toRadius: number,
|
||||||
|
public readonly gameObject: GameObject = null
|
||||||
) {
|
) {
|
||||||
this.toFromDelta = vec2.subtract(vec2.create(), to, from);
|
this.toFromDelta = vec2.subtract(vec2.create(), to, from);
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +108,8 @@ export class TunnelShape implements IShape {
|
||||||
vec2.clone(this.from),
|
vec2.clone(this.from),
|
||||||
vec2.clone(this.to),
|
vec2.clone(this.to),
|
||||||
this.fromRadius,
|
this.fromRadius,
|
||||||
this.toRadius
|
this.toRadius,
|
||||||
|
this.gameObject
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue