-
Notifications
You must be signed in to change notification settings - Fork 0
feat: save and load state of the creator #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,16 +3,34 @@ import getDevice from 'WebGPU/getDevice' | |||||||||||||||||||||||||||||||||||||||||||
| import initPrograms from 'WebGPU/programs/initPrograms' | ||||||||||||||||||||||||||||||||||||||||||||
| import runCreator from 'run' | ||||||||||||||||||||||||||||||||||||||||||||
| import { createTextureFromSource } from 'WebGPU/getTexture' | ||||||||||||||||||||||||||||||||||||||||||||
| import clamp from 'utils/clamp' | ||||||||||||||||||||||||||||||||||||||||||||
| import { init_state, add_texture, ASSET_ID_TRESHOLD } from './logic/index.zig' | ||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||
| init_state, | ||||||||||||||||||||||||||||||||||||||||||||
| add_texture, | ||||||||||||||||||||||||||||||||||||||||||||
| connectOnAssetUpdateCallback, | ||||||||||||||||||||||||||||||||||||||||||||
| ASSET_ID_TRESHOLD, | ||||||||||||||||||||||||||||||||||||||||||||
| } from './logic/index.zig' | ||||||||||||||||||||||||||||||||||||||||||||
| import initMouseController from 'WebGPU/pointer' | ||||||||||||||||||||||||||||||||||||||||||||
| import getDefaultPoints from 'utils/getDefaultPoints' | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| export type SerializedAsset = Omit<Texture, 'texture_id'> & { | ||||||||||||||||||||||||||||||||||||||||||||
| url: string | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| export interface CreatorAPI { | ||||||||||||||||||||||||||||||||||||||||||||
| addImage: (id: number, img: HTMLImageElement) => void | ||||||||||||||||||||||||||||||||||||||||||||
| addImage: (id: number, img: HTMLImageElement, points?: PointUV[]) => void | ||||||||||||||||||||||||||||||||||||||||||||
| destroy: VoidFunction | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| export default async function initCreator(canvas: HTMLCanvasElement): Promise<CreatorAPI> { | ||||||||||||||||||||||||||||||||||||||||||||
| export interface TextureSource { | ||||||||||||||||||||||||||||||||||||||||||||
| url: string | ||||||||||||||||||||||||||||||||||||||||||||
| texture: GPUTexture | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| export default async function initCreator( | ||||||||||||||||||||||||||||||||||||||||||||
| canvas: HTMLCanvasElement, | ||||||||||||||||||||||||||||||||||||||||||||
| assets: SerializedAsset[], | ||||||||||||||||||||||||||||||||||||||||||||
| onAssetsUpdate: (assets: SerializedAsset[]) => void | ||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<CreatorAPI> { | ||||||||||||||||||||||||||||||||||||||||||||
| /* setup WebGPU stuff */ | ||||||||||||||||||||||||||||||||||||||||||||
| const device = await getDevice() | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -36,52 +54,48 @@ export default async function initCreator(canvas: HTMLCanvasElement): Promise<Cr | |||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| initMouseController(canvas) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const textures: GPUTexture[] = [] | ||||||||||||||||||||||||||||||||||||||||||||
| const textures: TextureSource[] = [] | ||||||||||||||||||||||||||||||||||||||||||||
| runCreator(canvas, context, device, presentationFormat, textures) | ||||||||||||||||||||||||||||||||||||||||||||
| connectOnAssetUpdateCallback((serializedData: Texture[]) => { | ||||||||||||||||||||||||||||||||||||||||||||
| const serializedAssetsTextureUrl = [...serializedData].map<SerializedAsset>((asset) => ({ | ||||||||||||||||||||||||||||||||||||||||||||
| id: asset.id, | ||||||||||||||||||||||||||||||||||||||||||||
| points: [...asset.points].map((point) => ({ | ||||||||||||||||||||||||||||||||||||||||||||
| x: point.x, | ||||||||||||||||||||||||||||||||||||||||||||
| y: point.y, | ||||||||||||||||||||||||||||||||||||||||||||
| u: point.u, | ||||||||||||||||||||||||||||||||||||||||||||
| v: point.v, | ||||||||||||||||||||||||||||||||||||||||||||
| })), | ||||||||||||||||||||||||||||||||||||||||||||
| url: textures[asset.texture_id].url, | ||||||||||||||||||||||||||||||||||||||||||||
| })) | ||||||||||||||||||||||||||||||||||||||||||||
| onAssetsUpdate(serializedAssetsTextureUrl) | ||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+59
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Simplify the deep copy of serialized data. The spread operators and map functions create unnecessary copies. Since you're transforming the data anyway, the explicit copying is redundant. -connectOnAssetUpdateCallback((serializedData: Texture[]) => {
- const serializedAssetsTextureUrl = [...serializedData].map<SerializedAsset>((asset) => ({
- id: asset.id,
- points: [...asset.points].map((point) => ({
- x: point.x,
- y: point.y,
- u: point.u,
- v: point.v,
- })),
- url: textures[asset.texture_id].url,
- }))
- onAssetsUpdate(serializedAssetsTextureUrl)
-})
+connectOnAssetUpdateCallback((serializedData: Texture[]) => {
+ const serializedAssetsTextureUrl = serializedData.map<SerializedAsset>((asset) => ({
+ id: asset.id,
+ points: asset.points,
+ url: textures[asset.texture_id].url,
+ }))
+ onAssetsUpdate(serializedAssetsTextureUrl)
+})📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||
| addImage: (id, img) => { | ||||||||||||||||||||||||||||||||||||||||||||
| if (id < ASSET_ID_TRESHOLD) { | ||||||||||||||||||||||||||||||||||||||||||||
| throw Error(`ID should be unique and not smaller than ${ASSET_ID_TRESHOLD}.`) | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| const newTextureIndex = textures.length | ||||||||||||||||||||||||||||||||||||||||||||
| textures.push(createTextureFromSource(device, img)) | ||||||||||||||||||||||||||||||||||||||||||||
| const scale = getDefaultTextureScale(img, canvas) | ||||||||||||||||||||||||||||||||||||||||||||
| const scaledWidth = img.width * scale | ||||||||||||||||||||||||||||||||||||||||||||
| const scaledHeight = img.height * scale | ||||||||||||||||||||||||||||||||||||||||||||
| const paddingX = (canvas.width - scaledWidth) * 0.5 | ||||||||||||||||||||||||||||||||||||||||||||
| const paddingY = (canvas.height - scaledHeight) * 0.5 | ||||||||||||||||||||||||||||||||||||||||||||
| function addImage(id: number, img: HTMLImageElement, points?: PointUV[]) { | ||||||||||||||||||||||||||||||||||||||||||||
| if (id < ASSET_ID_TRESHOLD) { | ||||||||||||||||||||||||||||||||||||||||||||
| throw Error(`ID should be unique and not smaller than ${ASSET_ID_TRESHOLD}.`) | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| const newTextureIndex = textures.length | ||||||||||||||||||||||||||||||||||||||||||||
| textures.push({ | ||||||||||||||||||||||||||||||||||||||||||||
| url: img.src, | ||||||||||||||||||||||||||||||||||||||||||||
| texture: createTextureFromSource(device, img), | ||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| add_texture( | ||||||||||||||||||||||||||||||||||||||||||||
| id, | ||||||||||||||||||||||||||||||||||||||||||||
| [ | ||||||||||||||||||||||||||||||||||||||||||||
| { x: paddingX, y: paddingY, u: 0, v: 0 }, | ||||||||||||||||||||||||||||||||||||||||||||
| { x: paddingX + scaledWidth, y: paddingY, u: 1, v: 0 }, | ||||||||||||||||||||||||||||||||||||||||||||
| { x: paddingX + scaledWidth, y: paddingY + scaledHeight, u: 1, v: 1 }, | ||||||||||||||||||||||||||||||||||||||||||||
| { x: paddingX, y: paddingY + scaledHeight, u: 0, v: 1 }, | ||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||
| newTextureIndex | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||
| add_texture(id, points || getDefaultPoints(img, canvas), newTextureIndex) | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| assets.forEach((asset) => { | ||||||||||||||||||||||||||||||||||||||||||||
| const img = new Image() | ||||||||||||||||||||||||||||||||||||||||||||
| img.src = asset.url | ||||||||||||||||||||||||||||||||||||||||||||
| img.onload = () => { | ||||||||||||||||||||||||||||||||||||||||||||
| addImage(asset.id, img, asset.points) | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+86
to
+92
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for image loading failures. If an image fails to load, the error is silently ignored, which could lead to missing assets without any indication to the user. assets.forEach((asset) => {
const img = new Image()
img.src = asset.url
img.onload = () => {
addImage(asset.id, img, asset.points)
}
+ img.onerror = (error) => {
+ console.error(`Failed to load asset ${asset.id} from ${asset.url}:`, error)
+ }
})📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||
| addImage, | ||||||||||||||||||||||||||||||||||||||||||||
| destroy: () => { | ||||||||||||||||||||||||||||||||||||||||||||
| context.unconfigure() | ||||||||||||||||||||||||||||||||||||||||||||
| device.destroy() | ||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||
| * Returns visualy pleasant size of texture, to make sure it doesn't overflow canvas but also is not too small to manipulate | ||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||
| function getDefaultTextureScale(img: HTMLImageElement, canvas: HTMLCanvasElement) { | ||||||||||||||||||||||||||||||||||||||||||||
| const heightDiff = canvas.height - img.height | ||||||||||||||||||||||||||||||||||||||||||||
| const widthDiff = canvas.width - img.width | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| if (heightDiff < widthDiff) { | ||||||||||||||||||||||||||||||||||||||||||||
| const height = clamp(img.height, canvas.height * 0.2, canvas.height * 0.8) | ||||||||||||||||||||||||||||||||||||||||||||
| return height / img.height | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const width = clamp(img.width, canvas.width * 0.2, canvas.width * 0.8) | ||||||||||||||||||||||||||||||||||||||||||||
| return width / img.width | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -6,8 +6,13 @@ interface PointUV { | |||||
| } | ||||||
|
|
||||||
| type ZigF32Array = { typedArray: Float32Array } | ||||||
| type Texture = { | ||||||
| id: number | ||||||
| points: PointUV[] | ||||||
| texture_id: number | ||||||
| } | ||||||
|
|
||||||
| declare module "*.zig" { | ||||||
| declare module '*.zig' { | ||||||
| export const ASSET_ID_TRESHOLD: number | ||||||
| export const init_state: (width: number, height: number) => void | ||||||
| export const add_texture: (id: number, points: PointUV[], textre_index: number) => void | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix the typo in the parameter name. The parameter -export const add_texture: (id: number, points: PointUV[], textre_index: number) => void
+export const add_texture: (id: number, points: PointUV[], texture_index: number) => void📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
|
|
@@ -24,6 +29,8 @@ declare module "*.zig" { | |||||
| draw_triangle: (vertexData: ZigF32Array) => void | ||||||
| pick_texture: (vertexData: ZigF32Array, texture_id: number) => void | ||||||
| }) => void | ||||||
| export const connectOnAssetUpdateCallback: (cb: (data: Texture[]) => void) => void | ||||||
|
|
||||||
| export const canvas_render: VoidFunction | ||||||
| export const picks_render: VoidFunction | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -18,6 +18,11 @@ pub fn connectWebGPUPrograms(programs: *const WebGpuPrograms) void { | |||||||||||||||||||||||||||||||||||||||||||||||
| web_gpu_programs = programs; // orelse WebGpuPrograms{}; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| var on_asset_update_cb: *const fn ([]Texture) void = undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||
| pub fn connectOnAssetUpdateCallback(cb: *const fn ([]Texture) void) void { | ||||||||||||||||||||||||||||||||||||||||||||||||
| on_asset_update_cb = cb; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+21
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Initialize the callback pointer to prevent undefined behavior. The Consider initializing with a no-op function or checking for undefined before calling: -var on_asset_update_cb: *const fn ([]Texture) void = undefined;
+var on_asset_update_cb: ?*const fn ([]Texture) void = null;Then update the invocation to check for null: -if (result.len > 0) {
- on_asset_update_cb(result);
-}
+if (result.len > 0 and on_asset_update_cb != null) {
+ on_asset_update_cb.?(result);
+}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| pub const ASSET_ID_TRESHOLD: u32 = 1000; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const ActionType = enum { | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -78,6 +83,18 @@ pub fn on_pointer_down(x: f32, y: f32) void { | |||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| pub fn on_pointer_up() void { | ||||||||||||||||||||||||||||||||||||||||||||||||
| state.ongoing_action = .none; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| var result = std.heap.page_allocator.alloc(Texture, state.assets.count()) catch unreachable; | ||||||||||||||||||||||||||||||||||||||||||||||||
| var iterator = state.assets.iterator(); | ||||||||||||||||||||||||||||||||||||||||||||||||
| var i: usize = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||
| while (iterator.next()) |entry| { | ||||||||||||||||||||||||||||||||||||||||||||||||
| result[i] = entry.value_ptr.*; | ||||||||||||||||||||||||||||||||||||||||||||||||
| i += 1; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (result.len > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| on_asset_update_cb(result); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+87
to
+97
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix memory leak - allocated array is never freed. The array allocated with Since the callback likely needs to process the data asynchronously, consider either:
For immediate fix, if the callback processes synchronously, add deallocation: if (result.len > 0) {
on_asset_update_cb(result);
}
+defer std.heap.page_allocator.free(result);However, this won't work if the callback stores the reference. Consider passing ownership to the JavaScript side or using a different memory management approach. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| pub fn on_pointer_move(x: f32, y: f32) void { | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,6 +3,7 @@ import { drawTexture, drawTriangle, pickTexture } from 'WebGPU/programs/initProg | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import getCanvasMatrix from 'getCanvasMatrix' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import PickManager from 'WebGPU/pick' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { canvas_render, picks_render, connectWebGPUPrograms } from 'logic/index.zig' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { TextureSource } from '.' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const transformMatrix = new Float32Array() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const MAP_BACKGROUND_SCALE = 1000 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -12,7 +13,7 @@ export default function runCreator( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| context: GPUCanvasContext, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| device: GPUDevice, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| presentationFormat: GPUTextureFormat, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| textures: GPUTexture[] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| textures: TextureSource[] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const canvasMatrix = getCanvasMatrix(canvas) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let canvasPass: GPURenderPassEncoder | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -22,12 +23,11 @@ export default function runCreator( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let pickPass: GPURenderPassEncoder | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| connectWebGPUPrograms({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| draw_texture: (vertex_data, texture_id) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| drawTexture(canvasPass, canvasMatrix, vertex_data.typedArray, textures[texture_id]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| draw_texture: (vertex_data, texture_id) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| drawTexture(canvasPass, canvasMatrix, vertex_data.typedArray, textures[texture_id].texture), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| draw_triangle: (vertex_data) => drawTriangle(canvasPass, canvasMatrix, vertex_data.typedArray), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pick_texture: (vertex_data, texture_id) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pickTexture(pickPass, pickMatrix, vertex_data.typedArray, textures[texture_id]), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pickTexture(pickPass, pickMatrix, vertex_data.typedArray, textures[texture_id].texture), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+26
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider adding bounds checking for texture array access. The code accesses Consider adding bounds validation: connectWebGPUPrograms({
draw_texture: (vertex_data, texture_id) => {
+ if (texture_id >= textures.length) {
+ console.error(`Invalid texture_id: ${texture_id}`)
+ return
+ }
drawTexture(canvasPass, canvasMatrix, vertex_data.typedArray, textures[texture_id].texture)
},
pick_texture: (vertex_data, texture_id) => {
+ if (texture_id >= textures.length) {
+ console.error(`Invalid texture_id: ${texture_id}`)
+ return
+ }
pickTexture(pickPass, pickMatrix, vertex_data.typedArray, textures[texture_id].texture)
},
})📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function draw(now: DOMHighResTimeStamp) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| import clamp from 'utils/clamp' | ||
|
|
||
| export default function getDefaultPoints( | ||
| img: HTMLImageElement, | ||
| canvas: HTMLCanvasElement | ||
| ): PointUV[] { | ||
| const scale = getDefaultTextureScale(img, canvas) | ||
| const scaledWidth = img.width * scale | ||
| const scaledHeight = img.height * scale | ||
| const paddingX = (canvas.width - scaledWidth) * 0.5 | ||
| const paddingY = (canvas.height - scaledHeight) * 0.5 | ||
|
|
||
| return [ | ||
| { x: paddingX, y: paddingY, u: 0, v: 0 }, | ||
| { x: paddingX + scaledWidth, y: paddingY, u: 1, v: 0 }, | ||
| { x: paddingX + scaledWidth, y: paddingY + scaledHeight, u: 1, v: 1 }, | ||
| { x: paddingX, y: paddingY + scaledHeight, u: 0, v: 1 }, | ||
| ] | ||
| } | ||
|
|
||
| /** | ||
| * Returns visualy pleasant size of texture, to make sure it doesn't overflow canvas but also is not too small to manipulate | ||
| */ | ||
| function getDefaultTextureScale(img: HTMLImageElement, canvas: HTMLCanvasElement) { | ||
| const heightDiff = canvas.height - img.height | ||
| const widthDiff = canvas.width - img.width | ||
|
|
||
| if (heightDiff < widthDiff) { | ||
| const height = clamp(img.height, canvas.height * 0.2, canvas.height * 0.8) | ||
| return height / img.height | ||
| } | ||
|
|
||
| const width = clamp(img.width, canvas.width * 0.2, canvas.width * 0.8) | ||
| return width / img.width | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.