Projection Mapper — Cinema 4D plugin
Change log

Newest version first. Each entry summarises what was added or fixed. This file is
shipped at the root of every build ZIP and provides the release notes for the
GitLab Release (only the current tag's section is shown there).

================================================================================
v0.78.0 — La base se telecharge, elle ne se livre plus
================================================================================

-- Le plugin ne transporte plus la base de projecteurs -----------------------
- Les paquets R25, 2024 et 2025 emportaient 18 Mo de base chiffree que le
  plugin est cense aller chercher lui-meme. Ils passent de ~21 Mo a ~4 Mo, au
  niveau du paquet 2026 qui, lui, avait toujours ete correct.
- Ce n'etait pas qu'une question de poids : une base embarquee devient
  illisible des la rotation suivante de la cle de chiffrement. Le moteur ne
  sait plus l'ouvrir, le catalogue est vide, et rien ne l'explique.
- Deux chemins d'empaquetage cohabitent (project-tool pour R25/2024/2025, cmake
  pour 2026) et ils divergeaient depuis des semaines sans que personne le voie.
  La CI verifie desormais l'archive elle-meme : aucun .db ni .enc ne peut plus
  y entrer, par l'un ou l'autre chemin.

-- Les zips ne disent plus << cpp >> -----------------------------------------
- c4d-plugin_v0.78.0_cpp_2025_0_1-win.zip devient
  c4d-plugin_v0.78.0_2025-win.zip. L'ancien nom venait du dossier du SDK Maxon
  tronque : exact et illisible, puisque << cpp >> designe le SDK C++ et non le
  langage, et que << 2025_0_1 >> est une version de SDK, pas de Cinema 4D.
- Les quatre etiquettes sont r25, 2024, 2025, 2026. La correspondance est une
  table explicite : un SDK inconnu fait echouer le build la ou on l'ajoute,
  au lieu de produire en silence un nom que la CI attendra en vain plus loin.

-- La base vient du service de licences, plus du CDN --------------------------
- Le plugin va chercher la base sur https://remapengine.duckdns.org, derriere
  son jeton de licence, et non plus directement sur le CDN. Les BINAIRES de
  plugin, eux, continuent d'arriver du CDN : ils ne valent rien seuls, et faire
  transiter des megaoctets pour proteger un zip serait du cout sans benefice.
- Ce que ca change : le service remet a chaque compte une copie de la base
  chiffree avec SA cle, de sorte qu'une cle qui refait surface designe un compte
  au lieu de ne designer personne. Actif cote serveur depuis le 2026-08-27,
  publie en meme temps que cette version -- il n'y avait pas encore
  d'utilisateurs, donc pas de flotte a migrer.
- Consequence de deploiement : cette version exige un front end qui expose
  /api/downloads/db. Deployer le service AVANT de publier ce plugin.
- Les deux constantes XOR-voilees qui portaient l'adresse du CDN ont disparu
  avec leur dernier usage. La CI continue de verifier que << remapcdn >>
  n'apparait pas dans le binaire : ce n'est plus un voile a maintenir, c'est
  une garde contre la reintroduction d'un acces direct.

-- Le premier demarrage telecharge la base -----------------------------------
- Le controle de mise a jour au demarrage abandonnait quand la base etait
  absente. C'etait coherent tant qu'elle partait dans le zip ; depuis qu'elle
  n'y est plus, ce meme abandon livrait un plugin sans base et sans moyen d'en
  obtenir une, sauf a trouver << Force Database Update >> dans un menu.
  Il la telecharge maintenant, une fois, et la met en cache.
- Le telechargement est aussi declenche juste apres une connexion reussie. Au
  tout premier lancement il n'existe aucun jeton, donc le controle du demarrage
  s'etait deja retire faute de licence : sans ce second point d'entree, il
  aurait fallu redemarrer Cinema 4D pour obtenir une base apres s'etre connecte.
- Un echec le dit dans une fenetre, avec la raison et la marche a suivre,
  plutot que dans la console.

================================================================================
v0.77.1 — Le plugin exige une licence
================================================================================

-- La base ne s'ouvre plus sans licence --------------------------------------
- Le plugin refuse d'ouvrir la base de projecteurs tant qu'une licence valide
  n'a pas ete presentee. La base EST le produit (geometrie, optique, modele
  d'eclairement), donc la verrouiller verrouille tout.
- Le refus vit dans la bibliotheque compilee, pas dans une couche au-dessus :
  contourner le controle revient a se passer du moteur.
- Nouveau menu << Licence Remap... >> : se connecter, voir l'etat, se
  deconnecter. Rien d'autre. La saisie du mot de passe est masquee
  (EDITTEXT_PASSWORD) et le mot de passe n'est jamais conserve : il sert a
  obtenir le jeton de licence, puis il est oublie.
- La fenetre hors ligne n'est pas un compteur : c'est la duree de vie du jeton,
  14 jours, reemise a chaque demarrage connecte. Etre hors ligne ne bloque
  jamais en soi ; l'etre au-dela de la fenetre bloque. Le demarrage ne touche
  pas au reseau ; le rafraichissement se fait en arriere-plan.
- Une licence tenue par une autre machine peut etre deplacee, apres
  confirmation : l'autre poste la perd.

-- La fenetre de licence ------------------------------------------------------
- Les commandes du plugin s'eteignent quand la licence manque, au lieu de
  s'ouvrir puis d'echouer. Un menu grise dit ce qui se passe avant qu'on
  clique ; un menu qui repond par une erreur le dit apres.
- La fenetre de connexion reste vivante pendant l'appel reseau : le travail se
  fait en arriere-plan et la fenetre se rafraichit sur son Timer, plutot que
  de figer Cinema 4D le temps d'un aller-retour au serveur.
- Dialogue redessine aux couleurs du produit, bandeau trace au trait plutot
  qu'en image -- il reste net a toutes les echelles d'interface.

-- La base est chiffree sur le disque, et le reste ---------------------------
- La base de projecteurs est livree chiffree (AES-256) et n'existe JAMAIS en
  clair sur le disque : le moteur la dechiffre en memoire, cle en main, a
  l'ouverture. La cle n'est compilee nulle part -- elle arrive dans le jeton
  de licence signe, par utilisateur et par machine (chiffrement a enveloppe).
  Copier la base et le jeton sur un autre poste ne donne rien : le jeton ne
  verifie pas ailleurs que sur la machine pour laquelle il a ete emis.
- Les mises a jour en ligne suivent : le fichier chiffre du CDN s'installe
  TEL QUEL, verifie par son empreinte (payload_hash du manifest). L'updater
  ne dechiffre plus jamais rien -- il n'a pas de cle, c'est le principe.
- L'ancienne cle AES compilee dans les versions precedentes a ete RETIREE et
  la cle de la base a tourne : les fichiers publies ne sont plus lisibles avec
  ce qu'un binaire v0.76 contient. La CI verifie sur chaque artefact que ces
  octets n'y reviennent jamais, et que l'adresse du CDN n'apparait pas en
  clair (voilee dans le binaire).
- L'ancien sous-module de donnees common-motor (module Python historique) est
  supprime : la base chiffree est versionnee directement (LFS), et le moteur
  est common-motor-cpp seul.
- La verification de mise a jour ne se lance que si une licence est active :
  sans licence le produit est ferme, telecharger une base qu'on ne peut pas
  ouvrir ne serait que de la bande passante depensee.

-- Limites assumees ----------------------------------------------------------
- Le voile sur l'adresse du CDN est un voile, pas un secret : le trafic reseau
  la revele. Ce qui protege la base est sa cle, pas son adresse.
- La charge du jeton est signee mais pas chiffree : un licencie peut en
  extraire la cle de SA base. Inherent -- le client legitime doit pouvoir
  dechiffrer. Ce qui est garanti : on ne peut ni fabriquer un jeton, ni s'en
  servir sur une autre machine.

================================================================================
v0.76.2 — Nouvelle adresse du CDN (mise a jour REQUISE)
================================================================================

-- Le CDN a son propre nom d'hote -------------------------------------------
- La base de projecteurs est desormais servie depuis remapcdn.duckdns.org, un
  nom dedie qui ne depend d'aucun autre service de la machine. Le jour ou le
  CDN part chez un vrai diffuseur, l'adresse se repointe en DNS sans qu'une
  nouvelle version du plugin soit necessaire — ce qui est precisement le
  probleme que cette version-ci corrige.
- L'ancienne adresse, boiteakk.duckdns.org/projectors-db, a ete retiree le
  2026-08-25 et repond maintenant 410 Gone.

-- Consequence : les versions anterieures ne se mettent plus a jour -----------
- Tout plugin en v0.76.1 ou anterieure interroge l'ancienne adresse et ne
  recoit donc plus aucune mise a jour de la base. La base deja telechargee
  continue de fonctionner normalement, hors ligne : rien n'est perdu, mais
  plus rien n'arrive.
- Installer cette version retablit les mises a jour. La base locale est
  conservee, aucune autre action n'est necessaire.

-- Verifie avant publication -------------------------------------------------
- Manifeste, base complete et deltas repondent sur la nouvelle adresse, en
  canal prod comme en canal test, et un delta reel se telecharge.

================================================================================
v0.76.1 — Projector Pivot: SW-mode fixes (target drag, mode switch, lens swap)
================================================================================

-- SW mode + Projector Pivot: the projector no longer dances ------------------
- Dragging the target: the projector BASE is now the world-fixed end for the
  whole drag (frozen when the target handle is grabbed). The body pivots on
  its base to track the target and auto lens switches glide the optics
  sideways instead of kicking the body -- no more dance/recoil.
- Switching Projector Pivot <-> Optical Pivot no longer moves the stored
  target (the old handler re-captured it at the nominal distance along the
  gizmo axis, which teleported it -- sometimes to the OPPOSITE side of the
  projector when the target gizmo was still selected). A mode switch now
  also settles the nominal/world drift so the projected screen re-seats on
  the target immediately, without having to nudge it.
- Swapping the lens in the SW-family input modes now holds the DISTANCE to
  the target (the L-mode invariant): if the picked lens cannot reach
  TR = distance/SW, the image size (SW) is traded through the shared throw
  butee instead of letting the projected screen teleport to the nominal
  distance far off the target -- what a real lens swap does to the image on
  a wall. Lenses that cover the distance leave SW untouched.
- Pose solver for bent-lens swaps: more fixed-point iterations for the large
  (~90 degrees) direction changes of elbowed lenses.
- Known minor issue (to revisit): a small glitch remains right after a lens
  swap while the target handle is still armed.

================================================================================
v0.76.0 — Projector Pivot + mire text plates
================================================================================

-- Projector Pivot: the ID_PROJ_MODE option finally works ---------------------
- The option (renamed "Projector Pivot", 2 entries) now really selects what
  stays world-fixed when the lens or projector is swapped:
  * Optical Pivot: the optics (BoxOrigin) and the image hold their position,
    the body recoils through the lens geometry.
  * Projector Pivot: the projector stays ON ITS BASE (bottom-centre of the
    body bounding box, world-anchored) and PIVOTS AROUND IT so the beam keeps
    hitting the stored target -- like re-aiming a real installed projector
    without moving it. The image stays on target, the optics glide.
  The gizmo/axis always stays at the optics in both modes, and every optical
  formula keeps measuring from the BoxOrigin.
- Auto-lens selection gained hysteresis: when the throw ratio sits in the gap
  between two lens windows, the current lens is kept (its clamp pins TR at
  the window edge) instead of re-picking the nearest lens on every tick --
  this removed an endless bent<->straight flip-flop in L mode.
- The old unconditional compensation (body kept fixed in EVERY mode, which
  made the option inert) is gone; the Projector Pivot pose is solved
  world-anchored and history-free, so lens swap round trips return exactly
  (no more creeping/"dancing" projector).

-- Test card texts: translucent white plate + black outline ------------------
- Every text field of the mire now sits on a backing plate: white at 85 %
  opacity by default, padded around the glyph block, with its own
  show/colour/opacity settings per field. The text outline now defaults to
  2 px black. Keeps the labels readable over the busy card; the Blender
  readouts share the same style.

================================================================================
v0.75.1 — Parametric test card / mire (issue #45)
================================================================================

-- Test Pattern shader: full redesign to the issue #45 design spec ------------
- The mire is now defined in the projector's NATIVE PIXEL space and follows
  the agreed chart: 25% grey ground, magenta 1 px frame (always topmost)
  and centre axes, white 100 px grid justified on the axes (no centred
  cell), blue corner-to-corner diagonals, and concentric circles stepped on
  the grid pitch cycling red/green/blue out to the corners.
- Arrows at every line end, pointing outward and white-outlined: blue
  60 px arrows at the four axis ends and at the four corners (along the
  diagonals, drawn in front), magenta half-size arrows at every grid-line
  end. Height is adjustable (proportions and the 2:1 large/small ratio are
  fixed); the 1 px outline width is its own setting.
- Line width, grid step and every colour are editable; straight strokes
  snap to the native pixel grid so a 1 px line renders as exactly one
  crisp pixel at native resolution.
- Four text fields — projector name, lens, resolution ("1920 x 1200") and
  format ("16:10") — each with its own show/position/size/font/colour/
  opacity/outline settings. Name, lens and the format values are pushed
  automatically from the projector's DB selection (the lens label is new);
  custom projectors without a DB lens simply hide the lens text.
- The first-generation presets, SMPTE bars, greyscale ramp, checker,
  sub-grid, ruler and corner squares are retired.
- The card's geometry is computed by the shared engine (common-motor-cpp),
  so the Blender addon projects the exact same mire.

================================================================================
v0.74.0 — Projector series (DB schema 1.3), shift as % of the half matrix
================================================================================

-- Matrix shift readout: percent of the HALF matrix on each axis (issue #46) --
- The Attribute Manager vertical shift was shown as a percentage of the FULL
  matrix height (raw value / aspect): 45% V for the RQ50K + S400 at max
  shift. Projector spec sheets express each axis as a percentage of its own
  HALF matrix instead -- a floor-standing projector that puts the bottom
  edge of the image on the horizon reads 100% V. The vertical display scale
  is now 2 x resX/resY, so the RQ50K + S400 reads 32% H / 90% V at max
  shift, matching the spec sheet values. Display only: the stored raw
  values, the image-circle clamp and the cone/camera/OpenBox geometry are
  untouched, so existing scenes are unaffected.
- The FINAL clamped value snaps to the display precision (2 decimals of a
  percent), truncated TOWARD ZERO: an image-circle wall stored rounded in
  the DB (0.501 instead of 0.50097656) puts the geometric butee at
  90.0089% -- the stored value now snaps to exactly 90.00, never 90.01, so
  the reachable shift can never read above the spec-sheet maximum. The AM
  display truncates the same way, covering legacy scenes whose stored
  value predates the snap.

-- Projector series (DB schema 1.3) -------------------------------------------
- The database now groups projectors by commercial series (per-brand lookup
  table, e.g. Panasonic "PT-RQ"; schema 1.3, additive — older databases keep
  loading, the writer migrates them on open).
- Catalog flyout: the Extensions menu now reads Brand > Serie > Model > Lens;
  models without a series stay directly under their brand, after the serie
  submenus.
- Projector Search: new "Series" entry in the results "Group by" combo
  (headers read "Brand - Serie") and a new serie: search keyword; plain-word
  searches match the series name too.
- Series are assigned via the backend import (template 3.2, field IdSerie =
  series name, created on the fly within the brand).

================================================================================
v0.73.3 — Auto-lens gap snap, bare casing when no lens fits, viewport polish
================================================================================

-- L mode: per-lens TR windows now use the distance formulas ------------------
- Every consumer of the per-lens throw-ratio windows (availability gauge,
  lens auto-select, gap snap, TR slider bounds, locked-lens range, lens
  dropdown filter) evaluated the LW_SW / LT_SW formulas at the current SW in
  every input mode. In L mode SW = L/TR moves with the slider, so all the
  windows moved too: the gauge columns danced, the auto-select churned
  between lenses on a plain TR drag, and each spurious switch shifted the
  cone apex and target sideways (lens-origin compensation) -- the target
  visibly drifted in X/Z while only TR was edited.
- In L mode those windows are now evaluated with the LW_L / LT_L formulas at
  the held distance (ID_L), which is exactly what the L-mode TR clamp always
  used: stable rails, stable auto-select boundaries, and the target stays
  put. Other modes keep the SW formulas at the current SW.

-- Auto mode: TR/distance snap to the nearest lens window ---------------------
- In auto-lens mode the committed throw ratio can no longer rest in a gap
  BETWEEN two lens windows: it now sticks to the edge of the active lens's
  window and jumps to the nearest lens once the input crosses closer to it,
  so the derived distance (L = TR x SW) snaps between reachable values --
  the same blocked-then-jump feel L mode always had from its per-lens
  formula clamp. The lens coverage count is recomputed against the final
  snapped value so cone colour, gauge and status agree it is reachable.

-- Auto mode: no matching lens = bare casing ----------------------------------
- When no lens covers the current throw ratio (e.g. the target is dragged
  into a gap or beyond the set's range), the projector is now assembled
  WITHOUT the lens, the OpenBox slide plane and the projection light:
  nothing pretends an image can form. Everything remounts as soon as a lens
  window covers the ratio again. Locked mode keeps its lens mounted (the red
  cone signals out-of-range there).

-- Locked lens: red cone honoured the wrong TR range --------------------------
- With "Use Formulas for TR Range" enabled, the in-range test behind the wire
  colour still compared TR against the raw commercial ratios, so the cone
  turned red on values the formula range (and the clamp) legitimately allow.
  The test now runs after the clamp, against the same resolved range, and
  also refreshes on SW / formula-toggle / lens changes.

-- Viewport ---------------------------------------------------------------------
- The projected screen marker is a hollow white rectangle at the screen
  distance again (was four corner ticks).
- The image-circle overlay now also draws the matrix home position (zero
  shift) as a dark grey rectangle under the pink shifted one.
- Fixed two per-frame small memory leaks in the viewport draw path.

================================================================================
v0.73.2 — L mode: cone width exact at the zoom extremes (clamp-order fix)
================================================================================
- At the TR slider's butees the cone drew slightly narrower (~1%) than the
  projected diapo and the look-through camera, and the derived distance L
  drifted by the same amount on every slider edit held at the extreme. Cause:
  SW was derived from the TR clamped by the LW_L/LT_L formula window, then the
  global range clamp (commercial ratios, which differ from the formula window
  by the lens-offset term: 2.00 vs 1.99 wide, 3.41 vs 3.44 tele on the
  ET-D3QT500) tightened TR afterwards, leaving SW on the stale ratio.
- SW is now re-derived from the FINAL clamped TR, so the optical invariant
  L = TR x SW holds exactly at every slider position and the cone, diapo and
  camera agree at the extremes too. L no longer drifts.

================================================================================
v0.73.1 — "Info" datasheet tab, lens-shift overhaul, L-mode throw-ratio fix
================================================================================

-- L mode: the throw ratio drives the image again (formula regression) --------
- Fixes a regression introduced by v0.72.2: once the LW_L / LT_L formulas
  actually evaluated, L mode fed their result straight into the image width.
  Those formulas actually return the THROW RATIO at the lens's wide / tele
  zoom extremes for a given distance -- the code misread them as an SW in
  meters (a ~100x bogus width), so SW snapped to a nonsense value, editing TR
  no longer resized the projection cone, and the cone stopped meeting the
  edges of the projected diapo.
- L mode now keeps the optical invariant SW = L / TR: editing TR resizes the
  image at the held distance, and cone and diapo agree again at every ratio.
  The LW_L / LT_L formulas are used as what they are -- the reachable
  throw-ratio window at the current distance -- clamping the requested TR at
  the lens's zoom limits (their large-L limit is the commercial ratio; the
  affine term models the lens offset).

-- New "Info" tab: the full projector datasheet -------------------------------
- New read-only "Info" tab on the projector object, populated straight from the
  database record for the selected projector (and lens). It gathers everything
  the catalogue knows in one place, grouped into:
  * Identification — brand, model, reference.
  * Imaging / Technology — chip technology (DLP / LCoS type), lamp type
    (LASER / UHP), native resolution (with the XPR-doubled resolution when the
    panel has Quad Pixel Drive), image ratio, chip size, refresh rate, contrast.
  * Luminosity — Normal and Eco lumens, each in ISO and ANSI.
  * Physical / Electrical — dimensions, weight, chassis colour, lens mounting,
    power draw at 220 V (Normal / Eco / Strike), max V/H inclination, stack max.
  * Lens (Selected) — reference, model, type and F-value range of the mounted
    optic; it updates when you switch lenses.
- The tab appears only in Database mode (hidden for Custom projectors and while
  no projector is selected). Every field falls back to "-" when the underlying
  column is empty, so nothing ever reads as a blank or stale value.
- Chip-technology and lamp-type labels are resolved from their lookup tables, not
  shown as raw ids.

-- Lens shift: correct direction, spec-convention %, exact IC limits ----------
- Vertical shift direction fixed: dragging the matrix UP in the image-circle
  overlay now shifts the projected image UP (previously it went down). The sign
  is flipped in lockstep on all three consumers — the viewport cone, the
  look-through camera's film offset and the OpenBox projected slide (DB and
  custom assemblers) — so the cone, the render and the projected geometry stay
  consistent. Horizontal is unchanged.
- Shift percentages now follow the projector-spec convention. Horizontal is shown
  as a percentage of the HALF image width (x2), vertical as a percentage of the
  FULL image height (raw / aspect). On the PT-RQ50K / ET-D3QT500 the max reads
  32.0% horizontal and 45.0% vertical (was 16% / 23.7%). This is display-only:
  the stored value, the clamp and all optics keep using the raw IC-normalised
  shift, so nothing about the geometry changes.
- The maximum shift now equals the true geometric edge of the image circle. The
  clamp applied a 0.002 inset to the matrix RECTANGLE (halfW/halfH - margin)
  instead of to the image-circle polygon, which let the matrix centre overshoot
  the real boundary by 0.2% of the matrix width (16.2% instead of the exact
  16.0% = 0.66 - 0.5 horizontally). The inset is removed (margin = 0); a genuine
  safety margin, if ever needed, must inset the polygon, not shrink the rectangle.

================================================================================
v0.72.2 — "Use Formulas for TR Range" actually applies the formulas
================================================================================
- The projector/lens throw-ratio formulas are now evaluated. The formula parser
  was substituting the obsolete RMH/RMV variable names, but the database formulas
  use MH/MV (the raw MatrixH/MatrixV resolution) — so every formula silently
  failed and the TR range always fell back to the commercial ratios, in every
  mode.
- With the toggle ON (locked lens), the TR slider bounds now follow the LW_SW /
  LT_SW formulas at the current image size; OFF keeps the commercial ratios. The
  auto-mode global envelope, the projection-cone markers and the screen-width
  butée go through the same formulas too.
- Formulas are fed the raw MatrixH/MatrixV (not the reduced aspect ratio), and
  toggling the checkbox refreshes the slider bounds immediately.

================================================================================
v0.72.0 — Projector body texture loaded straight from the database
================================================================================
- New "Projector DB Texture" channel shader (ID 1069828): the projector body
  albedo is now sampled directly from the database texture BLOB, decoded in
  memory at render time. The texture is never written to disk, so it cannot leak
  as a loose file, and the .c4d stores only a hidden integer key — not a file
  path. This removes the stale-path "black projector" failure mode for good
  (superseding the v0.69.0 temp-dir workaround).
- Old documents self-heal: on rebuild, a projector whose body still carries the
  legacy on-disk bitmap is upgraded to the new shader automatically.
- Graceful fallback: if the database (or that texture) is unavailable at render
  time — e.g. a net-render node without the DB — the body falls back to the
  material's constant albedo colour instead of rendering black.

================================================================================
v0.71.0 — Render-matched look-through camera + "View From Projector"
================================================================================
- Looking through a projector now renders EXACTLY its view:
    * Camera focal length is driven by the throw ratio (horizontal FOV = the
      projection cone), aperture fixed at 36 mm. Works in DB and custom mode, no
      chip data needed.
    * Lens shift is mapped to the camera film offset: X maps 1:1, Y is scaled by
      matrixH/matrixV (width->height conversion) — both keep the shift's sign.
    * Render settings auto-sync to the active projector's native resolution
      (XRES/YRES + film aspect) while looking through it, and are restored to the
      user's originals when switching to another camera. Originals are stored in
      the render data, so they survive document save/reload.
- New command "View From Projector" (ID 1069815): moves the active viewport camera
  to the selected projector's viewpoint. If the view is already a projector (a
  locked camera), the default editor camera is used instead.

================================================================================
v0.70.0 — Image-circle shift overlay fixes
================================================================================
- Fix DB-mode IC overlay drawn upside-down (Y-flip centralised in IcScreenTransform).
- Double-click the matrix rectangle to reset H/V shift to 0 (recentre).
- CI matrix shift no longer clobbers the active 3D handle.
- AM H/V shift sliders clamp to the image circle and follow its arc when blocked.

================================================================================
v0.69.0 — Fix the "black projector"
================================================================================
- DB PBR textures are extracted to Cinema 4D's own temp directory (Application
  TEMP_DIR, "remap" subfolder) instead of the OS temp dir the renderer could not
  resolve. The projector body loads its albedo again.

================================================================================
v0.68.0 — Look-through camera + same-tick rebuild
================================================================================
- Projector look-through camera handles: centered layout, screen-axis drag, locked
  camera.
- Same-tick projector rebuild: removes the one-frame lag when dragging the projector
  or target with the Move tool.
- Look-through camera and projection light hidden in the editor from
  Execute@GENERATOR+1 (out of Draw), applied to the finalised cache every pass.

================================================================================
v0.67.0 — Luma Map post effect (ID 1069770)
================================================================================
- Illuminance heat map of the projectors, driven from Render Settings > Effects and
  toggled per viewport via Options > Post Effects: per pixel in the rendered image,
  adaptive OpenGL overlay in the editor, gradient gadget, min/max or auto scale,
  opacity, optional shadow rays.
- Also restores the R25 build (three 2024+-only API uses fixed).

================================================================================
v0.66.0 — Exclude body/lens from the projection light
================================================================================
- Projector body and lens excluded from the projection light (EXCLUDE mode,
  LIGHT_EXCLUSION_LIST) so the casing no longer blocks the beam or casts a shadow
  into the projected image.

================================================================================
v0.65.0 — Persist projector world-state
================================================================================
- Target, lens anchor, active handle and pivot persisted via Read/Write/CopyTo:
  position and aim kept on reload and duplicate; slide mire shows the advertised
  aspect ratio with XPR-doubled resolution.

================================================================================
v0.64.0 — One slide material per projector
================================================================================
- Unique Diapositive_<name> material carrying the projector's name on each slide,
  cloned on duplicate, renamed with the projector; legacy shared materials adopted.

================================================================================
v0.63.0 — True photometric lux (lm/m²)
================================================================================
- True lux everywhere: Attribute Manager ID_LUX, Sonde probe and Lux Meter tool;
  common-motor illuminance standardised on metres.

================================================================================
v0.62.0 — Sonde lux probe
================================================================================
- Scene object + click-to-place via the Lux Meter, shared common-motor illuminance
  (Blender-ready), dual-resolution mesh, aperture-bounded near-field lux.

================================================================================
v0.61.0 — 4K slide preview, light hide, material at creation
================================================================================
- Slide material: 4K preview + refraction index 1.0; Test Pattern defaults show
  name/resolution/ratio.
- Slide material created up-front at projector creation (menu + Catalog/Search).
- Projection light hidden in the editor (still renders + casts shadows).

================================================================================
v0.60.x — CI + auto cone fixes + per-lens gauge
================================================================================
- v0.60.3: CI, tagged releases built from main/dev (cpp branch retired).
- v0.60.1: cone hidden outside the lens range; lens auto-switch on move.
- v0.60.0: per-lens availability gauge (TR columns on the right edge, white line at
  current TR); cone/markers coloured by the active lens.

================================================================================
v0.59.0 — Image-size butée + continuous auto-switch
================================================================================
- Throw-ratio range as a single source of truth (mode + "Use Formulas" aware),
  shared by SW butée, TR clamp, slider bounds and cone markers; auto mode:
  continuous resize + lens auto-switch; keyboard entry validated.

================================================================================
v0.58.0 — Shared in-memory ProjectorDatabase
================================================================================
- Shared in-memory projector database + background lens-mesh preload for throw-ratio
  auto mode.

================================================================================
v0.55.0 – v0.57.1 — Handle/overlay polish, multi-selection matrix drag
================================================================================
- v0.57.1: darker, firmer viewport icon backdrop.
- v0.57.0: projector name above the IC circle in multi-selection.
- v0.56.0: IC matrix viewport drag for multi-selected projectors.
- v0.55.0: size handle stays on the target plane, +Z aim every pass, banking as a
  horizontal drag, lens<->target line, name HUD.

================================================================================
v0.54.0 — Projector banking
================================================================================
- Banking as a persistent parameter rolled inside the shared look-at (AimZAxis);
  RADIAL circle/knob handle, 45° snap, double-click reset; jump-free free-target
  mode; hidden Protection tag (rotation locked, position free).

================================================================================
v0.47.25 – v0.53.1 — C++ foundations (aiming, search, updater, drag)
================================================================================
- v0.53.0: database updater present in all four Cinema 4D builds
  (R25/2024/2025/2026), static OpenSSL 3, hard build failure if absent.
- v0.52.0: Projector Search revamp (lens/accessory trees, specs grid, field:value
  search).
- v0.51.0: aim delegated to common-motor-cpp + Projector Search command (ID 1069548).
- v0.50.0: interaction overhaul (body grab zone, free 3D target drag, live cone);
  textures moved to res/images.
- v0.49.0: C++ target-aiming system (world target, +Z convention).
- v0.48.0: schema version warning, per-parameter visibility toggles, Force Database
  Update.
- v0.47.25: CDN URL uses the /prod prefix, update pipeline validated end-to-end.

(Older history: see the annotated Git tags in the repository.)
