import { Color } from "./Color"

/** Linear distance fog: pixels are untouched at/before `near`, fully `color`
 *  at/after `far`, and blended in between. */
export type Fog = {
  color: Color
  near: number
  far: number
}

/**
 * Every PS1-look trait as a live dial. Nothing here is baked into the renderer;
 * the same scene rendered with two configs gives two eras of hardware, so this
 * is the object you tweak to experiment. Presets live in the namespace below.
 */
export type RenderConfig = {
  /** Internal render resolution before upscaling. The core chunkiness dial:
   *  the whole frame is drawn at this size then scaled up to the display, so
   *  lower numbers mean bigger, blockier pixels. PS1 output was ~320x240. */
  internalWidth: number
  internalHeight: number
  /** How the low-res buffer is scaled to the screen. `nearest` keeps crisp,
   *  blocky pixels (authentic); `linear` smooths them into a soft blur. */
  upscaleFilter: "nearest" | "linear"
  /** Bits per color channel. The PS1 framebuffer was 15-bit (5 bits each),
   *  which steps smooth gradients into visible bands. 8 = full 24-bit color,
   *  no banding. */
  colorDepth: number
  /** Ordered (Bayer 4x4) dither strength, 0..1. Trades color banding for a
   *  fixed crosshatch of alternating pixels, exactly how the PS1 masked its
   *  15-bit output. 0 = no dithering. */
  dither: number
  /** Screen-space vertex snap grid in pixels. The PS1 transformed vertices in
   *  low-precision fixed point, so they popped between pixels and models
   *  jittered as the camera moved. 0 = off (smooth), 1 = one-pixel snap,
   *  higher = coarser and more pronounced wobble. */
  vertexSnap: number
  /** Texture sampling. `nearest` point-samples for crunchy PS1 texels;
   *  `linear` does bilinear smoothing (cleaner, but not period-accurate).
   *  Neither uses mipmaps, so distant textures shimmer regardless. */
  textureFilter: "nearest" | "linear"
  /** `flat` gives one directional shade per face (the PS1 used cheap flat /
   *  per-vertex lighting); `none` draws the texture unlit at full brightness. */
  lighting: "none" | "flat"
  /** Distance fog, or null to disable. PS1 games leaned on fog to hide the
   *  short draw distance and the shimmer of far geometry. It also colors pixels
   *  no triangle covers, so the frame's clear color should match `fog.color`. */
  fog: Fog | null
  /** Beyond this distance (world units) trees + boulders draw as cheap low-poly
   *  impostors instead of full geometry, cutting per-triangle work in dense
   *  views. Kept inside `fog.far` so far detail is already fog-dimmed at the
   *  switch; `Infinity` disables LOD. */
  lodDistance: number
}

/** Ready-made looks. The demo binds keys 1/2/3 to these, sweeping resolution,
 *  color depth, dither, vertex snap, and filtering from crunchy PS1 to clean. */
export namespace RenderConfig {
  export const standard: RenderConfig = {
    internalWidth: 384,
    internalHeight: 216,
    upscaleFilter: "nearest",
    colorDepth: 5,
    dither: 1,
    vertexSnap: 1,
    textureFilter: "nearest",
    lighting: "flat",
    fog: { color: Color.rgb(150, 170, 200), near: 12, far: 200 },
    lodDistance: 60,
  }

  export const ps1: RenderConfig = {
    internalWidth: 320,
    internalHeight: 240,
    upscaleFilter: "nearest",
    colorDepth: 5,
    dither: 1,
    vertexSnap: 1,
    textureFilter: "nearest",
    lighting: "flat",
    fog: { color: Color.rgb(150, 170, 200), near: 12, far: 200 },
    lodDistance: 60,
  }

  export const soft: RenderConfig = {
    internalWidth: 480,
    internalHeight: 270,
    upscaleFilter: "nearest",
    colorDepth: 6,
    dither: 0.5,
    vertexSnap: 0.5,
    textureFilter: "nearest",
    lighting: "flat",
    fog: { color: Color.rgb(170, 190, 215), near: 16, far: 240 },
    lodDistance: 70,
  }

  export const clean: RenderConfig = {
    internalWidth: 960,
    internalHeight: 540,
    upscaleFilter: "linear",
    colorDepth: 8,
    dither: 0,
    vertexSnap: 0,
    textureFilter: "linear",
    lighting: "flat",
    fog: null,
    lodDistance: Infinity,
  }
}
