1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20// r_misc.c
21
22#include "quakedef.h"
23
24extern void R_InitBubble();
25
26/*
27==================
28R_InitTextures
29==================
30*/
31void	R_InitTextures (void)
32{
33	int		x,y, m;
34	byte	*dest;
35
36// create a simple checkerboard texture for the default
37	r_notexture_mip = Hunk_AllocName (sizeof(texture_t) + 16*16+8*8+4*4+2*2, "notexture");
38
39	r_notexture_mip->width = r_notexture_mip->height = 16;
40	r_notexture_mip->offsets[0] = sizeof(texture_t);
41	r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16;
42	r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8;
43	r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4;
44
45	for (m=0 ; m<4 ; m++)
46	{
47		dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m];
48		for (y=0 ; y< (16>>m) ; y++)
49			for (x=0 ; x< (16>>m) ; x++)
50			{
51				if (  (y< (8>>m) ) ^ (x< (8>>m) ) )
52					*dest++ = 0;
53				else
54					*dest++ = 0xff;
55			}
56	}
57}
58
59byte	dottexture[8][8] =
60{
61	{0,1,1,0,0,0,0,0},
62	{1,1,1,1,0,0,0,0},
63	{1,1,1,1,0,0,0,0},
64	{0,1,1,0,0,0,0,0},
65	{0,0,0,0,0,0,0,0},
66	{0,0,0,0,0,0,0,0},
67	{0,0,0,0,0,0,0,0},
68	{0,0,0,0,0,0,0,0},
69};
70void R_InitParticleTexture (void)
71{
72	int		x,y;
73	byte	data[8][8][4];
74
75	//
76	// particle texture
77	//
78	particletexture = texture_extension_number++;
79    GL_Bind(particletexture);
80
81	for (x=0 ; x<8 ; x++)
82	{
83		for (y=0 ; y<8 ; y++)
84		{
85			data[y][x][0] = 255;
86			data[y][x][1] = 255;
87			data[y][x][2] = 255;
88			data[y][x][3] = dottexture[x][y]*255;
89		}
90	}
91	glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_alpha_format, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
92
93	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
94
95	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
96	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
97}
98
99/*
100===============
101R_Envmap_f
102
103Grab six views for environment mapping tests
104===============
105*/
106void R_Envmap_f (void)
107{
108#ifdef USE_OPENGLES
109	// Not implemented
110#else
111	byte	buffer[256*256*4];
112
113	glDrawBuffer  (GL_FRONT);
114	glReadBuffer  (GL_FRONT);
115	envmap = true;
116
117	r_refdef.vrect.x = 0;
118	r_refdef.vrect.y = 0;
119	r_refdef.vrect.width = 256;
120	r_refdef.vrect.height = 256;
121
122	r_refdef.viewangles[0] = 0;
123	r_refdef.viewangles[1] = 0;
124	r_refdef.viewangles[2] = 0;
125	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
126	R_RenderView ();
127	glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
128	COM_WriteFile ("env0.rgb", buffer, sizeof(buffer));
129
130	r_refdef.viewangles[1] = 90;
131	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
132	R_RenderView ();
133	glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
134	COM_WriteFile ("env1.rgb", buffer, sizeof(buffer));
135
136	r_refdef.viewangles[1] = 180;
137	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
138	R_RenderView ();
139	glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
140	COM_WriteFile ("env2.rgb", buffer, sizeof(buffer));
141
142	r_refdef.viewangles[1] = 270;
143	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
144	R_RenderView ();
145	glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
146	COM_WriteFile ("env3.rgb", buffer, sizeof(buffer));
147
148	r_refdef.viewangles[0] = -90;
149	r_refdef.viewangles[1] = 0;
150	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
151	R_RenderView ();
152	glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
153	COM_WriteFile ("env4.rgb", buffer, sizeof(buffer));
154
155	r_refdef.viewangles[0] = 90;
156	r_refdef.viewangles[1] = 0;
157	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
158	R_RenderView ();
159	glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
160	COM_WriteFile ("env5.rgb", buffer, sizeof(buffer));
161
162	envmap = false;
163	glDrawBuffer  (GL_BACK);
164	glReadBuffer  (GL_BACK);
165	GL_EndRendering ();
166#endif
167}
168
169/*
170===============
171R_Init
172===============
173*/
174void R_Init (void)
175{
176	Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
177	Cmd_AddCommand ("envmap", R_Envmap_f);
178	Cmd_AddCommand ("pointfile", R_ReadPointFile_f);
179
180	Cvar_RegisterVariable (&r_norefresh);
181	Cvar_RegisterVariable (&r_lightmap);
182	Cvar_RegisterVariable (&r_fullbright);
183	Cvar_RegisterVariable (&r_drawentities);
184	Cvar_RegisterVariable (&r_drawviewmodel);
185	Cvar_RegisterVariable (&r_shadows);
186	Cvar_RegisterVariable (&r_mirroralpha);
187	Cvar_RegisterVariable (&r_wateralpha);
188	Cvar_RegisterVariable (&r_dynamic);
189	Cvar_RegisterVariable (&r_novis);
190	Cvar_RegisterVariable (&r_speeds);
191	Cvar_RegisterVariable (&r_netgraph);
192
193	Cvar_RegisterVariable (&gl_clear);
194	Cvar_RegisterVariable (&gl_texsort);
195
196 	if (gl_mtexable)
197		Cvar_SetValue ("gl_texsort", 0.0);
198
199	Cvar_RegisterVariable (&gl_cull);
200	Cvar_RegisterVariable (&gl_smoothmodels);
201	Cvar_RegisterVariable (&gl_affinemodels);
202	Cvar_RegisterVariable (&gl_polyblend);
203	Cvar_RegisterVariable (&gl_flashblend);
204	Cvar_RegisterVariable (&gl_playermip);
205	Cvar_RegisterVariable (&gl_nocolors);
206	Cvar_RegisterVariable (&gl_finish);
207
208	Cvar_RegisterVariable (&gl_keeptjunctions);
209	Cvar_RegisterVariable (&gl_reporttjunctions);
210
211	R_InitBubble();
212
213	R_InitParticles ();
214	R_InitParticleTexture ();
215
216#ifdef GLTEST
217	Test_Init ();
218#endif
219
220	netgraphtexture = texture_extension_number;
221	texture_extension_number++;
222
223	playertextures = texture_extension_number;
224	texture_extension_number += MAX_CLIENTS;
225}
226
227/*
228===============
229R_TranslatePlayerSkin
230
231Translates a skin texture by the per-player color lookup
232===============
233*/
234void R_TranslatePlayerSkin (int playernum)
235{
236	int		top, bottom;
237	byte	translate[256];
238	unsigned	translate32[256];
239	int		i, j;
240	byte	*original;
241	unsigned	pixels[512*256], *out;
242	unsigned	scaled_width, scaled_height;
243	int			inwidth, inheight;
244	int			tinwidth, tinheight;
245	byte		*inrow;
246	unsigned	frac, fracstep;
247	player_info_t *player;
248	extern	byte		player_8bit_texels[320*200];
249	char s[512];
250
251	GL_DisableMultitexture();
252
253	player = &cl.players[playernum];
254	if (!player->name[0])
255		return;
256
257	strcpy(s, Info_ValueForKey(player->userinfo, "skin"));
258	COM_StripExtension(s, s);
259	if (player->skin && !stricmp(s, player->skin->name))
260		player->skin = NULL;
261
262	if (player->_topcolor != player->topcolor ||
263		player->_bottomcolor != player->bottomcolor || !player->skin) {
264		player->_topcolor = player->topcolor;
265		player->_bottomcolor = player->bottomcolor;
266
267		top = player->topcolor;
268		bottom = player->bottomcolor;
269		top = (top < 0) ? 0 : ((top > 13) ? 13 : top);
270		bottom = (bottom < 0) ? 0 : ((bottom > 13) ? 13 : bottom);
271		top *= 16;
272		bottom *= 16;
273
274		for (i=0 ; i<256 ; i++)
275			translate[i] = i;
276
277		for (i=0 ; i<16 ; i++)
278		{
279			if (top < 128)	// the artists made some backwards ranges.  sigh.
280				translate[TOP_RANGE+i] = top+i;
281			else
282				translate[TOP_RANGE+i] = top+15-i;
283
284			if (bottom < 128)
285				translate[BOTTOM_RANGE+i] = bottom+i;
286			else
287				translate[BOTTOM_RANGE+i] = bottom+15-i;
288		}
289
290		//
291		// locate the original skin pixels
292		//
293		// real model width
294		tinwidth = 296;
295		tinheight = 194;
296
297		if (!player->skin)
298			Skin_Find(player);
299		if ((original = Skin_Cache(player->skin)) != NULL) {
300			//skin data width
301			inwidth = 320;
302			inheight = 200;
303		} else {
304			original = player_8bit_texels;
305			inwidth = 296;
306			inheight = 194;
307		}
308
309
310		// because this happens during gameplay, do it fast
311		// instead of sending it through gl_upload 8
312		GL_Bind(playertextures + playernum);
313
314	#if 0
315		s = 320*200;
316		byte	translated[320*200];
317
318		for (i=0 ; i<s ; i+=4)
319		{
320			translated[i] = translate[original[i]];
321			translated[i+1] = translate[original[i+1]];
322			translated[i+2] = translate[original[i+2]];
323			translated[i+3] = translate[original[i+3]];
324		}
325
326
327		// don't mipmap these, because it takes too long
328		GL_Upload8 (translated, paliashdr->skinwidth, paliashdr->skinheight,
329			false, false, true);
330	#endif
331
332		scaled_width = gl_max_size.value < 512 ? gl_max_size.value : 512;
333		scaled_height = gl_max_size.value < 256 ? gl_max_size.value : 256;
334		// allow users to crunch sizes down even more if they want
335		scaled_width >>= (int)gl_playermip.value;
336		scaled_height >>= (int)gl_playermip.value;
337
338		if (VID_Is8bit()) { // 8bit texture upload
339			byte *out2;
340
341			out2 = (byte *)pixels;
342			memset(pixels, 0, sizeof(pixels));
343			fracstep = tinwidth*0x10000/scaled_width;
344			for (i=0 ; i< (int) scaled_height ; i++, out2 += scaled_width)
345			{
346				inrow = original + inwidth*(i*tinheight/scaled_height);
347				frac = fracstep >> 1;
348				for (j=0 ; j< (int) scaled_width ; j+=4)
349				{
350					out2[j] = translate[inrow[frac>>16]];
351					frac += fracstep;
352					out2[j+1] = translate[inrow[frac>>16]];
353					frac += fracstep;
354					out2[j+2] = translate[inrow[frac>>16]];
355					frac += fracstep;
356					out2[j+3] = translate[inrow[frac>>16]];
357					frac += fracstep;
358				}
359			}
360
361			GL_Upload8_EXT ((byte *)pixels, scaled_width, scaled_height, false, false);
362			return;
363		}
364
365		for (i=0 ; i<256 ; i++)
366			translate32[i] = d_8to24table[translate[i]];
367
368		out = pixels;
369		memset(pixels, 0, sizeof(pixels));
370		fracstep = tinwidth*0x10000/scaled_width;
371		for (i=0 ; i< (int) scaled_height ; i++, out += scaled_width)
372		{
373			inrow = original + inwidth*(i*tinheight/scaled_height);
374			frac = fracstep >> 1;
375			for (j=0 ; j< (int) scaled_width ; j+=4)
376			{
377				out[j] = translate32[inrow[frac>>16]];
378				frac += fracstep;
379				out[j+1] = translate32[inrow[frac>>16]];
380				frac += fracstep;
381				out[j+2] = translate32[inrow[frac>>16]];
382				frac += fracstep;
383				out[j+3] = translate32[inrow[frac>>16]];
384				frac += fracstep;
385			}
386		}
387
388		glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_solid_format,
389			scaled_width, scaled_height, 0, GL_RGBA,
390			GL_UNSIGNED_BYTE, pixels);
391
392		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
393		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
394		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
395	}
396}
397
398/*
399===============
400R_NewMap
401===============
402*/
403void R_NewMap (void)
404{
405	int		i;
406
407	for (i=0 ; i<256 ; i++)
408		d_lightstylevalue[i] = 264;		// normal light value
409
410	memset (&r_worldentity, 0, sizeof(r_worldentity));
411	r_worldentity.model = cl.worldmodel;
412
413// clear out efrags in case the level hasn't been reloaded
414// FIXME: is this one short?
415	for (i=0 ; i<cl.worldmodel->numleafs ; i++)
416		cl.worldmodel->leafs[i].efrags = NULL;
417
418	r_viewleaf = NULL;
419	R_ClearParticles ();
420
421	GL_BuildLightmaps ();
422
423	// identify sky texture
424	skytexturenum = -1;
425	mirrortexturenum = -1;
426	for (i=0 ; i<cl.worldmodel->numtextures ; i++)
427	{
428		if (!cl.worldmodel->textures[i])
429			continue;
430		if (!Q_strncmp(cl.worldmodel->textures[i]->name,"sky",3) )
431			skytexturenum = i;
432		if (!Q_strncmp(cl.worldmodel->textures[i]->name,"window02_1",10) )
433			mirrortexturenum = i;
434 		cl.worldmodel->textures[i]->texturechain = NULL;
435	}
436#ifdef QUAKE2
437	R_LoadSkys ();
438#endif
439}
440
441
442/*
443====================
444R_TimeRefresh_f
445
446For program optimization
447====================
448*/
449void R_TimeRefresh_f (void)
450{
451#ifdef USE_OPENGLES
452	// Not implemented
453	Con_Printf("TimeRefresh not implemented.\n");
454#else
455	int			i;
456	float		start, stop, time;
457
458	glDrawBuffer  (GL_FRONT);
459	glFinish ();
460
461	start = Sys_DoubleTime ();
462	for (i=0 ; i<128 ; i++)
463	{
464		r_refdef.viewangles[1] = i/128.0*360.0;
465		R_RenderView ();
466	}
467
468	glFinish ();
469	stop = Sys_DoubleTime ();
470	time = stop-start;
471	Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
472
473	glDrawBuffer  (GL_BACK);
474	GL_EndRendering ();
475#endif
476}
477
478void D_FlushCaches (void)
479{
480}
481
482
483