wtf
This commit is contained in:
parent
1f18f3d16f
commit
aa97ec8837
11 changed files with 1822 additions and 138 deletions
|
@ -3,9 +3,12 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Hello wasm-pack!</title>
|
<title>Hello wasm-pack!</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="static/res/style.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<canvas id="c" width=1700 height=900></canvas>
|
<div id="loader" class="loading">
|
||||||
|
<canvas id="c" width=1700 height=900></canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
<noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
|
<noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
|
||||||
<script src="./bootstrap.js"></script>
|
<script src="./bootstrap.js"></script>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Game } from "planetwars";
|
import { Game } from "planetwars";
|
||||||
import { Shader } from "./webgl/shader"
|
import { Shader } from "./webgl/shader"
|
||||||
|
|
||||||
import { main } from './index.ts'
|
import { set_instance } from './index.ts'
|
||||||
|
|
||||||
const URL = window.location.origin+window.location.pathname;
|
const URL = window.location.origin+window.location.pathname;
|
||||||
const LOCATION = URL.substring(0, URL.lastIndexOf("/") + 1);
|
const LOCATION = URL.substring(0, URL.lastIndexOf("/") + 1);
|
||||||
|
@ -11,5 +11,5 @@ const game_location = LOCATION + "static/game.json";
|
||||||
fetch(game_location)
|
fetch(game_location)
|
||||||
.then((r) => r.text())
|
.then((r) => r.text())
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
main(Game.new(response));
|
set_instance(Game.new(response));
|
||||||
}).catch(console.error);
|
}).catch(console.error);
|
||||||
|
|
|
@ -1,15 +1,122 @@
|
||||||
import { Game } from "planetwars";
|
import { Game } from "planetwars";
|
||||||
import { memory } from "planetwars/plantwars_bg";
|
import { memory } from "planetwars/plantwars_bg";
|
||||||
|
import { Resizer, resizeCanvasToDisplaySize, FPSCounter } from "./webgl/util";
|
||||||
|
import { Shader, Uniform4f, Uniform2fv, Uniform3fv, Uniform1i, Uniform1f, Uniform2f, ShaderFactory } from './webgl/shader';
|
||||||
|
import { Renderer } from "./webgl/renderer";
|
||||||
|
import { VertexBuffer, IndexBuffer } from "./webgl/buffer";
|
||||||
|
import { VertexBufferLayout, VertexArray } from "./webgl/vertexBufferLayout";
|
||||||
|
import { callbackify } from "util";
|
||||||
|
|
||||||
|
const COUNTER = new FPSCounter();
|
||||||
|
const LOADER = document.getElementById("loader");
|
||||||
|
|
||||||
|
function set_loading(loading: boolean) {
|
||||||
|
if (loading) {
|
||||||
|
if (!LOADER.classList.contains("loading")) {
|
||||||
|
LOADER.classList.add("loading");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOADER.classList.remove("loading");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const URL = window.location.origin+window.location.pathname;
|
||||||
|
const LOCATION = URL.substring(0, URL.lastIndexOf("/") + 1);
|
||||||
const CANVAS = <HTMLCanvasElement>document.getElementById("c");
|
const CANVAS = <HTMLCanvasElement>document.getElementById("c");
|
||||||
|
const RESOLUTION = [CANVAS.width, CANVAS.height];
|
||||||
|
|
||||||
|
const GL = CANVAS.getContext("webgl");
|
||||||
|
resizeCanvasToDisplaySize(<HTMLCanvasElement>GL.canvas);
|
||||||
|
GL.viewport(0, 0, GL.canvas.width, GL.canvas.height);
|
||||||
|
|
||||||
|
GL.clearColor(0, 0, 0, 0);
|
||||||
|
GL.clear(GL.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
GL.enable(GL.BLEND);
|
||||||
|
GL.blendFunc(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
const positionBuffer = new VertexBuffer(GL, [
|
||||||
|
-1, -1,
|
||||||
|
-1, 1,
|
||||||
|
1, -1,
|
||||||
|
1, 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const layout = new VertexBufferLayout();
|
||||||
|
layout.push(GL.FLOAT, 2, 4, "a_position");
|
||||||
|
const vao = new VertexArray();
|
||||||
|
vao.addBuffer(positionBuffer, layout);
|
||||||
|
|
||||||
|
const indexBuffer = new IndexBuffer(GL, [
|
||||||
|
0, 1, 2,
|
||||||
|
1, 2, 3,
|
||||||
|
]);
|
||||||
|
|
||||||
|
var SHADERFACOTRY: ShaderFactory;
|
||||||
|
ShaderFactory.create_factory(
|
||||||
|
LOCATION + "static/shaders/frag/simple.glsl", LOCATION + "static/shaders/vert/simple.glsl"
|
||||||
|
).then((e) => SHADERFACOTRY = e);
|
||||||
|
|
||||||
|
|
||||||
function create_array(ptr: number, size: number): Float64Array {
|
function create_array(ptr: number, size: number): Float64Array {
|
||||||
return new Float64Array(memory.buffer, ptr, size);
|
return new Float64Array(memory.buffer, ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main(game: Game) {
|
class GameInstance {
|
||||||
|
resizer: Resizer;
|
||||||
|
game: Game;
|
||||||
|
shader: Shader;
|
||||||
|
renderer: Renderer;
|
||||||
|
|
||||||
|
constructor(game: Game) {
|
||||||
|
this.game = game;
|
||||||
|
this.shader = SHADERFACOTRY.create_shader(GL, {"MAX_CIRCLES": "50"});
|
||||||
|
this.resizer = new Resizer(CANVAS, [...create_array(game.get_viewbox(), 4)], true);
|
||||||
|
this.renderer = new Renderer();
|
||||||
|
this.renderer.addToDraw(indexBuffer, vao, this.shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
render(time: number) {
|
||||||
|
this.shader.uniform(GL, "u_circle_count", new Uniform1i(3));
|
||||||
|
|
||||||
|
this.shader.uniform(GL, "u_time", new Uniform1f(time * 0.001));
|
||||||
|
this.shader.uniform(GL, "u_mouse", new Uniform2f(this.resizer.get_mouse_pos()));
|
||||||
|
this.shader.uniform(GL, "u_viewbox", new Uniform4f(this.resizer.get_viewbox()));
|
||||||
|
this.shader.uniform(GL, "u_resolution", new Uniform2f(RESOLUTION));
|
||||||
|
|
||||||
|
this.shader.uniform(GL, "u_circles", new Uniform3fv([
|
||||||
|
0, 0, 3.5,
|
||||||
|
-2, -2, 2,
|
||||||
|
5, 2, 4,
|
||||||
|
]));
|
||||||
|
this.shader.uniform(GL, "u_color", new Uniform4f([1, 1, 0, 1]));
|
||||||
|
|
||||||
|
this.renderer.render(GL);
|
||||||
|
COUNTER.frame(time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var game_instance: GameInstance;
|
||||||
|
|
||||||
|
export function set_instance(game: Game) {
|
||||||
|
game_instance = new GameInstance(game);
|
||||||
|
|
||||||
console.log(game.turn_count());
|
console.log(game.turn_count());
|
||||||
|
|
||||||
console.log(create_array(game.get_viewbox(), 4));
|
console.log(create_array(game.get_viewbox(), 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function step(time: number) {
|
||||||
|
if (game_instance) {
|
||||||
|
game_instance.render(time);
|
||||||
|
set_loading(false);
|
||||||
|
} else {
|
||||||
|
set_loading(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(step);
|
||||||
|
}
|
||||||
|
set_loading(true);
|
||||||
|
|
||||||
|
requestAnimationFrame(step);
|
||||||
|
|
57
frontend/www/static/res/style.css
Normal file
57
frontend/www/static/res/style.css
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading::before{
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
background-color: #1c5ba2;
|
||||||
|
border-radius: 100%;
|
||||||
|
z-index: 5;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
-webkit-animation: slide-top 0.5s ease-out infinite alternate ;
|
||||||
|
animation: slide-top 0.5s ease-out infinite alternate ;
|
||||||
|
}
|
||||||
|
|
||||||
|
#c {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------
|
||||||
|
* Generated by Animista on 2019-9-17 14:35:13
|
||||||
|
* Licensed under FreeBSD License.
|
||||||
|
* See http://animista.net/license for more info.
|
||||||
|
* w: http://animista.net, t: @cssanimista
|
||||||
|
* ---------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ----------------------------------------
|
||||||
|
* animation slide-top
|
||||||
|
* ----------------------------------------
|
||||||
|
*/
|
||||||
|
@-webkit-keyframes slide-top {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(-50%, 50%);
|
||||||
|
transform: translate(-50%, 50%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(-50%, -150%);
|
||||||
|
transform: translate(-50%, -150%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes slide-top {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(-50%, 50%);
|
||||||
|
transform: translate(-50%, 50%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(-50%, -150%);
|
||||||
|
transform: translate(-50%, -150%);
|
||||||
|
}
|
||||||
|
}
|
27
frontend/www/static/shaders/frag/simple.glsl
Normal file
27
frontend/www/static/shaders/frag/simple.glsl
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uniform int u_circle_count;
|
||||||
|
uniform float u_time;
|
||||||
|
uniform vec2 u_mouse;
|
||||||
|
uniform vec4 u_viewbox; // [x, y, width, height]
|
||||||
|
uniform vec2 u_resolution;
|
||||||
|
uniform vec3 u_circles[$MAX_CIRCLES];
|
||||||
|
uniform vec4 u_color;
|
||||||
|
|
||||||
|
varying vec2 v_pos;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 uv = v_pos;
|
||||||
|
|
||||||
|
float alpha = 0.0;
|
||||||
|
for (int i = 0; i < $MAX_CIRCLES; i++ ){
|
||||||
|
if (i >= u_circle_count) { break; }
|
||||||
|
float d = distance(uv.xy, u_circles[i].xy);
|
||||||
|
alpha = max(1.0 - d/u_circles[i].z, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_FragColor = u_color;
|
||||||
|
gl_FragColor.w *= alpha;
|
||||||
|
}
|
22
frontend/www/static/shaders/vert/simple.glsl
Normal file
22
frontend/www/static/shaders/vert/simple.glsl
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
attribute vec2 a_position;
|
||||||
|
|
||||||
|
uniform vec4 u_viewbox; // [x, y, width, height]
|
||||||
|
uniform vec2 u_resolution;
|
||||||
|
|
||||||
|
varying vec2 v_pos;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
vec2 uv = ( a_position.xy + 1.0 ) * 0.5;
|
||||||
|
|
||||||
|
uv *= u_viewbox.zw;
|
||||||
|
uv += u_viewbox.xy;
|
||||||
|
|
||||||
|
v_pos = uv.xy;
|
||||||
|
|
||||||
|
gl_Position = vec4(a_position.xy, 0.0, 1.0);
|
||||||
|
}
|
115
frontend/www/webgl/index.ts
Normal file
115
frontend/www/webgl/index.ts
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
|
||||||
|
import { Shader, Uniform4f, Uniform2fv, Uniform3fv, Uniform1i, Uniform1f, Uniform2f, ShaderFactory } from './shader';
|
||||||
|
import { resizeCanvasToDisplaySize, FPSCounter, onload2promise, Resizer } from "./util";
|
||||||
|
import { VertexBuffer, IndexBuffer } from './buffer';
|
||||||
|
import { VertexArray, VertexBufferLayout } from './vertexBufferLayout';
|
||||||
|
import { Renderer } from './renderer';
|
||||||
|
import { Texture } from './texture';
|
||||||
|
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
|
||||||
|
const URL = window.location.origin+window.location.pathname;
|
||||||
|
const LOCATION = URL.substring(0, URL.lastIndexOf("/") + 1);
|
||||||
|
|
||||||
|
|
||||||
|
// Get A WebGL context
|
||||||
|
var canvas = <HTMLCanvasElement>document.getElementById("c");
|
||||||
|
const resolution = [canvas.width, canvas.height];
|
||||||
|
|
||||||
|
const resizer = new Resizer(canvas, [0, 0, 900, 900], true);
|
||||||
|
|
||||||
|
var gl = canvas.getContext("webgl");
|
||||||
|
if (!gl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderer = new Renderer();
|
||||||
|
|
||||||
|
const factory = await ShaderFactory.create_factory(LOCATION + "static/shaders/frag/simple.glsl", LOCATION + "static/shaders/vert/simple.glsl");
|
||||||
|
const program = factory.create_shader(gl, {"MAX_CIRCLES": "50"});
|
||||||
|
|
||||||
|
var positions = [
|
||||||
|
-1, -1, 0, 1,
|
||||||
|
-1, 1, 0, 0,
|
||||||
|
1, -1, 1, 1,
|
||||||
|
1, 1, 1, 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
var positionBuffer = new VertexBuffer(gl, positions);
|
||||||
|
var layout = new VertexBufferLayout();
|
||||||
|
layout.push(gl.FLOAT, 2, 4, "a_position");
|
||||||
|
layout.push(gl.FLOAT, 2, 4, "a_tex");
|
||||||
|
|
||||||
|
const vao = new VertexArray();
|
||||||
|
vao.addBuffer(positionBuffer, layout);
|
||||||
|
|
||||||
|
resizeCanvasToDisplaySize(<HTMLCanvasElement>gl.canvas);
|
||||||
|
|
||||||
|
// Tell WebGL how to convert from clip space to pixels
|
||||||
|
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
|
||||||
|
|
||||||
|
// Clear the canvas
|
||||||
|
gl.clearColor(0, 0, 0, 0);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
gl.enable(gl.BLEND);
|
||||||
|
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
program.bind(gl);
|
||||||
|
vao.bind(gl, program);
|
||||||
|
|
||||||
|
var indices = [
|
||||||
|
0, 1, 2,
|
||||||
|
1, 2, 3,
|
||||||
|
];
|
||||||
|
|
||||||
|
var indexBuffer = new IndexBuffer(gl, indices);
|
||||||
|
indexBuffer.bind(gl);
|
||||||
|
|
||||||
|
renderer.addToDraw(indexBuffer, vao, program);
|
||||||
|
|
||||||
|
var blue = 1.0;
|
||||||
|
var inc = 0.05;
|
||||||
|
|
||||||
|
const counter = new FPSCounter();
|
||||||
|
|
||||||
|
const step = function (time: number) {
|
||||||
|
blue += inc;
|
||||||
|
// if (blue > 1.0 || blue < 0.0) {
|
||||||
|
// inc = -1 * inc;
|
||||||
|
// blue += inc;
|
||||||
|
// }
|
||||||
|
|
||||||
|
program.uniform(gl, "u_circle_count", new Uniform1i(3));
|
||||||
|
|
||||||
|
program.uniform(gl, "u_time", new Uniform1f(time * 0.001));
|
||||||
|
program.uniform(gl, "u_mouse", new Uniform2f(resizer.get_mouse_pos()));
|
||||||
|
program.uniform(gl, "u_viewbox", new Uniform4f(resizer.get_viewbox()));
|
||||||
|
program.uniform(gl, "u_resolution", new Uniform2f(resolution));
|
||||||
|
program.uniform(gl, "u_circles", new Uniform3fv([
|
||||||
|
450, 450, 100,
|
||||||
|
200, 200, 200,
|
||||||
|
900, 0, 300,
|
||||||
|
]));
|
||||||
|
program.uniform(gl, "u_color", new Uniform4f([1, blue, 0, 1]));
|
||||||
|
|
||||||
|
renderer.render(gl);
|
||||||
|
|
||||||
|
counter.frame(time);
|
||||||
|
requestAnimationFrame(step);
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(step);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
|
||||||
|
const loader = document.getElementById("loader");
|
||||||
|
setInterval(() => {
|
||||||
|
if (loader.classList.contains("loading")) {
|
||||||
|
loader.classList.remove("loading")
|
||||||
|
} else {
|
||||||
|
loader.classList.add("loading");
|
||||||
|
}
|
||||||
|
}, 2000);
|
|
@ -1,7 +1,7 @@
|
||||||
import { Dictionary } from './util';
|
import { Dictionary } from './util';
|
||||||
|
|
||||||
function error(msg: string) {
|
function error(msg: string) {
|
||||||
console.log(msg);
|
console.error(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultShaderType = [
|
const defaultShaderType = [
|
||||||
|
@ -9,6 +9,7 @@ const defaultShaderType = [
|
||||||
"FRAGMENT_SHADER"
|
"FRAGMENT_SHADER"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// Create Shader from Source string
|
||||||
function loadShader(
|
function loadShader(
|
||||||
gl: WebGLRenderingContext,
|
gl: WebGLRenderingContext,
|
||||||
shaderSource: string,
|
shaderSource: string,
|
||||||
|
@ -41,6 +42,7 @@ function loadShader(
|
||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Actually Create Program with Shader's
|
||||||
function createProgram(
|
function createProgram(
|
||||||
gl: WebGLRenderingContext,
|
gl: WebGLRenderingContext,
|
||||||
shaders: WebGLShader[],
|
shaders: WebGLShader[],
|
||||||
|
@ -76,39 +78,45 @@ function createProgram(
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createShaderFromScript(
|
export class ShaderFactory {
|
||||||
gl: WebGLRenderingContext,
|
frag_source: string;
|
||||||
scriptId: string,
|
vert_source: string;
|
||||||
context: Dictionary<any>,
|
|
||||||
opt_shaderType: number,
|
|
||||||
opt_errorCallback: any,
|
|
||||||
): WebGLShader {
|
|
||||||
var shaderSource = "";
|
|
||||||
var shaderType;
|
|
||||||
var shaderScript = document.getElementById(scriptId) as HTMLScriptElement;
|
|
||||||
if (!shaderScript) {
|
|
||||||
console.log("*** Error: unknown script element" + scriptId);
|
|
||||||
}
|
|
||||||
shaderSource = shaderScript.text;
|
|
||||||
|
|
||||||
for (let key in context) {
|
static async create_factory(frag_url: string, vert_url: string): Promise<ShaderFactory> {
|
||||||
console.log("substitute " + key);
|
const sources = await Promise.all([
|
||||||
shaderSource = shaderSource.replace(new RegExp("\\$" + key, 'g'), context[key]);
|
fetch(frag_url).then((r) => r.text()),
|
||||||
|
fetch(vert_url).then((r) => r.text()),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return new ShaderFactory(sources[0], sources[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opt_shaderType) {
|
constructor(frag_source: string, vert_source: string ) {
|
||||||
if (shaderScript.type === "x-shader/x-vertex") {
|
this.frag_source = frag_source;
|
||||||
shaderType = 35633;
|
this.vert_source = vert_source;
|
||||||
} else if (shaderScript.type === "x-shader/x-fragment") {
|
}
|
||||||
shaderType = 35632;
|
|
||||||
} else if (shaderType !== gl.VERTEX_SHADER && shaderType !== gl.FRAGMENT_SHADER) {
|
create_shader(
|
||||||
console.log("*** Error: unknown shader type");
|
gl: WebGLRenderingContext,
|
||||||
|
context?: Dictionary<string>,
|
||||||
|
opt_attribs?: string[],
|
||||||
|
opt_locations?: number[],
|
||||||
|
opt_errorCallback?: any,
|
||||||
|
): Shader {
|
||||||
|
let vert = this.vert_source.slice();
|
||||||
|
let frag = this.frag_source.slice();
|
||||||
|
for (let key in context) {
|
||||||
|
vert = vert.replace(new RegExp("\\$" + key, 'g'), context[key]);
|
||||||
|
frag = frag.replace(new RegExp("\\$" + key, 'g'), context[key]);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return loadShader(
|
const shaders = [
|
||||||
gl, shaderSource, opt_shaderType ? opt_shaderType : shaderType,
|
loadShader(gl, vert, gl.VERTEX_SHADER, opt_errorCallback),
|
||||||
opt_errorCallback);
|
loadShader(gl, frag, gl.FRAGMENT_SHADER, opt_errorCallback),
|
||||||
|
];
|
||||||
|
|
||||||
|
return new Shader(createProgram(gl, shaders, opt_attribs, opt_locations, opt_errorCallback));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Shader {
|
export class Shader {
|
||||||
|
@ -116,22 +124,6 @@ export class Shader {
|
||||||
uniformCache: Dictionary<WebGLUniformLocation>;
|
uniformCache: Dictionary<WebGLUniformLocation>;
|
||||||
attribCache: Dictionary<number>;
|
attribCache: Dictionary<number>;
|
||||||
|
|
||||||
static createProgramFromScripts(
|
|
||||||
gl: WebGLRenderingContext,
|
|
||||||
shaderScriptIds: string[],
|
|
||||||
context = {},
|
|
||||||
opt_attribs?: string[],
|
|
||||||
opt_locations?: number[],
|
|
||||||
opt_errorCallback?: any,
|
|
||||||
): Shader {
|
|
||||||
var shaders = [];
|
|
||||||
for (var ii = 0; ii < shaderScriptIds.length; ++ii) {
|
|
||||||
shaders.push(createShaderFromScript(
|
|
||||||
gl, shaderScriptIds[ii], context, (gl as any)[defaultShaderType[ii % 2]] as number, opt_errorCallback));
|
|
||||||
}
|
|
||||||
return new Shader(createProgram(gl, shaders, opt_attribs, opt_locations, opt_errorCallback));
|
|
||||||
}
|
|
||||||
|
|
||||||
static async createProgramFromUrls(
|
static async createProgramFromUrls(
|
||||||
gl: WebGLRenderingContext,
|
gl: WebGLRenderingContext,
|
||||||
vert_url: string,
|
vert_url: string,
|
||||||
|
@ -198,6 +190,10 @@ export class Shader {
|
||||||
|
|
||||||
uniform.setUniform(gl, location);
|
uniform.setUniform(gl, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear(gl: WebGLRenderingContext) {
|
||||||
|
gl.deleteProgram(this.shader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Uniform {
|
export interface Uniform {
|
||||||
|
@ -226,6 +222,22 @@ export class Uniform3fv implements Uniform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class Uniform3f implements Uniform {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
z: number;
|
||||||
|
|
||||||
|
constructor(x: number, y: number, z: number) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) {
|
||||||
|
gl.uniform3f(location, this.x ,this.y, this.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Uniform1iv implements Uniform {
|
export class Uniform1iv implements Uniform {
|
||||||
data: number[];
|
data: number[];
|
||||||
constructor(data: number[]) {
|
constructor(data: number[]) {
|
||||||
|
@ -265,9 +277,9 @@ export class Uniform2f implements Uniform {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
|
||||||
constructor(x: number, y: number) {
|
constructor(xy: number[]) {
|
||||||
this.x = x;
|
this.x = xy[0];
|
||||||
this.y = y;
|
this.y = xy[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) {
|
setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) {
|
||||||
|
@ -281,25 +293,14 @@ export class Uniform4f implements Uniform {
|
||||||
v2: number;
|
v2: number;
|
||||||
v3: number;
|
v3: number;
|
||||||
|
|
||||||
constructor(vec: number[]) {
|
constructor(xyzw: number[]) {
|
||||||
this.v0 = vec[0];
|
this.v0 = xyzw[0];
|
||||||
this.v1 = vec[1];
|
this.v1 = xyzw[1];
|
||||||
this.v2 = vec[2];
|
this.v2 = xyzw[2];
|
||||||
this.v3 = vec[3];
|
this.v3 = xyzw[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) {
|
setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) {
|
||||||
gl.uniform4f(location, this.v0, this.v1, this.v2, this.v3);
|
gl.uniform4f(location, this.v0, this.v1, this.v2, this.v3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UniformMatrix3fv implements Uniform {
|
|
||||||
data: number[];
|
|
||||||
constructor(data: number[]) {
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
setUniform(gl: WebGLRenderingContext, location: WebGLUniformLocation) {
|
|
||||||
gl.uniformMatrix3fv(location, false, this.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ export class FPSCounter {
|
||||||
|
|
||||||
frame(now: number) {
|
frame(now: number) {
|
||||||
this.count += 1;
|
this.count += 1;
|
||||||
if (now - this.last > 1) {
|
if (now - this.last > 1000) {
|
||||||
this.last = now;
|
this.last = now;
|
||||||
console.log(this.count + " fps");
|
console.log(this.count + " fps");
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
|
@ -47,83 +47,122 @@ export class FPSCounter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class M3 {
|
export class Resizer {
|
||||||
_data: any;
|
hoovering: boolean;
|
||||||
|
dragging: boolean;
|
||||||
|
|
||||||
constructor(data: any) {
|
mouse_pos: number[];
|
||||||
this._data = data;
|
last_drag: number[];
|
||||||
}
|
|
||||||
|
|
||||||
static ident(): M3 {
|
viewbox: number[];
|
||||||
return new M3([
|
orig_viewbox: number[];
|
||||||
1, 0, 0,
|
|
||||||
0, 1, 0,
|
|
||||||
0, 0, 1
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
multiply(other: M3): M3 {
|
el_width: number;
|
||||||
const a = this._data;
|
|
||||||
const b = other._data;
|
|
||||||
|
|
||||||
var a00 = a[0 * 3 + 0];
|
scaleX = 1;
|
||||||
var a01 = a[0 * 3 + 1];
|
scaleY = 1;
|
||||||
var a02 = a[0 * 3 + 2];
|
|
||||||
var a10 = a[1 * 3 + 0];
|
|
||||||
var a11 = a[1 * 3 + 1];
|
|
||||||
var a12 = a[1 * 3 + 2];
|
|
||||||
var a20 = a[2 * 3 + 0];
|
|
||||||
var a21 = a[2 * 3 + 1];
|
|
||||||
var a22 = a[2 * 3 + 2];
|
|
||||||
var b00 = b[0 * 3 + 0];
|
|
||||||
var b01 = b[0 * 3 + 1];
|
|
||||||
var b02 = b[0 * 3 + 2];
|
|
||||||
var b10 = b[1 * 3 + 0];
|
|
||||||
var b11 = b[1 * 3 + 1];
|
|
||||||
var b12 = b[1 * 3 + 2];
|
|
||||||
var b20 = b[2 * 3 + 0];
|
|
||||||
var b21 = b[2 * 3 + 1];
|
|
||||||
var b22 = b[2 * 3 + 2];
|
|
||||||
|
|
||||||
return new M3([
|
constructor(el: HTMLCanvasElement, viewbox: number[], keep_aspect_ratio=false) {
|
||||||
b00 * a00 + b01 * a10 + b02 * a20,
|
console.log("viewbox:" + viewbox);
|
||||||
b00 * a01 + b01 * a11 + b02 * a21,
|
this.hoovering = false;
|
||||||
b00 * a02 + b01 * a12 + b02 * a22,
|
this.dragging = false;
|
||||||
b10 * a00 + b11 * a10 + b12 * a20,
|
|
||||||
b10 * a01 + b11 * a11 + b12 * a21,
|
|
||||||
b10 * a02 + b11 * a12 + b12 * a22,
|
|
||||||
b20 * a00 + b21 * a10 + b22 * a20,
|
|
||||||
b20 * a01 + b21 * a11 + b22 * a21,
|
|
||||||
b20 * a02 + b21 * a12 + b22 * a22,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
translation(x: number, y: number): M3 {
|
this.mouse_pos = [0, 0];
|
||||||
const out = [...this._data];
|
this.last_drag = [0, 0];
|
||||||
out[6] += x;
|
|
||||||
out[7] += y;
|
|
||||||
return new M3(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
rotate(rad: number): M3 {
|
this.viewbox = [...viewbox];
|
||||||
var c = Math.cos(rad);
|
|
||||||
var s = Math.sin(rad);
|
|
||||||
|
|
||||||
const out = new M3([...this._data]);
|
if (keep_aspect_ratio) {
|
||||||
|
const or_width = this.viewbox[2];
|
||||||
|
const or_height = this.viewbox[3];
|
||||||
|
const scaleX = el.height / el.width;
|
||||||
|
if (scaleX < 1) {
|
||||||
|
this.scaleX= 1 / scaleX;
|
||||||
|
|
||||||
return out.multiply(new M3([
|
this.viewbox[2] *= this.scaleX;
|
||||||
c, -s, 0,
|
} else {
|
||||||
s, c, 0,
|
this.scaleY = scaleX;
|
||||||
0, 0, 1
|
this.viewbox[3] *= scaleX;
|
||||||
]));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
scale(s_x: number, s_y = s_x, s_z = 1): M3 {
|
this.viewbox[0] -= (this.viewbox[2] - or_width) / 2;
|
||||||
const out = new M3([...this._data]);
|
this.viewbox[1] -= (this.viewbox[3] - or_height) / 2;
|
||||||
return out.multiply(new M3([
|
}
|
||||||
s_x, 0, 0,
|
|
||||||
0, s_y, 0,
|
this.orig_viewbox = [...this.viewbox];
|
||||||
0, 0, s_z,
|
|
||||||
]));
|
this.el_width = el.width;
|
||||||
}
|
|
||||||
|
el.addEventListener("mouseenter", this.mouseenter.bind(this), { capture: false, passive: true});
|
||||||
|
el.addEventListener("mouseleave", this.mouseleave.bind(this), { capture: false, passive: true});
|
||||||
|
el.addEventListener("mousemove", this.mousemove.bind(this), { capture: false, passive: true});
|
||||||
|
el.addEventListener("mousedown", this.mousedown.bind(this), { capture: false, passive: true});
|
||||||
|
el.addEventListener("mouseup", this.mouseup.bind(this), { capture: false, passive: true});
|
||||||
|
|
||||||
|
window.addEventListener('wheel', this.wheel.bind(this), { capture: false, passive: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
clip_viewbox() {
|
||||||
|
this.viewbox[0] = Math.max(this.viewbox[0], this.orig_viewbox[0]);
|
||||||
|
this.viewbox[1] = Math.max(this.viewbox[1], this.orig_viewbox[1]);
|
||||||
|
|
||||||
|
this.viewbox[0] = Math.min(this.viewbox[0] + this.viewbox[2], this.orig_viewbox[0] + this.orig_viewbox[2]) - this.viewbox[2];
|
||||||
|
this.viewbox[1] = Math.min(this.viewbox[1] + this.viewbox[3], this.orig_viewbox[1] + this.orig_viewbox[3]) - this.viewbox[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
mouseenter() {
|
||||||
|
this.hoovering = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mouseleave() {
|
||||||
|
this.hoovering = false;
|
||||||
|
this.dragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mousemove(e: MouseEvent) {
|
||||||
|
this.mouse_pos = [e.offsetX, this.el_width - e.offsetY];
|
||||||
|
|
||||||
|
if (this.dragging) {
|
||||||
|
const scale = this.viewbox[3] / this.orig_viewbox[3];
|
||||||
|
this.viewbox[0] += (this.last_drag[0] - this.mouse_pos[0]) * scale;
|
||||||
|
this.viewbox[1] += (this.last_drag[1] - this.mouse_pos[1]) * scale;
|
||||||
|
|
||||||
|
this.last_drag = [...this.mouse_pos];
|
||||||
|
|
||||||
|
this.clip_viewbox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mousedown() {
|
||||||
|
this.dragging = true;
|
||||||
|
this.last_drag = [...this.mouse_pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
mouseup() {
|
||||||
|
this.dragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wheel(e: WheelEvent) {
|
||||||
|
if (this.hoovering) {
|
||||||
|
const dx = e.deltaY * this.scaleX;
|
||||||
|
this.viewbox[2] += dx;
|
||||||
|
this.viewbox[0] -= dx / 2;
|
||||||
|
this.viewbox[2] = Math.min(this.viewbox[2], this.orig_viewbox[2]);
|
||||||
|
|
||||||
|
const dy = e.deltaY * this.scaleY;
|
||||||
|
this.viewbox[3] += dy;
|
||||||
|
this.viewbox[1] -= dy / 2;
|
||||||
|
this.viewbox[3] = Math.min(this.viewbox[3], this.orig_viewbox[3]);
|
||||||
|
|
||||||
|
this.clip_viewbox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get_viewbox(): number[] {
|
||||||
|
return this.viewbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_mouse_pos(): number[] {
|
||||||
|
return this.mouse_pos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
20
frontend/www/webgl/webgl-utils.d.ts
vendored
Normal file
20
frontend/www/webgl/webgl-utils.d.ts
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Type definitions for [~THE LIBRARY NAME~] [~OPTIONAL VERSION NUMBER~]
|
||||||
|
// Project: [~THE PROJECT NAME~]
|
||||||
|
// Definitions by: [~YOUR NAME~] <[~A URL FOR YOU~]>
|
||||||
|
|
||||||
|
/*~ This is the module template file. You should rename it to index.d.ts
|
||||||
|
*~ and place it in a folder with the same name as the module.
|
||||||
|
*~ For example, if you were writing a file for "super-greeter", this
|
||||||
|
*~ file should be 'super-greeter/index.d.ts'
|
||||||
|
*/
|
||||||
|
|
||||||
|
// /*~ If this module is a UMD module that exposes a global variable 'myLib' when
|
||||||
|
// *~ loaded outside a module loader environment, declare that global here.
|
||||||
|
// *~ Otherwise, delete this declaration.
|
||||||
|
// */
|
||||||
|
// export as namespace myLib;
|
||||||
|
|
||||||
|
/*~ If this module has methods, declare them as functions like so.
|
||||||
|
*/
|
||||||
|
export function createProgramFromScripts(gl: WebGLRenderingContext, shaderScriptIds: string[], opt_attribs?: string[], opt_locations?: number[], opt_errorCallback?: any): any;
|
||||||
|
export function resizeCanvasToDisplaySize(canvas: HTMLCanvasElement, multiplier?: number): boolean;
|
1293
frontend/www/webgl/webgl-utils.js
Normal file
1293
frontend/www/webgl/webgl-utils.js
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue