input View { mat4 mvp, mat4 proj, mat4 proj_inverse, mat4 view, mat4 world, //geometry.world atm float2 fov, //fov.x, fov.y float2 resolution, float4 target_region, float4 target_region_size } input Font { image2D pages[8] } input UI { float2 canvas_size, float textured, float pixelated, #0 image2D tex_mask, #1 image2D tex, #1 image2D tex_pixelated } input FUI { float2 canvas_size, #0 image2D tex_mask } stage vertex vert( input { View view, UI ui }, vertex in { #0 float4 pos, #1 float4 color, #2 float2 uv, #3 float4 data, #4 float2 bounds }, fragment out { float4 color, float2 uv, float2 mask_uv, float clip, float page }) { out.uv = in.uv; out.color = in.color; out.clip = in.data.x; out.page = in.pos.w; //for fonts the text pos is text local and needs to be converted to canvas space. //we pass the bounds of the text item in via the vertices (I know) so we can calculate bounds-local space. //Then we convert that to canvas space, by * (bounds_w/canvas_w) //Then finally we add to the canvas local u/v from the data.z/w in float bounds_u = 0.0; float bounds_v = 0.0; if(in.bounds.x != 0.0) { bounds_u = (in.pos.x / in.bounds.x); } if(in.bounds.y != 0.0) { bounds_v = 1.0 - (in.pos.y / in.bounds.y); } //bounds_u/v is the 0...1 value for where this vert is in the text item itself //Note we flip the bounds_v because the text is in world space, bottom left origin, y+ up, //canvas space is top left, y+ down so it has to be reversed to be bounds local in canvas space float to_canvas_u = in.bounds.x / input.ui.canvas_size.x; float to_canvas_v = in.bounds.y / input.ui.canvas_size.y; //to_canvas_u is the text item width and height in 0...1 relative to the canvas //e.g if the text item width is 100 and the canvas is 200, the value is 0.5 //then what we do is add in.data.y/z which is the text x/y position, //but relative to the canvas space. we add this to shift the x/y into place. bounds_u = (bounds_u * to_canvas_u) + in.data.y; bounds_v = (bounds_v * to_canvas_v) + in.data.z; out.mask_uv = float2(bounds_u, bounds_v); stage.pos = input.view.mvp * float4(in.pos.xyz, 1.0); } stage fragment frag( input { FUI ui, Font font }, fragment in { float4 color, float2 uv, float2 mask_uv, float clip, float page }) { //outside mask uvs? bool outside_mask = in.mask_uv.x < 0.0 || in.mask_uv.x > 1.0 || in.mask_uv.y < 0.0 || in.mask_uv.y > 1.0; if(outside_mask) { discard; // stage.color[0] = float4(1,0.2,0.3,1); return; } float4 mask = texture(input.ui.tex_mask, in.mask_uv); //16 bit mask // float mask_clip = round(mask.r * 65535.0); //8 bit mask int lsb = int(round(mask.r * 255.0)); int msb = int(round(mask.g * 255.0)) * 256; //<< 8; int mask_clip = lsb | msb; // int mask_clip = lsb + msb; //webgl1 //outside our clipping bounds? int my_clip = int(in.clip); if(my_clip != 0 && mask_clip < my_clip) { discard; // stage.color[0] = float4(0,1,1,0.2); return; } int page = int(in.page); float4 msdf_sample = texture(input.font.pages[0], in.uv.xy); if(page == 1) { msdf_sample = texture(input.font.pages[1], in.uv.xy); } if(page == 2) { msdf_sample = texture(input.font.pages[2], in.uv.xy); } if(page == 3) { msdf_sample = texture(input.font.pages[3], in.uv.xy); } if(page == 4) { msdf_sample = texture(input.font.pages[4], in.uv.xy); } if(page == 5) { msdf_sample = texture(input.font.pages[5], in.uv.xy); } if(page == 6) { msdf_sample = texture(input.font.pages[6], in.uv.xy); } if(page == 7) { msdf_sample = texture(input.font.pages[7], in.uv.xy); } float r = msdf_sample.r; float g = msdf_sample.g; float b = msdf_sample.b; float median = max(min(r, g), min(max(r, g), b)); float opacity = float(median > 0.5); stage.color[0] = float4(in.color.rgb, in.color.a * opacity * mask.a); }