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