@@ -129,9 +129,21 @@ import {
129129 verifyString ,
130130} from "#src/util/json.js" ;
131131import { Signal } from "#src/util/signal.js" ;
132- import { makeWatchableShaderError } from "#src/webgl/dynamic_shader.js" ;
132+ import {
133+ makeTrackableFragmentMain ,
134+ makeWatchableShaderError ,
135+ parameterizedEmitterDependentShaderGetter ,
136+ } from "#src/webgl/dynamic_shader.js" ;
133137import type { DependentViewContext } from "#src/widget/dependent_view_widget.js" ;
134138import { registerLayerShaderControlsTool } from "#src/widget/shader_controls.js" ;
139+ import { ShaderControlState } from "#src/webgl/shader_ui_controls.js" ;
140+ import { initializeWebGL } from "#src/webgl/context.js" ;
141+ import {
142+ bigIntPreprocessing ,
143+ glsl_equalUint64 ,
144+ glsl_uint64 ,
145+ } from "#src/webgl/shader_lib.js" ;
146+ import { GLBuffer } from "#src/webgl/buffer.js" ;
135147
136148const MAX_LAYER_BAR_UI_INDICATOR_COLORS = 6 ;
137149
@@ -410,7 +422,15 @@ class LinkedSegmentationGroupState<
410422 }
411423}
412424
425+ const DEFAULT_FRAGMENT_MAIN = `
426+ vec4 segmentColor(vec4 color, uint64_t valueForColor) {
427+ return color;
428+ }
429+ ` ;
430+
413431class SegmentationUserLayerDisplayState implements SegmentationDisplayState {
432+ private getShader ;
433+
414434 constructor ( public layer : SegmentationUserLayer ) {
415435 // Even though `SegmentationUserLayer` assigns this to its `displayState` property, redundantly
416436 // assign it here first in order to allow it to be accessed by `segmentationGroupState`.
@@ -520,6 +540,9 @@ class SegmentationUserLayerDisplayState implements SegmentationDisplayState {
520540 ( group ) => group . segmentPropertyMap ,
521541 ) ,
522542 ) ;
543+ // end constructor
544+
545+ this . getShader = this . makeGetter ( ) ;
523546 }
524547
525548 segmentSelectionState = new SegmentSelectionState ( ) ;
@@ -536,6 +559,8 @@ class SegmentationUserLayerDisplayState implements SegmentationDisplayState {
536559 ignoreNullVisibleSet = new TrackableBoolean ( true , true ) ;
537560 skeletonRenderingOptions = new SkeletonRenderingOptions ( ) ;
538561 shaderError = makeWatchableShaderError ( ) ;
562+ fragmentMain = makeTrackableFragmentMain ( DEFAULT_FRAGMENT_MAIN ) ;
563+ shaderControlState = new ShaderControlState ( this . fragmentMain ) ;
539564 renderScaleHistogram = new RenderScaleHistogram ( ) ;
540565 renderScaleTarget = trackableRenderScaleTarget ( 1 ) ;
541566 selectSegment : ( id : bigint , pin : boolean | "toggle" ) => void ;
@@ -551,6 +576,77 @@ class SegmentationUserLayerDisplayState implements SegmentationDisplayState {
551576 this . layer . moveToSegment ( id ) ;
552577 } ;
553578
579+ makeGetter = ( ) => {
580+ const gl = initializeWebGL ( new OffscreenCanvas ( 1 , 1 ) ) ;
581+ const parameters = this . shaderControlState . builderState ;
582+ return parameterizedEmitterDependentShaderGetter ( this . layer , gl , {
583+ memoizeKey : `segmentColorShaderTODO` ,
584+ parameters,
585+ encodeParameters : ( p ) => {
586+ return `${ p . parseResult . code } ` ;
587+ } ,
588+ shaderError : this . layer . displayState . shaderError , // TODO can I reuse this?
589+ defineShader : ( builder , shaderBuilderState ) => {
590+ builder . addAttribute ( "highp vec4" , "aVertexPosition" ) ;
591+ builder . addUniform ( "highp vec4" , "uColor" ) ;
592+ builder . addUniform ( "highp uvec2" , "uID" ) ;
593+ builder . addVarying ( "highp vec4" , "vColor" ) ;
594+ builder . addVertexCode ( glsl_uint64 ) ;
595+ builder . addVertexCode ( glsl_equalUint64 ) ;
596+ builder . addVertexCode (
597+ bigIntPreprocessing ( shaderBuilderState . parseResult . code ) ,
598+ ) ;
599+ builder . addVertexMain ( `
600+ gl_Position = aVertexPosition;
601+ vColor = segmentColor(uColor, uint64_t(uID));
602+ ` ) ;
603+ builder . addOutputBuffer ( "vec4" , "out_fragColor" , 0 ) ;
604+ builder . setFragmentMain ( "out_fragColor = vColor;" ) ;
605+ } ,
606+ } ) ;
607+ } ;
608+
609+ context = ( ) => { } ; // TEMP
610+
611+ getShaderSegmentColor = ( id : bigint , color : Float32Array ) => {
612+ const { shader, parameters } = this . getShader ( this . context ) ;
613+ if ( shader === null ) return color ;
614+ parameters ;
615+ shader . bind ( ) ;
616+ const { gl } = shader ;
617+ {
618+ const positionBuffer = GLBuffer . fromData (
619+ gl ,
620+ new Float32Array ( [ 1 , 1 , - 1 , 1 , 1 , - 1 , - 1 , - 1 ] ) ,
621+ ) ;
622+ positionBuffer . bindToVertexAttrib ( shader . attribute ( "aVertexPosition" ) , 2 ) ;
623+ }
624+ {
625+ gl . uniform4fv ( shader . uniform ( "uColor" ) , color ) ;
626+ gl . uniform2ui (
627+ shader . uniform ( `uID` ) ,
628+ Number ( id & 0xffffffffn ) ,
629+ Number ( id >> 32n ) ,
630+ ) ;
631+ }
632+ gl . drawArrays ( gl . TRIANGLE_STRIP , 0 , 4 ) ;
633+ const data = new Uint8Array ( 4 ) ;
634+ // TODO can I read straight to float?
635+ gl . readPixels (
636+ 0 ,
637+ 0 ,
638+ 1 ,
639+ 1 ,
640+ WebGL2RenderingContext . RGBA ,
641+ WebGL2RenderingContext . UNSIGNED_BYTE ,
642+ data ,
643+ ) ;
644+ for ( let i = 0 ; i < data . length ; i ++ ) {
645+ color [ i ] = data [ i ] / 255.0 ;
646+ }
647+ return color ;
648+ } ;
649+
554650 linkedSegmentationGroup : LinkedLayerGroup ;
555651 linkedSegmentationColorGroup : LinkedLayerGroup ;
556652 originalSegmentationGroupState : SegmentationUserLayerGroupState ;
@@ -689,6 +785,9 @@ export class SegmentationUserLayer extends Base {
689785 this . displayState . linkedSegmentationGroup . changed . add ( ( ) =>
690786 this . updateDataSubsourceActivations ( ) ,
691787 ) ;
788+ this . displayState . fragmentMain . changed . add (
789+ this . specificationChanged . dispatch ,
790+ ) ;
692791 this . tabs . add ( "rendering" , {
693792 label : "Render" ,
694793 order : - 100 ,
@@ -996,6 +1095,9 @@ export class SegmentationUserLayer extends Base {
9961095 this . displayState . ignoreNullVisibleSet . restoreState (
9971096 specification [ json_keys . IGNORE_NULL_VISIBLE_SET_JSON_KEY ] ,
9981097 ) ;
1098+ this . displayState . fragmentMain . restoreState (
1099+ specification [ json_keys . SHADER_JSON_KEY ] ,
1100+ ) ;
9991101
10001102 const { skeletonRenderingOptions } = this . displayState ;
10011103 skeletonRenderingOptions . restoreState (
@@ -1066,6 +1168,7 @@ export class SegmentationUserLayer extends Base {
10661168 this . displayState . renderScaleTarget . toJSON ( ) ;
10671169 x [ json_keys . CROSS_SECTION_RENDER_SCALE_JSON_KEY ] =
10681170 this . sliceViewRenderScaleTarget . toJSON ( ) ;
1171+ x [ json_keys . SHADER_JSON_KEY ] = this . displayState . fragmentMain . toJSON ( ) ;
10691172
10701173 const { linkedSegmentationGroup, linkedSegmentationColorGroup } =
10711174 this . displayState ;
@@ -1365,6 +1468,7 @@ export class SegmentationUserLayer extends Base {
13651468
13661469 const visibleSegments = [ ...visibleSegmentsSet ] ;
13671470 const colors = visibleSegments . map ( ( id ) => {
1471+ // here we can do a batch get of colors using the segment color shader instead of one at a time
13681472 const color = getCssColor ( getBaseObjectColor ( displayState , id ) ) ;
13691473 return { color, id } ;
13701474 } ) ;
@@ -1401,6 +1505,10 @@ registerLayerTypeDetector((subsource) => {
14011505 return undefined ;
14021506} ) ;
14031507
1508+ registerLayerShaderControlsTool ( SegmentationUserLayer , ( layer ) => ( {
1509+ shaderControlState : layer . displayState . shaderControlState ,
1510+ } ) ) ;
1511+
14041512registerLayerShaderControlsTool (
14051513 SegmentationUserLayer ,
14061514 ( layer ) => ( {
0 commit comments