| /* |
| Copyright (C) 1996-1997 Id Software, Inc. |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License |
| as published by the Free Software Foundation; either version 2 |
| of the License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| |
| See the GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| |
| */ |
| // r_misc.c |
| |
| #include "quakedef.h" |
| |
| |
| |
| /* |
| ================== |
| R_InitTextures |
| ================== |
| */ |
| void R_InitTextures (void) |
| { |
| int x,y, m; |
| byte *dest; |
| |
| // create a simple checkerboard texture for the default |
| r_notexture_mip = (texture_t*) Hunk_AllocName (sizeof(texture_t) + 16*16+8*8+4*4+2*2, "notexture"); |
| |
| r_notexture_mip->width = r_notexture_mip->height = 16; |
| r_notexture_mip->offsets[0] = sizeof(texture_t); |
| r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16; |
| r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8; |
| r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4; |
| |
| for (m=0 ; m<4 ; m++) |
| { |
| dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m]; |
| for (y=0 ; y< (16>>m) ; y++) |
| for (x=0 ; x< (16>>m) ; x++) |
| { |
| if ( (y< (8>>m) ) ^ (x< (8>>m) ) ) |
| *dest++ = 0; |
| else |
| *dest++ = 0xff; |
| } |
| } |
| } |
| |
| byte dottexture[8][8] = |
| { |
| {0,1,1,0,0,0,0,0}, |
| {1,1,1,1,0,0,0,0}, |
| {1,1,1,1,0,0,0,0}, |
| {0,1,1,0,0,0,0,0}, |
| {0,0,0,0,0,0,0,0}, |
| {0,0,0,0,0,0,0,0}, |
| {0,0,0,0,0,0,0,0}, |
| {0,0,0,0,0,0,0,0}, |
| }; |
| // Initialize particle texture, can be called multiple times. |
| void R_InitParticleTexture2 (void) |
| { |
| int x,y; |
| byte data[8][8][4]; |
| |
| // |
| // particle texture |
| // |
| GL_Bind(particletexture); |
| |
| for (x=0 ; x<8 ; x++) |
| { |
| for (y=0 ; y<8 ; y++) |
| { |
| data[y][x][0] = 255; |
| data[y][x][1] = 255; |
| data[y][x][2] = 255; |
| data[y][x][3] = dottexture[x][y]*255; |
| } |
| } |
| glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_alpha_format, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); |
| |
| glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); |
| |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| } |
| |
| void R_InitParticleTexture (void) |
| { |
| particletexture = texture_extension_number++; |
| R_InitParticleTexture2(); |
| } |
| |
| /* |
| =============== |
| R_Envmap_f |
| |
| Grab six views for environment mapping tests |
| =============== |
| */ |
| void R_Envmap_f (void) |
| { |
| #ifdef USE_OPENGLES |
| // Not implemented |
| #else |
| byte buffer[256*256*4]; |
| char name[1024]; |
| |
| glDrawBuffer (GL_FRONT); |
| glReadBuffer (GL_FRONT); |
| envmap = true; |
| |
| r_refdef.vrect.x = 0; |
| r_refdef.vrect.y = 0; |
| r_refdef.vrect.width = 256; |
| r_refdef.vrect.height = 256; |
| |
| r_refdef.viewangles[0] = 0; |
| r_refdef.viewangles[1] = 0; |
| r_refdef.viewangles[2] = 0; |
| GL_BeginRendering (&glx, &gly, &glwidth, &glheight); |
| R_RenderView (); |
| glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); |
| COM_WriteFile ("env0.rgb", buffer, sizeof(buffer)); |
| |
| r_refdef.viewangles[1] = 90; |
| GL_BeginRendering (&glx, &gly, &glwidth, &glheight); |
| R_RenderView (); |
| glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); |
| COM_WriteFile ("env1.rgb", buffer, sizeof(buffer)); |
| |
| r_refdef.viewangles[1] = 180; |
| GL_BeginRendering (&glx, &gly, &glwidth, &glheight); |
| R_RenderView (); |
| glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); |
| COM_WriteFile ("env2.rgb", buffer, sizeof(buffer)); |
| |
| r_refdef.viewangles[1] = 270; |
| GL_BeginRendering (&glx, &gly, &glwidth, &glheight); |
| R_RenderView (); |
| glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); |
| COM_WriteFile ("env3.rgb", buffer, sizeof(buffer)); |
| |
| r_refdef.viewangles[0] = -90; |
| r_refdef.viewangles[1] = 0; |
| GL_BeginRendering (&glx, &gly, &glwidth, &glheight); |
| R_RenderView (); |
| glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); |
| COM_WriteFile ("env4.rgb", buffer, sizeof(buffer)); |
| |
| r_refdef.viewangles[0] = 90; |
| r_refdef.viewangles[1] = 0; |
| GL_BeginRendering (&glx, &gly, &glwidth, &glheight); |
| R_RenderView (); |
| glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); |
| COM_WriteFile ("env5.rgb", buffer, sizeof(buffer)); |
| |
| envmap = false; |
| glDrawBuffer (GL_BACK); |
| glReadBuffer (GL_BACK); |
| GL_EndRendering (); |
| #endif |
| } |
| |
| /* |
| =============== |
| R_Init |
| =============== |
| */ |
| void R_Init (void) |
| { |
| extern byte *hunk_base; |
| extern cvar_t gl_finish; |
| |
| Cmd_AddCommand ("timerefresh", R_TimeRefresh_f); |
| Cmd_AddCommand ("envmap", R_Envmap_f); |
| Cmd_AddCommand ("pointfile", R_ReadPointFile_f); |
| |
| Cvar_RegisterVariable (&r_norefresh); |
| Cvar_RegisterVariable (&r_lightmap); |
| Cvar_RegisterVariable (&r_fullbright); |
| Cvar_RegisterVariable (&r_drawentities); |
| Cvar_RegisterVariable (&r_drawviewmodel); |
| Cvar_RegisterVariable (&r_shadows); |
| Cvar_RegisterVariable (&r_mirroralpha); |
| Cvar_RegisterVariable (&r_wateralpha); |
| Cvar_RegisterVariable (&r_dynamic); |
| Cvar_RegisterVariable (&r_novis); |
| Cvar_RegisterVariable (&r_speeds); |
| |
| Cvar_RegisterVariable (&gl_finish); |
| Cvar_RegisterVariable (&gl_clear); |
| Cvar_RegisterVariable (&gl_texsort); |
| |
| if (gl_mtexable) |
| Cvar_SetValue ("gl_texsort", 0.0); |
| |
| Cvar_RegisterVariable (&gl_cull); |
| Cvar_RegisterVariable (&gl_smoothmodels); |
| Cvar_RegisterVariable (&gl_affinemodels); |
| Cvar_RegisterVariable (&gl_polyblend); |
| Cvar_RegisterVariable (&gl_flashblend); |
| Cvar_RegisterVariable (&gl_playermip); |
| Cvar_RegisterVariable (&gl_nocolors); |
| |
| Cvar_RegisterVariable (&gl_keeptjunctions); |
| Cvar_RegisterVariable (&gl_reporttjunctions); |
| |
| Cvar_RegisterVariable (&gl_doubleeyes); |
| |
| R_InitParticles (); |
| R_InitParticleTexture (); |
| |
| #ifdef GLTEST |
| Test_Init (); |
| #endif |
| |
| playertextures = texture_extension_number; |
| texture_extension_number += 16; |
| } |
| |
| /* |
| =============== |
| R_TranslatePlayerSkin |
| |
| Translates a skin texture by the per-player color lookup |
| =============== |
| */ |
| void R_TranslatePlayerSkin (int playernum) |
| { |
| int top, bottom; |
| byte translate[256]; |
| unsigned translate32[256]; |
| int i, j, s; |
| model_t *model; |
| aliashdr_t *paliashdr; |
| byte *original; |
| unsigned* pixels; |
| unsigned *out; |
| unsigned scaled_width, scaled_height; |
| int inwidth, inheight; |
| byte *inrow; |
| unsigned frac, fracstep; |
| extern byte **player_8bit_texels_tbl; |
| |
| GL_DisableMultitexture(); |
| |
| top = cl.scores[playernum].colors & 0xf0; |
| bottom = (cl.scores[playernum].colors &15)<<4; |
| |
| for (i=0 ; i<256 ; i++) |
| translate[i] = i; |
| |
| for (i=0 ; i<16 ; i++) |
| { |
| if (top < 128) // the artists made some backwards ranges. sigh. |
| translate[TOP_RANGE+i] = top+i; |
| else |
| translate[TOP_RANGE+i] = top+15-i; |
| |
| if (bottom < 128) |
| translate[BOTTOM_RANGE+i] = bottom+i; |
| else |
| translate[BOTTOM_RANGE+i] = bottom+15-i; |
| } |
| |
| // |
| // locate the original skin pixels |
| // |
| currententity = &cl_entities[1+playernum]; |
| model = currententity->model; |
| if (!model) |
| return; // player doesn't have a model yet |
| if (model->type != mod_alias) |
| return; // only translate skins on alias models |
| |
| paliashdr = (aliashdr_t *)Mod_Extradata (model); |
| s = paliashdr->skinwidth * paliashdr->skinheight; |
| if (currententity->skinnum < 0 || currententity->skinnum >= paliashdr->numskins) { |
| Con_Printf("(%d): Invalid player skin #%d\n", playernum, currententity->skinnum); |
| original = (byte *)paliashdr + paliashdr->texels[0]; |
| } else |
| original = (byte *)paliashdr + paliashdr->texels[currententity->skinnum]; |
| if (s & 3) |
| Sys_Error ("R_TranslateSkin: s&3"); |
| |
| inwidth = paliashdr->skinwidth; |
| inheight = paliashdr->skinheight; |
| |
| // because this happens during gameplay, do it fast |
| // instead of sending it through gl_upload 8 |
| GL_Bind(playertextures + playernum); |
| |
| #if 0 |
| byte translated[320*200]; |
| |
| for (i=0 ; i<s ; i+=4) |
| { |
| translated[i] = translate[original[i]]; |
| translated[i+1] = translate[original[i+1]]; |
| translated[i+2] = translate[original[i+2]]; |
| translated[i+3] = translate[original[i+3]]; |
| } |
| |
| |
| // don't mipmap these, because it takes too long |
| GL_Upload8 (translated, paliashdr->skinwidth, paliashdr->skinheight, false, false, true); |
| #else |
| scaled_width = (unsigned int) (gl_max_size.value < 512 ? gl_max_size.value : 512); |
| scaled_height = (unsigned int) (gl_max_size.value < 256 ? gl_max_size.value : 256); |
| |
| // allow users to crunch sizes down even more if they want |
| scaled_width >>= (int)gl_playermip.value; |
| scaled_height >>= (int)gl_playermip.value; |
| |
| #define PIXEL_COUNT (512*256) |
| #define PIXELS_SIZE (PIXEL_COUNT * sizeof(unsigned)) |
| |
| pixels = (unsigned*) malloc(PIXELS_SIZE); |
| if(!pixels) |
| { |
| Sys_Error("Out of memory."); |
| } |
| |
| if (VID_Is8bit()) { // 8bit texture upload |
| byte *out2; |
| |
| out2 = (byte *)pixels; |
| memset(pixels, 0, PIXELS_SIZE); |
| fracstep = inwidth*0x10000/scaled_width; |
| for (i=0 ; i< (int) scaled_height ; i++, out2 += scaled_width) |
| { |
| inrow = original + inwidth*(i*inheight/scaled_height); |
| frac = fracstep >> 1; |
| for (j=0 ; j< (int) scaled_width ; j+=4) |
| { |
| out2[j] = translate[inrow[frac>>16]]; |
| frac += fracstep; |
| out2[j+1] = translate[inrow[frac>>16]]; |
| frac += fracstep; |
| out2[j+2] = translate[inrow[frac>>16]]; |
| frac += fracstep; |
| out2[j+3] = translate[inrow[frac>>16]]; |
| frac += fracstep; |
| } |
| } |
| |
| GL_Upload8_EXT ((byte *)pixels, scaled_width, scaled_height, false, false); |
| } |
| else |
| { |
| |
| for (i=0 ; i<256 ; i++) |
| translate32[i] = d_8to24table[translate[i]]; |
| |
| out = pixels; |
| fracstep = inwidth*0x10000/scaled_width; |
| for (i=0 ; i< (int) scaled_height ; i++, out += scaled_width) |
| { |
| inrow = original + inwidth*(i*inheight/scaled_height); |
| frac = fracstep >> 1; |
| for (j=0 ; j< (int) scaled_width ; j+=4) |
| { |
| out[j] = translate32[inrow[frac>>16]]; |
| frac += fracstep; |
| out[j+1] = translate32[inrow[frac>>16]]; |
| frac += fracstep; |
| out[j+2] = translate32[inrow[frac>>16]]; |
| frac += fracstep; |
| out[j+3] = translate32[inrow[frac>>16]]; |
| frac += fracstep; |
| } |
| } |
| glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_solid_format, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); |
| |
| glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| } |
| #endif |
| free(pixels); |
| } |
| |
| |
| /* |
| =============== |
| R_NewMap |
| =============== |
| */ |
| void R_NewMap (void) |
| { |
| int i; |
| |
| for (i=0 ; i<256 ; i++) |
| d_lightstylevalue[i] = 264; // normal light value |
| |
| memset (&r_worldentity, 0, sizeof(r_worldentity)); |
| r_worldentity.model = cl.worldmodel; |
| |
| // clear out efrags in case the level hasn't been reloaded |
| // FIXME: is this one short? |
| for (i=0 ; i<cl.worldmodel->numleafs ; i++) |
| cl.worldmodel->leafs[i].efrags = NULL; |
| |
| r_viewleaf = NULL; |
| R_ClearParticles (); |
| |
| GL_BuildLightmaps (); |
| |
| // identify sky texture |
| skytexturenum = -1; |
| mirrortexturenum = -1; |
| for (i=0 ; i<cl.worldmodel->numtextures ; i++) |
| { |
| if (!cl.worldmodel->textures[i]) |
| continue; |
| if (!Q_strncmp(cl.worldmodel->textures[i]->name,"sky",3) ) |
| skytexturenum = i; |
| if (!Q_strncmp(cl.worldmodel->textures[i]->name,"window02_1",10) ) |
| mirrortexturenum = i; |
| cl.worldmodel->textures[i]->texturechain = NULL; |
| } |
| #ifdef QUAKE2 |
| R_LoadSkys (); |
| #endif |
| } |
| |
| |
| /* |
| ==================== |
| R_TimeRefresh_f |
| |
| For program optimization |
| ==================== |
| */ |
| void R_TimeRefresh_f (void) |
| { |
| #ifdef USE_OPENGLES |
| // Not implemented |
| Con_Printf("TimeRefresh not implemented.\n"); |
| #else |
| int i; |
| float start, stop, time; |
| int startangle; |
| vrect_t vr; |
| |
| glDrawBuffer (GL_FRONT); |
| glFinish (); |
| |
| start = Sys_FloatTime (); |
| for (i=0 ; i<128 ; i++) |
| { |
| r_refdef.viewangles[1] = i/128.0*360.0; |
| R_RenderView (); |
| } |
| |
| glFinish (); |
| stop = Sys_FloatTime (); |
| time = stop-start; |
| Con_Printf ("%f seconds (%f fps)\n", time, 128/time); |
| |
| glDrawBuffer (GL_BACK); |
| GL_EndRendering (); |
| #endif |
| } |
| |
| void D_FlushCaches (void) |
| { |
| } |