Fix custom skins in GL for QW.

This commit is contained in:
Bill Currie 2012-01-26 12:50:37 +09:00
parent df87cffe15
commit 5dcaeae97b
2 changed files with 154 additions and 10 deletions

View file

@ -69,6 +69,7 @@ Mod_LoadSkin (byte * skin, int skinsize, int snum, int gnum, qboolean group,
Mod_FloodFillSkin (pskin, pheader->mdl.skinwidth, pheader->mdl.skinheight);
// save 8 bit texels for the player model to remap
// FIXME remove model restriction
if (strequal (loadmodel->name, "progs/player.mdl"))
Skin_SetPlayerSkin (pheader->mdl.skinwidth, pheader->mdl.skinheight,
pskin);

View file

@ -42,31 +42,169 @@ static __attribute__ ((used)) const char rcsid[] = "$Id$";
#include <stdlib.h>
#include "QF/cvar.h"
#include "QF/image.h"
#include "QF/model.h"
#include "QF/skin.h"
#include "QF/sys.h"
#include "QF/vid.h"
#include "QF/GL/defines.h"
#include "QF/GL/funcs.h"
#include "QF/GL/qf_textures.h"
#include "r_cvar.h"
typedef struct {
tex_t *tex;
tex_t *fb_tex;
qboolean fb;
} glskin_t;
static int skin_textures;
static int skin_fb_textures;
static byte skin_cmap[MAX_TRANSLATIONS][256];
static tex_t *skin_tex[MAX_TRANSLATIONS];
static tex_t *player_tex;
static glskin_t skins[MAX_TRANSLATIONS];
static glskin_t player_skin;
static void
do_fb_skin (glskin_t *s)
{
int size = s->tex->width * s->tex->height;
s->fb_tex = realloc (s->fb_tex, field_offset(tex_t, data[size]));
s->fb_tex->width = s->tex->width;
s->fb_tex->height = s->tex->height;
s->fb_tex->format = tex_palette;
s->fb_tex->palette = vid.palette;
s->fb = Mod_CalcFullbright (s->tex->data, s->fb_tex->data, size);
}
void
Skin_SetPlayerSkin (int width, int height, const byte *data)
{
int size = width * height;
glskin_t *s;
player_tex = realloc (player_tex, field_offset(tex_t, data[size]));
player_tex->width = width;
player_tex->height = height;
player_tex->format = tex_palette;
player_tex->palette = vid.palette;
memcpy (player_tex->data, data, size);
s = &player_skin;
s->tex = realloc (s->tex, field_offset(tex_t, data[size]));
s->tex->width = width;
s->tex->height = height;
s->tex->format = tex_palette;
s->tex->palette = vid.palette;
memcpy (s->tex->data, data, size);
do_fb_skin (s);
}
static void
build_skin_8 (tex_t *tex, int texnum, byte *translate,
unsigned scaled_width, unsigned scaled_height, qboolean alpha)
{
// Improvements should be mirrored in GL_ResampleTexture in gl_textures.c
byte *inrow;
byte pixels[512 * 256], *out;
unsigned int i, j;
unsigned int frac, fracstep;
out = pixels;
memset (pixels, 0, sizeof (pixels));
fracstep = tex->width * 0x10000 / scaled_width;
for (i = 0; i < scaled_height; i++, out += scaled_width) {
inrow = tex->data + tex->width * (i * tex->height / scaled_height);
frac = fracstep >> 1;
for (j = 0; j < scaled_width; j++) {
out[j] = translate[inrow[frac >> 16]];
frac += fracstep;
}
}
GL_Upload8_EXT ((byte *) pixels, scaled_width, scaled_height, false,
alpha);
}
static void
build_skin_32 (tex_t *tex, int texnum, byte *translate,
unsigned scaled_width, unsigned scaled_height, qboolean alpha)
{
// Improvements should be mirrored in GL_ResampleTexture in gl_textures.c
byte *inrow;
unsigned i, j;
int samples = alpha ? gl_alpha_format : gl_solid_format;
unsigned frac, fracstep;
byte pixels[512 * 256 * 4], *out, *pal;
byte c;
out = pixels;
memset (pixels, 0, sizeof (pixels));
fracstep = tex->width * 0x10000 / scaled_width;
for (i = 0; i < scaled_height; i++) {
inrow = tex->data + tex->width * (i * tex->height / scaled_height);
frac = fracstep >> 1;
for (j = 0; j < scaled_width; j++) {
c = translate[inrow[frac >> 16]];
pal = vid.palette + c * 3;
*out++ = *pal++;
*out++ = *pal++;
*out++ = *pal++;
*out++ = (alpha && c == 255) ? 0 : 255;
frac += fracstep;
}
}
qfglBindTexture (GL_TEXTURE_2D, texnum);
qfglTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, pixels);
qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (Anisotropy)
qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
aniso);
}
static void
build_skin (skin_t *skin, int cmap)
{
glskin_t *s;
unsigned scaled_width, scaled_height;
int texnum, fb_texnum;
// FIXME deek: This 512x256 limit sucks!
scaled_width = min (gl_max_size->int_val, 512);
scaled_height = min (gl_max_size->int_val, 256);
// allow users to crunch sizes down even more if they want
scaled_width >>= gl_playermip->int_val;
scaled_height >>= gl_playermip->int_val;
scaled_width = max (scaled_width, 1);
scaled_height = max (scaled_height, 1);
s = skins + cmap;
if (!s->tex)
s = &player_skin;
texnum = skin_textures + cmap;
fb_texnum = 0;
if (s->fb)
fb_texnum = skin_fb_textures + cmap;
if (skin) {
skin->texnum = texnum;
skin->auxtex = fb_texnum;
}
if (VID_Is8bit ()) {
build_skin_8 (s->tex, texnum, skin_cmap[cmap],
scaled_width, scaled_height, false);
if (s->fb)
build_skin_8 (s->fb_tex, fb_texnum, skin_cmap[cmap],
scaled_width, scaled_height, true);
} else {
build_skin_32 (s->tex, texnum, skin_cmap[cmap],
scaled_width, scaled_height, false);
if (s->fb)
build_skin_32 (s->fb_tex, fb_texnum, skin_cmap[cmap],
scaled_width, scaled_height, true);
}
}
void
@ -82,19 +220,24 @@ Skin_ProcessTranslation (int cmap, const byte *translation)
memcpy (skin_cmap[cmap], translation, 256);
if (!changed)
return;
build_skin (0, cmap);
}
void
Skin_SetupSkin (skin_t *skin, int cmap)
{
int changed;
glskin_t *s;
// simplify cmap usage (texture offset/array index)
cmap--;
changed = (skin_tex[cmap] != skin->texels);
skin_tex[cmap] = skin->texels;
s = skins + cmap;
changed = (s->tex != skin->texels);
s->tex = skin->texels;
if (!changed)
return;
do_fb_skin (s);
build_skin (skin, cmap);
}
void