code wiki / (root) / nx_char_layers.nx

nx_char_layers.nx source

↩ module page · 131 lines · 7979 B

1// nx_char_layers.nx -- the LAYER STACK (operator: "a nude base + add layers of armor/clothing/makeup/other stuff"). 2// A character = a licensed nude BASE (variant + figure) + an ORDERED stack of layers, each applied in turn so 3// outer layers sit over inner. Layer types: OUTFIT (nx_outfit clothing/armor), ACCESSORY (belt/hat/necklace = extra 4// worn geometry), MAKEUP (a face-region cosmetic -- rendered in the charlab detailed-face pipeline, modeled here so 5// the stack + consent tier know about it). Generalizes the single nx_outfit slot into a composable stack; the 6// delivered nudity tier (nx_char_asset) reads the stack for a covering outfit. license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_sdfrender.nx" 9import "nx_outfit.nx" 10const LT_MAGIC_1405: i64 = 1405 11const LT_MAGIC_1330: i64 = 1330 12const LT_MAGIC_1350: i64 = 1350 13const LT_MAGIC_1180: i64 = 1180 14 15// layer types (operator: "really layer and change things" -- clothing/armor/makeup/jewelry/piercings/body-paint/ 16// body-hair grooming/hairstyles, all as data on the stack, on synthetic OR licensed-real characters) 17const LT_OUTFIT: i64 = 1 // clothing/armor via nx_outfit (tunic/robe/cloak/armor) 18const LT_ACCESSORY: i64 = 2 // worn geometry: belt / hat / necklace 19const LT_MAKEUP: i64 = 3 // face cosmetic (charlab face pipeline; nx_makeup) 20const LT_PIERCING: i64 = 4 // body jewelry / piercings (small metal studs at anatomical points) 21const LT_BODYHAIR: i64 = 5 // body-hair grooming STATE (id: 0 natural / 1 shaved / 2 trimmed) -- a render nuance 22const LT_BODYPAINT: i64 = 6 // body paint (a colored material on a body region) 23const LT_HAIRSTYLE: i64 = 7 // head hairstyle variant 24// accessories 25const ACC_BELT: i64 = 1 26const ACC_HAT: i64 = 2 27const ACC_NECKLACE: i64 = 3 28// piercings (small metal studs; tiny geometry at anatomical points) 29const PIERCE_NAVEL: i64 = 1 30const PIERCE_COLLAR: i64 = 2 31 32// add an accessory's geometry on the humanoid body (reuses nx_outfit's of_part; existing cloth/metal materials). 33func acc_apply(base: i64, n0: i64, id: i64) -> i64 { 34 var n: i64 = n0 35 if id == ACC_BELT { n = of_part(base, n, 0, 480, 30, 272, 62, 226, 8) } // metal-buckled waist belt (mat 8) 36 if id == ACC_HAT { n = of_part(base, n, 0, LT_MAGIC_1405, 0, 258, 150, 258, 5) } // crimson cap over the crown (mat 5) 37 if id == ACC_NECKLACE { n = of_part(base, n, 0, 950, 70, 168, 52, 150, 8) } // metal choker at the throat (mat 8) 38 let np: *i64 = (base + O_NPART) as *i64; np[0] = n 39 return n 40} 41// add piercing geometry: small metal studs at anatomical points (reuses of_part, mat 8 = metal). 42func pierce_apply(base: i64, n0: i64, id: i64) -> i64 { 43 var n: i64 = n0 44 if id == PIERCE_NAVEL { n = of_part(base, n, 0, 130, 285, 34, 34, 46, 8) } // navel stud 45 if id == PIERCE_COLLAR { n = of_part(base, n, 0-140, 900, 225, 30, 30, 30, 8); n = of_part(base, n, 140, 900, 225, 30, 30, 30, 8) } // collarbone studs 46 let np: *i64 = (base + O_NPART) as *i64; np[0] = n 47 return n 48} 49// body paint: recolor a body REGION by swapping its part material (like makeup but on the body). id selects a 50// preset; reuses cloth/paint materials. Applies to av_base_human part indices (2=chest,5-8=arms,9-10=legs). 51func bodypaint_apply(base: i64, id: i64) -> i64 { 52 if id == 1 { sdf_set_mat(base, 5, 7); sdf_set_mat(base, 8, 7) } // green paint on both upper arms (tribal) 53 if id == 2 { sdf_set_mat(base, 2, 5) } // crimson paint across the chest 54 return 0 55} 56// ★body-hair GROOMING (operator "body-hair grooming e.g. shave pubic/arm" -- the render half landed in 57// nx_sdfrender mats 14 natural / 15 trimmed = HAIRY SKIN, full skin pipeline + stubble flecks 38%/15%; this is 58// the layer half, landed 2026-07-07). PER-REGION as data: stack id = region*4 + state. 59// region: 0=ALL 1=ARMS (av parts 5-8) 2=LEGS (9-10) 3=CHEST (2) 4=PELVIC (4) 60// state: 1=NATURAL (mat 14) 2=TRIMMED (mat 15) 3=SHAVED (mat 0 = plain skin, explicit bare) 61// Stacks compose in order: [groom_id(0,1), groom_id(4,3), groom_id(1,3)] = natural all over, then pubic + 62// arms SHAVED -- the operator's exact ask. Shaved-after-natural returns the region byte-identical to bare. 63const GROOM_NATURAL: i64 = 1 64const GROOM_TRIMMED: i64 = 2 65const GROOM_SHAVED: i64 = 3 66const HREG_ALL: i64 = 0 67const HREG_ARMS: i64 = 1 68const HREG_LEGS: i64 = 2 69const HREG_CHEST: i64 = 3 70const HREG_PELVIC: i64 = 4 71func groom_id(region: i64, state: i64) -> i64 { return region * 4 + state } 72func bh_region(base: i64, region: i64, mat: i64) -> i64 { 73 if region == HREG_ARMS { sdf_set_mat(base, 5, mat); sdf_set_mat(base, 6, mat); sdf_set_mat(base, 7, mat); sdf_set_mat(base, 8, mat) } 74 if region == HREG_LEGS { sdf_set_mat(base, 9, mat); sdf_set_mat(base, 10, mat) } 75 if region == HREG_CHEST { sdf_set_mat(base, 2, mat) } 76 if region == HREG_PELVIC { sdf_set_mat(base, 4, mat) } 77 return 0 78} 79func bodyhair_apply(base: i64, id: i64) -> i64 { 80 let region: i64 = id / 4 81 let state: i64 = id % 4 82 if state == 0 { return 0 } // malformed id -> no-op (fail-closed) 83 var mat: i64 = 0 // SHAVED = back to plain skin 84 if state == GROOM_NATURAL { mat = 14 } 85 if state == GROOM_TRIMMED { mat = 15 } 86 if region == HREG_ALL { 87 bh_region(base, HREG_ARMS, mat) 88 bh_region(base, HREG_LEGS, mat) 89 bh_region(base, HREG_CHEST, mat) 90 bh_region(base, HREG_PELVIC, mat) 91 } else { bh_region(base, region, mat) } 92 return 0 93} 94// ★HAIRSTYLE on the VARIANT body head (av_base_human head part 0 at y=1250; landed 2026-07-07): appended 95// mat-2 HAIR volume, so the body render (synth bestiary scale) wears hair too. ids: 1 bob cap · 2 long 96// (cap + back-fall down the back, +z) · 3 pixie (tight cap) · 4 ponytail (cap + high tail) · 5 bald (no 97// parts -- the bare av head IS bald). The DETAILED close-up face has its own variants: sdf_face_hairstyle. 98func hairstyle_apply(base: i64, n0: i64, id: i64) -> i64 { 99 var n: i64 = n0 100 if id == 1 { n = of_part(base, n, 0, LT_MAGIC_1330, 40, 245, 240, 250, 2) } 101 if id == 2 { n = of_part(base, n, 0, LT_MAGIC_1330, 40, 245, 240, 250, 2); n = of_part(base, n, 0, 1020, 250, 210, 430, 130, 2) } 102 if id == 3 { n = of_part(base, n, 0, LT_MAGIC_1350, 25, 232, 215, 240, 2) } 103 if id == 4 { n = of_part(base, n, 0, LT_MAGIC_1330, 40, 245, 240, 250, 2); n = of_part(base, n, 0, LT_MAGIC_1180, 340, 90, 320, 90, 2) } 104 let np: *i64 = (base + O_NPART) as *i64; np[0] = n 105 return n 106} 107// apply an ordered layer stack. stack = i64[2*nl]: [type,id] pairs, applied in order. Returns the new part count. 108func char_layers_apply(base: i64, n0: i64, stack: *i64, nl: i64) -> i64 { 109 var n: i64 = n0 110 var i: i64 = 0 111 while i < nl { 112 let ty: i64 = stack[i*2] 113 let id: i64 = stack[i*2+1] 114 if ty == LT_OUTFIT { if id > 0 { n = outfit_apply(base, n, id) } } 115 if ty == LT_ACCESSORY { if id > 0 { n = acc_apply(base, n, id) } } 116 if ty == LT_PIERCING { if id > 0 { n = pierce_apply(base, n, id) } } 117 if ty == LT_BODYPAINT { if id > 0 { bodypaint_apply(base, id) } } 118 if ty == LT_BODYHAIR { if id > 0 { bodyhair_apply(base, id) } } 119 if ty == LT_HAIRSTYLE { if id > 0 { if id < 5 { n = hairstyle_apply(base, n, id) } } } // 5 = bald = the bare head 120 // LT_MAKEUP: face cosmetic -- executes on the DETAILED face pipeline (nx_makeup makeup_apply2 + 121 // nx_sdfrender sdf_face_hairstyle for the close-up head); recorded here for stack + delivered-tier logic. 122 i = i + 1 123 } 124 return n 125} 126// does the stack put a covering outfit on the base? (drives the delivered nudity tier in nx_char_asset) 127func stack_has_outfit(stack: *i64, nl: i64) -> i64 { 128 var i: i64 = 0 129 while i < nl { if stack[i*2] == LT_OUTFIT { if stack[i*2+1] > 0 { return 1 } } i = i + 1 } 130 return 0 131}