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