mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 14:20:59 +00:00
Move the tex conversion to libQFimage.
This is for the conversion /to/ paletted textures. The conversion is necessary for csqc support. In the process, the conversion has been sped up by implementing a color cache for the conversion process. I haven't measured the difference yet, but Mr Fixit does seem to load much faster for the sw renderer than it did before the change (many months old memory).
This commit is contained in:
parent
d39adc6a64
commit
0cae54d25d
5 changed files with 190 additions and 61 deletions
|
@ -29,15 +29,16 @@
|
|||
#ifndef __QF_image_h
|
||||
#define __QF_image_h
|
||||
|
||||
#include "QF/qtypes.h"
|
||||
#include "QF/quakeio.h"
|
||||
|
||||
// could not use texture_t as that is used for models.
|
||||
typedef struct tex_s {
|
||||
int width;
|
||||
int height;
|
||||
int format;
|
||||
unsigned char *palette; // 0 = 32 bit, otherwise 8
|
||||
unsigned char data[4]; // variable length
|
||||
int width;
|
||||
int height;
|
||||
int format;
|
||||
const byte *palette; // 0 = 32 bit, otherwise 8
|
||||
byte data[4]; // variable length
|
||||
} tex_t;
|
||||
|
||||
#define tex_palette 0
|
||||
|
@ -47,6 +48,12 @@ typedef struct tex_s {
|
|||
#define tex_rgb 3
|
||||
#define tex_rgba 4
|
||||
|
||||
typedef struct colcache_s colcache_t;
|
||||
|
||||
tex_t *LoadImage (const char *imageFile);
|
||||
colcache_t *ColorCache_New (void);
|
||||
void ColorCache_Delete (colcache_t *cache);
|
||||
byte ConvertColor (const byte *rgb, const byte *pal, colcache_t *cache);
|
||||
tex_t *ConvertImage (const tex_t *tex, const byte *pal);
|
||||
|
||||
#endif //__QF_image_h
|
||||
|
|
|
@ -13,6 +13,6 @@ libQFimage_la_LDFLAGS= $(lib_ldflags)
|
|||
libQFimage_la_LIBADD= $(image_deps) $(PNG_LIBS)
|
||||
libQFimage_la_DEPENDENCIES= $(pmage_deps)
|
||||
libQFimage_la_SOURCES= \
|
||||
image.c pcx.c png.c tga.c
|
||||
convert.c image.c pcx.c png.c tga.c
|
||||
|
||||
EXTRA_DIST=
|
||||
|
|
175
libs/image/convert.c
Normal file
175
libs/image/convert.c
Normal file
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
convert.c
|
||||
|
||||
Image/color conversion routins (RGB to paletted)
|
||||
|
||||
Copyright (C) 2013 Bill Currie <bill@taniwha.org>
|
||||
|
||||
Author: Bill Currie <bill@taniwha.org>
|
||||
Date: 2013/5/10
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA
|
||||
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "QF/alloc.h"
|
||||
#include "QF/hash.h"
|
||||
#include "QF/image.h"
|
||||
#include "QF/mathlib.h"
|
||||
|
||||
struct colcache_s {
|
||||
struct colcache_s *next;
|
||||
hashtab_t *tab;
|
||||
};
|
||||
|
||||
typedef struct colcache_color_s {
|
||||
struct colcache_color_s *next;
|
||||
byte rgb[3];
|
||||
byte col;
|
||||
} colcache_color_t;
|
||||
|
||||
static colcache_t *colcache_freelist;
|
||||
static colcache_color_t *colcache_color_freelist;
|
||||
|
||||
static colcache_color_t *
|
||||
colcache_new_color (const byte *rgb, byte ind)
|
||||
{
|
||||
colcache_color_t *col;
|
||||
ALLOC (256, colcache_color_t, colcache_color, col);
|
||||
VectorCopy (rgb, col->rgb);
|
||||
col->col = ind;
|
||||
return col;
|
||||
}
|
||||
|
||||
static void
|
||||
colcache_free_color (void *_col, void *unused)
|
||||
{
|
||||
colcache_color_t *col = (colcache_color_t *) _col;
|
||||
FREE (colcache_color, col);
|
||||
}
|
||||
|
||||
static uintptr_t
|
||||
colcache_get_hash (const void *_col, void *unused)
|
||||
{
|
||||
colcache_color_t *col = (colcache_color_t *) _col;
|
||||
uintptr_t r, g, b;
|
||||
r = col->rgb[0];
|
||||
g = col->rgb[1];
|
||||
b = col->rgb[2];
|
||||
return (r << 8) ^ (g << 4) ^ b;
|
||||
}
|
||||
|
||||
static int
|
||||
colcache_compare (const void *_cola, const void *_colb, void *unused)
|
||||
{
|
||||
colcache_color_t *cola = (colcache_color_t *) _cola;
|
||||
colcache_color_t *colb = (colcache_color_t *) _colb;
|
||||
|
||||
return VectorCompare (cola->rgb, colb->rgb);
|
||||
}
|
||||
|
||||
colcache_t *
|
||||
ColorCache_New (void)
|
||||
{
|
||||
colcache_t *cache;
|
||||
|
||||
ALLOC (16, colcache_t, colcache, cache);
|
||||
cache->tab = Hash_NewTable (1023, 0, colcache_free_color, 0);
|
||||
Hash_SetHashCompare (cache->tab, colcache_get_hash, colcache_compare);
|
||||
return cache;
|
||||
}
|
||||
|
||||
void
|
||||
ColorCache_Delete (colcache_t *cache)
|
||||
{
|
||||
Hash_DelTable (cache->tab);
|
||||
FREE (colcache, cache);
|
||||
}
|
||||
|
||||
byte
|
||||
ConvertColor (const byte *rgb, const byte *pal, colcache_t *cache)
|
||||
{
|
||||
//FIXME slow!
|
||||
int dist[3];
|
||||
int d, bestd = 256 * 256 * 3, bestc = -1;
|
||||
int i;
|
||||
colcache_color_t *col;
|
||||
|
||||
if (cache) {
|
||||
colcache_color_t search;
|
||||
VectorCopy (rgb, search.rgb);
|
||||
col = Hash_FindElement (cache->tab, &search);
|
||||
if (col)
|
||||
return col->col;
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
VectorSubtract (pal + i * 3, rgb, dist);
|
||||
d = DotProduct (dist, dist);
|
||||
if (d < bestd) {
|
||||
bestd = d;
|
||||
bestc = i;
|
||||
}
|
||||
}
|
||||
if (cache) {
|
||||
col = colcache_new_color (rgb, bestc);
|
||||
Hash_AddElement (cache->tab, col);
|
||||
}
|
||||
return bestc;
|
||||
}
|
||||
|
||||
tex_t *
|
||||
ConvertImage (const tex_t *tex, const byte *pal)
|
||||
{
|
||||
tex_t *new;
|
||||
int pixels;
|
||||
int bpp = 3;
|
||||
int i;
|
||||
colcache_t *cache;
|
||||
|
||||
pixels = tex->width * tex->height;
|
||||
new = malloc (field_offset (tex_t, data[pixels]));
|
||||
new->width = tex->width;
|
||||
new->height = tex->height;
|
||||
new->format = tex_palette;
|
||||
new->palette = pal;
|
||||
switch (tex->format) {
|
||||
case tex_palette:
|
||||
case tex_l: // will not work as expected
|
||||
case tex_a: // will not work as expected
|
||||
memcpy (new->data, tex->data, pixels);
|
||||
break;
|
||||
case tex_la: // will not work as expected
|
||||
for (i = 0; i < pixels; i++)
|
||||
new->data[i] = tex->data[i * 2];
|
||||
break;
|
||||
case tex_rgba:
|
||||
bpp = 4;
|
||||
case tex_rgb:
|
||||
cache = ColorCache_New ();
|
||||
for (i = 0; i < pixels; i++)
|
||||
new->data[i] = ConvertColor (tex->data + i * bpp, pal, cache);
|
||||
ColorCache_Delete (cache);
|
||||
break;
|
||||
}
|
||||
return new;
|
||||
}
|
|
@ -81,59 +81,6 @@ sw_iqm_clear (model_t *mod)
|
|||
Mod_FreeIQM (iqm);
|
||||
}
|
||||
|
||||
static byte
|
||||
convert_color (byte *rgb)
|
||||
{
|
||||
//FIXME slow!
|
||||
int dist[3];
|
||||
int d, bestd = 256 * 256 * 3, bestc = -1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
VectorSubtract (vid.basepal + i * 3, rgb, dist);
|
||||
d = DotProduct (dist, dist);
|
||||
if (d < bestd) {
|
||||
bestd = d;
|
||||
bestc = i;
|
||||
}
|
||||
}
|
||||
return bestc;
|
||||
}
|
||||
|
||||
static tex_t *
|
||||
convert_tex (tex_t *tex)
|
||||
{
|
||||
tex_t *new;
|
||||
int pixels;
|
||||
int bpp = 3;
|
||||
int i;
|
||||
|
||||
pixels = tex->width * tex->height;
|
||||
new = malloc (field_offset (tex_t, data[pixels]));
|
||||
new->width = tex->width;
|
||||
new->height = tex->height;
|
||||
new->format = tex_palette;
|
||||
new->palette = 0;
|
||||
switch (tex->format) {
|
||||
case tex_palette:
|
||||
case tex_l: // will not work as expected
|
||||
case tex_a: // will not work as expected
|
||||
memcpy (new->data, tex->data, pixels);
|
||||
break;
|
||||
case tex_la: // will not work as expected
|
||||
for (i = 0; i < pixels; i++)
|
||||
new->data[i] = tex->data[i * 2];
|
||||
break;
|
||||
case tex_rgba:
|
||||
bpp = 4;
|
||||
case tex_rgb:
|
||||
for (i = 0; i < pixels; i++)
|
||||
new->data[i] = convert_color (tex->data + i * bpp);
|
||||
break;
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
static inline void
|
||||
convert_coord (byte *tc, int size)
|
||||
{
|
||||
|
@ -166,7 +113,7 @@ sw_iqm_load_textures (iqm_t *iqm)
|
|||
dstring_copystr (str, iqm->text + iqm->meshes[i].material);
|
||||
QFS_StripExtension (str->str, str->str);
|
||||
if ((tex = LoadImage (va ("textures/%s", str->str))))
|
||||
tex = sw->skins[i] = convert_tex (tex);
|
||||
tex = sw->skins[i] = ConvertImage (tex, vid.basepal);
|
||||
else
|
||||
tex = sw->skins[i] = &null_texture;
|
||||
for (j = 0; j < (int) iqm->meshes[i].num_triangles * 3; j++) {
|
||||
|
|
|
@ -104,7 +104,7 @@ load_image (const char *name)
|
|||
switch (tex->format) {
|
||||
case tex_palette:
|
||||
for (i = 0, s = tex->data, d = image->data; i < pixels; i++) {
|
||||
byte *v = tex->palette + *s++ * 3;
|
||||
const byte *v = tex->palette + *s++ * 3;
|
||||
*d++ = *v++;
|
||||
*d++ = *v++;
|
||||
*d++ = *v++;
|
||||
|
|
Loading…
Reference in a new issue