diff --git a/src/assets/shader.ts b/src/assets/shader.ts index 718d28bf..eb74b741 100644 --- a/src/assets/shader.ts +++ b/src/assets/shader.ts @@ -8,7 +8,7 @@ import { import { type GfxCtx } from "../gfx"; import { _k } from "../kaplay"; import { Color } from "../math/color"; -import { Mat4, Vec2 } from "../math/math"; +import { Mat23, Mat4, Vec2 } from "../math/math"; import type { RenderProps } from "../types"; import { arrayIsColor, @@ -30,6 +30,7 @@ export type UniformValue = | Vec2 | Color | Mat4 + | Mat23 | number[] | Vec2[] | Color[]; @@ -109,6 +110,15 @@ export class Shader { else if (val instanceof Mat4) { gl.uniformMatrix4fv(loc, false, new Float32Array(val.m)); } + else if (val instanceof Mat23) { + gl.uniformMatrix4fv(loc, false, new Float32Array([ + val.a, val.b, 0, 0, + val.c, val.d, 0, 0, + 0, 0, 1, 0, + val.e, val.f, 0, 1 + ])); + //console.log(val) + } else if (val instanceof Color) { gl.uniform3f(loc, val.r, val.g, val.b); } diff --git a/src/constants.ts b/src/constants.ts index 2924876e..4179ce17 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,6 +1,6 @@ // some default charsets for loading bitmap fonts export const ASCII_CHARS = - " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; + " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; export const DEF_ANCHOR = "topleft"; export const BG_GRID_SIZE = 64; export const DEF_FONT = "monospace"; @@ -19,9 +19,9 @@ export const DEF_FONT_FILTER = "linear"; export const LOG_MAX = 8; export const LOG_TIME = 4; export const VERTEX_FORMAT = [ - { name: "a_pos", size: 2 }, - { name: "a_uv", size: 2 }, - { name: "a_color", size: 4 }, + { name: "a_pos", size: 2 }, + { name: "a_uv", size: 2 }, + { name: "a_color", size: 4 }, ]; const STRIDE = VERTEX_FORMAT.reduce((sum, f) => sum + f.size, 0); const MAX_BATCHED_QUAD = 2048; @@ -39,9 +39,11 @@ varying vec4 v_color; uniform float width; uniform float height; +uniform mat4 camera; vec4 def_vert() { - return vec4(a_pos.x / width * 2.0 - 1.0, a_pos.y / -height * 2.0 + 1.0, 0.0, 1.0); + vec4 pos = camera * vec4(a_pos, 0.0, 1.0); + return vec4(pos.x / width * 2.0 - 1.0, pos.y / -height * 2.0 + 1.0, pos.z, pos.w); } {{user}} @@ -92,13 +94,13 @@ vec4 frag(vec2 pos, vec2 uv, vec4 color, sampler2D tex) { `; export const COMP_DESC = new Set(["id", "require"]); export const COMP_EVENTS = new Set([ - "add", - "fixedUpdate", - "update", - "draw", - "destroy", - "inspect", - "drawInspect", + "add", + "fixedUpdate", + "update", + "draw", + "destroy", + "inspect", + "drawInspect", ]); export const DEF_OFFSCREEN_DIS = 200; // maximum y velocity with body() diff --git a/src/gfx/draw/drawFrame.ts b/src/gfx/draw/drawFrame.ts index 0ad4890d..bcd70565 100644 --- a/src/gfx/draw/drawFrame.ts +++ b/src/gfx/draw/drawFrame.ts @@ -9,7 +9,7 @@ export function drawFrame() { const shake = Vec2.fromAngle(rand(0, 360)).scale(cam.shake); cam.shake = lerp(cam.shake, 0, 5 * dt()); - cam.transform = new Mat23() + cam.transform.setIdentity() .translateSelfV(center()) .scaleSelfV(cam.scale) .rotateSelf(cam.angle) diff --git a/src/gfx/draw/drawRaw.ts b/src/gfx/draw/drawRaw.ts index 91388132..1bc1d17e 100644 --- a/src/gfx/draw/drawRaw.ts +++ b/src/gfx/draw/drawRaw.ts @@ -25,9 +25,7 @@ export function drawRaw( return; } - const transform = (_k.gfx.fixed || fixed) - ? _k.gfx.transform - : _k.game.cam.transform.mul(_k.gfx.transform); + const transform = _k.gfx.transform; const vertLength = attributes.pos.length / 2; const vv: number[] = new Array(vertLength * 8); @@ -58,5 +56,6 @@ export function drawRaw( blend ?? BlendMode.Normal, width(), height(), + _k.gfx.fixed || fixed ); } diff --git a/src/gfx/gfx.ts b/src/gfx/gfx.ts index 49f0b9ac..9c251b41 100644 --- a/src/gfx/gfx.ts +++ b/src/gfx/gfx.ts @@ -1,4 +1,6 @@ import type { Shader, Uniform } from "../assets"; +import { getCamTransform } from "../game"; +import { Mat23, Mat4 } from "../math"; import { BlendMode, type ImageSource, @@ -111,6 +113,8 @@ export type VertexFormat = { size: number; }[]; +const fixedCameraMatrix = new Mat4(); + export class BatchRenderer { ctx: GfxCtx; @@ -130,6 +134,7 @@ export class BatchRenderer { curShader: Shader | null = null; curUniform: Uniform | null = null; curBlend: BlendMode = BlendMode.Normal; + curFixed: boolean | undefined = undefined; constructor( ctx: GfxCtx, @@ -173,6 +178,7 @@ export class BatchRenderer { blend: BlendMode, width: number, height: number, + fixed: boolean, ) { if ( primitive !== this.curPrimitive @@ -181,6 +187,7 @@ export class BatchRenderer { || ((this.curUniform != uniform) && !deepEq(this.curUniform, uniform)) || blend !== this.curBlend + || fixed !== this.curFixed || this.vqueue.length + verts.length * this.stride > this.maxVertices || this.iqueue.length + indices.length > this.maxIndices @@ -246,6 +253,7 @@ export class BatchRenderer { this.curShader = shader; this.curTex = tex; this.curUniform = uniform; + this.curFixed = fixed; } flush(width: number, height: number) { @@ -260,38 +268,60 @@ export class BatchRenderer { const gl = this.ctx.gl; + // Bind vertex data this.ctx.pushArrayBuffer(this.glVBuf); gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Float32Array(this.vqueue)); + + // Bind index data this.ctx.pushElementArrayBuffer(this.glIBuf); gl.bufferSubData( gl.ELEMENT_ARRAY_BUFFER, 0, new Uint16Array(this.iqueue), ); + + // Set vertex format this.ctx.setVertexFormat(this.vertexFormat); + + // Bind Shader this.curShader.bind(); + + // Send user uniforms if (this.curUniform) { this.curShader.send(this.curUniform); } + + // Send system uniforms this.curShader.send({ width, height, + camera: this.curFixed ? fixedCameraMatrix : getCamTransform() }); + + // Bind texture this.curTex?.bind(); + + // Draw vertex buffer using active indices gl.drawElements( this.curPrimitive, this.iqueue.length, gl.UNSIGNED_SHORT, 0, ); + + // Unbind texture and shader this.curTex?.unbind(); this.curShader.unbind(); + // Unbind buffers this.ctx.popArrayBuffer(); this.ctx.popElementArrayBuffer(); - this.vqueue = []; - this.iqueue = []; + // Reset local buffers + this.vqueue.length = 0; + this.iqueue.length = 0; + + // Increase draw this.numDraws++; } diff --git a/src/math/math.ts b/src/math/math.ts index c6a07dcf..ad8acef6 100644 --- a/src/math/math.ts +++ b/src/math/math.ts @@ -125,8 +125,8 @@ export class Vec2 { return Math.abs(this.x) > Math.abs(this.y) ? this.x < 0 ? Vec2.LEFT : Vec2.RIGHT : this.y < 0 - ? Vec2.UP - : Vec2.DOWN; + ? Vec2.UP + : Vec2.DOWN; } /** Clone the vector */ @@ -890,6 +890,7 @@ export class Mat23 { this.d = m.d; this.e = m.e; this.f = m.f; + return this; } setIdentity() { this.a = 1; @@ -898,6 +899,7 @@ export class Mat23 { this.d = 1; this.e = 0; this.f = 0; + return this; } mul(other: Mat23): Mat23 { return new Mat23( @@ -1385,7 +1387,7 @@ export class Mat4 { const r = Math.sqrt(this.m[0] * this.m[0] + this.m[1] * this.m[1]); return new Vec2( Math.atan(this.m[0] * this.m[4] + this.m[1] * this.m[5]) - / (r * r), + / (r * r), 0, ); } @@ -1394,7 +1396,7 @@ export class Mat4 { return new Vec2( 0, Math.atan(this.m[0] * this.m[4] + this.m[1] * this.m[5]) - / (s * s), + / (s * s), ); } else { @@ -1933,7 +1935,7 @@ export function testPolygonPoint(poly: Polygon, pt: Vec2): boolean { ((p[i].y > pt.y) != (p[j].y > pt.y)) && (pt.x < (p[j].x - p[i].x) * (pt.y - p[i].y) / (p[j].y - p[i].y) - + p[i].x) + + p[i].x) ) { c = !c; } @@ -1951,7 +1953,7 @@ export function testEllipsePoint(ellipse: Ellipse, pt: Vec2): boolean { const vx = pt.x * c + pt.y * s; const vy = -pt.x * s + pt.y * c; return vx * vx / (ellipse.radiusX * ellipse.radiusX) - + vy * vy / (ellipse.radiusY * ellipse.radiusY) < 1; + + vy * vy / (ellipse.radiusY * ellipse.radiusY) < 1; } export function testEllipseCircle(ellipse: Ellipse, circle: Circle): boolean { @@ -2888,7 +2890,7 @@ export class Ellipse { const vx = point.x * c + point.y * s; const vy = -point.x * s + point.y * c; return vx * vx / (this.radiusX * this.radiusX) - + vy * vy / (this.radiusY * this.radiusY) < 1; + + vy * vy / (this.radiusY * this.radiusY) < 1; } raycast(origin: Vec2, direction: Vec2): RaycastResult { return raycastEllipse(origin, direction, this); @@ -3287,21 +3289,21 @@ export function kochanekBartels( const hx = h( pt2.x, 0.5 * (1 - tension) * (1 + bias) * (1 + continuity) * (pt2.x - pt1.x) - + 0.5 * (1 - tension) * (1 - bias) * (1 - continuity) - * (pt3.x - pt2.x), + + 0.5 * (1 - tension) * (1 - bias) * (1 - continuity) + * (pt3.x - pt2.x), 0.5 * (1 - tension) * (1 + bias) * (1 - continuity) * (pt3.x - pt2.x) - + 0.5 * (1 - tension) * (1 - bias) * (1 + continuity) - * (pt4.x - pt3.x), + + 0.5 * (1 - tension) * (1 - bias) * (1 + continuity) + * (pt4.x - pt3.x), pt3.x, ); const hy = h( pt2.y, 0.5 * (1 - tension) * (1 + bias) * (1 + continuity) * (pt2.y - pt1.y) - + 0.5 * (1 - tension) * (1 - bias) * (1 - continuity) - * (pt3.y - pt2.y), + + 0.5 * (1 - tension) * (1 - bias) * (1 - continuity) + * (pt3.y - pt2.y), 0.5 * (1 - tension) * (1 + bias) * (1 - continuity) * (pt3.y - pt2.y) - + 0.5 * (1 - tension) * (1 - bias) * (1 + continuity) - * (pt4.y - pt3.y), + + 0.5 * (1 - tension) * (1 - bias) * (1 + continuity) + * (pt4.y - pt3.y), pt3.y, ); return (t: number) => {