/*
 * Copyright (C) 2026  Behdad Esfahbod
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Author(s): Behdad Esfahbod
 */

#include "hb.hh"

#include "hb-gpu.h"

/**
 * SECTION:hb-gpu
 * @title: hb-gpu
 * @short_description: GPU shape encoding
 * @include: hb-gpu.h
 *
 * This module implements the
 * [Slug](https://github.com/EricLengyel/Slug) GPU text
 * rasterization algorithm by Eric Lengyel.  Glyph outlines are
 * encoded on the CPU into compact blobs that the GPU decodes
 * and rasterizes directly in the fragment shader, with no
 * intermediate bitmap atlas.
 *
 * See the [live web demo](https://harfbuzz.github.io/hb-gpu-demo/).
 *
 * # Encoding
 *
 * Each glyph is encoded independently into an opaque blob of
 * RGBA16I texels (8 bytes each).  Typical encoding flow:
 *
 * |[<!-- language="plain" -->
 * hb_gpu_draw_t *draw = hb_gpu_draw_create_or_fail ();
 *
 * hb_gpu_draw_glyph (draw, font, gid);
 * hb_blob_t *blob = hb_gpu_draw_encode (draw);
 *
 * // Upload hb_blob_get_data(blob) to the atlas at some offset.
 * unsigned atlas_offset = upload_to_atlas (blob);
 *
 * hb_gpu_draw_recycle_blob (draw, blob);
 * hb_gpu_draw_reset (draw);
 * // repeat for more glyphs...
 *
 * hb_gpu_draw_destroy (draw);
 * ]|
 *
 * The encoder object and its internal buffers are reused across
 * glyphs.  Call hb_gpu_draw_recycle_blob() after each encode to
 * allow buffer reuse; call hb_gpu_draw_reset() before each new
 * glyph.
 *
 * # Atlas setup
 *
 * All encoded blobs are uploaded into a single GL_TEXTURE_BUFFER
 * backed by a GL_RGBA16I format buffer.  Each glyph occupies a
 * contiguous range of texels at a known offset:
 *
 * |[<!-- language="plain" -->
 * GLuint buf, tex;
 * glGenBuffers (1, &buf);
 * glGenTextures (1, &tex);
 *
 * glBindBuffer (GL_TEXTURE_BUFFER, buf);
 * glBufferData (GL_TEXTURE_BUFFER, capacity * 8, NULL, GL_STATIC_DRAW);
 *
 * glBindTexture (GL_TEXTURE_BUFFER, tex);
 * glTexBuffer (GL_TEXTURE_BUFFER, GL_RGBA16I, buf);
 *
 * // Upload a glyph blob at 'offset' texels:
 * glBufferSubData (GL_TEXTURE_BUFFER,
 *                  offset * 8,
 *                  hb_blob_get_length (blob),
 *                  hb_blob_get_data (blob, NULL));
 * ]|
 *
 * # Shader compilation
 *
 * The library provides GLSL source strings for a vertex helper
 * function and a fragment rendering function.  Prepend a #version
 * directive and append your own main():
 *
 * |[<!-- language="plain" -->
 * unsigned vert_count, frag_count;
 * const char * const *vert_lib = hb_gpu_shader_vertex_sources (
 *     HB_GPU_SHADER_LANG_GLSL, &vert_count);
 * const char * const *frag_lib = hb_gpu_shader_fragment_sources (
 *     HB_GPU_SHADER_LANG_GLSL, &frag_count);
 *
 * const char *vert_sources[] = {
 *     "#version 330\n",
 *     hb_gpu_shader_vertex_source (HB_GPU_SHADER_LANG_GLSL),
 *     your_vertex_main
 * };
 * glShaderSource (vert_shader, 3, vert_sources, NULL);
 * // Same pattern for the fragment shader.
 * ]|
 *
 * # Vertex shader
 *
 * The vertex library provides one function:
 *
 * |[<!-- language="plain" -->
 * void hb_gpu_dilate (inout vec2 position, inout vec2 texcoord,
 *                     vec2 normal, vec4 jac,
 *                     mat4 m, vec2 viewport);
 * ]|
 *
 * This expands each glyph quad by approximately half a pixel on
 * screen to ensure proper antialiasing coverage at the edges.
 * It must be called in the vertex shader before computing
 * gl_Position.
 *
 * Per-vertex attributes for each glyph quad (2 triangles, 6
 * vertices, 4 unique corners):
 *
 * - position (vec2): object-space vertex position, computed from
 *   the glyph's bounding box.  For corner (cx, cy) where cx,cy
 *   are 0 or 1:
 *   |[<!-- language="plain" -->
 *   pos.x = pen_x + scale * lerp(extent_min_x, extent_max_x, cx)
 *   pos.y = pen_y - scale * lerp(extent_min_y, extent_max_y, cy)
 *   ]|
 *   where scale = font_size / upem.
 *
 * - texcoord (vec2): em-space texture coordinates, equal to the
 *   raw extent values: `(ex, ey)` where ex/ey are the glyph's
 *   bounding box corners in font design units.  The fragment shader
 *   samples the encoded blob in this coordinate space.
 *
 * - normal (vec2): outward normal at each corner.
 *   `(-1, +1)` for (0,0), `(+1, +1)` for (1,0),
 *   `(-1, -1)` for (0,1), `(+1, -1)` for (1,1).
 *   Note: y is negated relative to cx,cy because the common
 *   em-to-object transform flips y.
 *
 * - jac (vec4): maps object-space displacements back to
 *   em-space after dilation, stored row-major as
 *   (j00, j01, j10, j11).  For the common case of uniform
 *   scaling with y-flip:
 *   |[<!-- language="plain" -->
 *   jac = vec4(emPerPos, 0.0, 0.0, -emPerPos)
 *   ]|
 *   where emPerPos = upem / font_size.  For non-trivial
 *   transforms, see the hb_gpu_dilate source.
 *
 * - m (mat4): the model-view-projection matrix (uniform).
 *
 * - viewport (vec2): the viewport size in pixels (uniform).
 *
 * A typical vertex main:
 *
 * |[<!-- language="plain" -->
 * uniform mat4 u_matViewProjection;
 * uniform vec2 u_viewport;
 *
 * in vec2 a_position;
 * in vec2 a_texcoord;
 * in vec2 a_normal;
 * in float a_emPerPos;
 * in uint a_glyphLoc;
 *
 * out vec2 v_texcoord;
 * flat out uint v_glyphLoc;
 *
 * void main () {
 *   vec2 pos = a_position;
 *   vec2 tex = a_texcoord;
 *   vec4 jac = vec4 (a_emPerPos, 0.0, 0.0, -a_emPerPos);
 *   hb_gpu_dilate (pos, tex, a_normal, jac,
 *                  u_matViewProjection, u_viewport);
 *   gl_Position = u_matViewProjection * vec4 (pos, 0.0, 1.0);
 *   v_texcoord = tex;
 *   v_glyphLoc = a_glyphLoc;
 * }
 * ]|
 *
 * # Font scale
 *
 * The encoder works in font design units (upem).  For best
 * results, do not set a scale on the #hb_font_t passed to
 * hb_gpu_draw_glyph() — leave it at the default (upem).
 * Scaling is applied later when computing vertex positions:
 *
 * |[<!-- language="plain" -->
 * float scale = font_size / upem;
 * pos.x = pen_x + scale * extent_x;
 * pos.y = pen_y - scale * extent_y;
 * ]|
 *
 * If you do set a font scale (e.g. for hinting), the encoded
 * blob and extents will be in the scaled coordinate space,
 * and you must adjust emPerPos accordingly.
 *
 * # Dilation
 *
 * Each glyph is rendered on a screen-aligned quad whose
 * corners match the glyph's bounding box.  Without dilation,
 * the antialiased edges at the quad boundary get clipped — the
 * fragment shader needs at least half a pixel of padding
 * around the glyph to produce smooth coverage gradients.
 *
 * hb_gpu_dilate computes a perspective-correct half-pixel
 * expansion.  It adjusts both the vertex position (expanding
 * the quad) and the texcoord (so the fragment shader samples
 * the right location in em-space after expansion).
 *
 * The `jac` parameter maps object-space displacements back to
 * em-space.  For the common case of uniform scaling with
 * y-flip (`pos.y = pen_y - scale * ey`):
 *
 * |[<!-- language="plain" -->
 * float emPerPos = upem / font_size;
 * jac = vec4(emPerPos, 0.0, 0.0, -emPerPos);
 * ]|
 *
 * For non-uniform scaling or shearing transforms, jac is the
 * 2x2 inverse of the em-to-object linear transform, stored
 * row-major.
 *
 * ## Static dilation alternative
 *
 * Applications that do not need perspective correctness (e.g.
 * strictly 2D rendering at known sizes) can skip hb_gpu_dilate
 * and instead expand each quad vertex by a fixed amount along
 * its normal, based on the minimum expected font size:
 *
 * |[<!-- language="plain" -->
 * float min_ppem = 10.0;  // smallest expected size in pixels
 * float pad = 0.5 * upem / min_ppem;  // half-pixel in em units
 * pos += normal * pad * scale;
 * texcoord += normal * pad;
 * ]|
 *
 * This over-dilates at larger sizes (wasting fill rate on
 * transparent pixels) but is simpler to implement and avoids
 * the need for the MVP matrix and viewport size in the vertex
 * shader.
 *
 * # Fragment shader
 *
 * The fragment library provides two functions:
 *
 * |[<!-- language="plain" -->
 * float hb_gpu_render (vec2 renderCoord, uint glyphLoc);
 * ]|
 *
 * It requires the `hb_gpu_atlas` uniform to be bound to the
 * texture containing the encoded glyph data.  By default this
 * is an `isamplerBuffer` (GL_TEXTURE_BUFFER).  For platforms
 * without texture buffers (e.g. WebGL2), define
 * `HB_GPU_ATLAS_2D` before including the shader source; the
 * atlas then becomes an `isampler2D` and a
 * `uniform int hb_gpu_atlas_width` must also be set to the
 * texture width.
 *
 * Parameters:
 *
 * - renderCoord: the interpolated em-space coordinate from
 *   the vertex shader (v_texcoord).
 *
 * - glyphLoc: the texel offset of this glyph's encoded blob
 *   in the atlas buffer.  Passed as a flat varying from the
 *   vertex shader.
 *
 * Returns the coverage in [0, 1]: 1.0 inside the glyph, 0.0
 * outside, with antialiased edges.
 *
 * A typical fragment main:
 *
 * |[<!-- language="plain" -->
 * in vec2 v_texcoord;
 * flat in uint v_glyphLoc;
 * out vec4 fragColor;
 *
 * void main () {
 *   float coverage = hb_gpu_render (v_texcoord, v_glyphLoc);
 *   fragColor = vec4 (0.0, 0.0, 0.0, coverage);
 * }
 * ]|
 *
 * The coverage value can be used with alpha blending
 * (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) to composite
 * over a background, or multiplied with any color.
 *
 * # Stem darkening
 *
 * |[<!-- language="plain" -->
 * float hb_gpu_darken (float coverage, float brightness, float ppem);
 * ]|
 *
 * Optional stem darkening adjusts coverage at small sizes so
 * thin stems are not washed out by gamma correction.
 *
 * Parameters:
 *
 * - coverage: the output of hb_gpu_render.
 *
 * - brightness: foreground brightness in [0, 1], computed as
 *   `dot (foreground.rgb, vec3 (1.0 / 3.0))`.
 *
 * - ppem: pixels per em at this fragment, computed as
 *   `1.0 / max (fwidth (v_texcoord).x, fwidth (v_texcoord).y)`.
 *
 * Example:
 *
 * |[<!-- language="plain" -->
 * float coverage = hb_gpu_render (v_texcoord, v_glyphLoc);
 * float brightness = dot (u_foreground.rgb, vec3 (1.0 / 3.0));
 * float ppem = 1.0 / max (fwidth (v_texcoord).x,
 *                          fwidth (v_texcoord).y);
 * coverage = hb_gpu_darken (coverage, brightness, ppem);
 * ]|
 **/
