Ordered dithering the console background
Moderator: InsideQC Admins
4 posts
• Page 1 of 1
Ordered dithering the console background
Preamble, with comparison screenshot.
This is my current code, which only dithers horizontally:
I've tried several different approaches to get vertical dithering working in the original code, but none worked. Any ideas?
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?
-

mankrip - Posts: 915
- Joined: Fri Jul 04, 2008 3:02 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;
}
}
-
qbism - Posts: 1236
- Joined: Thu Nov 04, 2004 5:51 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.
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.
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.
-

mankrip - Posts: 915
- Joined: Fri Jul 04, 2008 3:02 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.
[edit] Included the current matrix.
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.
-

mankrip - Posts: 915
- Joined: Fri Jul 04, 2008 3:02 am
4 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 1 guest