Skip to content

Commit

Permalink
Add Canvas.loadFontRaw and Surface.fromRaw (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
littledivy committed Aug 31, 2024
1 parent bb4bd3e commit 25a431f
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 30 deletions.
12 changes: 12 additions & 0 deletions client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
if (
typeof WorkerGlobalScope === "undefined" ||
!(self instanceof WorkerGlobalScope)
) {
const selfPath = new URL(import.meta.url).pathname;
const worker = new Worker(`file://${selfPath}`, { type: "module" });
} else {
const ws = new WebSocket("ws://localhost:1234");
self.onmessage = (event) => {
ws.send(event.data);
};
}
Empty file added examples/sprite/client.ts
Empty file.
79 changes: 57 additions & 22 deletions examples/sprite/main.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { EventType, Rect, Surface, WindowBuilder } from "../../mod.ts";
import { drawMap, sleepSync, Sprite } from "./util.ts";
import { drawMap, Sprite } from "./util.ts";

const canvasSize = { width: 400, height: 400 };
function sleepSync(ms: number) {
const start = Date.now();
while (true) {
if (Date.now() - start > ms) {
break;
}
}
}

const canvasSize = { width: 1000, height: 800 };
const window = new WindowBuilder(
"Hello, Deno!",
canvasSize.width,
Expand All @@ -15,14 +24,22 @@ const creator = canv.textureCreator();
const texture = creator.createTextureFromSurface(surface);

const map = [
[8, 8, 9, 8, 11, 8, 8, 8],
[8, 8, 8, 8, 8, 8, 8, 8],
[8, 10, 8, 8, 8, 8, 8, 8],
[8, 8, 8, 8, 8, 8, 8, 8],
[8, 8, 8, 8, 8, 8, 10, 8],
[8, 8, 8, 8, 8, 9, 8, 8],
[10, 8, 8, 8, 8, 8, 8, 8],
[8, 8, 11, 8, 8, 8, 8, 8],
[8, 8, 9, 8, 11, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8],
[8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 8, 8, 8, 8],
[8, 10, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 8, 8],
[8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 8, 8, 8],
[8, 8, 8, 8, 8, 8, 10, 8, 8, 8, 8, 8, 8, 8, 8],
[8, 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8],
[10, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 8, 8, 8, 8],
[8, 8, 11, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 8],
[8, 8, 9, 8, 11, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8],
[8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 8, 8, 8, 8],
[8, 10, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 8, 8],
[8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 8, 8, 8],
[8, 8, 8, 8, 8, 8, 10, 8, 8, 8, 8, 8, 8, 8, 8],
[8, 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8],
[10, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 8, 8, 8, 8],
[8, 8, 11, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 8],
];

const denoTextureFrames = [
Expand Down Expand Up @@ -52,33 +69,31 @@ function createShadowInstance() {
return shadow;
}

function createDenoInstance() {
function createDenoInstance(id) {
const deno = new Sprite(texture, denoTextureFrames);
deno.x = random(0, canvasSize.width);
deno.y = random(0, canvasSize.height);
deno.originX = deno.frames[0].width / 2;
deno.originY = deno.frames[0].height;
deno.scale = 4;
deno.vx = 2;
deno.vy = 1;
deno.vx = 0;
deno.vy = 0;
deno.id = id || 0;
return deno;
}

const denos: Sprite[] = [];

for (let i = 0; i < 1; i++) {
denos.push(createDenoInstance());
}

const self = createDenoInstance();
const shadow = createShadowInstance();

let cnt = 0;
let mouse = { x: 0, y: 0 };

function frame() {
function frame(e) {
canv.clear();
drawMap(texture, canv, map, 16);
const tiles = drawMap(texture, canv, map, 16);

for (const deno of denos) {
for (const deno of [...denos, self]) {
deno.tick();
shadow.draw(canv);
deno.draw(canv);
Expand Down Expand Up @@ -111,10 +126,26 @@ function frame() {
}
}

cnt++;
deno.vx = (mouse.x - deno.x) / 100;
deno.vy = (mouse.y - deno.y) / 100;

// check for collision with tiles on map
for (const tile of tiles) {
if (
deno.x < tile.x + tile.width &&
deno.x + deno.frames[0].width * deno.scale > tile.x &&
deno.y < tile.y + tile.height &&
deno.y + deno.frames[0].height * deno.scale > tile.y
) {
deno.x -= deno.vx;
deno.y -= deno.vy;
}
}
}

cnt++;
canv.present();

sleepSync(10);
}

Expand All @@ -126,6 +157,10 @@ for await (const event of window.events()) {
case EventType.Quit:
Deno.exit(0);
break;
case EventType.MouseMotion:
mouse.x = event.x;
mouse.y = event.y;
break;
default:
break;
}
Expand Down
13 changes: 6 additions & 7 deletions examples/sprite/util.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import { Canvas, Rect, Texture } from "../../mod.ts";

export function sleepSync(timeout: number) {
const sab = new SharedArrayBuffer(1024);
const int32 = new Int32Array(sab);
Atomics.wait(int32, 0, 0, timeout);
}

export interface Area {
x: number;
y: number;
Expand All @@ -18,7 +12,8 @@ export function drawMap(
canvas: Canvas,
map: number[][],
chipSize: number,
) {
): Rect[] {
const frames: Rect[] = [];
for (let i = 0; i < map.length; i++) {
for (let j = 0; j < map[i].length; j++) {
const chip = map[i][j];
Expand All @@ -34,13 +29,17 @@ export function drawMap(
chipSize * 4,
chipSize * 4,
);
// 9 = cactus
// 8 = normal tile
if (chip === 9) frames.push(dst);
canvas.copy(
texture,
src,
dst,
);
}
}
return frames;
}

export class Sprite {
Expand Down
56 changes: 55 additions & 1 deletion mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,10 @@ const sdl2 = Deno.dlopen(getLibraryPath("SDL2"), {
"parameters": [],
"result": "i32",
},
"SDL_RWFromMem": {
"parameters": ["buffer", "i32"],
"result": "pointer",
},
});

const SDL2_Image_symbols = {
Expand All @@ -297,6 +301,10 @@ const SDL2_Image_symbols = {
"parameters": ["buffer"],
"result": "pointer",
},
"IMG_Load_RW": {
"parameters": ["pointer"],
"result": "pointer",
},
} as const;

const SDL2_TTF_symbols = {
Expand All @@ -308,6 +316,10 @@ const SDL2_TTF_symbols = {
"parameters": ["buffer", "i32"],
"result": "pointer",
},
"TTF_OpenFontRW": {
"parameters": ["pointer", "i32", "i32"],
"result": "pointer",
},
"TTF_RenderText_Solid": {
"parameters": ["pointer", "buffer", "pointer"],
"result": "pointer",
Expand Down Expand Up @@ -410,6 +422,7 @@ function init() {
}

init();

/**
* An enum that contains structures for the different event types.
*/
Expand Down Expand Up @@ -486,6 +499,15 @@ export class Canvas {
private target: Deno.PointerValue,
) {}

serialize(): ArrayBuffer {
return new BigUint64Array([Deno.UnsafePointer.value(this.target)]).buffer;
}

static deserialize(data: ArrayBuffer): Canvas {
const [ptr] = new BigUint64Array(data);
return new Canvas(null!, Deno.UnsafePointer.create(ptr));
}

/**
* Set the color used for drawing operations (Rect, Line and Clear).
* @param r the red value used to draw on the rendering target
Expand Down Expand Up @@ -679,6 +701,18 @@ export class Canvas {
const raw = sdl2Font.symbols.TTF_OpenFont(asCString(path), size);
return new Font(raw);
}

loadFontRaw(data: Uint8Array, size: number): Font {
const rwops = sdl2.symbols.SDL_RWFromMem(data, data.byteLength);
if (rwops === null) {
throwSDLError();
}
const raw = sdl2Font.symbols.TTF_OpenFontRW(rwops, 1, size);
if (raw === null) {
throwSDLError();
}
return new Font(raw);
}
}

/**
Expand Down Expand Up @@ -1015,6 +1049,20 @@ export class Surface {
}
return new Surface(raw);
}

static fromRaw(data: Uint8Array): Surface {
if (!sdl2Image) {
throw new Error("SDL2_image was not loaded");
}

const rwops = sdl2.symbols.SDL_RWFromMem(data, data.byteLength);
const raw = sdl2Image.symbols.IMG_Load_RW(rwops);
if (raw === null) {
throwSDLError();
}

return new Surface(raw);
}
}

const sizeOfEvent = 56; // type (u32) + event
Expand Down Expand Up @@ -1332,7 +1380,7 @@ export class Window {
/**
* Events from the window.
*/
*events(wait = false): Generator<any> {
async *events(wait = false): AsyncGenerator<any> {
while (true) {
const event = Deno.UnsafePointer.of(eventBuf);

Expand All @@ -1342,6 +1390,12 @@ export class Window {
const pending = (shouldWait
? sdl2.symbols.SDL_WaitEvent(event)
: sdl2.symbols.SDL_PollEvent(event)) == 1;
if (shouldWait) {
// Run microtasks.
await new Promise((resolve) =>
setTimeout(resolve, 0)
);
}
if (!pending) {
yield { type: EventType.Draw };
}
Expand Down

0 comments on commit 25a431f

Please sign in to comment.