Skip to content

Commit

Permalink
feat: Strahd cursor
Browse files Browse the repository at this point in the history
  • Loading branch information
micahg committed Sep 2, 2024
1 parent c7991d8 commit 22568f8
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 3 deletions.
4 changes: 3 additions & 1 deletion packages/mui/src/components/ContentEditor/ContentEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,9 @@ const ContentEditor = ({
setCallback(sm, "record_mouse_wheel", (args) => {
if (
internalState.rec &&
(internalState.act === "erase" || internalState.act === "paint")
(internalState.act === "erase" ||
internalState.act === "paint" ||
internalState.act === "token")
) {
sm.transition("done");
const e: WheelEvent = args[0] as WheelEvent;
Expand Down
90 changes: 88 additions & 2 deletions packages/mui/src/utils/contentworker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
copyRect,
zoomFromViewport,
adjustImageToViewport,
adjustTokenDimensions,
} from "./geometry";
import { Rect } from "@micahg/tbltp-common";

Expand Down Expand Up @@ -72,6 +73,11 @@ let green = "0";
let blue = "0";
let brush = MIN_BRUSH;

let _token_dw = 0;
let _token_dh = 0;
const _token_delta = MIN_BRUSH;
let vamp: ImageBitmap;

function trimPanning() {
if (_img.x <= 0) _img.x = 0;
if (_img.y <= 0) _img.y = 0;
Expand Down Expand Up @@ -124,6 +130,30 @@ function renderImage(
ctx.restore();
}

function renderToken(x: number, y: number) {
overlayCtx.save();
// may be best to not translate since we're scaling
overlayCtx.translate(-vamp.width / 2, -vamp.height / 2);
overlayCtx.drawImage(
vamp,
// source (should always just be source dimensions)
0,
0,
vamp.width,
vamp.height,
// destination (adjust according to scale)
x,
y,
_token_dw,
_token_dh,
// vamp.width,
// vamp.height,
);

overlayCtx.restore();
return;
}

function calculateViewport() {
// REMEMBER THIS METHOD UPDATES THE _vp and the _img
adjustImageToViewport(
Expand All @@ -139,6 +169,18 @@ function calculateViewport() {
return;
}

function calculateToken(delta: number) {
[_token_dw, _token_dh] = adjustTokenDimensions(
delta,
vamp.width,
vamp.height,
_token_dw,
_token_dh,
overlayCtx.canvas.width,
overlayCtx.canvas.height,
);
}

/**
* Given a desired viewport, set our current viewport accordingly, set the zoom,
* and then center the request viewport within our screen, extending its short
Expand Down Expand Up @@ -400,6 +442,13 @@ function animateBrush() {
requestAnimationFrame(() => animateBrush());
}

function animateToken() {
if (!recording) return;
renderImage(overlayCtx, imageCanvasses, _angle);
renderToken(startX, startY);
requestAnimationFrame(() => animateToken());
}

function animateSelection() {
if (!recording) return;
if (selecting) {
Expand Down Expand Up @@ -477,6 +526,11 @@ async function update(values: TableUpdate) {
}

try {
try {
vamp = await loadImage("/vneven.png", values.bearer);
} catch (err) {
console.error(err);
}
const [bgImg, ovImg] = await loadAllImages(values);
if (!bgImg) return;

Expand Down Expand Up @@ -509,7 +563,7 @@ async function update(values: TableUpdate) {

// eslint-disable-next-line no-restricted-globals
self.onmessage = async (evt) => {
// console.log(evt.data.cmd);
console.log(evt.data.cmd);
switch (evt.data.cmd) {
case "init": {
// ensure the background canvas is valid
Expand Down Expand Up @@ -542,7 +596,6 @@ self.onmessage = async (evt) => {

// indicate if things should be rendered on top of the overlay
_things_on_top_of_overlay = !!evt.data.thingsOnTop;

break;
}
case "update": {
Expand Down Expand Up @@ -635,6 +688,36 @@ self.onmessage = async (evt) => {
}
break;
}
case "token": {
startX = evt.data.x;
startY = evt.data.y;
// here we do not turn recording on or off (thats handled by the move/record/end events elsewhere)
// also "recording" is not "painting" TODO MICAH COME BACK HERE AND CONFIRM ITS ABOUT CANVAS ANIMATION
// where we do not paint (painting is separate from drawing the selection or the translucent brush)
if (evt.data.buttons === 0) {
// here we don't draw BUT if you look at animateBrush, you'll see that we'll just repaint the
// overlay and then render the translucent brush
if (!recording) {
overlayCtx.fillStyle = GUIDE_FILL;
recording = true;
// _token_adjust = 0;
_token_dw = vamp.width;
_token_dh = vamp.height;
requestAnimationFrame(animateToken);
}
} else if (evt.data.buttons === 1) {
// here however we just update the canvas with the actual brush. It seems that the fill call
// in renderBrush will force the canvas to update so there isn't much point in using animation
// frames
if (recording) {
recording = false;
overlayCtx.fillStyle = `rgba(${red}, ${green}, ${blue}, ${opacity})`;
fullCtx.fillStyle = `rgba(${red}, ${green}, ${blue}, ${opacity})`;
}
renderBrush(evt.data.x, evt.data.y, brush);
}
break;
}
case "move":
case "select":
case "record": {
Expand Down Expand Up @@ -676,6 +759,7 @@ self.onmessage = async (evt) => {
case "end_paint": {
recording = false;
panning = false;
brush = MIN_BRUSH;
storeOverlay();
renderImage(overlayCtx, imageCanvasses, _angle);
break;
Expand Down Expand Up @@ -772,10 +856,12 @@ self.onmessage = async (evt) => {
break;
}
case "brush_inc": {
calculateToken(_token_delta);
brush += MIN_BRUSH;
break;
}
case "brush_dec": {
calculateToken(-_token_delta);
brush -= brush > MIN_BRUSH ? MIN_BRUSH : 0;
break;
}
Expand Down
35 changes: 35 additions & 0 deletions packages/mui/src/utils/geometry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,3 +318,38 @@ export function equalRects(r1: Rect, r2: Rect): boolean {
r1.height === r2.height
);
}

/**
* @param delta the how much to add (or subtract if negative) to the dimensions
* @param ow original (and minimum) width of token
* @param oh original (and minimum) height of token
* @param cw: current width of token
* @param ch: current height of token
* @param mw: max width
* @param mh: max height
* @return array (width and height) of two numbers
*/
export function adjustTokenDimensions(
delta: number,
ow: number,
oh: number,
cw: number,
ch: number,
mw: number,
mh: number,
): number[] {
let dh, dw;
if (ow > oh) {
dw = cw + delta;
dh = Math.round((dw * oh) / ow);
} else {
dh = ch + delta;
dw = Math.round((dh * ow) / oh);
}
// don't go passed that max width and height
if (dw < mw && dh < mh && dw >= ow && dh >= oh) {
cw = dw;
ch = dh;
}
return [cw, ch];
}

0 comments on commit 22568f8

Please sign in to comment.