import * as THREE from 'https://unpkg.com/three/build/three.module.js'; import { drawLucideIcon, type LucideIconName } from '../dom/icons.js'; type Radius = number | { tl?: number; tr?: number; br?: number; bl?: number; }; export function drawRoundedRect( ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number, radius: Radius = 5, fill: boolean | string, stroke: boolean | string = true ): void { let corners; if (typeof radius === 'number') { corners = { tl: radius, tr: radius, br: radius, bl: radius }; } else { corners = { tl: 0, tr: 0, br: 0, bl: 0, ...radius }; } if (width < 2 * corners.tl) corners.tl = width / 2; if (width < 2 * corners.tr) corners.tr = width / 2; if (width < 2 * corners.bl) corners.bl = width / 2; if (width < 2 * corners.br) corners.br = width / 2; if (height < 2 * corners.tl) corners.tl = height / 2; if (height < 2 * corners.tr) corners.tr = height / 2; if (height < 2 * corners.bl) corners.bl = height / 2; if (height < 2 * corners.br) corners.br = height / 2; ctx.beginPath(); ctx.moveTo(x + corners.tl, y); ctx.lineTo(x + width - corners.tr, y); ctx.quadraticCurveTo(x + width, y, x + width, y + corners.tr); ctx.lineTo(x + width, y + height - corners.br); ctx.quadraticCurveTo(x + width, y + height, x + width - corners.br, y + height); ctx.lineTo(x + corners.bl, y + height); ctx.quadraticCurveTo(x, y + height, x, y + height - corners.bl); ctx.lineTo(x, y + corners.tl); ctx.quadraticCurveTo(x, y, x + corners.tl, y); ctx.closePath(); if (fill) { if (typeof fill === 'string') ctx.fillStyle = fill; ctx.fill(); } if (stroke) { if (typeof stroke === 'string') ctx.strokeStyle = stroke; ctx.stroke(); } } export function createLucideButtonTexture( iconName: LucideIconName, color = '#ffffff', textureSize = 128, iconSize = 82, skipLabel?: string ) { const canvas = document.createElement('canvas'); canvas.width = textureSize; canvas.height = textureSize; const ctx = canvas.getContext('2d'); if (!ctx) { throw new Error('Unable to create 2D canvas context for Lucide button texture.'); } const iconOffset = (textureSize - iconSize) / 2; drawLucideIcon(ctx, iconName, iconOffset, iconOffset, iconSize, color, 2); if (skipLabel) { ctx.fillStyle = color; ctx.font = `700 ${Math.round(textureSize * 0.18)}px Helvetica, Arial, sans-serif`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(skipLabel, textureSize / 2, textureSize / 2); } const texture = new THREE.CanvasTexture(canvas); texture.minFilter = THREE.LinearFilter; texture.needsUpdate = true; return texture; } export function createVideoTexture(video: HTMLVideoElement) { const texture = new THREE.VideoTexture(video); texture.minFilter = THREE.LinearFilter; texture.magFilter = THREE.LinearFilter; texture.colorSpace = THREE.SRGBColorSpace; return texture; } export function createImageTexture(image: HTMLImageElement) { const texture = new THREE.Texture(image); texture.minFilter = THREE.LinearFilter; texture.magFilter = THREE.LinearFilter; texture.colorSpace = THREE.SRGBColorSpace; texture.needsUpdate = true; return texture; } export function createMediaTexture(source: HTMLImageElement | HTMLVideoElement) { if (source.tagName.toLowerCase() === 'img') { return createImageTexture(source as HTMLImageElement); } return createVideoTexture(source as HTMLVideoElement); }