Big crt mask function for copypaste

I pushed the current one up to the GLSL repo and I’ll get working on converting it to slang ASAP.

If it’s useful to anyone, I made a big function that can drop into pretty much any shader (including this one) to pick from a big pile of masks, including the ones mentioned here and the ones from cgwg’s geom-deluxe LUTs (14 masks in total):

vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
   vec3 weights = vec3(0.,0.,0.);
   float intens = 1.;
   float inv = 1.-mask_intensity;
   vec3 green   = vec3(inv, intens, inv);
   vec3 magenta = vec3(intens,inv,intens);
   vec3 black   = vec3(inv,inv,inv);
   vec3 red     = vec3(intens,inv,inv);
   vec3 yellow  = vec3(intens,inv,intens);
   vec3 cyan    = vec3(inv,intens,intens);
   vec3 blue    = vec3(inv,inv,intens);
   int w, z = 0;
   
   vec3 aperture_weights = mix(magenta, green, floor(mod(coord.x, 2.0)));

   if(phosphor_layout == 1){
      // classic aperture for RGB panels; good for 1080p, too small for 4K+
      // aka aperture_1_2_bgr
      weights  = aperture_weights;
   }

   else if(phosphor_layout == 2){
      // 2x2 shadow mask for RGB panels; good for 1080p, too small for 4K+
      // aka delta_1_2x1_bgr
      vec3 inverse_aperture = mix(green, magenta, floor(mod(coord.x, 2.0)));
      weights               = mix(aperture_weights, inverse_aperture, floor(mod(coord.y, 2.0)));
   }

   else if(phosphor_layout == 3){
      // slot mask for RGB panels; too low-pitch for 1080p, looks okay at 4K, but wants 8K+
      vec3 slotmask[4][6] = {
         {magenta, green, black, magenta, green, black},
         {magenta, green, black, black,   black, black},
         {magenta, green, black, magenta, green, black},
         {black,   black, black, magenta, green, black}
      };
      
      // find the vertical index
      w = int(floor(mod(coord.y, 4.0)));

      // find the horizontal index
      z = int(floor(mod(coord.x, 6.0)));

      // use the indexes to find which color to apply to the current pixel
      weights = slotmask[w][z];
   }

   if(phosphor_layout == 4){
      // classic aperture for RBG panels; good for 1080p, too small for 4K+
      weights  = mix(yellow, blue, floor(mod(coord.x, 2.0)));
   }

   else if(phosphor_layout == 5){
      // 2x2 shadow mask for RBG panels; good for 1080p, too small for 4K+
      vec3 inverse_aperture = mix(blue, yellow, floor(mod(coord.x, 2.0)));
      weights               = mix(mix(yellow, blue, floor(mod(coord.x, 2.0))), inverse_aperture, floor(mod(coord.y, 2.0)));
   }
   
   else if(phosphor_layout == 6){
      // aperture_1_4_rgb
      vec3 ap4[4] = vec3[](red, green, blue, black);
      
      z = int(floor(mod(coord.x, 4.0)));
      
      weights = ap4[z];
   }
   
   else if(phosphor_layout == 7){
      // aperture_2_5_bgr
      vec3 ap3[5] = vec3[](red, magenta, blue, green, green);
      
      z = int(floor(mod(coord.x, 5.0)));
      
      weights = ap3[z];
   }
   
   else if(phosphor_layout == 8){
      // aperture_3_6_rgb
      
      vec3 big_ap[7] = vec3[](red, red, yellow, green, cyan, blue, blue);
      
      w = int(floor(mod(coord.x, 8.)));
      
      weights = big_ap[w];
   }
   
   else if(phosphor_layout == 9){
      // reduced TVL aperture for RGB panels
      // aperture_2_4_rgb
      
      vec3 big_ap_rgb[4] = vec3[](red, yellow, cyan, blue);
      
      w = int(floor(mod(coord.x, 4.)));
      
      weights = big_ap_rgb[w];
   }
   
   else if(phosphor_layout == 10){
      // reduced TVL aperture for RBG panels
      
      vec3 big_ap_rbg[4] = vec3[](red, magenta, cyan, green);
      
      w = int(floor(mod(coord.x, 4.)));
      
      weights = big_ap_rbg[w];
   }
   
   else if(phosphor_layout == 11){
      // delta_1_4x1_rgb; dunno why this is called 4x1 when it's obviously 4x2 /shrug
      vec3 delta1[2][4] = {
         { red, green, blue, black },
         { blue, black, red, green }
      };
      
      w = int(floor(mod(coord.y, 2.0)));
      z = int(floor(mod(coord.x, 4.0)));
      
      weights = delta1[w][z];
   }
   
   else if(phosphor_layout == 12){
      // delta_2_4x1_rgb
      vec3 delta[2][4] = {
         {red, yellow, cyan, blue},
         {cyan, blue, red, yellow}
      };
      
      w = int(floor(mod(coord.y, 2.0)));
      z = int(floor(mod(coord.x, 4.0)));
      
      weights = delta[w][z];
   }
   
   else if(phosphor_layout == 13){
      // delta_2_4x2_rgb
      vec3 delta[4][4] = {
         {red, yellow, cyan, blue},
         {red, yellow, cyan, blue},
         {cyan, blue, red, yellow},
         {cyan, blue, red, yellow}
      };
      
      w = int(floor(mod(coord.y, 4.0)));
      z = int(floor(mod(coord.x, 4.0)));
      
      weights = delta[w][z];
   }
   
   else if(phosphor_layout == 14){
      // slot_2_4x4_rgb
      vec3 slot2[4][8] = {
         {red, yellow, cyan, blue, red, yellow, cyan, blue},
         {red, yellow, cyan, blue, black, black, black, black},
         {red, yellow, cyan, blue, red, yellow, cyan, blue},
         {black, black, black, black, red, yellow, cyan, blue}
      };
   
      w = int(floor(mod(coord.y, 4.0)));
      z = int(floor(mod(coord.x, 8.0)));
      
      weights = slot2[w][z];
   }

   else if(phosphor_layout == 15){
      // slot mask for RBG panels; too low-pitch for 1080p, looks okay at 4K, but wants 8K+
      vec3 slotmask[4][6] = {
         {yellow, blue, black, yellow, blue, black},
         {yellow, blue, black, black,   black, black},
         {yellow, blue, black, yellow, blue, black},
         {black,   black, black, yellow, blue, black}
      };
      
      // find the vertical index
      w = int(floor(mod(coord.y, 4.0)));

      // find the horizontal index
      z = int(floor(mod(coord.x, 6.0)));

      // use the indexes to find which color to apply to the current pixel
      weights = slotmask[w][z];
   }
   
   else if(phosphor_layout == 16){
      // slot_2_5x4_bgr
      vec3 slot2[4][10] = {
         {red, magenta, blue, green, green, red, magenta, blue, green, green},
         {black, blue, blue, green, green, red, red, black, black, black},
         {red, magenta, blue, green, green, red, magenta, blue, green, green},
         {red, red, black, black, black, black, blue, blue, green, green}
      };
   
      w = int(floor(mod(coord.y, 4.0)));
      z = int(floor(mod(coord.x, 10.0)));
      
      weights = slot2[w][z];
   }
   
   else if(phosphor_layout == 17){
      // slot_3_7x6_rgb
      vec3 slot[6][14] = {
         {red,   red,   yellow, green, cyan,  blue,  blue,  red,   red,   yellow, green,  cyan,  blue,  blue},
         {red,   red,   yellow, green, cyan,  blue,  blue,  red,   red,   yellow, green,  cyan,  blue,  blue},
         {red,   red,   yellow, green, cyan,  blue,  blue,  black, black, black,  black,  black, black, black},
         {red,   red,   yellow, green, cyan,  blue,  blue,  red,   red,   yellow, green,  cyan,  blue,  blue},
         {red,   red,   yellow, green, cyan,  blue,  blue,  red,   red,   yellow, green,  cyan,  blue,  blue},
         {black, black, black,  black, black, black, black, black, red,   red,    yellow, green, cyan,  blue}
      };
      
      w = int(floor(mod(coord.y, 6.0)));
      z = int(floor(mod(coord.x, 14.0)));
      
      weights = slot[w][z];
   }

   return weights;
}

It’s trivial to add more masks in this manner, and they’re laid out in such a way that even non-coders should be able to play around with it, if they like.

EDIT: updated with moar masks. Up to 16 17 now.

8 Likes

Nice! This is the mask mega-pack! :grin:

So does that mean we CAN do dotmask with this shader, after all…?

Going to give it a shot later today.

One thing-

```
   else if(phosphor_layout == 3){
      // slot mask for RGB panels; good for 1080p, too small for 4K+
      vec3 slotmask[4][6] = {
         {magenta, green, black, magenta, green, black},
         {magenta, green, black, black,   black, black},
         {magenta, green, black, magenta, green, black},
         {black,   black, black, magenta, green, black}
      };
```

Are you sure you didn’t mean to say something like “Ideally, needs 8K or higher to produce a realistic result. Too coarse for either 1080p or 4K.”

The usual way of determining “TVL” (number of LCD pixels measured vertically divided by number of “phosphor triads” measured horizontally within a distance equal to the height of the display) doesn’t really work with the slotmask. Instead we just have to count phosphor triads measured vertically. The lowest TVL displays probably had 5 phosphor triads per scanline, multiplied by 4 pixels per “phosphor triad,” multiplied by 240 scanlines, (using a 13" Commodore monitor for reference). 5 * 4 * 240 = 4800 pixels needed. Or, slightly more than what you have available at 8K… If you’re starting with 224 scanlines, then you need 4480 pixels, so 8K would be enough with just a slight amount of overscan.

whoops, yeah. fixed.

As for putting it into this shader, it seems there’s no way to completely disable the mask through parameters, but it looks like you can comment out this line:

color = mix(1.15*scan3, color, (1.0-maskstr)*tmp1)*(1.0 + 0.15*maskstr);

and then you just need to add this line above the last line (i.e., just above the FragColor line):

color *= mask_weights(gl_FragCoord.xy, 1.0, 4);

In the above example, the ‘4’ is the mask that’s being picked, 1.0 is the mask strength. You could replace either one with a parameter.

EDIT: I made a slight change to the function posted above to reflect these instructions.

EDIT2: just realized I was working from the slang version I just pushed up and changed it to match the GLSL syntax instead.

EDIT3: gah, nvm, it’s not going to work with GLSL because of all the 2D arrays. I could convert them to work with GLSL, but it may not be worth the trouble.

2 Likes

GLSL technically supports 2D arrays but it was only added very recently, and our GLSL shaders are typically written for very old standards. We can force it to the new one using the version directives, but that would cause a lot of problems for mobile, etc. so probably not worth doing. We only lose masks 11-14 anyway.

You should already have glcore. It’s in settings > driver > video driver.

2 Likes

Just updated assets and I don’t see it… just GL, vulkan, d3d9-12, sdl2, gdi

Hmm, weird. It shouldn’t need any assets or anything. Are you using a super-old version of RetroArch, by chance?

Anyway, I went ahead and converted all but the 14th mask, which seemed like a weird one to me anyway:

vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
   vec3 weights = vec3(0.,0.,0.);
   float intens = 1.;
   float inv = 1.-mask_intensity;
   vec3 green   = vec3(inv, intens, inv);
   vec3 magenta = vec3(intens,inv,intens);
   vec3 black   = vec3(inv,inv,inv);
   vec3 red     = vec3(intens,inv,inv);
   vec3 yellow  = vec3(intens,inv,intens);
   vec3 cyan    = vec3(inv,intens,intens);
   vec3 blue    = vec3(inv,inv,intens);
   int w, z = 0;
   
   vec3 aperture_weights = mix(magenta, green, floor(mod(coord.x, 2.0)));

   if(phosphor_layout == 1){
      // classic aperture for RGB panels; good for 1080p, too small for 4K+
      weights  = aperture_weights;
   }

   else if(phosphor_layout == 2){
      // 2x2 shadow mask for RGB panels; good for 1080p, too small for 4K+
      vec3 inverse_aperture = mix(green, magenta, floor(mod(coord.x, 2.0)));
      weights               = mix(aperture_weights, inverse_aperture, floor(mod(coord.y, 2.0)));
   }

   else if(phosphor_layout == 3){
      // slot mask for RGB panels; too low-pitched for 1080p, looks okay at 4K but wants 8K+
      // Can't do 2D arrays until version 430, so do this stupid thing instead
      // first lay out the horizontal pixels in arrays
      vec3 slotmask_x1[6] = vec3[](magenta,green,black,magenta,green,black);
      vec3 slotmask_x2[6] = vec3[](magenta,green,black,black,black,black);
      vec3 slotmask_x3[6] = vec3[](magenta,green,black,magenta,green,black);
      vec3 slotmask_x4[6] = vec3[](black,black,black,magenta,green,black);
      
      // find the vertical index
      w = int(floor(mod(coord.y, 4.0)));
      
      // find the horizontal index
      z = int(floor(mod(coord.x, 6.0)));

      // do a big, dumb comparison in place of a 2D array
      weights = (w == 1) ? slotmask_x1[z] : (w == 2) ? slotmask_x2[z] : (w == 3) ? slotmask_x3[z] : slotmask_x4[z];
    }

   if(phosphor_layout == 4){
      // classic aperture for RBG panels; good for 1080p, too small for 4K+
      weights  = mix(yellow, blue, floor(mod(coord.x, 2.0)));
   }

   else if(phosphor_layout == 5){
      // 2x2 shadow mask for RBG panels; good for 1080p, too small for 4K+
      vec3 inverse_aperture = mix(blue, yellow, floor(mod(coord.x, 2.0)));
      weights               = mix(mix(yellow, blue, floor(mod(coord.x, 2.0))), inverse_aperture, floor(mod(coord.y, 2.0)));
   }
   
   else if(phosphor_layout == 6){
      // aperture_1_4_rgb
      vec3 ap4[4] = vec3[](red, green, blue, black);
      
      z = int(floor(mod(coord.x, 4.0)));
      
      weights = ap4[z];
   }
   
   else if(phosphor_layout == 7){
      // aperture_2_5_bgr
      vec3 ap3[5] = vec3[](red, magenta, blue, green, green);
      
      z = int(floor(mod(coord.x, 5.0)));
      
      weights = ap3[z];
   }
   
   else if(phosphor_layout == 8){
      // aperture_3_6_rgb
      
      vec3 big_ap[7] = vec3[](red, red, yellow, green, cyan, blue, blue);
      
      w = int(floor(mod(coord.x, 8.)));
      
      weights = big_ap[w];
   }
   
   else if(phosphor_layout == 9){
      // reduced TVL aperture for RGB panels
      
      vec3 big_ap_rgb[4] = vec3[](red, yellow, cyan, blue);
      
      w = int(floor(mod(coord.x, 4.)));
      
      weights = big_ap_rgb[w];
   }
   
   else if(phosphor_layout == 10){
      // reduced TVL aperture for RBG panels
      
      vec3 big_ap_rbg[4] = vec3[](red, magenta, cyan, green);
      
      w = int(floor(mod(coord.x, 4.)));
      
      weights = big_ap_rbg[w];
   }
   
   else if(phosphor_layout == 11){
      // delta_1_4x1_rgb; dunno why this is called 4x1 when it's obviously 4x2 /shrug
      vec3 delta_1_1[4] = vec3[](red, green, blue, black);
      vec3 delta_1_2[4] = vec3[](blue, black, red, green);
      
      w = int(floor(mod(coord.y, 2.0)));
      z = int(floor(mod(coord.x, 4.0)));
      
      weights = (w == 1) ? delta_1_1[z] : delta_1_2[z];
   }
   
   else if(phosphor_layout == 12){
      // delta_2_4x1_rgb
      vec3 delta_2_1[4] = vec3[](red, yellow, cyan, blue);
      vec3 delta_2_2[4] = vec3[](cyan, blue, red, yellow);
      
      z = int(floor(mod(coord.x, 4.0)));
      
      weights = (w == 1) ? delta_2_1[z] : delta_2_2[z];
   }
   
   else if(phosphor_layout == 13){
      // delta_2_4x2_rgb
      vec3 delta_1[4] = vec3[](red, yellow, cyan, blue);
      vec3 delta_2[4] = vec3[](red, yellow, cyan, blue);
      vec3 delta_3[4] = vec3[](cyan, blue, red, yellow);
      vec3 delta_4[4] = vec3[](cyan, blue, red, yellow);
     
      w = int(floor(mod(coord.y, 4.0)));
      z = int(floor(mod(coord.x, 4.0)));
      
      weights = (w == 1) ? delta_1[z] : (w == 2) ? delta_2[z] : (w == 3) ? delta_3[z] : delta_4[z];
   }
   
   else if(phosphor_layout == 14){
      // slot_2_4x4_rgb
      vec3 slot2_1[8] = vec3[](red, yellow, cyan, blue, red, yellow, cyan, blue);
      vec3 slot2_2[8] = vec3[](red, yellow, cyan, blue, black, black, black, black);
      vec3 slot2_3[8] = vec3[](red, yellow, cyan, blue, red, yellow, cyan, blue);
      vec3 slot2_4[8] = vec3[](black, black, black, black, red, yellow, cyan, blue);
   
      w = int(floor(mod(coord.y, 4.0)));
      z = int(floor(mod(coord.x, 8.0)));
      
      weights = (w == 1) ? slot2_1[z] : (w == 2) ? slot2_2[z] : (w == 3) ? slot2_3[z] : slot2_4[z];
   }

   else if(phosphor_layout == 15){
      // slot mask for RBG panels; too low-pitched for 1080p, looks okay at 4K but wants 8K+
      vec3 slotmask_RBG_x1[6] = vec3[](yellow,blue,black,yellow,blue,black);
      vec3 slotmask_RBG_x2[6] = vec3[](yellow,blue,black,black,black,black);
      vec3 slotmask_RBG_x3[6] = vec3[](yellow,blue,black,yellow,blue,black);
      vec3 slotmask_RBG_x4[6] = vec3[](black,black,black,yellow,blue,black);
      
      // find the vertical index
      w = int(floor(mod(coord.y, 4.0)));
      
      // find the horizontal index
      z = int(floor(mod(coord.x, 6.0)));

      weights = (w == 1) ? slotmask_RBG_x1[z] : (w == 2) ? slotmask_RBG_x2[z] : (w == 3) ? slotmask_RBG_x3[z] : slotmask_RBG_x4[z];
    }
   
   else if(phosphor_layout == 16){
      // slot_2_5x4_bgr
      vec3 slot2_1[10] = vec3[](red, magenta, blue, green, green, red, magenta, blue, green, green);
      vec3 slot2_2[10] = vec3[](black, blue, blue, green, green, red, red, black, black, black);
      vec3 slot2_3[10] = vec3[](red, magenta, blue, green, green, red, magenta, blue, green, green);
      vec3 slot2_4[10] = vec3[](red, red, black, black, black, black, blue, blue, green, green);
   
      w = int(floor(mod(coord.y, 4.0)));
      z = int(floor(mod(coord.x, 10.0)));
      
      weights = (w == 1) ? slot2_1[z] : (w == 2) ? slot2_2[z] : (w == 3) ? slot2_3[z] : slot2_4[z];
   }
   
   else if(phosphor_layout == 17){
      // slot_3_7x6_rgb
      vec3 slot_1[14] = vec3[](red,   red,   yellow, green, cyan,  blue,  blue,  red,   red,   yellow, green,  cyan,  blue,  blue);
      vec3 slot_2[14] = vec3[](red,   red,   yellow, green, cyan,  blue,  blue,  red,   red,   yellow, green,  cyan,  blue,  blue);
      vec3 slot_3[14] = vec3[](red,   red,   yellow, green, cyan,  blue,  blue,  black, black, black,  black,  black, black, black);
      vec3 slot_4[14] = vec3[](red,   red,   yellow, green, cyan,  blue,  blue,  red,   red,   yellow, green,  cyan,  blue,  blue);
      vec3 slot_5[14] = vec3[](red,   red,   yellow, green, cyan,  blue,  blue,  red,   red,   yellow, green,  cyan,  blue,  blue);
      vec3 slot_6[14] = vec3[](black, black, black,  black, black, black, black, black, red,   red,    yellow, green, cyan,  blue);
      
      w = int(floor(mod(coord.y, 6.0)));
      z = int(floor(mod(coord.x, 14.0)));
      
      weights = (w == 1) ? slot_1[z] : (w == 2) ? slot_2[z] : (w == 3) ? slot_3[z] : (w == 4) ? slot_4[z] : (w == 5) ? slot_5[z] : slot_6[z];
   }
   
   return weights;
}

I guess this is getting pretty OT for Guest’s thread, so I’ll break this off into its own so as not to muddy the waters.

EDIT: updated with the rest of the masks.

2 Likes

read my mind… was just about to ask you to do this.

Woah, yeah. That one is weird! Looking at it up close though, it’s actually a pretty awesome slotmask pattern - it solves the problem of the excessive black spaces between the phosphor triads that you get with the regular magenta/green slotmask, which means less brightness is lost and you get a higher dot pitch (slot pitch?). Also gives you a more accurate phosphor shape. Still wants 8K for the best result.

image

image

Also, here’s this, for the 5 people on the planet that have an 8K display with RBG pixels :stuck_out_tongue:

image

image

And now I need to come up with a RBG version of the wacky one above. :smiley:

Probably. After updating assets I can’t even get RA to launch. Going to try a re-install sometime this evening.

2 Likes

That one actually did make the cut, and I agree that its result looks surprisingly good for how weird it looks in macro. The one that didn’t make it in is this goofball (I think I had it mislabeled):

image

2 Likes

Here we go… for 8K displays that use RBG subpixels. Could be of use to one or two people on the planet :smile:

image

image

This slotmask type is definitely superior to the earlier version we’ve discussed using just magenta/green. Advantages:

-less black space between phosphor groups 
-less lost brightness
-more accurate phosphor shape
-edit: same phosphor density measured vertically 

I’d go ahead and just remove the earlier magenta/green/black and yellow/blue/black slotmasks because they don’t really offer any advantages over this one, but I suppose they could be left in there for the sake of completeness.

1 Like

Are you sure? It looks significantly larger here:

Yeah, dot pitch isn’t the right word to use, here.

It’s actually a higher lower higher dot pitch (distance between same-colored phosphors), but it’s the same number of phosphor triads measured vertically.

So, both slotmask types should probably be included since they look pretty different. This one is clearly the more accurate/realistic of the two, though.

edit: bah, confusing terms. The more complicated slotmask is lower higher-pitch, but same number of phosphor triads measured vertically

Wait, have I been using these terms wrong this whole time? :joy:

low-pitch: better picture? edit2: yep

Oh, yeah, sure enough. Same vertical height… With that in mind, if we cut out one of the horizontal lines on the magenta/green/black mask, we can shorten the vertical height at the cost of some brightness (i.e., a higher proportion of subpixels are black):

image

If we take some of the black out, it’s basically just the aperture grill with (slightly too large) crossbars:

image

2 Likes

The difference in brightness isn’t as bad as you might think, and it has a more realistic phosphor shape than the earlier slotmask pattern, although it’s still not as accurate as the “complicated” slotmask seen above.

image

36 active subpixels out of 162. reduces brightness by 77.777%

vs.

image

54 active subpixels out of 216. Reduces brightness by 75%

Also cool!

image

36 out of 108

reduces brightness by 66.666%

Both masks are an improvement over the earlier one, and worthy inclusions in the mask mega-pack shader function! :smiley:

Also need to add the yellow/blue versions, of course :wink:

edit: might be obvious, but with these patterns you can have 5 phosphor triads per scanline with 240 scanlines @ 8K without needing to ovsercan the image. With the 4 pixel high slotmask patterns, you can’t have 5 triads per scanline unless you overscan the image.

5 phosphor triads per scanline, 3 pixels per triad, 240 scanlines.

5 * 3 * 240 = 3600 pixels needed

2 Likes

If anyone has some free time could they help me out with putting this in crt-guest-dr-venom?

I’m just not sure how to pipe it in at the end.

EDIT: I’m supposed to take the big mask code block put it in, then in the voidmain area at the end apply this (this is what actually adds the mask to the screen)?

vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
   vec3 weights = vec3(0.,0.,0.);
   float intens = 1.;
   float inv = 1.-mask_intensity;
   vec3 green   = vec3(inv, intens, inv);
   vec3 magenta = vec3(intens,inv,intens);
   vec3 black   = vec3(inv,inv,inv);
   vec3 red     = vec3(intens,inv,inv);
   vec3 yellow  = vec3(intens,inv,intens);
   vec3 cyan    = vec3(inv,intens,intens);
   vec3 blue    = vec3(inv,inv,intens);
   int w, z = 0;
   
   vec3 aperture_weights = mix(magenta, green, floor(mod(coord.x, 2.0)));

   if(phosphor_layout == 1){
      // classic aperture for RGB panels; good for 1080p, too small for 4K+
      weights  = aperture_weights;
   }

   else if(phosphor_layout == 2){
      // 2x2 shadow mask for RGB panels; good for 1080p, too small for 4K+
      vec3 inverse_aperture = mix(green, magenta, floor(mod(coord.x, 2.0)));
      weights               = mix(aperture_weights, inverse_aperture, floor(mod(coord.y, 2.0)));
   }

   else if(phosphor_layout == 3){
      // slot mask for RGB panels; too low-pitched for 1080p, looks okay at 4K but wants 8K+
      // Can't do 2D arrays until version 430, so do this stupid thing instead
      // first lay out the horizontal pixels in arrays
      vec3 slotmask_x1[6] = vec3[](magenta,green,black,magenta,green,black);
      vec3 slotmask_x2[6] = vec3[](magenta,green,black,black,black,black);
      vec3 slotmask_x3[6] = vec3[](magenta,green,black,magenta,green,black);
      vec3 slotmask_x4[6] = vec3[](black,black,black,magenta,green,black);
      
      // find the vertical index
      w = int(floor(mod(coord.y, 4.0)));
      
      // find the horizontal index
      z = int(floor(mod(coord.x, 6.0)));

      // do a big, dumb comparison in place of a 2D array
      weights = (w == 1) ? slotmask_x1[z] : (w == 2) ? slotmask_x2[z] : (w == 3) ? slotmask_x3[z] : slotmask_x4[z];
    }

   if(phosphor_layout == 4){
      // classic aperture for RBG panels; good for 1080p, too small for 4K+
      weights  = mix(yellow, blue, floor(mod(coord.x, 2.0)));
   }

   else if(phosphor_layout == 5){
      // 2x2 shadow mask for RBG panels; good for 1080p, too small for 4K+
      vec3 inverse_aperture = mix(blue, yellow, floor(mod(coord.x, 2.0)));
      weights               = mix(mix(yellow, blue, floor(mod(coord.x, 2.0))), inverse_aperture, floor(mod(coord.y, 2.0)));
   }
   
   else if(phosphor_layout == 6){
      // aperture_1_4_rgb
      vec3 ap4[4] = vec3[](red, green, blue, black);
      
      z = int(floor(mod(coord.x, 4.0)));
      
      weights = ap4[z];
   }
   
   else if(phosphor_layout == 7){
      // aperture_2_5_bgr
      vec3 ap3[5] = vec3[](red, magenta, blue, green, green);
      
      z = int(floor(mod(coord.x, 5.0)));
      
      weights = ap3[z];
   }
   
   else if(phosphor_layout == 8){
      // aperture_3_6_rgb
      
      vec3 big_ap[7] = vec3[](red, red, yellow, green, cyan, blue, blue);
      
      w = int(floor(mod(coord.x, 8.)));
      
      weights = big_ap[w];
   }
   
   else if(phosphor_layout == 9){
      // reduced TVL aperture for RGB panels
      
      vec3 big_ap_rgb[4] = vec3[](red, yellow, cyan, blue);
      
      w = int(floor(mod(coord.x, 4.)));
      
      weights = big_ap_rgb[w];
   }
   
   else if(phosphor_layout == 10){
      // reduced TVL aperture for RBG panels
      
      vec3 big_ap_rbg[4] = vec3[](red, magenta, cyan, green);
      
      w = int(floor(mod(coord.x, 4.)));
      
      weights = big_ap_rbg[w];
   }
   
   else if(phosphor_layout == 11){
      // delta_1_4x1_rgb; dunno why this is called 4x1 when it's obviously 4x2 /shrug
      vec3 delta_1_1[4] = vec3[](red, green, blue, black);
      vec3 delta_1_2[4] = vec3[](blue, black, red, green);
      
      w = int(floor(mod(coord.y, 2.0)));
      z = int(floor(mod(coord.x, 4.0)));
      
      weights = (w == 1) ? delta_1_1[z] : delta_1_2[z];
   }
   
   else if(phosphor_layout == 12){
      // delta_2_4x1_rgb
      vec3 delta_2_1[4] = vec3[](red, yellow, cyan, blue);
      vec3 delta_2_2[4] = vec3[](cyan, blue, red, yellow);
      
      z = int(floor(mod(coord.x, 4.0)));
      
      weights = (w == 1) ? delta_2_1[z] : delta_2_2[z];
   }
   
   else if(phosphor_layout == 13){
      // delta_2_4x2_rgb
      vec3 delta_1[4] = vec3[](red, yellow, cyan, blue);
      vec3 delta_2[4] = vec3[](red, yellow, cyan, blue);
      vec3 delta_3[4] = vec3[](cyan, blue, red, yellow);
      vec3 delta_4[4] = vec3[](cyan, blue, red, yellow);
     
      w = int(floor(mod(coord.y, 4.0)));
      z = int(floor(mod(coord.x, 4.0)));
      
      weights = (w == 1) ? delta_1[z] : (w == 2) ? delta_2[z] : (w == 3) ? delta_3[z] : delta_4[z];
   }
   
   else if(phosphor_layout == 14){
      // slot_2_4x4_rgb
      vec3 slot2_1[8] = vec3[](red, yellow, cyan, blue, red, yellow, cyan, blue);
      vec3 slot2_2[8] = vec3[](red, yellow, cyan, blue, black, black, black, black);
      vec3 slot2_3[8] = vec3[](red, yellow, cyan, blue, red, yellow, cyan, blue);
      vec3 slot2_4[8] = vec3[](black, black, black, black, red, yellow, cyan, blue);
   
      w = int(floor(mod(coord.y, 4.0)));
      z = int(floor(mod(coord.x, 8.0)));
      
      weights = (w == 1) ? slot2_1[z] : (w == 2) ? slot2_2[z] : (w == 3) ? slot2_3[z] : slot2_4[z];
   }

   else if(phosphor_layout == 15){
      // slot mask for RBG panels; too low-pitched for 1080p, looks okay at 4K but wants 8K+
      vec3 slotmask_RBG_x1[6] = vec3[](yellow,blue,black,yellow,blue,black);
      vec3 slotmask_RBG_x2[6] = vec3[](yellow,blue,black,black,black,black);
      vec3 slotmask_RBG_x3[6] = vec3[](yellow,blue,black,yellow,blue,black);
      vec3 slotmask_RBG_x4[6] = vec3[](black,black,black,yellow,blue,black);
      
      // find the vertical index
      w = int(floor(mod(coord.y, 4.0)));
      
      // find the horizontal index
      z = int(floor(mod(coord.x, 6.0)));

      weights = (w == 1) ? slotmask_RBG_x1[z] : (w == 2) ? slotmask_RBG_x2[z] : (w == 3) ? slotmask_RBG_x3[z] : slotmask_RBG_x4[z];
    }
   
   else if(phosphor_layout == 16){
      // slot_2_5x4_bgr
      vec3 slot2_1[10] = vec3[](red, magenta, blue, green, green, red, magenta, blue, green, green);
      vec3 slot2_2[10] = vec3[](black, blue, blue, green, green, red, red, black, black, black);
      vec3 slot2_3[10] = vec3[](red, magenta, blue, green, green, red, magenta, blue, green, green);
      vec3 slot2_4[10] = vec3[](red, red, black, black, black, black, blue, blue, green, green);
   
      w = int(floor(mod(coord.y, 4.0)));
      z = int(floor(mod(coord.x, 10.0)));
      
      weights = (w == 1) ? slot2_1[z] : (w == 2) ? slot2_2[z] : (w == 3) ? slot2_3[z] : slot2_4[z];
   }
   
   else if(phosphor_layout == 17){
      // slot_3_7x6_rgb
      vec3 slot_1[14] = vec3[](red,   red,   yellow, green, cyan,  blue,  blue,  red,   red,   yellow, green,  cyan,  blue,  blue);
      vec3 slot_2[14] = vec3[](red,   red,   yellow, green, cyan,  blue,  blue,  red,   red,   yellow, green,  cyan,  blue,  blue);
      vec3 slot_3[14] = vec3[](red,   red,   yellow, green, cyan,  blue,  blue,  black, black, black,  black,  black, black, black);
      vec3 slot_4[14] = vec3[](red,   red,   yellow, green, cyan,  blue,  blue,  red,   red,   yellow, green,  cyan,  blue,  blue);
      vec3 slot_5[14] = vec3[](red,   red,   yellow, green, cyan,  blue,  blue,  red,   red,   yellow, green,  cyan,  blue,  blue);
      vec3 slot_6[14] = vec3[](black, black, black,  black, black, black, black, black, red,   red,    yellow, green, cyan,  blue);
      
      w = int(floor(mod(coord.y, 6.0)));
      z = int(floor(mod(coord.x, 14.0)));
      
      weights = (w == 1) ? slot_1[z] : (w == 2) ? slot_2[z] : (w == 3) ? slot_3[z] : (w == 4) ? slot_4[z] : (w == 5) ? slot_5[z] : slot_6[z];
   }
   
   return weights;
}
color *= mask_weights(gl_FragCoord.xy, 1.0, 4);

Also how do I adjust the mask strength?

Thank in advanced for taking the time to help!

yes, that’s how you would apply it. The first number (in this case, 1.0) is the strength, the second number (in this case 4) is the mask to use.

1 Like

0 being off, 1 being full strength?

And I should just be able to link a parameter in both of those to change them?

yep, that should be it.

1 Like

Im getting an error

[INFO] Shader log: Fragment shader failed to compile with the following errors:
WARNING: 3:275: warning(#253) Unsized array constructors are not supported in implicit GLSL version number 110
WARNING: 3:276: warning(#253) Unsized array constructors are not supported in implicit GLSL version number 110
WARNING: 3:277: warning(#253) Unsized array constructors are not supported in implicit GLSL version number 110
WARNING: 3:278: warning(#253) Unsized array constructors are not supported in implicit GLSL version number 110
WARNING: 3:303: warning(#253) Unsized array constructors are not supported in implicit GLSL version number 110
WARNING: 3:312: warning(#253) Unsized array constructors are not supported in implicit GLSL version number 110
WARNING: 3:332: warning(#253) Unsized array constructors are not supported in implicit GLSL version number 110

275 starts at vec3 slotmask_x1[6];

else if(phosphor_layout == 3){
      // slot mask for RGB panels; too low-pitched for 1080p, looks okay at 4K but wants 8K+
      // Can't do 2D arrays until version 430, so do this stupid thing instead
      // first lay out the horizontal pixels in arrays
      vec3 slotmask_x1[6] = vec3[](magenta,green,black,magenta,green,black);

Also if it helps any I’m adding this to crt-guest-dr-venom.

2 things you can try:

  1. take the same array size from the left side of the equation and add it to the right side, like this:

vec3 slotmask_x1[6] = vec3[6](magenta,green,black,magenta,green,black);

  1. go up to the top of the shader and add this as the first line:

#version 130

1 Like

Alright I did the version 130 thing and now I’m only getting this error.

No matching overloaded function found: mask_weights.

For this line.

color *= mask_weights(gl_FragCoord.xy, 1.0, 4);