@@ -129,7 +129,14 @@ 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 { GLBuffer } from "#src/webgl/buffer.js" ;
133+ import { initializeWebGL } from "#src/webgl/context.js" ;
134+ import {
135+ makeTrackableFragmentMain ,
136+ makeWatchableShaderError ,
137+ parameterizedEmitterDependentShaderGetter ,
138+ } from "#src/webgl/dynamic_shader.js" ;
139+ import { ShaderControlState } from "#src/webgl/shader_ui_controls.js" ;
133140import type { DependentViewContext } from "#src/widget/dependent_view_widget.js" ;
134141import { registerLayerShaderControlsTool } from "#src/widget/shader_controls.js" ;
135142
@@ -410,12 +417,22 @@ class LinkedSegmentationGroupState<
410417 }
411418}
412419
420+ const DEFAULT_FRAGMENT_SEGMENT_COLOR = `
421+ vec4 segmentColor(vec4 color) {
422+ return color;
423+ }
424+ ` ;
425+
413426class SegmentationUserLayerDisplayState implements SegmentationDisplayState {
427+ private getSegmentColorShader ;
428+
414429 constructor ( public layer : SegmentationUserLayer ) {
415430 // Even though `SegmentationUserLayer` assigns this to its `displayState` property, redundantly
416431 // assign it here first in order to allow it to be accessed by `segmentationGroupState`.
417432 layer . displayState = this ;
418433
434+ this . getSegmentColorShader = this . makeSegmentColorShaderGetter ( ) ;
435+
419436 this . linkedSegmentationGroup = layer . registerDisposer (
420437 new LinkedLayerGroup (
421438 layer . manager . rootLayers ,
@@ -536,6 +553,8 @@ class SegmentationUserLayerDisplayState implements SegmentationDisplayState {
536553 ignoreNullVisibleSet = new TrackableBoolean ( true , true ) ;
537554 skeletonRenderingOptions = new SkeletonRenderingOptions ( ) ;
538555 shaderError = makeWatchableShaderError ( ) ;
556+ fragmentSegmentColor = makeTrackableFragmentMain ( DEFAULT_FRAGMENT_SEGMENT_COLOR ) ;
557+ segmentColorShaderControlState = new ShaderControlState ( this . fragmentSegmentColor ) ;
539558 renderScaleHistogram = new RenderScaleHistogram ( ) ;
540559 renderScaleTarget = trackableRenderScaleTarget ( 1 ) ;
541560 selectSegment : ( id : bigint , pin : boolean | "toggle" ) => void ;
@@ -551,6 +570,65 @@ class SegmentationUserLayerDisplayState implements SegmentationDisplayState {
551570 this . layer . moveToSegment ( id ) ;
552571 } ;
553572
573+ makeSegmentColorShaderGetter = ( ) => {
574+ const gl = initializeWebGL ( new OffscreenCanvas ( 1 , 1 ) ) ;
575+ const parameters = this . segmentColorShaderControlState . builderState ;
576+ return parameterizedEmitterDependentShaderGetter ( this . layer , gl , {
577+ memoizeKey : `segmentColorShaderTODO` ,
578+ parameters,
579+ encodeParameters : ( p ) => {
580+ return `${ p . parseResult . code } ` ;
581+ } ,
582+ shaderError : this . layer . displayState . shaderError , // TODO can I reuse this?
583+ defineShader : ( builder , shaderBuilderState ) => {
584+ builder . addAttribute ( "highp vec4" , "aVertexPosition" ) ;
585+ builder . addUniform ( "highp vec4" , "uColor" ) ;
586+ builder . addUniform ( "highp uvec2" , "uID" ) ;
587+ builder . addVarying ( "highp vec4" , "vColor" ) ;
588+ builder . addVertexCode ( shaderBuilderState . parseResult . code ) ;
589+ builder . addVertexMain ( `
590+ gl_Position = aVertexPosition;
591+ vColor = segmentColor(uColor);
592+ ` ) ;
593+ builder . addOutputBuffer ( "vec4" , "out_fragColor" , 0 ) ;
594+ builder . setFragmentMain ( "out_fragColor = vColor;" ) ;
595+ } ,
596+ } ) ;
597+ } ;
598+
599+ context = ( ) => { } ; // TEMP how to get rid of this?
600+
601+ getShaderSegmentColor = ( id : bigint , color : Float32Array ) => {
602+ id ; // TODO
603+ const { shader, parameters } = this . getSegmentColorShader ( this . context ) ;
604+ if ( shader === null ) return color ;
605+ parameters ;
606+ shader . bind ( ) ;
607+ const { gl } = shader ;
608+ const positionBuffer = GLBuffer . fromData (
609+ gl ,
610+ new Float32Array ( [ 1 , 1 , - 1 , 1 , 1 , - 1 , - 1 , - 1 ] ) ,
611+ ) ;
612+ positionBuffer . bindToVertexAttrib ( shader . attribute ( "aVertexPosition" ) , 2 ) ;
613+ gl . uniform4fv ( shader . uniform ( "uColor" ) , color ) ;
614+ gl . drawArrays ( gl . TRIANGLE_STRIP , 0 , 4 ) ;
615+ const data = new Uint8Array ( 4 ) ;
616+ // TODO can I read straight to float?
617+ gl . readPixels (
618+ 0 ,
619+ 0 ,
620+ 1 ,
621+ 1 ,
622+ WebGL2RenderingContext . RGBA ,
623+ WebGL2RenderingContext . UNSIGNED_BYTE ,
624+ data ,
625+ ) ;
626+ for ( let i = 0 ; i < data . length ; i ++ ) {
627+ color [ i ] = data [ i ] / 255.0 ;
628+ }
629+ return color ;
630+ } ;
631+
554632 linkedSegmentationGroup : LinkedLayerGroup ;
555633 linkedSegmentationColorGroup : LinkedLayerGroup ;
556634 originalSegmentationGroupState : SegmentationUserLayerGroupState ;
@@ -689,6 +767,9 @@ export class SegmentationUserLayer extends Base {
689767 this . displayState . linkedSegmentationGroup . changed . add ( ( ) =>
690768 this . updateDataSubsourceActivations ( ) ,
691769 ) ;
770+ this . displayState . fragmentSegmentColor . changed . add (
771+ this . specificationChanged . dispatch ,
772+ ) ;
692773 this . tabs . add ( "rendering" , {
693774 label : "Render" ,
694775 order : - 100 ,
@@ -996,6 +1077,9 @@ export class SegmentationUserLayer extends Base {
9961077 this . displayState . ignoreNullVisibleSet . restoreState (
9971078 specification [ json_keys . IGNORE_NULL_VISIBLE_SET_JSON_KEY ] ,
9981079 ) ;
1080+ this . displayState . fragmentSegmentColor . restoreState (
1081+ specification [ json_keys . SHADER_JSON_KEY ] ,
1082+ ) ;
9991083
10001084 const { skeletonRenderingOptions } = this . displayState ;
10011085 skeletonRenderingOptions . restoreState (
@@ -1066,6 +1150,7 @@ export class SegmentationUserLayer extends Base {
10661150 this . displayState . renderScaleTarget . toJSON ( ) ;
10671151 x [ json_keys . CROSS_SECTION_RENDER_SCALE_JSON_KEY ] =
10681152 this . sliceViewRenderScaleTarget . toJSON ( ) ;
1153+ x [ json_keys . SHADER_JSON_KEY ] = this . displayState . fragmentSegmentColor . toJSON ( ) ;
10691154
10701155 const { linkedSegmentationGroup, linkedSegmentationColorGroup } =
10711156 this . displayState ;
@@ -1365,6 +1450,7 @@ export class SegmentationUserLayer extends Base {
13651450
13661451 const visibleSegments = [ ...visibleSegmentsSet ] ;
13671452 const colors = visibleSegments . map ( ( id ) => {
1453+ // here we can do a batch get of colors using the segment color shader instead of one at a time
13681454 const color = getCssColor ( getBaseObjectColor ( displayState , id ) ) ;
13691455 return { color, id } ;
13701456 } ) ;
@@ -1401,6 +1487,10 @@ registerLayerTypeDetector((subsource) => {
14011487 return undefined ;
14021488} ) ;
14031489
1490+ registerLayerShaderControlsTool ( SegmentationUserLayer , ( layer ) => ( {
1491+ shaderControlState : layer . displayState . segmentColorShaderControlState ,
1492+ } ) ) ;
1493+
14041494registerLayerShaderControlsTool (
14051495 SegmentationUserLayer ,
14061496 ( layer ) => ( {
0 commit comments