Skip to content

Commit

Permalink
feat: add spriteAtlasPadding configuration option (#582)
Browse files Browse the repository at this point in the history
  • Loading branch information
marianyp authored and lajbel committed Jan 15, 2025
1 parent b0e9813 commit fd5fb6d
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 22 deletions.
17 changes: 16 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,25 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3001.0.7] - 2025-01-15

### Added

- Added `kaplay({ spriteAtlasPadding })` for setting the space between the
sprites in the sprite atlas - @marianyp

```js
kaplay({
spriteAtlasPadding: 10, // 10 pixels of space between each sprite
});
```

### Changed

- Now you cannot pass parameters that are not a component or string to `.use()`.
Otherwise it will throw an error
Otherwise it will throw an error - @lajbel

### Fixed

- Fixed a bug where font atlas were working strange - @mflerackers

## [3001.0.6] "Santa Events" - 2024-12-27

Expand Down
9 changes: 7 additions & 2 deletions src/assets/asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export function load<T>(prom: Promise<T>): Asset<T> {
// create assets
export type AssetsCtx = ReturnType<typeof initAssets>;

export const initAssets = (ggl: GfxCtx) => {
export const initAssets = (ggl: GfxCtx, spriteAtlasPadding: number) => {
const assets = {
urlPrefix: "",
// asset holders
Expand All @@ -216,7 +216,12 @@ export const initAssets = (ggl: GfxCtx) => {
shaders: new AssetBucket<ShaderData>(),
custom: new AssetBucket<any>(),
music: {} as Record<string, string>,
packer: new TexPacker(ggl, SPRITE_ATLAS_WIDTH, SPRITE_ATLAS_HEIGHT),
packer: new TexPacker(
ggl,
SPRITE_ATLAS_WIDTH,
SPRITE_ATLAS_HEIGHT,
spriteAtlasPadding,
),
// if we finished initially loading all assets
loaded: false,
};
Expand Down
56 changes: 43 additions & 13 deletions src/gfx/texPacker.ts
Original file line number Diff line number Diff line change
@@ -1,64 +1,93 @@
import type { ImageSource } from "../types";

import { type GfxCtx, Texture } from "../gfx";

import { Quad, Vec2 } from "../math/math";

export default class TexPacker {
private lastTextureId: number = 0;
private textures: Texture[] = [];
private bigTextures: Texture[] = [];
private texturesPosition: Map<number, {
position: Vec2;
size: Vec2;
texture: Texture;
}> = new Map();
private canvas: HTMLCanvasElement;
private c2d: CanvasRenderingContext2D;
private x: number = 0;
private y: number = 0;
private curHeight: number = 0;
private gfx: GfxCtx;
constructor(gfx: GfxCtx, w: number, h: number) {
private padding: number;

constructor(gfx: GfxCtx, w: number, h: number, padding: number) {
this.gfx = gfx;
this.canvas = document.createElement("canvas");
this.canvas.width = w;
this.canvas.height = h;
this.textures = [Texture.fromImage(gfx, this.canvas)];
this.bigTextures = [];
this.padding = padding;

const context2D = this.canvas.getContext("2d");
if (!context2D) throw new Error("Failed to get 2d context");

this.c2d = context2D;
}
add(img: ImageSource): [Texture, Quad] {
if (img.width > this.canvas.width || img.height > this.canvas.height) {

add(img: ImageSource): [Texture, Quad, number] {
const paddedWidth = img.width + this.padding * 2;
const paddedHeight = img.height + this.padding * 2;

if (
paddedWidth > this.canvas.width || paddedHeight > this.canvas.height
) {
const tex = Texture.fromImage(this.gfx, img);
this.bigTextures.push(tex);
return [tex, new Quad(0, 0, 1, 1)];
return [tex, new Quad(0, 0, 1, 1), 0];
}

// next row
if (this.x + img.width > this.canvas.width) {
if (this.x + paddedWidth > this.canvas.width) {
this.x = 0;
this.y += this.curHeight;
this.curHeight = 0;
}

// next texture
if (this.y + img.height > this.canvas.height) {
if (this.y + paddedHeight > this.canvas.height) {
this.c2d.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.textures.push(Texture.fromImage(this.gfx, this.canvas));
this.x = 0;
this.y = 0;
this.curHeight = 0;
}

const curTex = this.textures[this.textures.length - 1];
const pos = new Vec2(this.x, this.y);
this.x += img.width;
if (img.height > this.curHeight) {
this.curHeight = img.height;
const pos = new Vec2(this.x + this.padding, this.y + this.padding);

this.x += paddedWidth;

if (paddedHeight > this.curHeight) {
this.curHeight = paddedHeight;
}

if (img instanceof ImageData) {
this.c2d.putImageData(img, pos.x, pos.y);
}
else {
this.c2d.drawImage(img, pos.x, pos.y);
}

curTex.update(this.canvas);

this.texturesPosition.set(this.lastTextureId, {
position: pos,
size: new Vec2(img.width, img.height),
texture: curTex,
});

this.lastTextureId++;

return [
curTex,
new Quad(
Expand All @@ -67,6 +96,7 @@ export default class TexPacker {
img.width / this.canvas.width,
img.height / this.canvas.height,
),
this.lastTextureId - 1,
];
}
free() {
Expand All @@ -77,4 +107,4 @@ export default class TexPacker {
tex.free();
}
}
}
}
11 changes: 5 additions & 6 deletions src/kaplay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,7 @@ const kaplay = <
tagsAsComponents: true,
},
): TPlugins extends [undefined] ? KAPLAYCtx<TButtons, TButtonsName>
: KAPLAYCtx<TButtons, TButtonsName> & MergePlugins<TPlugins> =>
{
: KAPLAYCtx<TButtons, TButtonsName> & MergePlugins<TPlugins> => {
if (_k.k) {
console.warn(
"KAPLAY already initialized, you are calling kaplay() multiple times, it may lead bugs!",
Expand Down Expand Up @@ -467,7 +466,7 @@ const kaplay = <
_k.gfx = gfx;
const audio = initAudio();
_k.audio = audio;
const assets = initAssets(ggl);
const assets = initAssets(ggl, gopt.spriteAtlasPadding ?? 0);
_k.assets = assets;
const game = initGame();
_k.game = game;
Expand Down Expand Up @@ -901,7 +900,7 @@ const kaplay = <

// TODO: this should only run once
app.run(
() => {},
() => { },
() => {
frameStart();

Expand Down Expand Up @@ -964,7 +963,7 @@ const kaplay = <
// clear canvas
gl.clear(
gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT
| gl.STENCIL_BUFFER_BIT,
| gl.STENCIL_BUFFER_BIT,
);

// unbind everything
Expand Down Expand Up @@ -1408,7 +1407,7 @@ const kaplay = <
// export everything to window if global is set
if (gopt.global !== false) {
for (const key in ctx) {
(<any> window[<any> key]) = ctx[key as keyof KAPLAYCtx];
(<any>window[<any>key]) = ctx[key as keyof KAPLAYCtx];
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5458,6 +5458,13 @@ export interface KAPLAYOpt<
* @experimental This feature is in experimental phase, it will be fully released in v3001.1.0
*/
tagsAsComponents?: boolean;
/**
* Padding used when adding sprites to texture atlas.
*
* @default 0
* @experimental This feature is in experimental phase, it will be fully released in v3001.1.0
*/
spriteAtlasPadding?: number;
}

/**
Expand Down

0 comments on commit fd5fb6d

Please sign in to comment.