summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2013-03-30 20:08:14 +0400
committerAndrey Nazarov <skuller@skuller.net>2013-03-30 20:08:14 +0400
commit459f16a43cda5e582052456affe682934bcd01ff (patch)
treec2e0ad233c5317933b780016a6c8d5ab8066d468
parent7040cc8d347773c718dd69e4e36fa3f002250f78 (diff)
Allow upscaling of PCX images using HQ4x filter.
Upscale 4x when ‘gl_upscale_pcx’ is set to 2. Remove unused rules from HQ2x blending routine, reorder existing rules for compatibility with HQ4x. Rename rules to make their weights obvious. Optimize HQx initialization routine, skip entirely when ‘gl_upscale_pcx’ is set to 0. Add ‘hqx_y’, ‘hqx_cb’ and ‘hqx_cr’ console variables for fine-tuning the HQx algorithm. Avoid performance bottleneck when scrap texture is uploaded several times in a row. Delay scrap uploading until the next drawing call.
-rw-r--r--doc/client.txt7
-rw-r--r--src/refresh/gl/gl.h1
-rw-r--r--src/refresh/gl/hq2x.c405
-rw-r--r--src/refresh/gl/images.c38
-rw-r--r--src/refresh/gl/tess.c2
5 files changed, 358 insertions, 95 deletions
diff --git a/doc/client.txt b/doc/client.txt
index 91ad038..6331ae7 100644
--- a/doc/client.txt
+++ b/doc/client.txt
@@ -546,8 +546,11 @@ gl_bilerp_pics::
- 2 — enabled for all pictures, including the scrap texture itself
gl_upscale_pcx::
- Enables upscaling of PCX images using HQ2x filter. This improves rendering
- quality when screen scaling is used. Default value is 0.
+ Enables upscaling of PCX images using HQ2x and HQ4x filters. This improves
+ rendering quality when screen scaling is used. Default value is 0.
+ - 0 — don't upscale
+ - 1 — upscale 2x (takes 5x more memory)
+ - 2 — upscale 4x (takes 21x more memory)
gl_maxmip::
When set to a positive integer N, limits maximum texture size to 2^N^.
diff --git a/src/refresh/gl/gl.h b/src/refresh/gl/gl.h
index 345de59..358d2d2 100644
--- a/src/refresh/gl/gl.h
+++ b/src/refresh/gl/gl.h
@@ -481,4 +481,5 @@ void GL_DrawAliasModel(model_t *model);
*
*/
void HQ2x_Render(uint32_t *output, const uint8_t *input, int width, int height);
+void HQ4x_Render(uint32_t *output, const uint8_t *input, int width, int height);
void HQ2x_Init(void);
diff --git a/src/refresh/gl/hq2x.c b/src/refresh/gl/hq2x.c
index 40c73e7..7eda311 100644
--- a/src/refresh/gl/hq2x.c
+++ b/src/refresh/gl/hq2x.c
@@ -26,6 +26,7 @@ written by Maxim Stepin (MaxSt). it is not 100% identical, but very similar.
*/
#include "shared/shared.h"
+#include "common/cvar.h"
#include "refresh/images.h"
#define MASK_G 0x0000ff00
@@ -34,47 +35,44 @@ written by Maxim Stepin (MaxSt). it is not 100% identical, but very similar.
#define MASK_ALPHA 0xff000000
static const uint8_t hqTable[256] = {
- 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
- 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
- 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
- 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
- 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
- 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
- 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
- 4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
- 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
- 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
- 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
- 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
- 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
- 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
- 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
- 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14,
+ 1, 1, 2, 4, 1, 1, 2, 4, 3, 5, 7, 8, 3, 5, 13, 15,
+ 1, 1, 2, 10, 1, 1, 2, 10, 3, 5, 8, 8, 3, 5, 6, 8,
+ 1, 1, 2, 4, 1, 1, 2, 4, 3, 5, 12, 14, 3, 5, 9, 16,
+ 1, 1, 2, 10, 1, 1, 2, 10, 3, 5, 9, 8, 3, 5, 6, 16,
+ 1, 1, 2, 4, 1, 1, 2, 4, 3, 11, 8, 8, 3, 11, 9, 8,
+ 1, 1, 2, 4, 1, 1, 2, 4, 3, 5, 9, 8, 3, 5, 9, 8,
+ 1, 1, 2, 4, 1, 1, 2, 4, 3, 11, 6, 8, 3, 11, 6, 16,
+ 1, 1, 2, 4, 1, 1, 2, 10, 3, 5, 9, 8, 3, 11, 6, 16,
+ 1, 1, 2, 4, 1, 1, 2, 4, 3, 5, 7, 8, 3, 5, 13, 15,
+ 1, 1, 2, 4, 1, 1, 2, 4, 3, 5, 9, 8, 3, 5, 9, 8,
+ 1, 1, 2, 4, 1, 1, 2, 4, 3, 5, 12, 14, 3, 5, 9, 16,
+ 1, 1, 2, 4, 1, 1, 2, 4, 3, 5, 9, 14, 3, 5, 6, 16,
+ 1, 1, 2, 4, 1, 1, 2, 4, 3, 5, 9, 8, 3, 5, 9, 15,
+ 1, 1, 2, 4, 1, 1, 2, 4, 3, 5, 9, 8, 3, 5, 6, 8,
+ 1, 1, 2, 4, 1, 1, 2, 4, 3, 5, 9, 8, 3, 5, 6, 16,
+ 1, 1, 2, 4, 1, 1, 2, 4, 3, 5, 6, 8, 3, 5, 6, 16,
};
static uint8_t rotTable[256];
static uint8_t equBitmap[65536 / CHAR_BIT];
-static int same(int A, int B)
+static inline int same(int A, int B)
{
return Q_IsBitSet(equBitmap, (A << 8) + B);
}
-static int diff(int A, int B)
+static inline int diff(int A, int B)
{
return !same(A, B);
}
-static uint32_t generic(int A, int B, int C, int w1, int w2, int w3, int s)
+static inline uint32_t generic(int A, int B, int C, int w1, int w2, int w3, int s)
{
uint32_t a = d_8to24table[A];
uint32_t b = d_8to24table[B];
uint32_t c = d_8to24table[C];
uint32_t g, rb, alpha;
- if ((A & B & C) == 255)
- return 0;
-
// if transparent, scan around for another color to avoid alpha fringes
if (A == 255) {
if (B == 255)
@@ -94,68 +92,258 @@ static uint32_t generic(int A, int B, int C, int w1, int w2, int w3, int s)
return (g & MASK_G) | (rb & MASK_RB) | (alpha & MASK_ALPHA);
}
-static uint32_t blend0(int A)
+static uint32_t blend_1(int A)
{
- if (A == 255)
- return 0;
-
return d_8to24table[A];
}
-static uint32_t blend1(int A, int B)
+static uint32_t blend_1_1(int A, int B)
+{
+ return generic(A, B, 0, 1, 1, 0, 1);
+}
+
+static uint32_t blend_3_1(int A, int B)
{
return generic(A, B, 0, 3, 1, 0, 2);
}
-static uint32_t blend2(int A, int B, int C)
+static uint32_t blend_7_1(int A, int B)
+{
+ return generic(A, B, 0, 7, 1, 0, 3);
+}
+
+static uint32_t blend_5_3(int A, int B)
+{
+ return generic(A, B, 0, 5, 3, 0, 3);
+}
+
+static uint32_t blend_2_1_1(int A, int B, int C)
{
return generic(A, B, C, 2, 1, 1, 2);
}
-static uint32_t blend3(int A, int B, int C)
+static uint32_t blend_5_2_1(int A, int B, int C)
{
return generic(A, B, C, 5, 2, 1, 3);
}
-static uint32_t blend4(int A, int B, int C)
+static uint32_t blend_6_1_1(int A, int B, int C)
{
return generic(A, B, C, 6, 1, 1, 3);
}
-static uint32_t blend5(int A, int B, int C)
+static uint32_t blend_2_3_3(int A, int B, int C)
{
return generic(A, B, C, 2, 3, 3, 3);
}
-static uint32_t blend6(int A, int B, int C)
+static uint32_t blend_14_1_1(int A, int B, int C)
{
return generic(A, B, C, 14, 1, 1, 4);
}
-static uint32_t blend(int rule, int E, int A, int B, int D, int F, int H)
+static uint32_t hq2x_blend(int rule, int E, int A, int B, int D, int F, int H)
{
switch (rule) {
- default:
- case 0: return blend0(E);
- case 1: return blend1(E, A);
- case 2: return blend1(E, D);
- case 3: return blend1(E, B);
- case 4: return blend2(E, D, B);
- case 5: return blend2(E, A, B);
- case 6: return blend2(E, A, D);
- case 7: return blend3(E, B, D);
- case 8: return blend3(E, D, B);
- case 9: return blend4(E, D, B);
- case 10: return blend5(E, D, B);
- case 11: return blend6(E, D, B);
- case 12: return same(B, D) ? blend2(E, D, B) : blend0(E);
- case 13: return same(B, D) ? blend5(E, D, B) : blend0(E);
- case 14: return same(B, D) ? blend6(E, D, B) : blend0(E);
- case 15: return same(B, D) ? blend2(E, D, B) : blend1(E, A);
- case 16: return same(B, D) ? blend4(E, D, B) : blend1(E, A);
- case 17: return same(B, D) ? blend5(E, D, B) : blend1(E, A);
- case 18: return same(B, F) ? blend3(E, B, D) : blend1(E, D);
- case 19: return same(D, H) ? blend3(E, D, B) : blend1(E, B);
+ case 1:
+ return blend_2_1_1(E, D, B);
+ case 2:
+ return blend_2_1_1(E, A, D);
+ case 3:
+ return blend_2_1_1(E, A, B);
+ case 4:
+ return blend_3_1(E, D);
+ case 5:
+ return blend_3_1(E, B);
+ case 6:
+ return blend_3_1(E, A);
+ case 7:
+ return same(B, D) ? blend_2_1_1(E, D, B) : blend_3_1(E, A);
+ case 8:
+ return same(B, D) ? blend_2_1_1(E, D, B) : blend_1(E);
+ case 9:
+ return same(B, D) ? blend_6_1_1(E, D, B) : blend_3_1(E, A);
+ case 10:
+ return same(B, F) ? blend_5_2_1(E, B, D) : blend_3_1(E, D);
+ case 11:
+ return same(D, H) ? blend_5_2_1(E, D, B) : blend_3_1(E, B);
+ case 12:
+ case 13:
+ return same(B, D) ? blend_2_3_3(E, D, B) : blend_3_1(E, A);
+ case 14:
+ case 15:
+ return same(B, D) ? blend_2_3_3(E, D, B) : blend_1(E);
+ case 16:
+ return same(B, D) ? blend_14_1_1(E, D, B) : blend_1(E);
+ default:
+ Com_Error(ERR_FATAL, "%s: bad rule %d", __func__, rule);
+ return 0;
+ }
+}
+
+static void hq4x_blend(int rule, uint32_t *p00, uint32_t *p01, uint32_t *p10, uint32_t *p11, int E, int A, int B, int D, int F, int H)
+{
+ switch (rule) {
+ case 1:
+ *p00 = blend_2_1_1(E, B, D);
+ *p01 = blend_5_2_1(E, B, D);
+ *p10 = blend_5_2_1(E, D, B);
+ *p11 = blend_6_1_1(E, D, B);
+ break;
+ case 2:
+ *p00 = blend_5_3(E, A);
+ *p01 = blend_3_1(E, A);
+ *p10 = blend_5_2_1(E, D, A);
+ *p11 = blend_7_1(E, A);
+ break;
+ case 3:
+ *p00 = blend_5_3(E, A);
+ *p01 = blend_5_2_1(E, B, A);
+ *p10 = blend_3_1(E, A);
+ *p11 = blend_7_1(E, A);
+ break;
+ case 4:
+ *p00 = blend_5_3(E, D);
+ *p01 = blend_7_1(E, D);
+ *p10 = blend_5_3(E, D);
+ *p11 = blend_7_1(E, D);
+ break;
+ case 5:
+ *p00 = blend_5_3(E, B);
+ *p01 = blend_5_3(E, B);
+ *p10 = blend_7_1(E, B);
+ *p11 = blend_7_1(E, B);
+ break;
+ case 6:
+ *p00 = blend_5_3(E, A);
+ *p01 = blend_3_1(E, A);
+ *p10 = blend_3_1(E, A);
+ *p11 = blend_7_1(E, A);
+ break;
+ case 7:
+ if (same(B, D)) {
+ *p00 = blend_1_1(B, D);
+ *p01 = blend_1_1(B, E);
+ *p10 = blend_1_1(D, E);
+ *p11 = blend_1(E);
+ } else {
+ *p00 = blend_5_3(E, A);
+ *p01 = blend_3_1(E, A);
+ *p10 = blend_3_1(E, A);
+ *p11 = blend_7_1(E, A);
+ }
+ break;
+ case 8:
+ if (same(B, D)) {
+ *p00 = blend_1_1(B, D);
+ *p01 = blend_1_1(B, E);
+ *p10 = blend_1_1(D, E);
+ } else {
+ *p00 = blend_1(E);
+ *p01 = blend_1(E);
+ *p10 = blend_1(E);
+ }
+ *p11 = blend_1(E);
+ break;
+ case 9:
+ if (same(B, D)) {
+ *p00 = blend_2_1_1(E, B, D);
+ *p01 = blend_3_1(E, B);
+ *p10 = blend_3_1(E, D);
+ *p11 = blend_1(E);
+ } else {
+ *p00 = blend_5_3(E, A);
+ *p01 = blend_3_1(E, A);
+ *p10 = blend_3_1(E, A);
+ *p11 = blend_7_1(E, A);
+ }
+ break;
+ case 10:
+ if (same(B, F)) {
+ *p00 = blend_3_1(E, B);
+ *p01 = blend_3_1(B, E);
+ } else {
+ *p00 = blend_5_3(E, D);
+ *p01 = blend_7_1(E, D);
+ }
+ *p10 = blend_5_3(E, D);
+ *p11 = blend_7_1(E, D);
+ break;
+ case 11:
+ if (same(D, H)) {
+ *p00 = blend_3_1(E, D);
+ *p10 = blend_3_1(D, E);
+ } else {
+ *p00 = blend_5_3(E, B);
+ *p10 = blend_7_1(E, B);
+ }
+ *p01 = blend_5_3(E, B);
+ *p11 = blend_7_1(E, B);
+ break;
+ case 12:
+ if (same(B, D)) {
+ *p00 = blend_1_1(B, D);
+ *p01 = blend_2_1_1(B, E, D);
+ *p10 = blend_5_3(D, B);
+ *p11 = blend_6_1_1(E, D, B);
+ } else {
+ *p00 = blend_5_3(E, A);
+ *p01 = blend_3_1(E, A);
+ *p10 = blend_3_1(E, A);
+ *p11 = blend_7_1(E, A);
+ }
+ break;
+ case 13:
+ if (same(B, D)) {
+ *p00 = blend_1_1(B, D);
+ *p01 = blend_5_3(B, D);
+ *p10 = blend_2_1_1(D, E, B);
+ *p11 = blend_6_1_1(E, D, B);
+ } else {
+ *p00 = blend_5_3(E, A);
+ *p01 = blend_3_1(E, A);
+ *p10 = blend_3_1(E, A);
+ *p11 = blend_7_1(E, A);
+ }
+ break;
+ case 14:
+ if (same(B, D)) {
+ *p00 = blend_1_1(B, D);
+ *p01 = blend_2_1_1(B, E, D);
+ *p10 = blend_5_3(D, B);
+ *p11 = blend_6_1_1(E, D, B);
+ } else {
+ *p00 = blend_1(E);
+ *p01 = blend_1(E);
+ *p10 = blend_1(E);
+ *p11 = blend_1(E);
+ }
+ break;
+ case 15:
+ if (same(B, D)) {
+ *p00 = blend_1_1(B, D);
+ *p01 = blend_5_3(B, D);
+ *p10 = blend_2_1_1(D, E, B);
+ *p11 = blend_6_1_1(E, D, B);
+ } else {
+ *p00 = blend_1(E);
+ *p01 = blend_1(E);
+ *p10 = blend_1(E);
+ *p11 = blend_1(E);
+ }
+ break;
+ case 16:
+ if (same(B, D))
+ *p00 = blend_2_1_1(E, B, D);
+ else
+ *p00 = blend_1(E);
+ *p01 = blend_1(E);
+ *p10 = blend_1(E);
+ *p11 = blend_1(E);
+ break;
+ default:
+ Com_Error(ERR_FATAL, "%s: bad rule %d", __func__, rule);
+ break;
}
}
@@ -165,8 +353,8 @@ void HQ2x_Render(uint32_t *output, const uint8_t *input, int width, int height)
for (y = 0; y < height; y++) {
const uint8_t *in = input + y * width;
- uint32_t *out0 = output + y * width * 4;
- uint32_t *out1 = output + y * width * 4 + width * 2;
+ uint32_t *out0 = output + (y * 2 + 0) * width * 2;
+ uint32_t *out1 = output + (y * 2 + 1) * width * 2;
int prevline = (y == 0 ? 0 : width);
int nextline = (y == height - 1 ? 0 : width);
@@ -195,10 +383,10 @@ void HQ2x_Render(uint32_t *output, const uint8_t *input, int width, int height)
pattern |= diff(E, H) << 6;
pattern |= diff(E, I) << 7;
- *(out0 + 0) = blend(hqTable[pattern], E, A, B, D, F, H); pattern = rotTable[pattern];
- *(out0 + 1) = blend(hqTable[pattern], E, C, F, B, H, D); pattern = rotTable[pattern];
- *(out1 + 1) = blend(hqTable[pattern], E, I, H, F, D, B); pattern = rotTable[pattern];
- *(out1 + 0) = blend(hqTable[pattern], E, G, D, H, B, F);
+ *(out0 + 0) = hq2x_blend(hqTable[pattern], E, A, B, D, F, H); pattern = rotTable[pattern];
+ *(out0 + 1) = hq2x_blend(hqTable[pattern], E, C, F, B, H, D); pattern = rotTable[pattern];
+ *(out1 + 1) = hq2x_blend(hqTable[pattern], E, I, H, F, D, B); pattern = rotTable[pattern];
+ *(out1 + 0) = hq2x_blend(hqTable[pattern], E, G, D, H, B, F);
in++;
out0 += 2;
@@ -207,6 +395,58 @@ void HQ2x_Render(uint32_t *output, const uint8_t *input, int width, int height)
}
}
+void HQ4x_Render(uint32_t *output, const uint8_t *input, int width, int height)
+{
+ int x, y;
+
+ for (y = 0; y < height; y++) {
+ const uint8_t *in = input + y * width;
+ uint32_t *out0 = output + (y * 4 + 0) * width * 4;
+ uint32_t *out1 = output + (y * 4 + 1) * width * 4;
+ uint32_t *out2 = output + (y * 4 + 2) * width * 4;
+ uint32_t *out3 = output + (y * 4 + 3) * width * 4;
+
+ int prevline = (y == 0 ? 0 : width);
+ int nextline = (y == height - 1 ? 0 : width);
+
+ for (x = 0; x < width; x++) {
+ int prev = (x == 0 ? 0 : 1);
+ int next = (x == width - 1 ? 0 : 1);
+
+ int A = *(in - prevline - prev);
+ int B = *(in - prevline);
+ int C = *(in - prevline + next);
+ int D = *(in - prev);
+ int E = *(in);
+ int F = *(in + next);
+ int G = *(in + nextline - prev);
+ int H = *(in + nextline);
+ int I = *(in + nextline + next);
+
+ int pattern;
+ pattern = diff(E, A) << 0;
+ pattern |= diff(E, B) << 1;
+ pattern |= diff(E, C) << 2;
+ pattern |= diff(E, D) << 3;
+ pattern |= diff(E, F) << 4;
+ pattern |= diff(E, G) << 5;
+ pattern |= diff(E, H) << 6;
+ pattern |= diff(E, I) << 7;
+
+ hq4x_blend(hqTable[pattern], out0 + 0, out0 + 1, out1 + 0, out1 + 1, E, A, B, D, F, H); pattern = rotTable[pattern];
+ hq4x_blend(hqTable[pattern], out0 + 3, out1 + 3, out0 + 2, out1 + 2, E, C, F, B, H, D); pattern = rotTable[pattern];
+ hq4x_blend(hqTable[pattern], out3 + 3, out3 + 2, out2 + 3, out2 + 2, E, I, H, F, D, B); pattern = rotTable[pattern];
+ hq4x_blend(hqTable[pattern], out3 + 0, out2 + 0, out3 + 1, out2 + 1, E, G, D, H, B, F);
+
+ in++;
+ out0 += 4;
+ out1 += 4;
+ out2 += 4;
+ out3 += 4;
+ }
+ }
+}
+
static void pix2ycc(float c[3], int C)
{
int r = d_8to24table[C] & 255;
@@ -220,7 +460,11 @@ static void pix2ycc(float c[3], int C)
void HQ2x_Init(void)
{
- int n;
+ int n, A, B;
+
+ cvar_t *hqx_y = Cvar_Get("hqx_y", "48", CVAR_FILES);
+ cvar_t *hqx_cb = Cvar_Get("hqx_cb", "7", CVAR_FILES);
+ cvar_t *hqx_cr = Cvar_Get("hqx_cr", "6", CVAR_FILES);
for (n = 0; n < 256; n++) {
rotTable[n] = ((n >> 2) & 0x11) | ((n << 2) & 0x88)
@@ -230,30 +474,25 @@ void HQ2x_Init(void)
memset(equBitmap, 0, sizeof(equBitmap));
- for (n = 0; n < 65536; n++) {
- int A = n >> 8;
- int B = n & 255;
- float a[3];
- float b[3];
+ for (A = 0; A < 255; A++) {
+ for (B = 0; B <= A; B++) {
+ float a[3];
+ float b[3];
- if (A == 255 && B == 255) {
- Q_SetBit(equBitmap, n);
- continue;
- }
+ pix2ycc(a, A);
+ pix2ycc(b, B);
- if (A == 255 || B == 255)
- continue;
+ if (fabs(a[0] - b[0]) > hqx_y->value)
+ continue;
+ if (fabs(a[1] - b[1]) > hqx_cb->value)
+ continue;
+ if (fabs(a[2] - b[2]) > hqx_cr->value)
+ continue;
- pix2ycc(a, A);
- pix2ycc(b, B);
-
- if (fabs(a[0] - b[0]) > 0x30)
- continue;
- if (fabs(a[1] - b[1]) > 0x07)
- continue;
- if (fabs(a[2] - b[2]) > 0x06)
- continue;
-
- Q_SetBit(equBitmap, n);
+ Q_SetBit(equBitmap, (A << 8) + B);
+ Q_SetBit(equBitmap, (B << 8) + A);
+ }
}
+
+ Q_SetBit(equBitmap, 65535);
}
diff --git a/src/refresh/gl/images.c b/src/refresh/gl/images.c
index 777e4d8..551ad92 100644
--- a/src/refresh/gl/images.c
+++ b/src/refresh/gl/images.c
@@ -592,14 +592,33 @@ static void GL_Upload8(byte *data, int width, int height, int baselevel, imagety
static void GL_Upscale8(byte *data, int width, int height, imagetype_t type, imageflags_t flags)
{
- byte *buffer;
+ int maxlevel;
+ byte *buffer;
+ uint32_t saved;
+
+ maxlevel = Cvar_ClampInteger(gl_upscale_pcx, 1, 2);
+ buffer = FS_AllocTempMem((width * height) << ((maxlevel + 1) * 2));
+
+ // small hack for optimization
+ saved = d_8to24table[255];
+ d_8to24table[255] = 0;
+
+ if (maxlevel >= 2) {
+ HQ4x_Render((uint32_t *)buffer, data, width, height);
+ GL_Upload32(buffer, width * 4, height * 4, maxlevel - 2, type, flags);
+ }
+
+ if (maxlevel >= 1) {
+ HQ2x_Render((uint32_t *)buffer, data, width, height);
+ GL_Upload32(buffer, width * 2, height * 2, maxlevel - 1, type, flags);
+ }
+
+ d_8to24table[255] = saved;
- buffer = FS_AllocTempMem(width * height * 16);
- HQ2x_Render((uint32_t *)buffer, data, width, height);
- GL_Upload32(buffer, width * 2, height * 2, 0, type, flags);
FS_FreeTempMem(buffer);
- GL_Upload8(data, width, height, 1, type, flags);
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+
+ GL_Upload8(data, width, height, maxlevel, type, flags);
+ qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, maxlevel);
}
static void GL_SetFilterAndRepeat(imagetype_t type, imageflags_t flags)
@@ -697,9 +716,6 @@ void IMG_Load(image_t *image, byte *pic, int width, int height)
image->flags |= IF_UPSCALED;
scrap_dirty = qtrue;
- if (!gl_static.registering) {
- Scrap_Upload();
- }
return;
}
@@ -941,7 +957,9 @@ void GL_InitImages(void)
IMG_GetPalette();
- HQ2x_Init();
+ if (gl_upscale_pcx->integer) {
+ HQ2x_Init();
+ }
GL_BuildIntensityTable();
diff --git a/src/refresh/gl/tess.c b/src/refresh/gl/tess.c
index 0571ef4..56cd3bc 100644
--- a/src/refresh/gl/tess.c
+++ b/src/refresh/gl/tess.c
@@ -43,6 +43,8 @@ void GL_Flush2D(void)
bits |= GLS_ALPHATEST_ENABLE;
}
+ Scrap_Upload();
+
GL_BindTexture(0, tess.texnum[0]);
GL_StateBits(bits);
GL_ArrayBits(GLA_VERTEX | GLA_TC | GLA_COLOR);