Commit 46214c56 authored by Grant's avatar Grant
Browse files

Pixel pick on template (fixes #70)

parent 924815e6
Loading
Loading
Loading
Loading
+37 −3
Original line number Diff line number Diff line
@@ -7,10 +7,12 @@ import { ViewportMoveEvent } from "@sc07-canvas/lib/src/renderer/PanZoom";
import throttle from "lodash.throttle";
import { IPosition } from "@sc07-canvas/lib/src/net";
import { Template } from "./Templating/Template";
import { Template as TemplateCl } from "../lib/template";
import { IRouterData, Router } from "../lib/router";
import { KeybindManager } from "../lib/keybinds";
import { BlankOverlay } from "./Overlay/BlankOverlay";
import { HeatmapOverlay } from "./Overlay/HeatmapOverlay";
import { useTemplateContext } from "../contexts/TemplateContext";

export const CanvasWrapper = () => {
  const { config } = useAppContext();
@@ -65,6 +67,11 @@ const CanvasInner = () => {
  const canvas = useRef<Canvas>();
  const { config, setCanvasPosition, setCursor, setPixelWhois } =
    useAppContext();
  const {
    x: templateX,
    y: templateY,
    enable: templateEnable,
  } = useTemplateContext();
  const PanZoom = useContext(RendererContext);

  /**
@@ -129,6 +136,19 @@ const CanvasInner = () => {
    [canvas.current]
  );

  const getTemplatePixel = useCallback(
    (x: number, y: number) => {
      if (!templateEnable) return;
      if (x < templateX || y < templateY) return;

      x -= templateX;
      y -= templateY;

      return TemplateCl.instance.getPixel(x, y);
    },
    [templateX, templateY]
  );

  const handlePickPixel = useCallback(
    ({ clientX, clientY }: { clientX: number; clientY: number }) => {
      if (!canvas.current) {
@@ -141,13 +161,27 @@ const CanvasInner = () => {
      const [x, y] = canvas.current.screenToPos(clientX, clientY);
      if (!isCoordInCanvas(x, y)) return; // out of bounds

      const pixel = canvas.current.getPixel(x, y);
      if (!pixel) return;
      let pixelColor = -1;

      const templatePixel = getTemplatePixel(x, y);
      if (templatePixel) {
        pixelColor =
          canvas.current.Pallete.getColorFromHex(templatePixel.slice(1))?.id ||
          -1;
      }

      if (pixelColor === -1) {
        pixelColor = canvas.current.getPixel(x, y)?.color || -1;
      }

      if (pixelColor === -1) {
        return;
      }

      // no need to use canvas#setCursor as Palette.tsx already does that
      setCursor((v) => ({
        ...v,
        color: pixel.color,
        color: pixelColor,
      }));
    },
    [canvas.current]
+57 −2
Original line number Diff line number Diff line
import EventEmitter from "eventemitter3";
import { WebGLUtils } from "./webgl";
import { ClientConfig } from "@sc07-canvas/lib/src/net";
import { rgbToHex } from "./utils";

interface TemplateEvents {
  updateImageURL(url: string | undefined): void;
@@ -28,6 +29,8 @@ enum TemplateStyle {
}

export class Template extends EventEmitter<TemplateEvents> {
  static instance: Template;

  config: ClientConfig;

  $wrapper: HTMLDivElement;
@@ -43,9 +46,10 @@ export class Template extends EventEmitter<TemplateEvents> {

  constructor(config: ClientConfig, templateHolder: HTMLDivElement) {
    super();
    Template.instance = this;
    this.config = config;

    console.log("template init", config, templateHolder);
    console.log("[Template] Initialize", config, templateHolder);

    this.$wrapper = templateHolder;

@@ -53,7 +57,7 @@ export class Template extends EventEmitter<TemplateEvents> {
    this.$imageLoader.style.setProperty("display", "none");
    this.$imageLoader.setAttribute("crossorigin", "");
    this.$imageLoader.addEventListener("load", () => {
      console.log("imageLoader loaded image");
      console.log("[Template] Image loaded");
      if (!this.options.width) {
        this.setOption("width", this.$imageLoader.naturalWidth);
        this.emit("autoDetectWidth", this.$imageLoader.naturalWidth);
@@ -115,6 +119,57 @@ export class Template extends EventEmitter<TemplateEvents> {
    }
  }

  getPixel(x: number, y: number): string | undefined {
    if (!this.context) {
      console.warn("[Template#getPixel] No context is available");
      return undefined;
    }

    const width = this.context.drawingBufferWidth;
    const height = this.context.drawingBufferHeight;

    const arr = new Uint8Array(4 * width * height);
    this.context.bindFramebuffer(
      this.context.FRAMEBUFFER,
      this.framebuffers.intermediate
    );

    if (x < 0 || y < 0 || x > width || y > height) {
      return undefined;
    }

    this.context.readPixels(
      0,
      0,
      width,
      height,
      this.context.RGBA,
      this.context.UNSIGNED_BYTE,
      arr
    );
    this.context.bindFramebuffer(
      this.context.FRAMEBUFFER,
      this.framebuffers.main
    );

    const pixels = new Uint8Array(4 * width * height);
    const length = width * height * 4;
    const row = width * 4;
    const end = (height - 1) * row;
    for (let i = 0; i < length; i += row) {
      pixels.set(arr.subarray(i, i + row), end - i);
    }

    const [r, g, b, a] = pixels.slice(
      4 * (y * this.context.drawingBufferWidth + x),
      4 * (y * this.context.drawingBufferWidth + x) + 4
    );

    if (a === 254) return undefined;

    return rgbToHex(r, g, b);
  }

  rasterizeTemplate() {
    this.downscaleTemplate();
    this.stylizeTemplate();
+14 −0
Original line number Diff line number Diff line
@@ -17,6 +17,20 @@ export const getRenderer = (): Renderer => {

Debug._getRenderer = getRenderer;

export const rgbToHex = (r: number, g: number, b: number) => {
  function componentToHex(c: number) {
    var hex = c.toString(16);
    return hex.length == 1 ? "0" + hex : hex;
  }

  return (
    "#" +
    componentToHex(r) +
    componentToHex(g) +
    componentToHex(b)
  ).toUpperCase();
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const api = async <T = unknown, Error = string>(
  endpoint: string,