1 //----------------------------------------------------------------------------
2 // EDGE Texture Upload
3 //----------------------------------------------------------------------------
4 //
5 // Copyright (c) 1999-2009 The EDGE Team.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 //----------------------------------------------------------------------------
18
19 #include "i_defs.h"
20 #include "i_defs_gl.h"
21
22 #include <limits.h>
23
24 #include "epi/image_data.h"
25
26 #include "e_search.h"
27 #include "e_main.h"
28 #include "m_argv.h"
29 #include "m_misc.h"
30 #include "p_local.h"
31 #include "r_gldefs.h"
32 #include "r_image.h"
33 #include "r_sky.h"
34 #include "r_texgl.h"
35 #include "r_colormap.h"
36
37 #include "w_texture.h"
38 #include "w_wad.h"
39
40
W_MakeValidSize(int value)41 int W_MakeValidSize(int value)
42 {
43 SYS_ASSERT(value > 0);
44
45 if (value <= 1) return 1;
46 if (value <= 2) return 2;
47 if (value <= 4) return 4;
48 if (value <= 8) return 8;
49 if (value <= 16) return 16;
50 if (value <= 32) return 32;
51 if (value <= 64) return 64;
52 if (value <= 128) return 128;
53 if (value <= 256) return 256;
54 if (value <= 512) return 512;
55 if (value <= 1024) return 1024;
56 if (value <= 2048) return 2048;
57 if (value <= 4096) return 4096;
58
59 I_Error("Texture size (%d) too large !\n", value);
60 return -1; /* NOT REACHED */
61 }
62
63
R_PalettisedToRGB(epi::image_data_c * src,const byte * palette,int opacity)64 epi::image_data_c *R_PalettisedToRGB(epi::image_data_c *src,
65 const byte *palette, int opacity)
66 {
67 int bpp = (opacity == OPAC_Solid) ? 3 : 4;
68
69 epi::image_data_c *dest = new epi::image_data_c(src->width, src->height, bpp);
70
71 dest->used_w = src->used_w;
72 dest->used_h = src->used_h;
73
74 for (int y=0; y < src->height; y++)
75 for (int x=0; x < src->width; x++)
76 {
77 byte src_pix = src->PixelAt(x, y)[0];
78
79 byte *dest_pix = dest->PixelAt(x, y);
80
81 if (src_pix == TRANS_PIXEL)
82 {
83 dest_pix[0] = dest_pix[1] = dest_pix[2] = 0;
84
85 if (bpp == 4)
86 dest_pix[3] = 0;
87 }
88 else
89 {
90 dest_pix[0] = palette[src_pix*3 + 0];
91 dest_pix[1] = palette[src_pix*3 + 1];
92 dest_pix[2] = palette[src_pix*3 + 2];
93
94 if (bpp == 4)
95 dest_pix[3] = 255;
96 }
97 }
98
99 return dest;
100 }
101
102
R_UploadTexture(epi::image_data_c * img,int flags,int max_pix)103 GLuint R_UploadTexture(epi::image_data_c *img, int flags, int max_pix)
104 {
105 /* Send the texture data to the GL, and returns the texture ID
106 * assigned to it.
107 */
108
109 SYS_ASSERT(img->bpp == 3 || img->bpp == 4);
110
111 bool clamp = (flags & UPL_Clamp) ? true : false;
112 bool nomip = (flags & UPL_MipMap) ? false : true;
113 bool smooth = (flags & UPL_Smooth) ? true : false;
114
115 int total_w = img->width;
116 int total_h = img->height;
117
118 int new_w, new_h;
119
120 // scale down, if necessary, to fix the maximum size
121 for (new_w = total_w; new_w > glmax_tex_size; new_w /= 2)
122 { /* nothing here */ }
123
124 for (new_h = total_h; new_h > glmax_tex_size; new_h /= 2)
125 { /* nothing here */ }
126
127 while (new_w * new_h > max_pix)
128 {
129 if (new_h >= new_w)
130 new_h /= 2;
131 else
132 new_w /= 2;
133 }
134
135 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
136
137 GLuint id;
138
139 glGenTextures(1, &id);
140 glBindTexture(GL_TEXTURE_2D, id);
141
142 int tmode = GL_REPEAT;
143
144 if (clamp)
145 tmode = r_dumbclamp.d ? GL_CLAMP : GL_CLAMP_TO_EDGE;
146
147 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tmode);
148 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tmode);
149
150 // magnification mode
151 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
152 smooth ? GL_LINEAR : GL_NEAREST);
153
154 // minification mode
155 int mip_level = CLAMP(0, var_mipmapping, 2);
156
157 // special logic for mid-masked textures. The UPL_Thresh flag
158 // guarantees that each texture level has simple alpha (0 or 255),
159 // but we must also disable Trilinear Mipmapping because it will
160 // produce partial alpha values when interpolating between mips.
161 if (flags & UPL_Thresh)
162 mip_level = CLAMP(0, mip_level, 1);
163
164 static GLuint minif_modes[2*3] =
165 {
166 GL_NEAREST,
167 GL_NEAREST_MIPMAP_NEAREST,
168 GL_NEAREST_MIPMAP_LINEAR,
169
170 GL_LINEAR,
171 GL_LINEAR_MIPMAP_NEAREST,
172 GL_LINEAR_MIPMAP_LINEAR
173 };
174
175 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
176 minif_modes[(smooth ? 3 : 0) +
177 (nomip ? 0 : mip_level)]);
178
179 for (int mip=0; ; mip++)
180 {
181 if (img->width != new_w || img->height != new_h)
182 {
183 img->ShrinkMasked(new_w, new_h);
184
185 if (flags & UPL_Thresh)
186 img->ThresholdAlpha((mip&1) ? 96 : 144);
187 }
188
189 glTexImage2D(GL_TEXTURE_2D, mip, (img->bpp == 3) ? GL_RGB : GL_RGBA,
190 new_w, new_h, 0 /* border */,
191 (img->bpp == 3) ? GL_RGB : GL_RGBA,
192 GL_UNSIGNED_BYTE, img->PixelAt(0,0));
193
194 // stop if mipmapping disabled or we have reached the end
195 if (nomip || !var_mipmapping || (new_w == 1 && new_h == 1))
196 break;
197
198 new_w = MAX(1, new_w / 2);
199 new_h = MAX(1, new_h / 2);
200
201 // -AJA- 2003/12/05: workaround for Radeon 7500 driver bug, which
202 // incorrectly draws the 1x1 mip texture as black.
203 #ifndef WIN32
204 if (new_w == 1 && new_h == 1)
205 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mip);
206 #endif
207 }
208
209 return id;
210 }
211
212
213 //----------------------------------------------------------------------------
214
215
R_PaletteRemapRGBA(epi::image_data_c * img,const byte * new_pal,const byte * old_pal)216 void R_PaletteRemapRGBA(epi::image_data_c *img,
217 const byte *new_pal, const byte *old_pal)
218 {
219 const int max_prev = 16;
220
221 // cache of previously looked-up colours (in pairs)
222 u8_t previous[max_prev * 6];
223 int num_prev = 0;
224
225 for (int y = 0; y < img->height; y++)
226 for (int x = 0; x < img->width; x++)
227 {
228 u8_t *cur = img->PixelAt(x, y);
229
230 // skip completely transparent pixels
231 if (img->bpp == 4 && cur[3] == 0)
232 continue;
233
234 // optimisation: if colour matches previous one, don't need
235 // to compute the remapping again.
236 int i;
237 for (i = 0; i < num_prev; i++)
238 {
239 if (previous[i*6+0] == cur[0] &&
240 previous[i*6+1] == cur[1] &&
241 previous[i*6+2] == cur[2])
242 {
243 break;
244 }
245 }
246
247 if (i < num_prev)
248 {
249 // move to front (Most Recently Used)
250 #if 1
251 if (i != 0)
252 {
253 u8_t tmp[6];
254
255 memcpy(tmp, previous, 6);
256 memcpy(previous, previous + i*6, 6);
257 memcpy(previous + i*6, tmp, 6);
258 }
259 #endif
260 cur[0] = previous[3];
261 cur[1] = previous[4];
262 cur[2] = previous[5];
263
264 continue;
265 }
266
267 if (num_prev < max_prev)
268 {
269 memmove(previous+6, previous, num_prev*6);
270 num_prev++;
271 }
272
273 // most recent lookup is at the head
274 previous[0] = cur[0];
275 previous[1] = cur[1];
276 previous[2] = cur[2];
277
278 int best = 0;
279 int best_dist = (1 << 30);
280
281 int R = int(cur[0]);
282 int G = int(cur[1]);
283 int B = int(cur[2]);
284
285 for (int p = 0; p < 256; p++)
286 {
287 int dR = int(old_pal[p*3+0]) - R;
288 int dG = int(old_pal[p*3+1]) - G;
289 int dB = int(old_pal[p*3+2]) - B;
290
291 int dist = dR * dR + dG * dG + dB * dB;
292
293 if (dist < best_dist)
294 {
295 best_dist = dist;
296 best = p;
297 }
298 }
299
300 // if this colour is not affected by the colourmap, then
301 // keep the original colour (which has more precision).
302 if (old_pal[best*3+0] != new_pal[best*3+0] ||
303 old_pal[best*3+1] != new_pal[best*3+1] ||
304 old_pal[best*3+2] != new_pal[best*3+2])
305 {
306 cur[0] = new_pal[best*3+0];
307 cur[1] = new_pal[best*3+1];
308 cur[2] = new_pal[best*3+2];
309 }
310
311 previous[3] = cur[0];
312 previous[4] = cur[1];
313 previous[5] = cur[2];
314 }
315 }
316
R_DetermineOpacity(epi::image_data_c * img)317 int R_DetermineOpacity(epi::image_data_c *img)
318 {
319 if (img->bpp == 3)
320 return OPAC_Solid;
321
322 if (img->bpp == 1)
323 {
324 for (int y=0; y < img->used_h; y++)
325 for (int x=0; x < img->used_w; x++)
326 {
327 u8_t pix = img->PixelAt(x, y)[0];
328
329 if (pix == TRANS_PIXEL)
330 return OPAC_Masked;
331 }
332
333 return OPAC_Solid;
334 }
335 else
336 {
337 SYS_ASSERT(img->bpp == 4);
338
339 bool is_masked = false;
340
341 for (int y=0; y < img->used_h; y++)
342 for (int x=0; x < img->used_w; x++)
343 {
344 u8_t alpha = img->PixelAt(x, y)[3];
345
346 if (alpha == 0)
347 is_masked = true;
348 else if (alpha != 255)
349 return OPAC_Complex;
350 }
351
352 return is_masked ? OPAC_Masked : OPAC_Solid;
353 }
354 }
355
R_BlackenClearAreas(epi::image_data_c * img)356 void R_BlackenClearAreas(epi::image_data_c *img)
357 {
358 // makes sure that any totally transparent pixel (alpha == 0)
359 // has a colour of black.
360
361 byte *dest = img->pixels;
362
363 int count = img->width * img->height;
364
365 if (img->bpp == 1)
366 {
367 for (; count > 0; count--, dest++)
368 {
369 if (*dest == TRANS_PIXEL)
370 *dest = pal_black;
371 }
372 }
373 else if (img->bpp == 4)
374 {
375 for (; count > 0; count--, dest += 4)
376 {
377 if (dest[3] == 0)
378 {
379 dest[0] = dest[1] = dest[2] = 0;
380 }
381 }
382 }
383 }
384
R_DumpImage(epi::image_data_c * img)385 void R_DumpImage(epi::image_data_c *img)
386 {
387 L_WriteDebug("DUMP IMAGE: size=%dx%d [%dx%d] bpp=%d\n",
388 img->used_w, img->used_h,
389 img->width, img->height, img->bpp);
390
391 for (int y=img->height-1; y >= 0; y--)
392 {
393 for (int x=0; x < img->width; x++)
394 {
395 u8_t pixel = img->PixelAt(x,y)[0];
396
397 // L_WriteDebug("%02x", pixel);
398 L_WriteDebug("%c", 'A' + (pixel % 26));
399 }
400
401 L_WriteDebug("\n");
402 }
403 }
404
405
406 //--- editor settings ---
407 // vi:ts=4:sw=4:noexpandtab
408