Skip to content

Commit

Permalink
feat(graphics): configurable filter on canvases
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaisthorpe committed Mar 17, 2024
1 parent d1567e5 commit f09fe41
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 35 deletions.
5 changes: 5 additions & 0 deletions .changeset/many-snakes-roll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tedengine/ted": minor
---

Add configuable filter on canvases
3 changes: 1 addition & 2 deletions apps/docs/src/2d/sprite-canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ class CanvasState extends TGameState {
ctx.fillStyle = 'green';
ctx.fillRect(10, 10, 80, 80);

this.texture = await canvas.getTexture();
this.texture.filter = TTextureFilter.Nearest;
this.texture = await canvas.getTexture({ filter: TTextureFilter.Nearest });

this.onReady(engine);
}
Expand Down
8 changes: 3 additions & 5 deletions packages/ted/src/actor-components/tilemap-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type TActor from '../core/actor';
import type TEngine from '../engine/engine';
import TCanvas from '../graphics/canvas';
import TImage from '../graphics/image';
import { TTextureFilter } from '../graphics/texture';
import TTilemap from '../graphics/tilemap';
import type { TPhysicsBodyOptions } from '../physics/physics-world';
import TSpriteComponent from './sprite-component';
Expand All @@ -27,7 +26,7 @@ export default class TTilemapComponent extends TSpriteComponent {
actor: TActor,
tilemapPath: string | TTilemap,
tilesets: TTilesetConfig[],
bodyOptions?: TPhysicsBodyOptions
bodyOptions?: TPhysicsBodyOptions,
) {
super(engine, actor, 1, 1);

Expand All @@ -38,7 +37,7 @@ export default class TTilemapComponent extends TSpriteComponent {
Object.assign({}, result, {
[tileset.id]: this.getTileset(engine, tileset),
}),
{}
{},
);

this.width = this.tilemap.displayWidth;
Expand Down Expand Up @@ -107,13 +106,12 @@ export default class TTilemapComponent extends TSpriteComponent {
gridTile.px[0],
gridTile.px[1],
tileset.tileSize,
tileset.tileSize
tileset.tileSize,
);
}
}

this.texture = await canvas.getTexture();
this.texture.filter = TTextureFilter.Linear;

this.generateMesh();

Expand Down
7 changes: 4 additions & 3 deletions packages/ted/src/graphics/canvas.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import type TEngine from '../engine/engine';
import type { TTextureOptions } from '../renderer/renderable-texture';
import TTexture from './texture';

export default class TCanvas {
private canvas: OffscreenCanvas;
constructor(
private engine: TEngine,
public width: number,
public height: number
public height: number,
) {
this.canvas = new OffscreenCanvas(this.width, this.height);
}
Expand All @@ -15,10 +16,10 @@ export default class TCanvas {
return this.canvas.getContext('2d') as OffscreenCanvasRenderingContext2D;
}

public async getTexture(): Promise<TTexture> {
public async getTexture(config?: TTextureOptions): Promise<TTexture> {
const image = await createImageBitmap(this.canvas);
const texture = new TTexture();
await texture.setImageBitmap(this.engine.jobs, image);
await texture.setImageBitmap(this.engine.jobs, image, config);

return texture;
}
Expand Down
46 changes: 28 additions & 18 deletions packages/ted/src/graphics/texture.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { TImage } from '..';
import type { TTextureOptions } from '../renderer/renderable-texture';
import { TTextureFilter } from '../renderer/renderable-texture';
import TImage from './image';
import type { IJobAsset } from '../core/resource-manager';
import type TJobManager from '../jobs/job-manager';
import type {
Expand All @@ -8,29 +10,29 @@ import type {
TRenderJobContext,
} from '../jobs/jobs';

/**
* Filter = Nearest | Linear
*/
export enum TTextureFilter {
Nearest = 0x2600,
Linear = 0x2601,
}

function hasResourceManager(
additionalContext:
| TJobContext
| TRenderJobContext
| TAudioJobContext
| TPhysicsJobContext
| TPhysicsJobContext,
): additionalContext is TJobContext | TRenderJobContext | TAudioJobContext {
return (additionalContext as TJobContext).resourceManager !== undefined;
}

export default class TTexture implements IJobAsset {
public uuid?: string;
// @todo make this functional
public filter: TTextureFilter = TTextureFilter.Linear;

private _filter: TTextureFilter = TTextureFilter.Linear;

/**
* Returns the filter used for the texture, this cannot be changed after texture is loaded
*/
public get filter(): TTextureFilter {
return this._filter;
}

// @todo - add support for setting the filter
public async loadWithJob(jobs: TJobManager, url: string): Promise<void> {
if (!hasResourceManager(jobs.additionalContext)) {
throw new Error('job manager does not have resource manager');
Expand All @@ -39,27 +41,35 @@ export default class TTexture implements IJobAsset {
// First load the image
const image = await jobs.additionalContext.resourceManager.load<TImage>(
TImage,
url
url,
);

const result = await jobs.do(
{
type: 'load_texture_from_imagebitmap',
args: [image.image],
args: [image.image, { filter: this.filter }],
},
[image.image!]
[image.image!],
);

this.uuid = result;
}

public async setImageBitmap(jobs: TJobManager, image: ImageBitmap) {
public async setImageBitmap(
jobs: TJobManager,
image: ImageBitmap,
options?: TTextureOptions,
): Promise<void> {
if (options?.filter !== undefined) {
this._filter = options.filter;
}

const result = await jobs.do(
{
type: 'load_texture_from_imagebitmap',
args: [image],
args: [image, options],
},
[image]
[image],
);

this.uuid = result;
Expand Down
2 changes: 2 additions & 0 deletions packages/ted/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ export * from './physics/colliders/sphere-collider';

export * from './renderer/events';
export { default as TProgram } from './renderer/program';
export * from './renderer/renderable-texture';
export { default as TRenderableTexture } from './renderer/renderable-texture';

export { default as TGame } from './ui/components/Game';
export * from './ui/context';
Expand Down
17 changes: 11 additions & 6 deletions packages/ted/src/renderer/jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { TJobConfigs, TRenderJobContext } from '../jobs/jobs';
import TProgram from './program';
import type { TPaletteIndex } from './renderable-mesh';
import TRenderableMesh from './renderable-mesh';
import type { TTextureOptions } from './renderable-texture';
import TRenderableTexture from './renderable-texture';
import TRenderableTexturedMesh from './renderable-textured-mesh';

Expand All @@ -12,7 +13,7 @@ export const RendererJobs: TJobConfigs = {
func: async (ctx: TRenderJobContext, shaderLocation: string) => {
const program = await ctx.resourceManager.load<TProgram>(
TProgram,
shaderLocation
shaderLocation,
);

if (!ctx.renderer.hasProgram(program.uuid!)) {
Expand All @@ -28,7 +29,7 @@ export const RendererJobs: TJobConfigs = {
func: async (ctx: TRenderJobContext, meshLocation: string) => {
const mesh = await ctx.resourceManager.load<TRenderableMesh>(
TRenderableMesh,
meshLocation
meshLocation,
);

if (!ctx.renderer.hasMesh(mesh.uuid)) {
Expand All @@ -46,7 +47,7 @@ export const RendererJobs: TJobConfigs = {
normals: number[],
indexes: number[],
colors: number[],
paletteIndex: TPaletteIndex
paletteIndex: TPaletteIndex,
) => {
// todo: ensure resource manager knows this mesh is loaded?
const mesh = new TRenderableMesh();
Expand All @@ -68,7 +69,7 @@ export const RendererJobs: TJobConfigs = {
positions: number[],
normals: number[],
indexes: number[],
uvs: number[]
uvs: number[],
) => {
// todo: ensure resource manager knows this mesh is loaded?
const mesh = new TRenderableTexturedMesh();
Expand All @@ -84,9 +85,13 @@ export const RendererJobs: TJobConfigs = {
},
load_texture_from_imagebitmap: {
requiredContext: TJobContextTypes.Renderer,
func: async (ctx: TRenderJobContext, image: ImageBitmap) => {
func: async (
ctx: TRenderJobContext,
image: ImageBitmap,
config?: TTextureOptions,
) => {
const texture = new TRenderableTexture();
texture.load(ctx.renderer.context(), image);
texture.load(ctx.renderer.context(), image, config);

ctx.renderer.registerTexture(texture);

Expand Down
14 changes: 13 additions & 1 deletion packages/ted/src/renderer/renderable-texture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export enum TTextureFilter {
Linear = 0x2601,
}

export interface TTextureOptions {
filter?: TTextureFilter;
}

export default class TRenderableTexture {
public uuid: string = uuidv4();
public texture?: WebGLTexture;
Expand All @@ -19,9 +23,17 @@ export default class TRenderableTexture {
* @param {TGraphics} graphics
* @returns WebGLTexture
*/
public load(gl: WebGL2RenderingContext, image: ImageBitmap) {
public load(
gl: WebGL2RenderingContext,
image: ImageBitmap,
options?: TTextureOptions,
) {
this.texture = gl.createTexture()!;

if (options?.filter !== undefined) {
this.filter = options.filter;
}

gl.bindTexture(gl.TEXTURE_2D, this.texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.filter);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, this.filter);
Expand Down

0 comments on commit f09fe41

Please sign in to comment.