nx_texpaint_gate.nx
buildroot/runtime/nx_texpaint_gate.nx
about
nx_texpaint_gate.nx -- the gate for nx_texpaint_lib (/compare/dcc DC7, texture painting).
THE HAZARD THIS GATE IS SHAPED AGAINST is the one the task names: a paint function that writes THE WHOLE
ATLAS trivially passes "the known texel changed". So the load-bearing cell here is not the positive
control on its own -- it is the pair of BOUNDED-WRITE teeth beside it, which count the changed texels
against a HAND-COMPUTED disc area and then count the changed texels OUTSIDE the brush and require zero.
A whole-atlas painter fails both, a do-nothing painter fails the first, and only a correct one passes
both. Every disc area, every texel address and every painted BYTE VALUE below was worked out by hand
before the code was run; they are written as literals with their arithmetic in the comment, so a fixture
that agrees with a wrong implementation would have to be wrong in exactly the same way.
THE ANTI-TEAR PROOF IS A PERMANENT NEGATIVE CONTROL, NOT AN ANECDOTE. tp_stroke_core is the naive painter
-- shipped, public, callable -- so the tooth that proves the seam bleed matters RUNS the bleed-free
version and shows the far side of the cut untouched, then runs the full stroke and shows it painted. That
is a gv_bite that can be re-run by anyone, rather than a claim that the author once deleted the fix and
watched a test go red.
FIXTURE GEOMETRY, chosen so every boundary is exact and nothing rests on a rounding accident:
res 64, grid 4 -> tile width in UV units 65536/4 = 16384, chart bounds 16384*64/65536 = 16 texels.
So chart 0 is texels [0,16) x [0,16) and the four charts tile the atlas exactly, with no remainder.
A SECOND map set at grid 3 is carried on purpose: 65536/3 truncates to 21845, the charts land at 0,21,42
and stop at 63, so ONE texel column belongs to no chart at all. That is the case where a partition claim
could quietly leak, and it is asserted to SUM rather than assumed to.
100% sovereign. No hardware writes (Rule 26). license_tier: ORIGINAL expect_exit: 0
dependencies 5 imports · 0 importers
imports: nx_syscalls.nxnx_gate_verdict.nxnx_vecmath.nxnx_editstack_lib.nxnx_texpaint_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
| 31 | const TG_RES: i64 = 64 |
| 32 | const TG_GRID: i64 = 4 |
| 33 | const TG_GRID_ODD: i64 = 3 // the grid that does NOT divide the UV span evenly |
| 34 | const TG_NMAPS: i64 = 4 // albedo, specular, gloss, normal -- the shape of ntb_bake_pbr's map set |
| 35 | const TG_CAP: i64 = 8 // stroke-log capacity for the session fixtures |
| 36 | const TG_ALL_CH: i64 = 7 // every channel: mask 111 |
| 37 | const TG_CH_G: i64 = 2 // green only: mask 010 |
| 38 | const TG_CH_R: i64 = 1 // red only: mask 001 |
| 45 | const TG_CX: i64 = 8 |
| 46 | const TG_CY: i64 = 8 |
| 47 | const TG_R: i64 = 3 |
| 48 | const TG_DISC_AREA: i64 = 25 |
| 51 | const TG_CENTRE_BYTE: i64 = 255 |
| 55 | const TG_RIM_IN_DX: i64 = 2 |
| 56 | const TG_RIM_IN_BYTE: i64 = 65 |
| 58 | const TG_RIM_OUT_DX: i64 = 3 |
| 69 | const TG_SEAM_CX: i64 = 1 |
| 70 | const TG_SEAM_PLANAR: i64 = 20 |
| 71 | const TG_SEAM_BLEED: i64 = 5 |
| 72 | const TG_SEAM_FAR_X: i64 = 15 |
| 74 | const TG_STRENGTH: i64 = 1000 |
| 75 | const TG_VALUE: i64 = 255 |
| 76 | const TG_HALFSTR: i64 = 500 |
| 80 | const TG_NSTROKES: i64 = 3 |
| 82 | const TG_S2_MAP: i64 = 1 |
| 83 | const TG_S2_STRENGTH: i64 = 600 |
| 84 | const TG_S2_VALUE: i64 = 10 |
| 89 | const TG_S3_CX: i64 = 9 |
| 90 | const TG_S3_CY: i64 = 9 |
| 91 | const TG_S3_R: i64 = 2 |
| 92 | const TG_S3_STRENGTH: i64 = 300 |
| 93 | const TG_S3_VALUE: i64 = 200 |
| 94 | const TG_REEVAL_VALUE: i64 = 100 |
| 97 | const TG_UVSTRIDE_TEXC: i64 = 3 |
| 98 | const TG_UVSTRIDE_PAIR: i64 = 2 |
| 99 | const TG_NVERT: i64 = 3 |
| 100 | const TG_NTRI: i64 = 1 |
| 101 | const TG_U1: i64 = 32768 |
| 102 | const TG_V2: i64 = 32768 |
| 103 | const TG_B0: i64 = 200 |
| 104 | const TG_B1: i64 = 300 |
| 105 | const TG_B2: i64 = 500 |
| 106 | const TG_EXP_U: i64 = 9830 // (200*0 + 300*32768 + 500*0)/1000 = 9830400/1000 = 9830 (floor of 9830.4) |
| 107 | const TG_EXP_V: i64 = 16384 // (200*0 + 300*0 + 500*32768)/1000 = 16384000/1000 = 16384 exactly |
| 108 | const TG_EXP_X: i64 = 9 // 9830*64/65536 = 629120/65536 = 9 (floor of 9.5996) |
| 109 | const TG_EXP_Y: i64 = 16 // 16384*64/65536 = 1048576/65536 = 16 exactly |
| 112 | const TG_ODD_COVER: i64 = 63 |
| 113 | const TG_ODD_UNCOVERED: i64 = 1 |
functions
| 115 | func tg_eq(a: i64, b: i64) -> i64 { if a == b { return 1 } return 0 } called by 1: main |
| 116 | func tg_ne(a: i64, b: i64) -> i64 { if a != b { return 1 } return 0 } called by 1: main |
| 117 | func tg_gt(a: i64, b: i64) -> i64 { if a > b { return 1 } return 0 } called by 1: main |
| 118 | func tg_ge(a: i64, b: i64) -> i64 { if a >= b { return 1 } return 0 } called by 1: main |
| 119 | func tg_le(a: i64, b: i64) -> i64 { if a <= b { return 1 } return 0 } called by 1: main |
| 120 | func tg_say(s: *u8, v: i64) -> i64 { gv_puts(s); gv_num(v); gv_puts("\n" as *u8); return 0 } |
| 124 | func tg_fill(ms: *i64) -> i64 |
| 148 | func tg_differs(a: *i64, b: *i64, m: i64, x: i64, y: i64) -> i64 |
| 156 | func tg_changed_map(a: *i64, b: *i64, m: i64) -> i64 |
| 169 | func tg_out_of_disc(ms: *i64, cx: i64, cy: i64, r: i64, x: i64, y: i64) -> i64 |
| 183 | func tg_changed_outside(a: *i64, b: *i64, m: i64, cx: i64, cy: i64, r: i64) -> i64 |
| 200 | func tg_changed_other_maps(a: *i64, b: *i64, m: i64) -> i64 |
| 209 | func tg_column_changed(a: *i64, b: *i64, m: i64, x: i64) -> i64 |
| 218 | func tg_black() -> *i64 { return tp_maps_new(TG_RES, TG_NMAPS, TG_GRID) } |
| 220 | func tg_patterned() -> *i64 |
| 227 | func tg_apply_session(ms: *i64, first_value: i64) -> i64 |
| 233 | func tg_record_session(st: *i64, ms: *i64, first_value: i64) -> i64 |
| 240 | func main(argc: i64, argv: *i64) -> i64 |