Added support for Textures

This commit is contained in:
Maciej Samborski 2024-12-24 20:37:22 +01:00
parent 129cf05b90
commit 2c81bc0684
25 changed files with 164 additions and 54 deletions

View File

@ -0,0 +1,3 @@
For a description of the contents of this pack, usage rights, and other useful details, go here:
http://blog.spiralgraphics.biz/2011/02/nine-cartoon-backdrops.html

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@ -1,4 +1,5 @@
import { Vec2 } from "./common.js";
import { Texture } from "./graphics.js";
function drawTriangle(gfx, positions, color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
@ -35,7 +36,6 @@ function drawTriangleExts(gfx, position, exts, color) {
}
function drawRectangle(gfx, position, exts, color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
const points = [
position.x, position.y,
position.x + exts.x, position.y,
@ -44,17 +44,35 @@ function drawRectangle(gfx, position, exts, color) {
position.x + exts.x, position.y,
position.x, position.y + exts.y,
];
const colors = [
color,
color,
color,
color,
color,
color,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
if (color instanceof Texture) {
const a_tex_position = gfx.getAttribute("a_tex_position");
const uv = [
0.0, 0.0,
-1.0, 0.0,
0.0, -1.0,
-1.0, -1.0,
-1.0, 0.0,
0.0, -1.0,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_tex_position.data(gfx.ctx, uv, gfx.ctx.STATIC_DRAW);
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, color.tex);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
}
else {
const a_color = gfx.getAttribute("a_color");
const colors = [
color,
color,
color,
color,
color,
color,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
}
}
function drawCircle(gfx, position, radius, color) {
const points = new Array();

View File

@ -1,5 +1,5 @@
import { Vec2, Color } from "./common.js"
import { Graphics } from "./graphics.js";
import { Graphics, Texture } from "./graphics.js";
function drawTriangle(gfx: Graphics, positions: [Vec2, Vec2, Vec2], color: Color) {
const a_position = gfx.getAttribute("a_position");
@ -43,9 +43,8 @@ function drawTriangleExts(gfx: Graphics, position: Vec2, exts: Vec2, color: Colo
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
}
function drawRectangle(gfx: Graphics, position: Vec2, exts: Vec2, color: Color) {
function drawRectangle(gfx: Graphics, position: Vec2, exts: Vec2, color: Color | Texture) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
const points: Array<number> = [
position.x, position.y,
@ -57,18 +56,38 @@ function drawRectangle(gfx: Graphics, position: Vec2, exts: Vec2, color: Color)
position.x, position.y + exts.y,
]
const colors: Array<number[]> = [
color,
color,
color,
color,
color,
color,
];
if (color instanceof Texture) {
const a_tex_position = gfx.getAttribute("a_tex_position");
const uv: Array<number> = [
0.0, 0.0,
-1.0, 0.0,
0.0, -1.0,
-1.0, -1.0,
-1.0, 0.0,
0.0, -1.0,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_tex_position.data(gfx.ctx, uv, gfx.ctx.STATIC_DRAW);
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, color.tex);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
} else {
const a_color = gfx.getAttribute("a_color");
const colors: Array<number[]> = [
color,
color,
color,
color,
color,
color,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
}
}

View File

@ -107,4 +107,30 @@ class Attribute {
ctx.vertexAttribPointer(this.loc, this.size, this.type, this.normalized, this.stride, this.offset);
}
}
export { fullscreenCanvas, Graphics, Attribute };
class Texture {
tex;
constructor(tex) {
this.tex = tex;
}
static async load(ctx, path) {
let image = await loadTexture(path);
let tex = ctx.createTexture();
ctx.bindTexture(ctx.TEXTURE_2D, tex);
ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image);
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR);
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_NEAREST);
ctx.generateMipmap(ctx.TEXTURE_2D);
ctx.bindTexture(ctx.TEXTURE_2D, null);
return new Texture(tex);
}
}
async function loadTexture(path) {
return new Promise(resolve => {
const img = new Image();
img.addEventListener("load", () => {
resolve(img);
});
img.src = path;
});
}
export { Texture, fullscreenCanvas, Graphics, Attribute };

View File

@ -1,5 +1,3 @@
import { Vec2 } from "./common.js"
function fullscreenCanvas(gfx: Graphics, id: string) {
const canvas = document.getElementById(id) as HTMLCanvasElement;
canvas.width = window.innerWidth;
@ -145,4 +143,36 @@ class Attribute {
}
}
export { fullscreenCanvas, Graphics, Attribute }
class Texture {
tex: WebGLTexture | null;
constructor(tex: WebGLTexture) {
this.tex = tex;
}
static async load(ctx: WebGL2RenderingContext, path: string): Promise<Texture> {
let image = await loadTexture(path);
let tex = ctx.createTexture();
ctx.bindTexture(ctx.TEXTURE_2D, tex);
ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image);
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR);
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_NEAREST);
ctx.generateMipmap(ctx.TEXTURE_2D);
ctx.bindTexture(ctx.TEXTURE_2D, null);
return new Texture(tex);
}
}
async function loadTexture(path: string): Promise<HTMLImageElement> {
return new Promise(resolve => {
const img = new Image();
img.addEventListener("load", () => {
resolve(img);
})
img.src = path;
});
}
export { Texture, fullscreenCanvas, Graphics, Attribute }

View File

@ -1,32 +1,35 @@
import { initializeContext, Vec2, Mat4 } from "./common.js";
import { Graphics, fullscreenCanvas } from "./graphics.js";
import { Graphics, fullscreenCanvas, Texture } from "./graphics.js";
import * as drawing from "./draw.js";
import * as wasm from "./wasm.js";
const vertexShader = `#version 300 es
in vec2 a_position;
in vec4 a_color;
out vec4 color;
in vec2 a_tex_position;
out vec2 v_tex_position;
uniform mat4 u_matrix;
void main() {
vec4 transformed = u_matrix * vec4(a_position.xy, 0.0, 1.0);
gl_Position = transformed;
color = a_color;
v_tex_position = a_tex_position;
}
`;
const fragmentShader = `#version 300 es
precision highp float;
in vec4 color;
in vec2 v_tex_position;
out vec4 outColor;
uniform sampler2D u_texture;
void main() {
outColor = color;
outColor = texture(u_texture, v_tex_position);
}
`;
function draw(gfx, angle) {
function draw(gfx, angle, tex) {
gfx.clear(0, 0, 0, 0);
let left = 0;
let right = gfx.ctx.canvas.width;
@ -39,7 +42,7 @@ function draw(gfx, angle) {
m = m.mult(Mat4.rotation_y(angle));
m = m.mult(Mat4.rotation_z(angle));
gfx.ctx.uniformMatrix4fv(gfx.getUniform("u_matrix"), false, m.splat());
drawing.drawRectangle(gfx, new Vec2(gfx.ctx.canvas.width / 2 - 50, gfx.ctx.canvas.height / 2 - 50), new Vec2(100, 100), [1, 0, 0, 1]);
drawing.drawRectangle(gfx, new Vec2(gfx.ctx.canvas.width / 2 - 200, gfx.ctx.canvas.height / 2 - 200), new Vec2(400, 400), tex);
}
(async () => {
const canvasId = "game";
@ -50,16 +53,19 @@ function draw(gfx, angle) {
fullscreenCanvas(gfx, canvasId);
const a_position = gfx.createAttribute("a_position");
a_position.format(2, gfx.ctx.FLOAT, false, 0, 0);
const a_color = gfx.createAttribute("a_color");
a_color.format(4, gfx.ctx.FLOAT, false, 0, 0);
//const a_color = gfx.createAttribute("a_color");
//a_color.format(4, gfx.ctx.FLOAT, false, 0, 0);
const a_tex_position = gfx.createAttribute("a_tex_position");
a_tex_position.format(2, gfx.ctx.FLOAT, false, 0, 0);
gfx.createUniform("u_matrix");
let city = await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg");
let angle = 0;
let prevTimestamp = 0;
const frame = (timestamp) => {
const deltaTime = (timestamp - prevTimestamp) / 1000;
prevTimestamp = timestamp;
fullscreenCanvas(gfx, "game");
draw(gfx, angle);
draw(gfx, angle, city);
angle += Math.PI * deltaTime * 0.5;
window.requestAnimationFrame(frame);
};

View File

@ -1,5 +1,5 @@
import { initializeContext, Vec2, Mat4, Vec4 } from "./common.js";
import { Graphics, fullscreenCanvas } from "./graphics.js";
import { Graphics, fullscreenCanvas, Texture } from "./graphics.js";
import * as drawing from "./draw.js";
import * as wasm from "./wasm.js";
@ -7,15 +7,15 @@ const vertexShader =
`#version 300 es
in vec2 a_position;
in vec4 a_color;
out vec4 color;
in vec2 a_tex_position;
out vec2 v_tex_position;
uniform mat4 u_matrix;
void main() {
vec4 transformed = u_matrix * vec4(a_position.xy, 0.0, 1.0);
gl_Position = transformed;
color = a_color;
v_tex_position = a_tex_position;
}
`;
@ -23,17 +23,20 @@ const fragmentShader =
`#version 300 es
precision highp float;
in vec4 color;
in vec2 v_tex_position;
out vec4 outColor;
uniform sampler2D u_texture;
void main() {
outColor = color;
outColor = texture(u_texture, v_tex_position);
}
`;
function draw(gfx: Graphics, angle: number) {
function draw(gfx: Graphics, angle: number, tex: Texture) {
gfx.clear(0, 0, 0, 0);
let left = 0;
@ -56,9 +59,9 @@ function draw(gfx: Graphics, angle: number) {
drawing.drawRectangle(
gfx,
new Vec2(gfx.ctx.canvas.width / 2 - 50, gfx.ctx.canvas.height / 2 - 50),
new Vec2(100, 100),
[1, 0, 0, 1]);
new Vec2(gfx.ctx.canvas.width / 2 - 200, gfx.ctx.canvas.height / 2 - 200),
new Vec2(400, 400),
tex);
}
(async () => {
@ -72,11 +75,16 @@ function draw(gfx: Graphics, angle: number) {
const a_position = gfx.createAttribute("a_position");
a_position.format(2, gfx.ctx.FLOAT, false, 0, 0);
const a_color = gfx.createAttribute("a_color");
a_color.format(4, gfx.ctx.FLOAT, false, 0, 0);
//const a_color = gfx.createAttribute("a_color");
//a_color.format(4, gfx.ctx.FLOAT, false, 0, 0);
const a_tex_position = gfx.createAttribute("a_tex_position");
a_tex_position.format(2, gfx.ctx.FLOAT, false, 0, 0);
gfx.createUniform("u_matrix");
let city = await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg");
let angle = 0;
let prevTimestamp = 0;
const frame = (timestamp: number) => {
@ -84,7 +92,7 @@ function draw(gfx: Graphics, angle: number) {
prevTimestamp = timestamp;
fullscreenCanvas(gfx, "game");
draw(gfx, angle);
draw(gfx, angle, city);
angle += Math.PI * deltaTime * 0.5;
window.requestAnimationFrame(frame);