/** * A renderable object for displaying textured triangle meshes. * Supports loading from Wavefront OBJ models (via `loader.preload` with type "obj") * or from raw geometry data (vertices, uvs, indices). * Includes a built-in perspective projection and supports 3D transforms * through the standard Renderable API (`rotate`, `scale`, `translate`). * Works on both WebGL (hardware depth testing) and Canvas (painter's algorithm) renderers. * @category Game Objects */ export default class Mesh extends Renderable { /** * @param {number} x - the x screen position of the mesh object * @param {number} y - the y screen position of the mesh object * @param {object} settings - Configuration parameters for the Mesh object * @param {string} [settings.model] - name of a preloaded OBJ model (via loader.preload with type "obj") * @param {Float32Array|number[]} [settings.vertices] - vertex positions as x,y,z triplets (alternative to settings.model) * @param {Float32Array|number[]} [settings.uvs] - texture coordinates as u,v pairs (alternative to settings.model) * @param {Uint16Array|number[]} [settings.indices] - triangle vertex indices (alternative to settings.model) * @param {HTMLImageElement|TextureAtlas|string} [settings.texture] - the texture to apply (image name, HTMLImageElement, or TextureAtlas). If omitted and settings.material is provided, the texture is resolved from the MTL material's map_Kd. * @param {string} [settings.material] - name of a preloaded MTL material (via loader.preload with type "mtl"). When provided, the diffuse texture (map_Kd), tint color (Kd), and opacity (d) are automatically applied. * @param {number} settings.width - display width in pixels (the 3D model is normalized and scaled to fit this size) * @param {number} settings.height - display height in pixels (the 3D model is normalized and scaled to fit this size) * @param {boolean} [settings.cullBackFaces=true] - enable backface culling * @example * // create from OBJ + MTL (texture auto-resolved from material) * let mesh = new me.Mesh(0, 0, { * model: "fox", * material: "fox", * width: 200, * height: 200, * }); * * // create from OBJ with explicit texture (no MTL needed) * let mesh = new me.Mesh(0, 0, { * model: "cube", * texture: "cube_texture", * width: 200, * height: 200, * }); * * // 3D rotation using the standard rotate() API * mesh.rotate(Math.PI / 4, new me.Vector3d(0, 1, 0)); // rotate around Y axis * * // 2D rotation (Z axis, same as Sprite) * mesh.rotate(Math.PI / 4); */ constructor(x: number, y: number, settings: { model?: string | undefined; vertices?: number[] | Float32Array | undefined; uvs?: number[] | Float32Array | undefined; indices?: number[] | Uint16Array | undefined; texture?: string | HTMLImageElement | TextureAtlas | undefined; material?: string | undefined; width: number; height: number; cullBackFaces?: boolean | undefined; }); /** * the original (untransformed) vertex positions as x,y,z triplets * @type {Float32Array} */ originalVertices: Float32Array; /** * texture coordinates as u,v pairs * @type {Float32Array} */ uvs: Float32Array; /** * number of vertices * @type {number} */ vertexCount: number; _indicesOriginal: number[]; /** * the projected vertex positions, updated each draw call * @type {Float32Array} */ vertices: Float32Array; /** * whether to cull back-facing triangles * @type {boolean} * @default true */ cullBackFaces: boolean; /** * Per-material submesh groups, populated when the OBJ * contains multiple `usemtl` directives AND a matching MTL * is bound via the `material` setting. Each entry slices * the shared `indices` buffer; field shape (`start`, * `count`, `materialName`) matches the glTF "groups" * convention. * * Under the per-vertex color baking path (tier 2), the * `tint` / `opacity` fields here are informational — the * actual rendered color is baked into `vertexColors` at * construction time. Mutating `groups[i].tint` after * construction has no visible effect; use `mesh.tint` for * runtime color multiplication, or rebuild the Mesh with * new material settings. * @type {Array<{materialName: string|null, start: number, * count: number, tint: Color, opacity: number}>} */ groups: Array<{ materialName: string | null; start: number; count: number; tint: Color; opacity: number; }>; /** * Per-vertex color buffer (one packed Uint32 per vertex) * populated for multi-material meshes. The mesh batcher * reads from this when present, pushing the per-vertex * color as the `aColor` attribute — so multi-material * rendering needs no extra draw calls per material vs * single-material rendering (the batcher still chunks * very large meshes across multiple draws to fit its * vertex/index buffer limits, same as the single-material * path). Multiplied at render time by the global * `mesh.tint`, so runtime tint mutation still works as * expected (flash, fade, team color, etc.). * * Vertices were split per-material at parse time (each * material has its own dedup scope in the OBJ parser), so * every vertex belongs to exactly one material group and * carries that group's color unambiguously. * @type {Uint32Array} */ vertexColors: Uint32Array; texture: any; /** * Projection matrix applied automatically before the model transform in draw(). * Defaults to a perspective projection (45° FOV, camera at z=-2.5) suitable for * viewing unit-cube-sized geometry. Set to identity for orthographic (flat) projection. * Most users don't need to modify this — the default works for standard OBJ models. * @type {Matrix3d} */ projectionMatrix: Matrix3d; /** @ignore */ _hullPoints: Vector2d[]; /** @ignore */ _hullPolygon: Polygon | null; /** * Project all vertices through projectionMatrix × currentTransform * and store the results in `this.vertices`. * @param {number} [offsetX=0] - x offset added to each projected vertex * @param {number} [offsetY=0] - y offset added to each projected vertex * @param {number} [zScale=0] - scale factor for Z output (0 = skip Z, 1000 = depth buffer range) * @ignore */ _projectVertices(offsetX?: number, offsetY?: number, zScale?: number): void; /** * Project vertices into **world space** for the Camera3d render path. * Bypasses {@link Mesh#projectionMatrix} (the self-contained * perspective that's meaningful only under Camera2d) and emits * vertices that the active 3D camera then projects via its own * view + projection matrices, the same way it does for Sprites. * * Per-vertex math: `currentTransform × originalVertex`, then a uniform * scale by `this.width`, a Y-flip (OBJ Y-up → engine Y-down), and a * translate to `(offsetX, offsetY, offsetZ)`. * * @param {number} offsetX - world X to place the mesh center at * @param {number} offsetY - world Y to place the mesh center at * @param {number} offsetZ - world Z to place the mesh center at * @ignore */ _projectVerticesWorld(offsetX: number, offsetY: number, offsetZ: number): void; /** * Build the winding-reversed indices buffer used by the Camera3d * world-space path. Called once, lazily, the first time the mesh * draws under Camera3d. Why: the world-space path Y-flips vertices * on output (a reflection, det = -1), which inverts triangle * winding in screen space. Without the swap, `cullBackFaces: true` * would end up culling the front faces and the model would look * hollow. * * Both buffers are kept alive — `_indicesOriginal` is the original * OBJ-shared (or user-supplied) winding, `_indicesReversed` is the * Camera3d-flipped copy. `draw()` swaps `this.indices` between them * each frame based on the active camera, so a Mesh that was first * drawn under Camera3d and later re-parented to a Camera2d stage * (e.g. a level transition into a 2D minigame) gets its original * winding back and stays correctly oriented under * `cullBackFaces: true`. * @ignore */ _setupWorldSpace(): void; _indicesReversed: Uint16Array | undefined; _worldSpace: boolean | undefined; _useWorldSpace: boolean | undefined; /** * Render the mesh at its current state (transforms, projection, tint) to an offscreen canvas. * The returned canvas can be used with `renderer.drawImage()`, as a `Sprite` image source, * or converted to an ImageBitmap via `createImageBitmap()`. * @returns {HTMLCanvasElement} an offscreen canvas containing the rendered mesh * @example * // snapshot the mesh and create a Sprite from it * const canvas = mesh.toCanvas(); * const sprite = new me.Sprite(100, 100, { image: canvas }); * * // or draw directly * renderer.drawImage(mesh.toCanvas(), 100, 100); */ toCanvas(): HTMLCanvasElement; /** * Render the mesh at its current state to an ImageBitmap. * Useful for creating textures or sprites from the rendered mesh. * @returns {Promise} a promise that resolves to an ImageBitmap of the rendered mesh * @example * const bitmap = await mesh.toImageBitmap(); * const sprite = new me.Sprite(100, 100, { image: bitmap }); */ toImageBitmap(): Promise; } import Renderable from "./renderable.js"; import { Color } from "../math/color.ts"; import { Matrix3d } from "../math/matrix3d.ts"; import { Vector2d } from "../math/vector2d.ts"; import { Polygon } from "../geometries/polygon.ts"; import { TextureAtlas } from "./../video/texture/atlas.js"; //# sourceMappingURL=mesh.d.ts.map