code wiki / (root) / nx_gltf_render_material_candidate_t181.nx

nx_gltf_render_material_candidate_t181.nx source

↩ module page · 131 lines · 13651 B

1// nx_gltf_render_material_candidate_t181.nx -- Generates JSON metadata for GLTF materials using SHA-256 hashing and buffer view data. 2import "nx_gltf_pose_candidate_t181.nx" 3import "nx_sha256.nx" 4func gpd_source_identity(w:*i64,cx:*i64)->i64{ 5 let digest:*u8=sys_mmap_try(32);if (digest as i64)==0{return -7};sha256_digest(cx[6] as *u8,cx[7],digest);let hex:*u8="0123456789abcdef";gpd_s(w,"\"sourceSha256\":\"");var i:i64=0;while i<32{let b:i64=digest[i] as i64;gpd_put(w,(hex as i64+b/16) as *u8,1);gpd_put(w,(hex as i64+b%16) as *u8,1);i=i+1};gpd_s(w,"\",");sys_munmap_direct(digest,32);return 0 6} 7 8// Native render descriptor over retained GLB bytes. No geometry or image transcoding. 9// Writer state: output, capacity, position, failure. A null output performs sizing. 10func gpd_put(w:*i64,s:*u8,n:i64)->i64{ 11 if w[3]!=0{return -1};if n<0||w[2]>GLD_I64_MAX-n{w[3]=-1;return -1} 12 if w[0]>0{if n>w[1]-w[2]{w[3]=-1;return -1};let b:*u8=w[0] as *u8;var i:i64=0;while i<n{b[w[2]+i]=s[i];i=i+1}} 13 w[2]=w[2]+n;return 0 14} 15func gpd_s(w:*i64,s:*u8)->i64{return gpd_put(w,s,gll_slen(s))} 16func gpd_n(w:*i64,n:i64)->i64{ 17 if n<0{w[3]=-1;return -1};var d:i64=1;while d<=n/10{d=d*10};var left:i64=n 18 while d>0{let digit:i64=48+left/d;let chars:*u8="0123456789";if gpd_put(w,(chars as i64+digit-48) as *u8,1)!=0{return -1};left=left%d;d=d/10};return 0 19} 20func gpd_raw(w:*i64,cx:*i64,parent:i64,key:*u8,fallback:*u8)->i64{ 21 let h:i64=gli_member(cx,parent,key);if h<0{return -1};if h==0{return gpd_s(w,fallback)} 22 let sp:*i64=cx[4] as *i64;return gpd_put(w,(cx[0]+sp[0]) as *u8,sp[1]-sp[0]) 23} 24func gpd_view(w:*i64,cx:*i64,accessor:i64,v:*i64)->i64{ 25 let st:*i64=cx[5] as *i64;if gltf_accessor_view(cx,accessor,st[2],v)!=0{return -1} 26 gpd_s(w,"[");gpd_n(w,accessor);var i:i64=0;while i<GLD_VIEW_WORDS{gpd_s(w,",");gpd_n(w,v[i]);i=i+1};return gpd_s(w,"]") 27} 28func gpd_alpha(cx:*i64,mat:i64)->i64{ 29 let have:i64=gli_member(cx,mat,"alphaMode");if have<0{return -1};if have==0{return 0} 30 let t:*NxJsonTok=cx[2] as *NxJsonTok;let sp:*i64=cx[4] as *i64;glp_reset(t,cx[0] as *u8,cx[1],sp[0]) 31 if glp_eq(t,"OPAQUE")==1{return 0};if glp_eq(t,"MASK")==1{return 1};if glp_eq(t,"BLEND")==1{return 2};return -1 32} 33func gpd_image(w:*i64,cx:*i64,texture:i64)->i64{ 34 let tx:i64=gld_nth(cx,0,"textures",texture);if tx<0||gli_member(cx,tx,"extensions")!=0{return -1} 35 let image:i64=gld_int(cx,tx,"source",-1);let im:i64=gld_nth(cx,0,"images",image);if im<0||gli_member(cx,im,"uri")!=0{return -1} 36 let vi:i64=gld_int(cx,im,"bufferView",-1);let view:i64=gld_nth(cx,0,"bufferViews",vi);if view<0||gld_int(cx,view,"buffer",-1)!=0||gli_member(cx,view,"extensions")!=0{return -1} 37 let off:i64=gld_int(cx,view,"byteOffset",0);let len:i64=gld_int(cx,view,"byteLength",-1);let bf:i64=gld_nth(cx,0,"buffers",0);let declared:i64=gld_int(cx,bf,"byteLength",-1) 38 if off<0||len<=0||off>declared||len>declared-off{return -1} 39 gpd_s(w,"{\"image\":");gpd_n(w,image);gpd_s(w,",\"offset\":");gpd_n(w,cx[8]-cx[6]+off);gpd_s(w,",\"bytes\":");gpd_n(w,len);gpd_s(w,",\"mime\":");if gpd_raw(w,cx,im,"mimeType","null")!=0{return -1} 40 let si:i64=gld_int(cx,tx,"sampler",-1);var sampler:i64=-1;if si>=0{sampler=gld_nth(cx,0,"samplers",si);if sampler<0{return -1}} 41 gpd_s(w,",\"sampler\":{");var mag:i64=9729;var min:i64=9987;var ws:i64=10497;var wt:i64=10497 42 if sampler>=0{mag=gld_int(cx,sampler,"magFilter",9729);min=gld_int(cx,sampler,"minFilter",9987);ws=gld_int(cx,sampler,"wrapS",10497);wt=gld_int(cx,sampler,"wrapT",10497)} 43 if mag!=9728&&mag!=9729{return -1};if min!=9728&&min!=9729&&min!=9984&&min!=9985&&min!=9986&&min!=9987{return -1} 44 if ws!=10497&&ws!=33071&&ws!=33648{return -1};if wt!=10497&&wt!=33071&&wt!=33648{return -1} 45 gpd_s(w,"\"mag\":");gpd_n(w,mag);gpd_s(w,",\"min\":");gpd_n(w,min);gpd_s(w,",\"wrapS\":");gpd_n(w,ws);gpd_s(w,",\"wrapT\":");gpd_n(w,wt);return gpd_s(w,"}}") 46} 47// Validate unit-interval decimals exactly; fixed-point truncation alone admits values just outside endpoints. 48func gpd_unit_token(s:*u8,n:i64)->i64{ 49 var value:i64=0;if gld_number_fixed(s,n,1,&value)!=0{return -1} 50 var start:i64=0;if s[0]==(45 as u8){start=1} 51 var i:i64=start;var digits:i64=0;var before:i64=0;var dotted:i64=0;var first:i64=-1;var leading:i64=0;var tail:i64=0 52 while i<n&&s[i]!=(101 as u8)&&s[i]!=(69 as u8){let c:i64=s[i] as i64;if c==46{before=digits;dotted=1}else{if c!=48{if first<0{first=digits;leading=c-48}else{tail=1}};digits=digits+1};i=i+1} 53 if first<0{return 0};if start!=0{return -1};if dotted==0{before=digits} 54 var exponent:i64=0;var sign:i64=1;let bound:i64=n+1 55 if i<n{i=i+1;if s[i]==(45 as u8){sign=0-1;i=i+1}else{if s[i]==(43 as u8){i=i+1}};while i<n{let d:i64=(s[i] as i64)-48;if exponent>(bound-d)/10{exponent=bound}else{exponent=exponent*10+d};i=i+1}} 56 let magnitude:i64=before-first-1+sign*exponent;if magnitude<0{return 0};if magnitude>0||leading!=1||tail!=0{return -1};return 0 57} 58func gpd_unit_field(w:*i64,cx:*i64,parent:i64,key:*u8,fallback:*u8,count:i64)->i64{ 59 if parent<0{return gpd_s(w,fallback)};let have:i64=gli_member(cx,parent,key);if have<0{return -1};if have==0{return gpd_s(w,fallback)} 60 let sp:*i64=cx[4] as *i64;let begin:i64=sp[0];let end:i64=sp[1];let t:*NxJsonTok=cx[2] as *NxJsonTok;glp_reset(t,cx[0] as *u8,cx[1],begin) 61 if count>1{if t.kind!=NX_JSON_LBRACKET{return -1};nx_json_next(t)};var i:i64=0 62 while i<count{if t.kind!=NX_JSON_NUMBER||gpd_unit_token((t.src as i64+t.tok_off) as *u8,t.tok_len)!=0{return -1};i=i+1;nx_json_next(t);if i<count{if t.kind!=NX_JSON_COMMA{return -1};nx_json_next(t)}} 63 if count>1&&t.kind!=NX_JSON_RBRACKET{return -1};return gpd_put(w,(cx[0]+begin) as *u8,end-begin) 64} 65// Retain unsupported map metadata and expose lit admission instead of silently dropping it. 66func gpd_material_inputs(w:*i64,cx:*i64,mat:i64,pbr:i64)->i64{ 67 var unsupported:i64=0;gpd_s(w,",\"mapInputs\":{");var i:i64=0 68 while i<4{var key:*u8="normalTexture";var parent:i64=mat;if i==1{key="occlusionTexture"};if i==2{key="emissiveTexture"};if i==3{key="metallicRoughnessTexture";parent=pbr} 69 if i>0{gpd_s(w,",")};gpd_s(w,"\"");gpd_s(w,key);gpd_s(w,"\":");var have:i64=0;if parent>=0{have=gli_member(cx,parent,key)};if have<0{return -1};if have==0{gpd_s(w,"null")}else{unsupported=unsupported+1;if gpd_raw(w,cx,parent,key,"null")!=0{return -1}};i=i+1 70 };gpd_s(w,"},\"litEligible\":");if unsupported==0{gpd_s(w,"true")}else{gpd_s(w,"false")};gpd_s(w,",\"litUnsupportedInputs\":");gpd_n(w,unsupported);gpd_s(w,",\"litReason\":\"");if unsupported==0{gpd_s(w,"scalar-basecolor-inputs-supported")}else{gpd_s(w,"material-map-inputs-not-rendered")};gpd_s(w,"\"");return 0 71} 72func gpd_material(w:*i64,cx:*i64,index:i64)->i64{ 73 let mat:i64=gld_nth(cx,0,"materials",index);if mat<0||gli_member(cx,mat,"extensions")!=0{return -1} 74 let mode:i64=gpd_alpha(cx,mat);if mode<0{return -1} 75 gpd_s(w,"{\"index\":");gpd_n(w,index);gpd_s(w,",\"alpha\":");gpd_n(w,mode);gpd_s(w,",\"cutoff\":");if gpd_raw(w,cx,mat,"alphaCutoff","0.5")!=0{return -1} 76 gpd_s(w,",\"doubleSided\":");if gpd_raw(w,cx,mat,"doubleSided","false")!=0{return -1} 77 var h:i64=gli_member(cx,mat,"pbrMetallicRoughness");if h<0{return -1};let sp:*i64=cx[4] as *i64;var pbr:i64=-1;if h==1{pbr=sp[0]} 78 gpd_s(w,",\"factor\":");if gpd_unit_field(w,cx,pbr,"baseColorFactor","[1,1,1,1]",4)!=0{return -1} 79 gpd_s(w,",\"metallicFactor\":");if gpd_unit_field(w,cx,pbr,"metallicFactor","1",1)!=0{return -1} 80 gpd_s(w,",\"roughnessFactor\":");if gpd_unit_field(w,cx,pbr,"roughnessFactor","1",1)!=0{return -1} 81 gpd_s(w,",\"emissiveFactor\":");if gpd_unit_field(w,cx,mat,"emissiveFactor","[0,0,0]",3)!=0{return -1} 82 gpd_s(w,",\"baseColor\":");var texture:i64=-1 83 if pbr>=0{h=gli_member(cx,pbr,"baseColorTexture");if h<0{return -1};if h==1{let bt:i64=sp[0];if gli_member(cx,bt,"extensions")!=0||gld_int(cx,bt,"texCoord",0)!=0{return -1};texture=gld_int(cx,bt,"index",-1);if texture<0{return -1}}} 84 if texture<0{gpd_s(w,"null")}else{if gpd_image(w,cx,texture)!=0{return -1}} 85 if gpd_material_inputs(w,cx,mat,pbr)!=0{return -1} 86 return gpd_s(w,"}") 87} 88func gltf_render_descriptor(cx:*i64,mesh:i64,skin:i64,w:*i64)->i64{ 89 if (cx as i64)<=0||(w as i64)<=0{return -1};let st:*i64=cx[5] as *i64 90 let m:i64=gld_nth(cx,0,"meshes",mesh);let sk:i64=gld_nth(cx,0,"skins",skin);if m<0||sk<0{return -1} 91 if gli_member(cx,m,"extensions")!=0||gli_member(cx,m,"weights")!=0{return -2} 92 let n:i64=gli_array(cx,m,"primitives",0);if n<=0{return -1};let joints:i64=gli_array(cx,sk,"joints",0);if joints<=0{return -1} 93 let v:*i64=sys_mmap_try(GLD_VIEW_WORDS*8) as *i64;if (v as i64)==0{return -7};var rc:i64=0 94 gpd_s(w,"{");if gpd_source_identity(w,cx)!=0{sys_munmap_direct(v as *u8,GLD_VIEW_WORDS*8);return -7};gpd_s(w,"\"schema\":\"nishi-authored-render/1\",\"scope\":\"source-albedo-and-discrete-native-pose\",\"basis\":\"gltf-Y-up\",\"physicalScale\":null,\"sourceBytes\":");gpd_n(w,cx[7]);gpd_s(w,",\"binOffset\":");gpd_n(w,cx[8]-cx[6]);gpd_s(w,",\"mesh\":");gpd_n(w,mesh);gpd_s(w,",\"skin\":");gpd_n(w,skin);gpd_s(w,",\"joints\":");gpd_n(w,joints);gpd_s(w,",\"parts\":[") 95 var i:i64=0 96 while i<n{ 97 let p:i64=gld_nth(cx,m,"primitives",i);if p<0||gli_member(cx,p,"extensions")!=0||gli_member(cx,p,"targets")!=0||gld_int(cx,p,"mode",4)!=4{rc=-2;break} 98 let h:i64=gli_member(cx,p,"attributes");let sp:*i64=cx[4] as *i64;if h!=1{rc=-1;break};let a:i64=sp[0] 99 let vertexColor:i64=gli_member(cx,a,"COLOR_0");if vertexColor<0{rc=-2;break} 100 if i>0{gpd_s(w,",")};gpd_s(w,"{\"attributes\":{");var j:i64=0 101 while j<6{var key:*u8="POSITION";if j==1{key="JOINTS_0"};if j==2{key="WEIGHTS_0"};if j==3{key="TEXCOORD_0"};if j==4{key="NORMAL"};if j==5{key="TANGENT"} 102 let ai:i64=gld_int(cx,a,key,-1);if ai<0{rc=-2;break};if j>0{gpd_s(w,",")};gpd_s(w,"\"");gpd_s(w,key);gpd_s(w,"\":");if gpd_view(w,cx,ai,v)!=0{rc=-2;break};j=j+1 103 };if rc!=0{break};gpd_s(w,"},\"vertexColorInput\":");if gpd_raw(w,cx,a,"COLOR_0","null")!=0{rc=-2;break};gpd_s(w,",\"litGeometryEligible\":");if vertexColor==0{gpd_s(w,"true")}else{gpd_s(w,"false")};gpd_s(w,",\"litGeometryReason\":\"");if vertexColor==0{gpd_s(w,"vertex-color-absent")}else{gpd_s(w,"linear-vertex-color-not-rendered")};gpd_s(w,"\",\"indices\":");let ix:i64=gld_int(cx,p,"indices",-1);if ix<0||gpd_view(w,cx,ix,v)!=0{rc=-2;break};if v[5]!=1||v[6]!=0||(v[3]!=5121&&v[3]!=5123&&v[3]!=5125)||v[1]%3!=0{rc=-2;break} 104 gpd_s(w,",\"material\":");let ma:i64=gld_int(cx,p,"material",-1);if ma<0||gpd_material(w,cx,ma)!=0{rc=-2;break};gpd_s(w,"}");i=i+1 105 } 106 gpd_s(w,"]}");sys_munmap_direct(v as *u8,GLD_VIEW_WORDS*8);if w[3]!=0{return -3};return rc 107} 108 109func gpd_i(w:*i64,n:i64)->i64{if n==0-GLD_I64_MAX-1{return -1};if n<0{gpd_s(w,"-");return gpd_n(w,0-n)};return gpd_n(w,n)} 110// Caller selects exact native sample times; no baked matrix interpolation. 111func gltf_render_poses(cx:*i64,animation:i64,skin:i64,position:i64,jointattr:i64,weightattr:i64,times:*i64,samples:i64,w:*i64)->i64{ 112 if samples<=0||(times as i64)<=0{return -1};let st:*i64=cx[5] as *i64;let count:i64=st[5];let sk:i64=gld_nth(cx,0,"skins",skin);if sk<0{return -1};let joints:i64=gli_array(cx,sk,"joints",0) 113 if count<=0||joints<=0||count>GLD_I64_MAX/368||joints>GLD_I64_MAX/128{return -1} 114 let need:i64=count*368;if joints*128>GLD_I64_MAX-need-GLD_VIEW_WORDS*24-72{return -1};let bytes:i64=need+joints*128+GLD_VIEW_WORDS*24+72 115 let mem:*u8=sys_mmap_try(bytes);if (mem as i64)==0{return -7};let parents:*i64=mem as *i64;let local:*i64=(mem as i64+count*8) as *i64;let world:*i64=(local as i64+count*128) as *i64;let done:*i64=(world as i64+count*128) as *i64;let trs:*i64=(done as i64+count*8) as *i64;let flags:*i64=(trs as i64+count*80) as *i64;let masks:*i64=(flags as i64+count*8) as *i64;let palette:*i64=(masks as i64+count*8) as *i64;let pv:*i64=(palette as i64+joints*128) as *i64;let jv:*i64=(pv as i64+GLD_VIEW_WORDS*8) as *i64;let wv:*i64=(jv as i64+GLD_VIEW_WORDS*8) as *i64;let vertex:*i64=(wv as i64+GLD_VIEW_WORDS*8) as *i64;let bounds:*i64=(vertex as i64+24) as *i64 116 var rc:i64=0 117 if gltf_accessor_view(cx,position,st[2],pv)!=0||gltf_accessor_view(cx,jointattr,st[2],jv)!=0||gltf_accessor_view(cx,weightattr,st[2],wv)!=0||gld_parents(cx,count,parents)!=0{rc=-2} 118 gpd_s(w,"{");if gpd_source_identity(w,cx)!=0{sys_munmap_direct(mem,bytes);return -7};gpd_s(w,"\"schema\":\"nishi-native-discrete-lbs/1\",\"q\":");gpd_n(w,FBB_Q);gpd_s(w,",\"timeQ\":");gpd_n(w,VM_Q30);gpd_s(w,",\"animation\":");gpd_n(w,animation);gpd_s(w,",\"skin\":");gpd_n(w,skin);gpd_s(w,",\"samples\":[") 119 var sample:i64=0 120 while sample<samples&&rc==0{ 121 var i:i64=0;while i<count{flags[i]=gld_node_trs(cx,i,(trs as i64+i*80) as *i64,(local as i64+i*128) as *i64);if flags[i]<0{rc=-2;break};i=i+1};if rc!=0{break} 122 let channels:i64=gld_animate(cx,animation,times[sample],trs,count,masks);if channels<0{rc=-3;break} 123 i=0;while i<count{if flags[i]==0{if gld_trs_matrix((trs as i64+i*80) as *i64,(local as i64+i*128) as *i64)!=0{rc=-4;break}};i=i+1};if rc!=0{break} 124 if gld_world_matrices(count,parents,local,world,done)!=0||gld_skin_palette(cx,skin,world,count,palette,joints)!=joints{rc=-5;break} 125 if sample>0{gpd_s(w,",")};gpd_s(w,"{\"time\":");gpd_i(w,times[sample]);gpd_s(w,",\"channels\":");gpd_n(w,channels);gpd_s(w,",\"palette\":[");i=0 126 while i<joints*16{if i>0{gpd_s(w,",")};gpd_i(w,palette[i]);i=i+1};gpd_s(w,"],\"bounds\":[") 127 i=0;while i<pv[1]{if gld_skin_vertex(cx,pv,jv,wv,i,palette,joints,vertex)!=0{rc=-6;break};var k:i64=0;while k<3{if i==0||vertex[k]<bounds[k]{bounds[k]=vertex[k]};if i==0||vertex[k]>bounds[k+3]{bounds[k+3]=vertex[k]};k=k+1};i=i+1};if rc!=0{break} 128 i=0;while i<6{if i>0{gpd_s(w,",")};gpd_i(w,bounds[i]);i=i+1};gpd_s(w,"]}");sample=sample+1 129 } 130 gpd_s(w,"]}");sys_munmap_direct(mem,bytes);if w[3]!=0{return -3};return rc 131}