import { Cache } from '../../../assets/cache/Cache.mjs';
import { ExtensionType } from '../../../extensions/Extensions.mjs';
import { BigPool } from '../../../utils/pool/PoolGroup.mjs';
import { GraphicsView } from '../../graphics/shared/GraphicsView.mjs';
import { ProxyRenderable } from '../../renderers/shared/ProxyRenderable.mjs';
import { SdfShader } from '../sdfShader/SdfShader.mjs';
import { BitmapFontManager } from './BitmapFontManager.mjs';
import { getBitmapTextLayout } from './utils/getBitmapTextLayout.mjs';

class GraphicsProxyRenderable extends ProxyRenderable {
  constructor() {
    super({
      view: new GraphicsView()
    });
  }
}
class BitmapTextPipe {
  constructor(renderer) {
    this._gpuBitmapText = {};
    this._renderer = renderer;
  }
  validateRenderable(renderable) {
    const graphicsRenderable = this._getGpuBitmapText(renderable);
    if (renderable.view._didUpdate) {
      renderable.view._didUpdate = false;
      this._updateContext(renderable, graphicsRenderable.view.context);
    }
    const rebuild = this._renderer.renderPipes.graphics.validateRenderable(graphicsRenderable);
    return rebuild;
  }
  addRenderable(renderable, instructionSet) {
    const graphicsRenderable = this._getGpuBitmapText(renderable);
    if (renderable.view._didUpdate) {
      renderable.view._didUpdate = false;
      this._updateContext(renderable, graphicsRenderable.view.context);
    }
    this._renderer.renderPipes.graphics.addRenderable(graphicsRenderable, instructionSet);
    if (graphicsRenderable.view.context.customShader) {
      this._updateDistanceField(renderable);
    }
  }
  destroyRenderable(renderable) {
    this._destroyRenderableByUid(renderable.uid);
  }
  _destroyRenderableByUid(renderableUid) {
    BigPool.return(this._gpuBitmapText[renderableUid]);
    this._gpuBitmapText[renderableUid] = null;
  }
  updateRenderable(renderable) {
    const graphicsRenderable = this._getGpuBitmapText(renderable);
    this._renderer.renderPipes.graphics.updateRenderable(graphicsRenderable);
    if (graphicsRenderable.view.context.customShader) {
      this._updateDistanceField(renderable);
    }
  }
  _updateContext(renderable, context) {
    const view = renderable.view;
    const bitmapFont = BitmapFontManager.getFont(view.text, view._style);
    context.clear();
    if (bitmapFont.distanceField.type !== "none") {
      if (!context.customShader) {
        if (!this._sdfShader) {
          this._sdfShader = new SdfShader();
        }
        context.customShader = this._sdfShader;
      }
    }
    const chars = Array.from(view.text);
    const style = view._style;
    let currentY = (style._stroke?.width || 0) / 2;
    currentY += bitmapFont.baseLineOffset;
    const bitmapTextLayout = getBitmapTextLayout(chars, style, bitmapFont);
    let index = 0;
    const padding = style.padding;
    const scale = bitmapTextLayout.scale;
    context.translate(
      -view.anchor._x * bitmapTextLayout.width - padding,
      -view.anchor._y * (bitmapTextLayout.height + bitmapTextLayout.offsetY) - padding
    ).scale(scale, scale);
    const tint = style._fill.color;
    for (let i = 0; i < bitmapTextLayout.lines.length; i++) {
      const line = bitmapTextLayout.lines[i];
      for (let j = 0; j < line.charPositions.length; j++) {
        const char = chars[index++];
        const charData = bitmapFont.chars[char];
        if (charData?.texture) {
          context.texture(
            charData.texture,
            tint,
            Math.round(line.charPositions[j] + charData.xOffset),
            Math.round(currentY + charData.yOffset)
          );
        }
      }
      currentY += bitmapFont.lineHeight;
    }
  }
  _getGpuBitmapText(renderable) {
    return this._gpuBitmapText[renderable.uid] || this._initGpuText(renderable);
  }
  _initGpuText(renderable) {
    renderable.view._style.update();
    const proxyRenderable = BigPool.get(GraphicsProxyRenderable, renderable);
    this._gpuBitmapText[renderable.uid] = proxyRenderable;
    this._updateContext(renderable, proxyRenderable.view.context);
    renderable.on("destroyed", () => {
      this.destroyRenderable(renderable);
    });
    return this._gpuBitmapText[renderable.uid];
  }
  _updateDistanceField(renderable) {
    const context = this._getGpuBitmapText(renderable).view.context;
    const view = renderable.view;
    const fontFamily = view._style.fontFamily;
    const dynamicFont = Cache.get(fontFamily);
    const { a, b, c, d } = renderable.layerTransform;
    const dx = Math.sqrt(a * a + b * b);
    const dy = Math.sqrt(c * c + d * d);
    const worldScale = (Math.abs(dx) + Math.abs(dy)) / 2;
    const fontScale = dynamicFont.baseRenderedFontSize / view._style.fontSize;
    const resolution = view.resolution ?? this._renderer.resolution;
    const distance = worldScale * dynamicFont.distanceField.range * (1 / fontScale) * resolution;
    context.customShader.resources.localUniforms.uniforms.uDistance = distance;
  }
  destroy() {
    for (const uid in this._gpuBitmapText) {
      this._destroyRenderableByUid(uid);
    }
    this._gpuBitmapText = null;
    this._sdfShader?.destroy(true);
    this._sdfShader = null;
    this._renderer = null;
  }
}
/** @ignore */
BitmapTextPipe.extension = {
  type: [
    ExtensionType.WebGLPipes,
    ExtensionType.WebGPUPipes,
    ExtensionType.CanvasPipes
  ],
  name: "bitmapText"
};

export { BitmapTextPipe };
//# sourceMappingURL=BitmapTextPipe.mjs.map
