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