From f09c196d762f96f00e33570ac994d128ac51f0f1 Mon Sep 17 00:00:00 2001 From: Micah Galizia Date: Tue, 21 Jan 2025 21:47:09 -0500 Subject: [PATCH] feat: work towards drawables --- packages/common/src/tokeninstance.ts | 5 ++- .../mui/src/middleware/ContentMiddleware.ts | 5 +++ packages/mui/src/reducers/ContentReducer.ts | 8 +++- packages/mui/src/utils/contentworker.ts | 20 +++++++--- packages/mui/src/utils/drawing.ts | 40 ++++++++++++++----- packages/mui/src/utils/tokens.ts | 13 ++++++ 6 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 packages/mui/src/utils/tokens.ts diff --git a/packages/common/src/tokeninstance.ts b/packages/common/src/tokeninstance.ts index 5ca4531..5467964 100644 --- a/packages/common/src/tokeninstance.ts +++ b/packages/common/src/tokeninstance.ts @@ -2,7 +2,7 @@ * IMPORTANT: Do not change the interfaces in this file without also reviewing the corresponding * mongoose models and (if applicable) omitting/redefining the types. */ -import { Token } from "./token"; +import { HydratedToken, Token } from "./token"; /** * Token placement properties without knowing the scene details @@ -18,6 +18,7 @@ export interface TokenInstance extends ScenelessTokenInstance{ scene: string; } +// TODO remove "scene" from this interface since once hydrated we know which scene its from export interface HydratedTokenInstance extends Omit { - "token": string; + "token": string; // technically an url not an object id } \ No newline at end of file diff --git a/packages/mui/src/middleware/ContentMiddleware.ts b/packages/mui/src/middleware/ContentMiddleware.ts index eb99030..0bceb2c 100644 --- a/packages/mui/src/middleware/ContentMiddleware.ts +++ b/packages/mui/src/middleware/ContentMiddleware.ts @@ -213,6 +213,11 @@ export const ContentMiddleware: Middleware = return next(action); } + if (!state.content.mediaPrefix) { + // I suppose when we use R2 or S3, this will be different (and likely from the environment config) + next({ type: "content/mediaprefix", payload: state.environment.api }); + } + switch (action.type) { case "content/updatetoken": { operate(state, store, next, "put", "token", action); diff --git a/packages/mui/src/reducers/ContentReducer.ts b/packages/mui/src/reducers/ContentReducer.ts index b848c2f..b051e27 100644 --- a/packages/mui/src/reducers/ContentReducer.ts +++ b/packages/mui/src/reducers/ContentReducer.ts @@ -20,6 +20,7 @@ export type ContentReducerError = { }; export type ContentReducerState = { + readonly mediaPrefix?: string; readonly pushTime: number | undefined; readonly currentScene?: Scene; readonly scenes: Scene[]; @@ -39,6 +40,8 @@ const initialState: ContentReducerState = { export const ContentReducer = (state = initialState, action: PayloadAction) => { switch (action.type) { + case "content/mediaprefix": + return { ...state, mediaPrefix: action.payload as unknown as string }; case "content/push": return { ...state, pushTime: new Date().getTime() }; case "content/pull": { @@ -169,7 +172,10 @@ export const ContentReducer = (state = initialState, action: PayloadAction) => { ); continue; } - hydrated.push({ ...instance, token: asset.location }); + hydrated.push({ + ...instance, + token: `${state.mediaPrefix}/${asset.location}`, + }); } scenes[idx] = { ...scenes[idx], tokens: hydrated }; diff --git a/packages/mui/src/utils/contentworker.ts b/packages/mui/src/utils/contentworker.ts index c0dc90a..b55cd12 100644 --- a/packages/mui/src/utils/contentworker.ts +++ b/packages/mui/src/utils/contentworker.ts @@ -21,10 +21,11 @@ import { adjustTokenDimensions, } from "./geometry"; import { - HydratedToken, + HydratedTokenInstance, Rect, ScenelessTokenInstance, } from "@micahg/tbltp-common"; +import { fromHydratedToken } from "./tokens"; /** * Worker for offscreen drawing in the content editor. @@ -47,7 +48,7 @@ let _max_zoom: number; let _first_zoom_step: number; let _things_on_top_of_overlay = false; let _default_token: ImageBitmap; -let _token: HydratedToken | undefined = undefined; +let _token: HydratedTokenInstance | undefined = undefined; // canvas width and height (sent from main thread) const _canvas: Rect = { x: 0, y: 0, width: 0, height: 0 }; @@ -331,6 +332,8 @@ function eraseBrush(x: number, y: number, radius: number) { function renderToken(x: number, y: number, full = true) { if (!full) { overlayCtx.save(); + if (_token) [_token.x, _token.y] = [x, y]; + // may be best to not translate since we're scaling overlayCtx.translate(-_token_dw / 2, -_token_dh / 2); overlayCtx.drawImage( @@ -559,7 +562,7 @@ async function updateThings( const promises: Promise[] = []; for (const thing of things.filter((thing) => thing)) { - promises.push(createDrawable(thing, apiUrl, bearer)); + promises.push(createDrawable(thing, bearer)); } let drawables: Drawable[]; try { @@ -771,8 +774,15 @@ self.onmessage = async (evt) => { } case "set_token": { if ("token" in evt.data && "bearer" in evt.data) { - _token = evt.data.token; - const location = _token?.asset?.location; + // hiMicah(); + // _token = evt.data.token; // HydratedToken + // const hydrated = fromHydratedToken(evt.data.token); + // console.log(hydrated); + _token = fromHydratedToken(evt.data.token); + const dt = await createDrawable(_token, evt.data.bearer); + console.log(dt); + // const d = createDrawable(_token, evt.data.bearer); + const location = _token.token; if (location) { loadImage(location, evt.data.bearer) .then((img) => setToken(img)) diff --git a/packages/mui/src/utils/drawing.ts b/packages/mui/src/utils/drawing.ts index 5729451..e353e66 100644 --- a/packages/mui/src/utils/drawing.ts +++ b/packages/mui/src/utils/drawing.ts @@ -1,3 +1,9 @@ +/** + * FOR TESTING THE MAIN SCENE IS 66106a4b867826e1074c9476 + * to remove from the other scene: + * db.tokeninstances.remove({scene: ObjectId("66106a6e867826e1074c9484")}) + */ + import { Rect, HydratedTokenInstance } from "@micahg/tbltp-common"; import { loadImage } from "./content"; @@ -18,6 +24,8 @@ type BitmapCache = { [key: string]: ImageBitmap; }; +let DEFAULT_TOIKEN: ImageBitmap; + const cache: BitmapCache = {}; export function isRect(d: unknown): d is Rect { @@ -55,12 +63,11 @@ export type Marker = { export async function createDrawable( d: T, - apiUrl: string, bearer: string, ): Promise { if (isRect(d)) return new DrawableSelectedRegion(d); if (isHydratedTokenInstnace(d)) { - const img = await cacheTokenImage(apiUrl, d.token, bearer); + const img = await cacheTokenImage(d.token, bearer); return new DrawableToken(d, img); } throw new TypeError("Invalid Drawable"); @@ -96,15 +103,11 @@ class DrawableSelectedRegion implements Drawable { } // TODO try with bad link and see what happens before merging - ideally fallack to X -async function cacheTokenImage( - apiUrl: string, - location: string, - bearer: string, -) { +async function cacheTokenImage(location: string, bearer: string) { if (location in cache) return cache[location]; console.warn(`Cache miss for token ${location}`); - const url = `${apiUrl}/${location}`; - const img = await loadImage(url, bearer); + + const img = await loadImage(location || "/x.webp", bearer); cache[location] = img; return img; } @@ -116,6 +119,25 @@ class DrawableToken implements Drawable { this.token = token; this.img = img; } + place(ctx: DrawContext) { + // TODO: don't draw if not in region + const [_token_dw, _token_dh] = [this.img.width, this.img.height]; + ctx.translate(-_token_dw / 2, -_token_dh / 2); + ctx.drawImage( + this.img, + // source (should always just be source dimensions) + 0, + 0, + this.img.width, + this.img.height, + // destination (adjust according to scale) + this.token.x, + this.token.y, + _token_dw, + _token_dh, + ); + } + draw(ctx: DrawContext) { // TODO: don't draw if not in region const [_token_dw, _token_dh] = [this.img.width, this.img.height]; diff --git a/packages/mui/src/utils/tokens.ts b/packages/mui/src/utils/tokens.ts new file mode 100644 index 0000000..8a1f177 --- /dev/null +++ b/packages/mui/src/utils/tokens.ts @@ -0,0 +1,13 @@ +import { HydratedToken, HydratedTokenInstance } from "@micahg/tbltp-common"; + +export function fromHydratedToken(d: HydratedToken): HydratedTokenInstance { + return { + name: d.name, + visible: false, + token: d.asset?.location || "", + scene: "", + x: 0, + y: 0, + scale: 1, + }; +}