nx_nxa_texm.nx
buildroot/runtime/nx_nxa_texm.nx
about
nx_nxa_texm.nx -- WRITE THE TEXM SECTION: the baked PBR map set carried INSIDE the asset.
THE MEASURED GAP THIS CLOSES. nx_asset_floor_gate scores the shipped character 4/7 and prints
"PBR texture maps (TEXM) -- we shade procedurally from genome: ABSENT". An independent lane
measured that this -- not triangle count -- is why renders read as clay: at 28,092 tris the
silhouette is already at 0.94x a shipping real-time budget, and the body carries 104 joints
against VRM 1.0's 15 required. Adequate FORM with NO SURFACE is the definition of clay.
TEXC (the UV unwrap) has been present in the asset for some time and nx_nxa_texbake produces
real maps -- but NOTHING WROTE A MAP BACK INTO THE CONTAINER. Proven absence, not assumed:
grep TEXM over 23,018 files, coverage_complete=1 corpus_complete=1, returns exactly TWO hits,
both inside nx_asset_floor_gate, both READS. This organ is the missing writer.
WHICH PBR MODEL TEXM STORES, AND WHY -- SETTLED HERE RATHER THAN LEFT IMPLICIT.
TEXM stores SPECULAR-GLOSSINESS: D(albedo) S(specular) G(gloss) N(normal), exactly the set
nx_nxa_texbake_lib bakes (NTB_MAP_ALBEDO/SPEC/GLOSS/NORMAL) and exactly the set
knowledge/asset_texture_floor.conf measured from 23 real shipped packages ("tex_map_set 4 maps
D(diffuse) S(specular) G(gloss) N|NM(normal)"). Storing anything else would mean transcoding at
bake time and recording a number no instrument in this estate produces.
!!THE CONSEQUENCE, STATED PLAINLY RATHER THAN DISCOVERED LATER: glTF 2.0 core is
METALLIC-ROUGHNESS, and KHR_materials_pbrSpecularGlossiness was ARCHIVED by Khronos. So a TEXM
set CANNOT be written to core glTF 2.0 without a conversion, and that conversion is LOSSY --
spec-gloss to metal-rough is not bijective (a dielectric with a coloured specular has no exact
metal-rough equivalent). Anyone exporting TEXM through glTF owes that conversion step; this
organ does not pretend it is free. The alternative -- baking metal-rough instead -- was NOT
chosen because it would make our own measured floor unusable as a comparison.
ADDITIVE ONLY (rule 13). Every pre-existing section is copied forward and its checksum is
RECOMPUTED rather than copied, because a copied checksum validates its own bug -- the same
discipline nx_nxa_texc_lib's ntx_apply already applies. An existing TEXM is REPLACED, not
duplicated, so the organ is idempotent: running it twice yields one TEXM, never two.
RESOLUTION IS NOT MINE TO PICK. The default is READ from knowledge/asset_texture_floor.conf
(tex_res_floor, measured at 4096 px from real package image headers). If the conf cannot be
read the organ REFUSES rather than inventing a default -- an unmeasured default is exactly the
magic number this estate forbids. A caller may override it explicitly, and the organ ANNOUNCES
the bytes each map cost so the resource decision is visible instead of buried.
nx_nxa_texm <in.nxa> <out.nxa> [res] [seed] [hue]
EXITS: 0 OK | 2 usage | 3 bad container | 4 missing prerequisite section | 1 I/O
license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
dependencies 6 imports · 0 importers
imports: nx_syscalls.nxnx_nxa.nxnx_nxa_texc_lib.nxnx_nxa_texbake_lib.nxnx_png.nxnx_relief_lib.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 52 | const TXM_OK: i64 = 0 |
| 53 | const TXM_E_IO: i64 = 1 |
| 54 | const TXM_E_USAGE: i64 = 2 |
| 55 | const TXM_E_BAD: i64 = 3 |
| 56 | const TXM_E_NOSEC: i64 = 4 |
| 62 | const TXM_HDR_WORDS: i64 = 6 |
| 63 | const TXM_MAPREC_WORDS: i64 = 3 |
| 64 | const TXM_W_NMAPS: i64 = 0 |
| 65 | const TXM_W_RES: i64 = 1 |
| 66 | const TXM_W_MODEL: i64 = 2 |
| 67 | const TXM_W_SEED: i64 = 3 |
| 68 | const TXM_W_HUE: i64 = 4 |
| 69 | const TXM_W_BLOBW: i64 = 5 |
| 72 | const TXM_MODEL_SPECGLOSS: i64 = 1 |
| 73 | const TXM_MODEL_METALROUGH: i64 = 2 |
| 76 | const TXM_CONF_PATH: *u8 = "knowledge/asset_texture_floor.conf" |
| 77 | const TXM_CONF_KEY: *u8 = "tex_res_floor" |
| 78 | const TXM_CONF_CAP: i64 = 65536 |
| 82 | const TXM_DEFAULT_SEED: i64 = 1 |
| 83 | const TXM_RES_MIN: i64 = 8 // a PNG smaller than one filter block is not a texture |
| 85 | const TXM_ASCII_NL: i64 = 10 |
| 86 | const TXM_ASCII_SP: i64 = 32 |
| 87 | const TXM_ASCII_TAB: i64 = 9 |
| 88 | const TXM_ASCII_ZERO: i64 = 48 |
| 89 | const TXM_ASCII_NINE: i64 = 57 |
| 90 | const TXM_DECIMAL: i64 = 10 |
| 91 | const TXM_RGB_BYTES: i64 = 3 |
| 92 | const TXM_PIX_G_SHIFT: i64 = 256 |
| 93 | const TXM_PIX_B_SHIFT: i64 = 65536 |
| 94 | const TXM_WORD_BYTES: i64 = 8 |
| 95 | const TXM_MISS: i64 = 0 - 1 |
| 100 | const TXM_SHIP_CONF: *u8 = "knowledge/texture_ship_budget.conf" |
| 101 | const TXM_SHIP_ARG: *u8 = "ship" |
| 105 | const TXM_RUNG_4096: i64 = 4096 |
| 106 | const TXM_RUNG_2048: i64 = 2048 |
| 107 | const TXM_RUNG_1024: i64 = 1024 |
| 108 | const TXM_RUNG_512: i64 = 512 |
functions
| 110 | func txm_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } |
| 116 | func txm_atoi(s: *u8) -> i64 called by 1: main |
| 136 | func txm_conf_int(key: *u8) -> i64 |
| 196 | func txm_apply(inp: *u8, outp: *u8, res: i64, seed: i64, hue: i64) -> i64 |
| 368 | func txm_conf_at(path: *u8, key: *u8) -> i64 |
| 424 | func txm_is_ship(s: *u8) -> i64 called by 1: main |
| 437 | func txm_ship_res(confpath: *u8) -> i64 |
| 452 | func main(argc: i64, argv: *i64) -> i64 |