#include "shaders_common.h"

static const char *output_fragment = GLSL(
   // We're sampling from the internal framebuffer texture
   uniform sampler2D fb;
   // Framebuffer sampling: 0: Normal 16bpp mode, 1: Use 24bpp mode
   uniform int depth_24bpp;
   // Internal resolution upscaling factor. Necessary for proper 24bpp
   // display since we need to know how the pixels are laid out in RAM.
   uniform uint internal_upscaling;
   // Coordinates of the top-left displayed pixel in VRAM (1x resolution)
   uniform uvec2 offset;
   // Normalized relative offset in the displayed area in VRAM. Absolute
   // coordinates must take `offset` into account.
   in vec2 frag_fb_coord;

   out vec4 frag_color;

   // Take a normalized color and convert it into a 16bit 1555 ABGR
   // integer in the format used internally by the Playstation GPU.
   uint rebuild_color(vec4 color) {
      uint a = uint(floor(color.a + 0.5));
      uint r = uint(floor(color.r * 31. + 0.5));
      uint g = uint(floor(color.g * 31. + 0.5));
      uint b = uint(floor(color.b * 31. + 0.5));

      return (a << 15) | (b << 10) | (g << 5) | r;
   }

   void main() {
      vec3 color;

      if (depth_24bpp == 0) {
         // Use the regular 16bpp mode, fetch directly from the framebuffer
         // texture. The alpha/mask bit is ignored here.
	vec2 off = vec2(offset) / vec2(1024., 512.);

	color = texture(fb, frag_fb_coord + off).rgb;
      } else {
         // In this mode we have to interpret the framebuffer as containing
         // 24bit RGB values instead of the usual 16bits 1555.
         ivec2 fb_size = textureSize(fb, 0);

         uint x_24 = uint(frag_fb_coord.x * float(fb_size.x));
         uint y = uint(frag_fb_coord.y * float(fb_size.y));

         uint x_native = x_24 / internal_upscaling;

         x_24 = x_native * internal_upscaling;

         // The 24bit color is stored over two 16bit pixels, convert the
         // coordinates
         uint x0_16 = (x_24 * 3U) / 2U;

	 // Add the offsets
	 x0_16 += offset.x * internal_upscaling;
	 y     += offset.y * internal_upscaling;

         // Move on to the next pixel at native resolution
         uint x1_16 = x0_16 + internal_upscaling;

         uint col0 = rebuild_color(texelFetch(fb, ivec2(x0_16, y), 0));
         uint col1 = rebuild_color(texelFetch(fb, ivec2(x1_16, y), 0));

         uint col = (col1 << 16) | col0;

         // If we're drawing an odd 24 bit pixel we're starting in the
         // middle of a 16bit cell so we need to adjust accordingly.
         col >>= 8U * (x_native & 1U);

         // Finally we can extract and normalize the 24bit pixel
         float b = float((col >> 16U) & 0xffU) / 255.;
         float g = float((col >> 8U) & 0xffU) / 255.;
         float r = float(col & 0xffU) / 255.;

         color = vec3(r, g, b);
      }

      frag_color = vec4(color, 1.0);
   }
);
