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