Forum

Ordered dithering the console background

Discuss programming topics for the various GPL'd game engine sources.

Moderator: InsideQC Admins

Ordered dithering the console background

Postby mankrip » Sat Jul 02, 2011 11:32 pm

Preamble, with comparison screenshot.

This is my current code, which only dithers horizontally:
Code: Select all
// mankrip - begin
int ordered_dither_threshold [4][4] =
{
   { 1,  9,  3, 11}
,   {13,  5, 15,  7}
,   { 4, 12,  2, 10}
,   {16,  8, 14,  6}
};
// mankrip - end

void Draw_ConsoleBackground (int lines)
{
...
   if (r_pixbytes == 1)
   {
...
            memcpy (dest, src, vid.conwidth);
         else
         {
            f = 0;
            // mankrip - begin
            #if 1
            for (x=0 ; x<vid.conwidth ; x++)
            {
               dest[x] = src[ (f +  (ordered_dither_threshold[x % 4][y % 4] * fstep) / 4) >> 16];
               f += fstep;
            }
            #else
            // mankrip - end
            for (x=0 ; x<vid.conwidth ; x+=4)
            {
               dest[x] = src[f>>16];
               f += fstep;
               dest[x+1] = src[f>>16];
               f += fstep;
               dest[x+2] = src[f>>16];
               f += fstep;
               dest[x+3] = src[f>>16];
               f += fstep;
            }
            #endif // mankrip
...
   }

...
}

I've tried several different approaches to get vertical dithering working in the original code, but none worked. Any ideas?
Ph'nglui mglw'nafh mankrip Hell's end wgah'nagl fhtagn.
==-=-=-=-=-=-=-=-=-=-==
Dev blog / Twitter / YouTube
User avatar
mankrip
 
Posts: 915
Joined: Fri Jul 04, 2008 3:02 am

Postby qbism » Wed Jul 06, 2011 2:15 am

That code is effectively only "jiggling" in the x-axis. Need to multiply by vid.conwidth to grab pixels in y axis. Probably a proper way to do this, but here's a hack to alternate x/y in a checkerboard pattern. Needs a check to avoid sampling outside of src:
Code: Select all
                    for (x=0 ; x<vid.conwidth ; x++)
                    {
                        //dest[x] = src[f>>16];
                        if ((x+y) % 2)
                        {
                            dest[x] = src[ (f +  (ordered_dither_threshold[x % 4][y % 4] /8) *fstep) >> 16];
                            f += fstep;
                        }
                        else
                        {
                            dest[x] = src[ (f +  (ordered_dither_threshold[(x) % 4][y % 4] /8)+vid.conwidth *fstep) >> 16];
                            f += fstep;
                        }
                    }
User avatar
qbism
 
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am

Postby mankrip » Wed Jul 06, 2011 3:01 am

I've figured it out after rewritting the code with floating point variables. I could probably get it working without them again, but it's not a priority.

qbism wrote:Needs a check to avoid sampling outside of src

I'll change it later to avoid dithering any pixels on the first and last lines, and on the first and last column.

And after that I'm going to unroll the inner loop and optimize all I can to see how fast it will perform in comparison to the original non-dithered code.
Ph'nglui mglw'nafh mankrip Hell's end wgah'nagl fhtagn.
==-=-=-=-=-=-=-=-=-=-==
Dev blog / Twitter / YouTube
User avatar
mankrip
 
Posts: 915
Joined: Fri Jul 04, 2008 3:02 am

Postby mankrip » Sat Jul 09, 2011 12:55 am

Here is it, but it is really slow; only 40% as fast as the original code.

It's so slow I haven't bothered coding either the translucent or the 16-bit color versions.

Now I wonder if it could be faster without all these floats. As it is, it's not useful.
Code: Select all
float ordered_dither_threshold [4][4] =
{
   { 1.0f / 16.0f,  9.0f / 16.0f,  3.0f / 16.0f, 11.0f / 16.0f}
,   {13.0f / 16.0f,  5.0f / 16.0f, 15.0f / 16.0f,  7.0f / 16.0f}
,   { 4.0f / 16.0f, 12.0f / 16.0f,  2.0f / 16.0f, 10.0f / 16.0f}
,   {16.0f / 16.0f,  8.0f / 16.0f, 14.0f / 16.0f,  6.0f / 16.0f}
};

void Draw_ConsoleBackground (int lines)
{
   // mankrip - begin
   extern cvar_t
      con_alpha
      ;
   if (con_alpha.value > 0.0f || con_forcedup)
   {
      qpic_t
         * conback = Draw_CachePic ("gfx/conback.lmp")
         ;
      if (conback)
      {
         float
            ustep = (float)conback->width  / (float)vid.conwidth
         ,   vstep = (float)conback->height / (float)vid.conheight
         ,   u
         ,   v = vstep * (float) (vid.conheight - lines)
         ,   threshold
         ,   ustep02 = ustep *  2.0f
         ,   ustep03 = ustep *  3.0f
         ,   ustep04 = ustep *  4.0f
         ,   ustep05 = ustep *  5.0f
         ,   ustep06 = ustep *  6.0f
         ,   ustep07 = ustep *  7.0f
         ,   ustep08 = ustep *  8.0f
         ,   ustep09 = ustep *  9.0f
         ,   ustep10 = ustep * 10.0f
         ,   ustep11 = ustep * 11.0f
         ,   ustep12 = ustep * 12.0f
         ,   ustep13 = ustep * 13.0f
         ,   ustep14 = ustep * 14.0f
         ,   ustep15 = ustep * 15.0f
         ,   ustep16 = ustep * 16.0f
         ,   * dither_threshold
            ;
         int
            x
         ,   y = 0
         ,   ditherwidth = vid.conwidth  - (int) (1.0f / ustep)
         ,   groupwidth = ditherwidth / 16
         ,   ditherheight = lines - (int) (1.0f / vstep)
         ,   srcwidth = conback->width
            ;
         byte
            * src
            ;
         if (r_pixbytes == 1)
         {
            byte
               * dest = vid.conbuffer
               ;
            #if 0
            if (con_alpha.value < 0.5f && !con_forcedup)
               for ( ; y < lines ; y++, dest += vid.conrowbytes, v += vstep)
               {
                  src = conback->data + v * srcwidth;
                  for (f = 0, x = 0 ; x < vid.conwidth ; x++, f += fstep)
                  {
                  }
               }
            else if (con_alpha.value < 1.0f && !con_forcedup)
               for ( ; y < lines ; y++, dest += vid.conrowbytes, v += vstep)
               {
                  src = conback->data + v * srcwidth;
                  for (f = 0, x = 0 ; x < vid.conwidth ; x++, f += fstep)
                  {
                  }
               }
            else
            #endif
            {
               for ( ; y < ditherheight ; y++, v += vstep, dest += vid.conrowbytes)
                  if (vid.conwidth == srcwidth && vid.conheight == conback->height)
                     memcpy (dest, conback->data + (int)v * srcwidth, vid.conwidth);
                  else
                  {
                     src = conback->data;
                     dither_threshold = ordered_dither_threshold[y % 4];
                     for (u = 0, x = 0 ; x < groupwidth ; x += 16, u += ustep16)
                     {
                        threshold = dither_threshold[  x       % 4]; dest[  x      ] = src[ (int) (v + threshold) * srcwidth + (int) (u           + threshold)];
                        threshold = dither_threshold[ (x +  1) % 4]; dest[ (x +  1)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep   + threshold)];
                        threshold = dither_threshold[ (x +  2) % 4]; dest[ (x +  2)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep02 + threshold)];
                        threshold = dither_threshold[ (x +  3) % 4]; dest[ (x +  3)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep03 + threshold)];
                        threshold = dither_threshold[ (x +  4) % 4]; dest[ (x +  4)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep04 + threshold)];
                        threshold = dither_threshold[ (x +  5) % 4]; dest[ (x +  5)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep05 + threshold)];
                        threshold = dither_threshold[ (x +  6) % 4]; dest[ (x +  6)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep06 + threshold)];
                        threshold = dither_threshold[ (x +  7) % 4]; dest[ (x +  7)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep07 + threshold)];
                        threshold = dither_threshold[ (x +  8) % 4]; dest[ (x +  8)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep08 + threshold)];
                        threshold = dither_threshold[ (x +  9) % 4]; dest[ (x +  9)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep09 + threshold)];
                        threshold = dither_threshold[ (x + 10) % 4]; dest[ (x + 10)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep10 + threshold)];
                        threshold = dither_threshold[ (x + 11) % 4]; dest[ (x + 11)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep11 + threshold)];
                        threshold = dither_threshold[ (x + 12) % 4]; dest[ (x + 12)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep12 + threshold)];
                        threshold = dither_threshold[ (x + 13) % 4]; dest[ (x + 13)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep13 + threshold)];
                        threshold = dither_threshold[ (x + 14) % 4]; dest[ (x + 14)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep14 + threshold)];
                        threshold = dither_threshold[ (x + 15) % 4]; dest[ (x + 15)] = src[ (int) (v + threshold) * srcwidth + (int) (u + ustep15 + threshold)];
                     }
                     for ( ; x < ditherwidth ; x++, u += ustep)
                     {
                        threshold = dither_threshold[x % 4];
                        dest[x] = src[
                           (int) (v + threshold) * srcwidth
                        +   (int) (u + threshold)
                        ];
                     }
                     for ( ; x < vid.conwidth ; x++, u += ustep)
                        dest[x] = src[
                           (int) (v + dither_threshold[x % 4]) * srcwidth
                        +   (int) u
                        ];
                  }
               for ( ; y < lines ; y++, v += vstep, dest += vid.conrowbytes)
                  if (vid.conwidth == srcwidth && vid.conheight == conback->height)
                     memcpy (dest, conback->data + (int)v * srcwidth, vid.conwidth);
                  else
                  {
                     src = conback->data;
                     dither_threshold = ordered_dither_threshold[y % 4];
                     for (u = 0, x = 0 ; x < ditherwidth ; x++, u += ustep)
                        dest[x] = src[
                           (int) v * srcwidth
                        +   (int) (u + dither_threshold[x % 4])
                        ];
                     for ( ; x < vid.conwidth ; x++, u += ustep)
                        dest[x] = src[
                           (int) v * srcwidth
                        +   (int) u
                        ];
                  }
            }
         }
         else
         {
            int
               f
            ,   fstep = conback->width * 0x10000 / vid.conwidth
               ;
            unsigned short
               * pusdest = (unsigned short *)vid.conbuffer
               ;
   // mankrip - end
            for (y=0 ; y<lines ; y++, pusdest += (vid.conrowbytes >> 1))
            {
               // FIXME: pre-expand to native format?
               // FIXME: does the endian switching go away in production?
               v = (vid.conheight - lines + y)*conback->height/vid.conheight; // mankrip - hi-res console background - edited
               src = conback->data + (int) v * conback->width; // mankrip - hi-res console background - edited
               for (f = 0, x = 0 ; x < vid.conwidth ; x+=4)
               {
                  pusdest[x  ] = d_8to16table[src[f>>16]];
                  f += fstep;
                  pusdest[x+1] = d_8to16table[src[f>>16]];
                  f += fstep;
                  pusdest[x+2] = d_8to16table[src[f>>16]];
                  f += fstep;
                  pusdest[x+3] = d_8to16table[src[f>>16]];
                  f += fstep;
               }
            }
         }
      }
   }
}

[edit] Included the current matrix.
Ph'nglui mglw'nafh mankrip Hell's end wgah'nagl fhtagn.
==-=-=-=-=-=-=-=-=-=-==
Dev blog / Twitter / YouTube
User avatar
mankrip
 
Posts: 915
Joined: Fri Jul 04, 2008 3:02 am


Return to Engine Programming

Who is online

Users browsing this forum: No registered users and 1 guest