Image data c api
This commit is contained in:
parent
b47fbca76d
commit
2484b82873
|
|
@ -1,3 +1,12 @@
|
|||
IndentWidth: 4
|
||||
ColumnLimit: 240
|
||||
PointerAlignment: Left
|
||||
PointerAlignment: Left
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortCompoundRequirementOnASingleLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: None
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
InsertBraces: true
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
uint8_t a;
|
||||
};
|
||||
uint32_t color;
|
||||
} image_pixel_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
image_pixel_t* pixels;
|
||||
} image_data_t;
|
||||
|
||||
image_data_t create_image(uint16_t width, uint16_t height);
|
||||
void free_image(image_data_t image);
|
||||
|
|
@ -16,9 +16,9 @@ void* malloc(size_t);
|
|||
void free(void*);
|
||||
void* realloc(void*, size_t);
|
||||
|
||||
void* memset(void* s, uint8_t c, uint32_t n);
|
||||
void* memcpy(void* dest, const void* src, uint32_t n);
|
||||
int memcmp(const void* s1, const void* s2, uint32_t n);
|
||||
void* memset(void* d, uint8_t c, size_t n);
|
||||
void* memcpy(void* dest, const void* src, size_t n);
|
||||
int memcmp(const void* s1, const void* s2, size_t n);
|
||||
|
||||
IMPORT(log) void printf(const char* format, ...);
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#include <stdlib.h>
|
||||
#include <image_data.h>
|
||||
|
||||
image_data_t create_image(uint16_t width, uint16_t height) {
|
||||
image_data_t data;
|
||||
data.width = width;
|
||||
data.height = height;
|
||||
size_t length = width * height * sizeof(image_pixel_t);
|
||||
data.pixels = (image_pixel_t*)malloc(length);
|
||||
|
||||
memset(data.pixels, 255, length);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void free_image(image_data_t image) {
|
||||
if (image.pixels) {
|
||||
free(image.pixels);
|
||||
}
|
||||
}
|
||||
|
|
@ -137,15 +137,15 @@ void* realloc(void* block, size_t size) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
void* memset(void* s, uint8_t c, uint32_t n) {
|
||||
uint8_t* p = (uint8_t*)s;
|
||||
void* memset(void* d, uint8_t c, size_t n) {
|
||||
uint8_t* p = (uint8_t*)d;
|
||||
while (n--) {
|
||||
*p++ = c;
|
||||
}
|
||||
return s;
|
||||
return d;
|
||||
}
|
||||
|
||||
void* memcpy(void* dest, const void* src, uint32_t n) {
|
||||
void* memcpy(void* dest, const void* src, size_t n) {
|
||||
uint8_t* d = (uint8_t*)dest;
|
||||
const uint8_t* s = (const uint8_t*)src;
|
||||
while (n--) {
|
||||
|
|
@ -154,7 +154,7 @@ void* memcpy(void* dest, const void* src, uint32_t n) {
|
|||
return dest;
|
||||
}
|
||||
|
||||
int memcmp(const void* s1, const void* s2, uint32_t n) {
|
||||
int memcmp(const void* s1, const void* s2, size_t n) {
|
||||
const uint8_t* p1 = (const uint8_t*)s1;
|
||||
const uint8_t* p2 = (const uint8_t*)s2;
|
||||
|
||||
|
|
@ -83,9 +83,11 @@ const wasmPlugin = ({ production, portable }: WasmLoaderConfig = {}): BunPlugin
|
|||
wasmPath = args.path;
|
||||
} else {
|
||||
const buildAssets = path.resolve(import.meta.dir, 'assets');
|
||||
const stdlib = `${buildAssets}/stdlib.c`;
|
||||
const include = `${buildAssets}/include`;
|
||||
const glob = new Bun.Glob(`${buildAssets}/lib/**/*.c`);
|
||||
const stdlib = await Array.fromAsync(glob.scan());
|
||||
const opt = production ? '-O3' : '-O0';
|
||||
const result = await $`clang --target=wasm32 ${opt} -flto -fno-builtin --no-standard-libraries -I ${buildAssets} -Wall -Wextra -Wpedantic -Werror -Wl,--lto-O3 -Wl,--no-entry -Wl,--import-memory -o ${wasmPath} ${args.path} ${stdlib}`;
|
||||
const result = await $`clang --target=wasm32 ${opt} -flto -fno-builtin --no-standard-libraries -I ${include} -Wall -Wextra -Wpedantic -Werror -Wl,--lto-O3 -Wl,--no-entry -Wl,--import-memory -o ${wasmPath} ${args.path} ${stdlib}`;
|
||||
|
||||
if (result.exitCode !== 0) {
|
||||
throw new Error('Compile failed, check output');
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
--target=wasm32
|
||||
--target=wasm32
|
||||
-fno-builtin
|
||||
--no-standard-libraries
|
||||
-I
|
||||
build/assets/
|
||||
build/assets/include
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wpedantic
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
import type { HTMLAttributes } from "preact/compat";
|
||||
import { useEffect, useMemo, useRef } from "preact/hooks";
|
||||
|
||||
interface Props extends HTMLAttributes<HTMLCanvasElement> {
|
||||
dataView: DataView;
|
||||
pointer: number;
|
||||
}
|
||||
|
||||
export const PointerCanvas = ({ dataView, pointer, ...otherProps }: Props) => {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const ctx = useMemo(() => canvasRef.current?.getContext('2d'), [canvasRef.current]);
|
||||
|
||||
const imageData = useMemo(() => loadImageData(dataView, pointer), [dataView, pointer]);
|
||||
|
||||
useEffect(() => {
|
||||
if (canvasRef.current) {
|
||||
canvasRef.current.width = imageData.width;
|
||||
canvasRef.current.height = imageData.height;
|
||||
}
|
||||
}, [imageData, canvasRef.current]);
|
||||
|
||||
useEffect(() => {
|
||||
let raf: number;
|
||||
const frame = () => {
|
||||
if (ctx) {
|
||||
ctx.putImageData(imageData, 0, 0);
|
||||
}
|
||||
raf = requestAnimationFrame(frame);
|
||||
}
|
||||
raf = requestAnimationFrame(frame);
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(raf);
|
||||
};
|
||||
}, [ctx, imageData]);
|
||||
|
||||
return <>
|
||||
<canvas ref={canvasRef} {...otherProps} />
|
||||
</>;
|
||||
};
|
||||
|
||||
export const loadImageData = (dataView: DataView, pointer: number) => {
|
||||
const width = dataView.getUint16(pointer + 0, true);
|
||||
const height = dataView.getUint16(pointer + 2, true);
|
||||
|
||||
const dataPtr = dataView.getUint32(pointer + 4, true);
|
||||
const imageBuffer = new Uint8ClampedArray(dataView.buffer, dataPtr, width * height * 4);
|
||||
const imageData = new ImageData(imageBuffer, width, height);
|
||||
|
||||
return imageData;
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import type { ComponentChildren } from "preact";
|
||||
import { useCallback, useEffect, useRef } from "preact/hooks";
|
||||
|
||||
import styles from './modal.module.css';
|
||||
import styles from './Modal.module.css';
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { useCallback, useContext, useEffect, useMemo, useState } from "preact/hooks";
|
||||
import { useBool } from "@common/hooks/useBool";
|
||||
import { Modal } from "@common/components/modal/modal";
|
||||
import { Modal } from "@common/components/modal/Modal";
|
||||
|
||||
import { StateContext } from "../../contexts/state";
|
||||
import { LLMContext } from "../../contexts/llm";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { MessageTools, type IMessage } from "../../tools/messages"
|
||||
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||
import { Modal } from "@common/components/modal/modal";
|
||||
import { Modal } from "@common/components/modal/Modal";
|
||||
import { DOMTools } from "../../tools/dom";
|
||||
|
||||
import styles from './minichat.module.css';
|
||||
|
|
|
|||
|
|
@ -1,21 +1,18 @@
|
|||
import { createCanvas } from "@common/display/canvas";
|
||||
import life from "./life.c";
|
||||
import { loadImageData } from "@common/components/PointerCanvas";
|
||||
|
||||
const width = life.getWidth();
|
||||
const height = life.getHeight();
|
||||
|
||||
const canvas = createCanvas(width, height);
|
||||
const context = canvas.getContext('2d')!;
|
||||
let context: CanvasRenderingContext2D | null;
|
||||
let imageData: ImageData;
|
||||
|
||||
const step = life.step as CallableFunction;
|
||||
|
||||
export default function main() {
|
||||
const pixelsPtr = life.initField();
|
||||
const pixels = new Uint8ClampedArray(life.memory.buffer, pixelsPtr, width * height * 4);
|
||||
imageData = new ImageData(pixels, width, height);
|
||||
const imageDataPtr = life.initField();
|
||||
imageData = loadImageData(life.data, imageDataPtr);
|
||||
|
||||
console.log(life, pixels.length);
|
||||
const canvas = createCanvas(imageData.width, imageData.height);
|
||||
context = canvas.getContext('2d');
|
||||
|
||||
console.log(life, imageData);
|
||||
|
||||
requestAnimationFrame(loop);
|
||||
}
|
||||
|
|
@ -26,16 +23,16 @@ let count = 0;
|
|||
async function loop() {
|
||||
const start = performance.now();
|
||||
|
||||
step();
|
||||
life.step();
|
||||
|
||||
context.putImageData(imageData, 0, 0);
|
||||
context.clearRect(0, 0, 35, 15);
|
||||
context?.putImageData(imageData, 0, 0);
|
||||
context?.clearRect(0, 0, 35, 15);
|
||||
|
||||
const end = performance.now();
|
||||
|
||||
sum += end - start;
|
||||
count++;
|
||||
|
||||
context.fillText(`${(sum / count).toFixed(1)} ms`, 2, 10);
|
||||
context?.fillText(`${(sum / count).toFixed(1)} ms`, 2, 10);
|
||||
requestAnimationFrame(loop);
|
||||
}
|
||||
|
|
@ -1,63 +1,54 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <image_data.h>
|
||||
|
||||
#define width 512
|
||||
#define height 512
|
||||
#define WIDTH 512
|
||||
#define HEIGHT 512
|
||||
|
||||
static uint8_t* field;
|
||||
static uint8_t* nextField;
|
||||
static uint8_t* pixels;
|
||||
static uint8_t* next_field;
|
||||
static image_data_t image_data;
|
||||
|
||||
static int countNeighbours(int x, int y);
|
||||
|
||||
EXPORT(getWidth) int get_width(void) { return width; }
|
||||
EXPORT(getHeight) int get_height(void) { return height; }
|
||||
static int count_neighbours(int x, int y);
|
||||
|
||||
EXPORT(step) void step(void) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int count = countNeighbours(x, y);
|
||||
uint8_t currentCell = field[x + y * width];
|
||||
int nextCell = currentCell;
|
||||
if (currentCell && count < 2)
|
||||
nextCell = 0;
|
||||
else if (currentCell && count > 3)
|
||||
nextCell = 0;
|
||||
else if (!currentCell && count == 3)
|
||||
nextCell = 1;
|
||||
for (int y = 0; y < HEIGHT; y++) {
|
||||
for (int x = 0; x < WIDTH; x++) {
|
||||
int count = count_neighbours(x, y);
|
||||
uint8_t current_cell = field[x + y * WIDTH];
|
||||
int next_cell = current_cell;
|
||||
if (current_cell && count < 2)
|
||||
next_cell = 0;
|
||||
else if (current_cell && count > 3)
|
||||
next_cell = 0;
|
||||
else if (!current_cell && count == 3)
|
||||
next_cell = 1;
|
||||
|
||||
nextField[x + y * width] = nextCell;
|
||||
next_field[x + y * WIDTH] = next_cell;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
field[i] = nextField[i];
|
||||
uint8_t px = field[i];
|
||||
for (int i = 0; i < WIDTH * HEIGHT; i++) {
|
||||
field[i] = next_field[i];
|
||||
uint8_t px = (!field[i]) * 255;
|
||||
|
||||
if (px) {
|
||||
pixels[(i << 2) + 0] = 0;
|
||||
pixels[(i << 2) + 1] = 0;
|
||||
pixels[(i << 2) + 2] = 0;
|
||||
} else {
|
||||
pixels[(i << 2) + 0] = 255;
|
||||
pixels[(i << 2) + 1] = 255;
|
||||
pixels[(i << 2) + 2] = 255;
|
||||
}
|
||||
pixels[(i << 2) + 3] = 255;
|
||||
image_data.pixels[i].r = px;
|
||||
image_data.pixels[i].g = px;
|
||||
image_data.pixels[i].b = px;
|
||||
}
|
||||
}
|
||||
|
||||
static int countNeighbours(int x, int y) {
|
||||
static int count_neighbours(int x, int y) {
|
||||
int count = 0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
if (i == 0 && j == 0)
|
||||
continue;
|
||||
|
||||
int xx = (x + i + width) % width;
|
||||
int yy = (y + j + height) % height;
|
||||
int xx = (x + i + WIDTH) % WIDTH;
|
||||
int yy = (y + j + HEIGHT) % HEIGHT;
|
||||
|
||||
if (field[xx + yy * width]) {
|
||||
if (field[xx + yy * WIDTH]) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
|
@ -66,14 +57,14 @@ static int countNeighbours(int x, int y) {
|
|||
}
|
||||
|
||||
|
||||
EXPORT(initField) uint8_t* init_field(void) {
|
||||
field = malloc(width * height);
|
||||
nextField = malloc(width * height);
|
||||
pixels = malloc(width * height * 4);
|
||||
EXPORT(initField) image_data_t* init_field(void) {
|
||||
field = malloc(WIDTH * HEIGHT);
|
||||
next_field = malloc(WIDTH * HEIGHT);
|
||||
image_data = create_image(WIDTH, HEIGHT);
|
||||
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
for (int i = 0; i < WIDTH * HEIGHT; i++) {
|
||||
field[i] = rand() & 1;
|
||||
}
|
||||
|
||||
return pixels;
|
||||
return &image_data;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue