1 /*
2 	glsl_skin.c
3 
4 	GLSL Skin support
5 
6 	Copyright (C) 2012 Bill Currie <bill@taniwha.org>
7 
8 	Author: Bill Currie <bill@taniwha.org>
9 	Date: 2012/1/23
10 
11 	This program is free software; you can redistribute it and/or
12 	modify it under the terms of the GNU General Public License
13 	as published by the Free Software Foundation; either version 2
14 	of the License, or (at your option) any later version.
15 
16 	This program is distributed in the hope that it will be useful,
17 	but WITHOUT ANY WARRANTY; without even the implied warranty of
18 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 
20 	See the GNU General Public License for more details.
21 
22 	You should have received a copy of the GNU General Public License
23 	along with this program; if not, write to:
24 
25 		Free Software Foundation, Inc.
26 		59 Temple Place - Suite 330
27 		Boston, MA  02111-1307, USA
28 
29 */
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33 
34 #ifdef HAVE_STRING_H
35 # include "string.h"
36 #endif
37 #ifdef HAVE_STRINGS_H
38 # include "strings.h"
39 #endif
40 
41 #include <stdlib.h>
42 
43 #include "QF/cvar.h"
44 #include "QF/image.h"
45 #include "QF/model.h"
46 #include "QF/skin.h"
47 #include "QF/sys.h"
48 #include "QF/vid.h"
49 
50 #include "QF/GL/defines.h"
51 #include "QF/GL/funcs.h"
52 #include "QF/GL/qf_textures.h"
53 
54 #include "mod_internal.h"
55 #include "r_internal.h"
56 
57 typedef struct {
58 	tex_t      *tex;
59 	tex_t      *fb_tex;
60 	qboolean    fb;
61 } glskin_t;
62 
63 static int skin_textures;
64 static int skin_fb_textures;
65 static byte skin_cmap[MAX_TRANSLATIONS][256];
66 
67 static glskin_t skins[MAX_TRANSLATIONS];
68 static glskin_t player_skin;
69 
70 static void
do_fb_skin(glskin_t * s)71 do_fb_skin (glskin_t *s)
72 {
73 	int         size = s->tex->width * s->tex->height;
74 
75 	s->fb_tex = realloc (s->fb_tex, field_offset(tex_t, data[size]));
76 	s->fb_tex->width = s->tex->width;
77 	s->fb_tex->height = s->tex->height;
78 	s->fb_tex->format = tex_palette;
79 	s->fb_tex->palette = vid.palette;
80 	s->fb = Mod_CalcFullbright (s->tex->data, s->fb_tex->data, size);
81 }
82 
83 void
gl_Skin_SetPlayerSkin(int width,int height,const byte * data)84 gl_Skin_SetPlayerSkin (int width, int height, const byte *data)
85 {
86 	int         size = width * height;
87 	glskin_t   *s;
88 
89 	s = &player_skin;
90 	s->tex = realloc (s->tex, field_offset(tex_t, data[size]));
91 	s->tex->width = width;
92 	s->tex->height = height;
93 	s->tex->format = tex_palette;
94 	s->tex->palette = vid.palette;
95 	memcpy (s->tex->data, data, size);
96 
97 	do_fb_skin (s);
98 }
99 
100 static void
build_skin_8(tex_t * tex,int texnum,byte * translate,unsigned scaled_width,unsigned scaled_height,qboolean alpha)101 build_skin_8 (tex_t *tex, int texnum, byte *translate,
102 			  unsigned scaled_width, unsigned scaled_height, qboolean alpha)
103 {
104 	//  Improvements should be mirrored in GL_ResampleTexture in gl_textures.c
105 	byte        *inrow;
106 	byte         pixels[512 * 256], *out;
107 	unsigned int i, j;
108 	unsigned int frac, fracstep;
109 
110 	out = pixels;
111 	memset (pixels, 0, sizeof (pixels));
112 	fracstep = tex->width * 0x10000 / scaled_width;
113 	for (i = 0; i < scaled_height; i++, out += scaled_width) {
114 		inrow = tex->data + tex->width * (i * tex->height / scaled_height);
115 		frac = fracstep >> 1;
116 		for (j = 0; j < scaled_width; j++) {
117 			out[j] = translate[inrow[frac >> 16]];
118 			frac += fracstep;
119 		}
120 	}
121 
122 	GL_Upload8_EXT ((byte *) pixels, scaled_width, scaled_height, false,
123 					alpha);
124 }
125 
126 static void
build_skin_32(tex_t * tex,int texnum,byte * translate,unsigned scaled_width,unsigned scaled_height,qboolean alpha)127 build_skin_32 (tex_t *tex, int texnum, byte *translate,
128 			   unsigned scaled_width, unsigned scaled_height, qboolean alpha)
129 {
130 	//  Improvements should be mirrored in GL_ResampleTexture in gl_textures.c
131 	byte       *inrow;
132 	unsigned    i, j;
133 	int         samples = alpha ? gl_alpha_format : gl_solid_format;
134 	unsigned    frac, fracstep;
135 	byte        pixels[512 * 256 * 4], *out, *pal;
136 	byte        c;
137 
138 	out = pixels;
139 	memset (pixels, 0, sizeof (pixels));
140 	fracstep = tex->width * 0x10000 / scaled_width;
141 	for (i = 0; i < scaled_height; i++) {
142 		inrow = tex->data + tex->width * (i * tex->height / scaled_height);
143 		frac = fracstep >> 1;
144 		for (j = 0; j < scaled_width; j++) {
145 			c = translate[inrow[frac >> 16]];
146 			pal = vid.palette + c * 3;
147 			*out++ = *pal++;
148 			*out++ = *pal++;
149 			*out++ = *pal++;
150 			*out++ = (alpha && c == 255) ? 0 : 255;
151 			frac += fracstep;
152 		}
153 	}
154 
155 	qfglBindTexture (GL_TEXTURE_2D, texnum);
156 	qfglTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0,
157 					GL_RGBA, GL_UNSIGNED_BYTE, pixels);
158 
159 	qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
160 	qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
161 	if (gl_Anisotropy)
162         qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
163 						   gl_aniso);
164 }
165 
166 static void
build_skin(skin_t * skin,int cmap)167 build_skin (skin_t *skin, int cmap)
168 {
169 	glskin_t   *s;
170 	unsigned    scaled_width, scaled_height;
171 	int         texnum, fb_texnum;
172 
173 	// FIXME deek: This 512x256 limit sucks!
174 	scaled_width = min (gl_max_size->int_val, 512);
175 	scaled_height = min (gl_max_size->int_val, 256);
176 
177 	// allow users to crunch sizes down even more if they want
178 	scaled_width >>= gl_playermip->int_val;
179 	scaled_height >>= gl_playermip->int_val;
180 	scaled_width = max (scaled_width, 1);
181 	scaled_height = max (scaled_height, 1);
182 
183 	s = skins + cmap;
184 	if (!s->tex)
185 		s = &player_skin;
186 	if (!s->tex)	// we haven't loaded the player model yet
187 		return;
188 	texnum = skin_textures + cmap;
189 	fb_texnum = 0;
190 	if (s->fb)
191 		fb_texnum = skin_fb_textures + cmap;
192 	if (skin) {
193 		skin->texnum = texnum;
194 		skin->auxtex = fb_texnum;
195 	}
196 	if (vid.is8bit) {
197 		build_skin_8 (s->tex, texnum, skin_cmap[cmap],
198 					  scaled_width, scaled_height, false);
199 		if (s->fb)
200 			build_skin_8 (s->fb_tex, fb_texnum, skin_cmap[cmap],
201 						  scaled_width, scaled_height, true);
202 	} else {
203 		build_skin_32 (s->tex, texnum, skin_cmap[cmap],
204 					   scaled_width, scaled_height, false);
205 		if (s->fb)
206 			build_skin_32 (s->fb_tex, fb_texnum, skin_cmap[cmap],
207 						   scaled_width, scaled_height, true);
208 	}
209 }
210 
211 void
gl_Skin_ProcessTranslation(int cmap,const byte * translation)212 gl_Skin_ProcessTranslation (int cmap, const byte *translation)
213 {
214 	int         changed;
215 
216 	// simplify cmap usage (texture offset/array index)
217 	cmap--;
218 	// skip over the colormap (GL can't use it) to the translated palette
219 	translation += VID_GRADES * 256;
220 	changed = memcmp (skin_cmap[cmap], translation, 256);
221 	memcpy (skin_cmap[cmap], translation, 256);
222 	if (!changed)
223 		return;
224 	build_skin (0, cmap);
225 }
226 
227 void
gl_Skin_SetupSkin(skin_t * skin,int cmap)228 gl_Skin_SetupSkin (skin_t *skin, int cmap)
229 {
230 	int         changed;
231 	glskin_t   *s;
232 
233 	skin->texnum = 0;
234 	skin->auxtex = 0;
235 	if (!cmap) {
236 		return;
237 	}
238 	// simplify cmap usage (texture offset/array index)
239 	cmap--;
240 	s = skins + cmap;
241 	changed = (s->tex != skin->texels);
242 	s->tex = skin->texels;
243 	if (!changed) {
244 		skin->texnum = skin_textures + cmap;
245 		if (s->fb)
246 			skin->auxtex = skin_fb_textures + cmap;
247 		return;
248 	}
249 	if (s->tex)
250 		do_fb_skin (s);
251 	build_skin (skin, cmap);
252 }
253 
254 void
gl_Skin_InitTranslations(void)255 gl_Skin_InitTranslations (void)
256 {
257 }
258 
259 int
gl_Skin_Init_Textures(int base)260 gl_Skin_Init_Textures (int base)
261 {
262 	skin_textures = base;
263 	base += MAX_TRANSLATIONS;
264 	skin_fb_textures = base;
265 	base += MAX_TRANSLATIONS;
266 	return base;
267 }
268