Skip to content

Commit

Permalink
chore: setup unjs package template
Browse files Browse the repository at this point in the history
  • Loading branch information
jsulpis committed Oct 13, 2024
1 parent e0801ca commit 4d74999
Show file tree
Hide file tree
Showing 27 changed files with 3,233 additions and 141 deletions.
11 changes: 0 additions & 11 deletions .vscode/launch.json

This file was deleted.

3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# useGL

WIP
3 changes: 1 addition & 2 deletions docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ import { defineConfig } from "astro/config";

// https://astro.build/config
export default defineConfig({
site: "https://jsulpis.github.io",
base: "/simple-webgl-library",
site: "https://usegl.pages.dev",
});
8 changes: 8 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import unjs from "eslint-config-unjs";

export default unjs({
rules: {
"unicorn/filename-case": "off",
"unicorn/no-null": "off",
},
});
17 changes: 0 additions & 17 deletions lib/index.ts

This file was deleted.

40 changes: 37 additions & 3 deletions lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,45 @@
"name": "usegl",
"version": "0.1.0",
"description": "Lightweight hooks library for WebGL",
"keywords": [],
"repository": "jsulpis/usegl",
"license": "MIT",
"author": "Julien SULPIS",
"main": "index.ts",
"sideEffects": false,
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs"
}
},
"main": "./dist/index.mjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"build": "unbuild",
"format": "prettier src --check",
"format:fix": "prettier src --write",
"lint": "eslint src",
"lint:fix": "eslint src --fix",
"prepack": "pnpm build",
"release": "changelogen --release --clean",
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"@types/node": "22.1.0",
"changelogen": "0.5.5",
"eslint": "9.8.0",
"eslint-config-unjs": "0.3.2",
"prettier": "3.3.3",
"typescript": "5.5.4",
"unbuild": "3.0.0-rc.7"
},
"changelog": {
"excludeAuthors": [
""
]
}
}
7 changes: 4 additions & 3 deletions lib/src/core/attribute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export function setAttribute(
gl: WebGL2RenderingContext,
program: WebGLProgram,
name: string,
attribute: Attribute
attribute: Attribute,
) {
const bufferData = getBufferData(attribute.data, name === "index");
const location = gl.getAttribLocation(program, name);
Expand All @@ -27,7 +27,7 @@ export function setAttribute(
attribute.type || getGLType(gl, bufferData),
attribute.normalize || false,
attribute.stride || 0,
attribute.offset || 0
attribute.offset || 0,
);
gl.bindBuffer(gl.ARRAY_BUFFER, null);

Expand All @@ -43,7 +43,7 @@ function getBufferData(data: Attribute["data"], isIndex: boolean) {
return data;
}
if (isIndex) {
return data.length < 65536 ? new Uint16Array(data) : new Uint32Array(data);
return data.length < 65_536 ? new Uint16Array(data) : new Uint32Array(data);
}
return new Float32Array(data);
}
Expand All @@ -56,4 +56,5 @@ function getGLType(gl: WebGL2RenderingContext, data: ArrayBufferView) {
if (data instanceof Int16Array) return gl.SHORT;
if (data instanceof Uint32Array) return gl.UNSIGNED_INT;
if (data instanceof Int32Array) return gl.INT;
return gl.FLOAT;
}
2 changes: 1 addition & 1 deletion lib/src/core/buffer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export function createAndBindBuffer(
gl: WebGLRenderingContext,
target: GLenum,
data: AllowSharedBufferSource | number[]
data: AllowSharedBufferSource | number[],
) {
const buffer = gl.createBuffer();
const bufferData = isSharedBufferSource(data) ? data : new Float32Array(data);
Expand Down
7 changes: 6 additions & 1 deletion lib/src/core/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ import { createShader } from "./shader";
export function createProgram(
gl: WebGL2RenderingContext,
fragment: string | WebGLShader,
vertex: string | WebGLShader
vertex: string | WebGLShader,
) {
const vertexShader =
vertex instanceof WebGLShader ? vertex : createShader(gl, vertex, gl.VERTEX_SHADER);
const fragmentShader =
fragment instanceof WebGLShader ? fragment : createShader(gl, fragment, gl.FRAGMENT_SHADER);

const program = gl.createProgram();
if (program === null || vertexShader == null || fragmentShader == null) {
console.error("could not create program");
gl.deleteProgram(program);
return null;
}
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/core/renderTarget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createTexture } from "./texture";

export function createRenderTarget(
gl: WebGL2RenderingContext,
size?: { width: number; height: number }
size?: { width: number; height: number },
): RenderTarget {
let _width = size?.width ?? gl.canvas.width;
let _height = size?.height ?? gl.canvas.height;
Expand Down
5 changes: 5 additions & 0 deletions lib/src/core/shader.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
export function createShader(gl: WebGL2RenderingContext, source: string, type: GLenum) {
const shader = gl.createShader(type);
if (shader == null) {
console.error("could not create shader");
gl.deleteShader(shader);
return null;
}
gl.shaderSource(shader, convertToGLSL300(source));
gl.compileShader(shader);

Expand Down
2 changes: 1 addition & 1 deletion lib/src/core/texture.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export function createTexture(
gl: WebGL2RenderingContext,
{ data = null, width, height }: { data: ArrayBufferView; width: number; height: number }
{ data = null, width, height }: { data: ArrayBufferView | null; width: number; height: number },
) {
const texture = gl.createTexture();

Expand Down
12 changes: 9 additions & 3 deletions lib/src/helpers/pointer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,26 @@ type PointerEvents = {
export function onPointerEvents(canvas: HTMLCanvasElement, { enter, move, leave }: PointerEvents) {
function onPointerEnter(e: PointerEvent) {
enter?.(e);
canvas.addEventListener("pointermove", move);
if (typeof move === "function") {
canvas.addEventListener("pointermove", move);
}
canvas.addEventListener("pointerout", onPointerOut, { once: true });
}

function onPointerOut(e: PointerEvent) {
leave?.(e);
canvas.removeEventListener("pointermove", move);
if (typeof move === "function") {
canvas.removeEventListener("pointermove", move);
}
}

canvas.addEventListener("pointerenter", onPointerEnter);

function stop() {
canvas.removeEventListener("pointerenter", onPointerEnter);
canvas.removeEventListener("pointermove", move);
if (typeof move === "function") {
canvas.removeEventListener("pointermove", move);
}
canvas.removeEventListener("pointerout", onPointerOut);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/src/helpers/resize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function onCanvasResize(
* canvas size in device pixels
*/
devicePixelSize: { width: number; height: number };
}) => void
}) => void,
) {
let size: ResizeObserverSize;
let devicePixelSize: ResizeObserverSize;
Expand Down
23 changes: 12 additions & 11 deletions lib/src/hooks/useCompositor.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { createRenderTarget } from "../core/renderTarget";
import type { PostEffect, RenderPass } from "../types";
import type { PostEffect, RenderPass, Uniforms } from "../types";
import { findUniformName } from "../internal/findName";

export function useCompositor(
export function useCompositor<U extends Uniforms>(
gl: WebGL2RenderingContext,
primaryPass: RenderPass,
effects: PostEffect[]
primaryPass: RenderPass<U>,
effects: PostEffect[],
) {
if (effects.length > 0 && primaryPass.target === null) {
primaryPass.setTarget(createRenderTarget(gl));
}

effects.forEach((effect, index) => {
for (const [index, effect] of effects.entries()) {
effect.initialize(gl);
effect.setTarget(index === effects.length - 1 ? null : createRenderTarget(gl));

Expand All @@ -21,23 +21,24 @@ export function useCompositor(
findUniformName(effect.fragment, "pass");

if (textureUniformName && effect.uniforms[textureUniformName] === undefined) {
/* @ts-expect-error the texture uniform is not declared in the uniforms object of the effect pass */
effect.uniforms[textureUniformName] = () =>
(index > 0 ? effects[index - 1] : primaryPass).target.texture;
(index > 0 ? effects[index - 1] : primaryPass).target?.texture;
}
});
}

const allPasses = [primaryPass, ...effects];

function render() {
allPasses.forEach((pass) => {
for (const pass of allPasses) {
pass.render();
});
}
}

function setSize(size: { width: number; height: number }) {
allPasses.forEach((pass) => {
for (const pass of allPasses) {
pass.setSize(size);
});
}
}

return { render, setSize, allPasses };
Expand Down
2 changes: 1 addition & 1 deletion lib/src/hooks/useEffectPass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useQuadRenderPass } from "./useQuadRenderPass";
import type { RenderPassOptions } from "./useRenderPass";

export function useEffectPass<Uniforms extends UniformsType>(
options: RenderPassOptions<Uniforms>
options: RenderPassOptions<Uniforms>,
): RenderPass<Uniforms> {
return useQuadRenderPass(undefined, options);
}
11 changes: 8 additions & 3 deletions lib/src/hooks/useQuadRenderPass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ import { quadVertexPositions, quadVertexShaderSource } from "../helpers/quad";
import { findAttributeName, findVaryingName } from "../internal/findName";

export function useQuadRenderPass<Uniforms extends UniformsType>(
gl: WebGL2RenderingContext,
{ attributes = {}, fragment, vertex, ...renderPassOptions }: RenderPassOptions<Uniforms>
gl: WebGL2RenderingContext | undefined,
{
attributes = {},
fragment,
vertex,
...renderPassOptions
}: Omit<RenderPassOptions<Uniforms>, "vertex"> & { vertex?: string },
) {
const uvVaryingName = findVaryingName(fragment, "uv");

Expand All @@ -16,7 +21,7 @@ export function useQuadRenderPass<Uniforms extends UniformsType>(
: quadVertexShaderSource);

const hasPositionAttribute = Object.keys(attributes).some((attributeName) =>
attributeName.toLocaleLowerCase().endsWith("position")
attributeName.toLocaleLowerCase().endsWith("position"),
);

if (!hasPositionAttribute) {
Expand Down
24 changes: 16 additions & 8 deletions lib/src/hooks/useRenderPass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,25 @@ import { useUniforms } from "../internal/useUniforms";
import { useAttributes } from "../internal/useAttributes";
import { useLifeCycleCallback } from "../internal/useLifeCycleCallback";

export type RenderPassOptions<Uniforms extends UniformsType = {}> = {
export type RenderPassOptions<Uniforms extends UniformsType = Record<string, never>> = {
target?: RenderTarget | null;
fragment: string;
vertex?: string;
vertex: string;
attributes?: Record<string, Attribute>;
uniforms?: Uniforms;
drawMode?: DrawMode;
};

export function useRenderPass<Uniforms extends UniformsType>(
gl: WebGL2RenderingContext,
gl: WebGL2RenderingContext | undefined,
{
target = null,
fragment,
vertex,
attributes = {},
uniforms: userUniforms = {} as Uniforms,
drawMode: userDrawMode,
}: RenderPassOptions<Uniforms>
}: RenderPassOptions<Uniforms>,
): RenderPass<Uniforms> {
/**
* INIT
Expand All @@ -58,7 +58,11 @@ export function useRenderPass<Uniforms extends UniformsType>(

function initialize(gl: WebGL2RenderingContext) {
_gl = gl;
_program = createProgram(_gl, fragment, vertex);
const program = createProgram(_gl, fragment, vertex);
if (program == null) {
throw new Error("could not initialize the render pass");
}
_program = program;
_gl.useProgram(_program);

initializeUniforms(_gl, _program);
Expand All @@ -77,7 +81,7 @@ export function useRenderPass<Uniforms extends UniformsType>(

function setSize(size: { width: number; height: number }) {
if (resolutionUniformName && userUniforms[resolutionUniformName] === undefined) {
uniformsProxy[resolutionUniformName] = [size.width, size.height];
(uniformsProxy as Record<string, unknown>)[resolutionUniformName] = [size.width, size.height];
}
if (_target != null) {
_target.setSize(size.width, size.height);
Expand All @@ -101,7 +105,9 @@ export function useRenderPass<Uniforms extends UniformsType>(
if (_gl == undefined) {
throw new Error("The render pass must be initialized before calling the render function");
}
beforeRenderCallbacks.forEach((callback) => callback({ uniforms: getUniformsSnapshot() }));
for (const callback of beforeRenderCallbacks) {
callback({ uniforms: getUniformsSnapshot() });
}

setRenderTarget(_gl, _target);
_gl.useProgram(_program);
Expand All @@ -115,7 +121,9 @@ export function useRenderPass<Uniforms extends UniformsType>(
_gl.drawArrays(_gl[drawMode], 0, getVertexCount());
}

afterRenderCallbacks.forEach((callback) => callback({ uniforms: getUniformsSnapshot() }));
for (const callback of afterRenderCallbacks) {
callback({ uniforms: getUniformsSnapshot() });
}
}

return {
Expand Down
Loading

0 comments on commit 4d74999

Please sign in to comment.