Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Draw()

Uses the bones from Construct() (usually armature.constructed_bones) to draw the armature.

Propagated visibility is handled via a fixed Bool array.

function Draw(
    bones: Bone[],
    visuals: Visuals[],
    atlases: Texture2D[],
    styles: Style[],
) {
    // bones with higher zindex should render first
    bones.sort((a, b) => {
        if (a.visuals_id == -1 || b.visuals_id == -1) {
            return -1;
        }
        const visualsA = visuals[a.visual_id];
        const visualsB = visuals[b.visual_id];
        return visualsA.zindex - visualsB.zindex;
    });

    // initialize a fixed array of false, for propagated visibility
    let hiddens = new Array(bones.length).fill(false);

    for (let bone of bones) {
        if (bone.visuals_id == -1) {
            continue;
        }
        const visual = visuals[bone.visual_id];

        // save this bone's hidden status so it can be propagated to its children,
        // and ignore rendering if it's hidden
        let hidden = bone.hidden || false;
        if (bone.parent_id != -1 && hiddens[bone.parent_id]) {
            hidden = true;
        }
        hiddens[b] = hidden;
        if (hidden) {
            continue;
        }

        // get active texture
        const tex: Texture = GenericRuntime.getBoneTexture(visual.tex, styles);
        if (!tex) {
            continue;
        }

        // will be used to flip pivots if necessary
        let dir = isFacingLeft(bone.scale) ? -1 : 1;

        // setup pivot
        let pivotPos = visual.pivot_pos * tex.size;
        pivotPos = rotateVec2(pivotPos, bone.rot * dir);
        pivotPos *= bone.scale * visual.pivot_scale;
        // invert Y if engine is -Y
        pivotPos.y = -pivotPos.y;

        // use tex.atlasIdx to get the atlas that this texture is in
        const atlas = atlases[tex.atlasIdx];

        // crop the atlas to the texture
        // here, clip() is assumed to be a texture clipper that takes:
        // (image, top_left, bottom_right)
        // do what is best for the engine
        const realTex = clip(atlas, tex.offset, tex.size);

        // render bone as mesh
        if (visual.vertices.length > 0) {
            drawMesh(bone, visual, tex, realTex);
            continue;
        }

        // A lot of game engines have a non-center sprite origin.
        // In this case, the origin is top-left of the sprite.
        // SkelForm uses center origin, so it must be adjusted like so.
        const pushCenter: Vec2 = (tex.size / 2) * bone.scale;

        let finalRot: Float = bone.rot + visual.pivot_rot * dir;
        let finalScale: Vec2 = bone.scale * visual.pivot_scale;

        // render bone as regular rect.
        // Assume this is a draw function that takes (texture, pos, rot, scale)
        drawTexture(
            realTex,
            bone.pos + pivotPos - pushCenter,
            finalRot,
            finalScale,
        );
    }
}