mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-10 22:51:57 +00:00
ce3c561cfe
Particle system functions renamed a bit, a few other cleanups in that area. Console handling tweeked. Better rules for subconsoles and plugins. Commands are coloured if it'll be execed, which should help reduce occurences of chat being commands. tab compleation tweeked, partial compleation no longer changes the suggestion. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@895 fc73d0e0-1445-4013-8a0c-d673dee63da5
1060 lines
25 KiB
C
1060 lines
25 KiB
C
/*
|
|
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"
|
|
#ifdef RGLQUAKE
|
|
#include "glquake.h"
|
|
#include "gl_draw.h"
|
|
|
|
#ifdef WATERLAYERS
|
|
cvar_t r_waterlayers = {"r_waterlayers","3"};
|
|
#endif
|
|
|
|
extern void R_InitBubble();
|
|
|
|
#ifndef SWQUAKE
|
|
//SW rendering has a faster method, which takes more memory and stuff.
|
|
//We need this for minor things though, so we'll just use the slow accurate method.
|
|
//this is unlikly to be called very often.
|
|
qbyte GetPalette(int red, int green, int blue)
|
|
{
|
|
//slow, horrible method.
|
|
{
|
|
int i, best=15;
|
|
int bestdif=256*256*256, curdif;
|
|
extern qbyte *host_basepal;
|
|
qbyte *pa;
|
|
|
|
#define _abs(x) ((x)*(x))
|
|
|
|
pa = host_basepal;
|
|
for (i = 0; i < 256; i++, pa+=3)
|
|
{
|
|
curdif = _abs(red - pa[0]) + _abs(green - pa[1]) + _abs(blue - pa[2]);
|
|
if (curdif < bestdif)
|
|
{
|
|
if (curdif<1)
|
|
return i;
|
|
bestdif = curdif;
|
|
best = i;
|
|
}
|
|
}
|
|
return best;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
==================
|
|
R_InitTextures
|
|
==================
|
|
*
|
|
void GLR_InitTextures (void)
|
|
{
|
|
int x,y, m;
|
|
qbyte *dest;
|
|
|
|
// create a simple checkerboard texture for the default
|
|
r_notexture_mip = 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 = (qbyte *)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;
|
|
}
|
|
}
|
|
}*/
|
|
//we could go for nice smooth round particles... but then we would loose a little bit of the chaotic nature of the particles.
|
|
static qbyte dottexture[8][8] =
|
|
{
|
|
{0,0,0,0,0,0,0,0},
|
|
{0,0,0,1,1,0,0,0},
|
|
{0,0,1,1,1,1,0,0},
|
|
{0,1,1,1,1,1,1,0},
|
|
{0,1,1,1,1,1,1,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},
|
|
};
|
|
static qbyte exptexture[16][16] =
|
|
{
|
|
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
|
{0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0},
|
|
{0,0,0,1,1,1,1,1,3,1,1,2,1,0,0,0},
|
|
{0,0,0,1,1,1,1,4,4,4,5,4,2,1,1,0},
|
|
{0,0,1,1,6,5,5,8,6,8,3,6,3,2,1,0},
|
|
{0,0,1,5,6,7,5,6,8,8,8,3,3,1,0,0},
|
|
{0,0,0,1,6,8,9,9,9,9,4,6,3,1,0,0},
|
|
{0,0,2,1,7,7,9,9,9,9,5,3,1,0,0,0},
|
|
{0,0,2,4,6,8,9,9,9,9,8,6,1,0,0,0},
|
|
{0,0,2,2,3,5,6,8,9,8,8,4,4,1,0,0},
|
|
{0,0,1,2,4,1,8,7,8,8,6,5,4,1,0,0},
|
|
{0,1,1,1,7,8,1,6,7,5,4,7,1,0,0,0},
|
|
{0,1,2,1,1,5,1,3,4,3,1,1,0,0,0,0},
|
|
{0,0,0,0,0,1,1,1,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,0},
|
|
};
|
|
void R_InitParticleTexture (void)
|
|
{
|
|
int x,y;
|
|
qbyte data[16*16][4];
|
|
|
|
//
|
|
// particle texture
|
|
//
|
|
particletexture = texture_extension_number++;
|
|
GL_Bind(particletexture);
|
|
|
|
for (x=0 ; x<8 ; x++)
|
|
{
|
|
for (y=0 ; y<8 ; y++)
|
|
{
|
|
data[y*8+x][0] = 255;
|
|
data[y*8+x][1] = 255;
|
|
data[y*8+x][2] = 255;
|
|
data[y*8+x][3] = dottexture[x][y]*255;
|
|
}
|
|
}
|
|
qglTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
|
|
|
qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
|
|
|
|
|
|
explosiontexture = texture_extension_number++;
|
|
GL_Bind(explosiontexture);
|
|
|
|
for (x=0 ; x<16 ; x++)
|
|
{
|
|
for (y=0 ; y<16 ; y++)
|
|
{
|
|
data[y*16+x][0] = 255;
|
|
data[y*16+x][1] = 255;
|
|
data[y*16+x][2] = 255;
|
|
data[y*16+x][3] = exptexture[x][y]*255/9.0;
|
|
}
|
|
}
|
|
qglTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
|
|
|
qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
}
|
|
|
|
/*
|
|
===============
|
|
R_Envmap_f
|
|
|
|
Grab six views for environment mapping tests
|
|
===============
|
|
*/
|
|
void R_Envmap_f (void)
|
|
{
|
|
qbyte buffer[256*256*4];
|
|
|
|
qglDrawBuffer (GL_FRONT);
|
|
qglReadBuffer (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 ();
|
|
qglReadPixels (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 ();
|
|
qglReadPixels (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 ();
|
|
qglReadPixels (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 ();
|
|
qglReadPixels (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 ();
|
|
qglReadPixels (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 ();
|
|
qglReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
|
COM_WriteFile ("env5.rgb", buffer, sizeof(buffer));
|
|
|
|
envmap = false;
|
|
qglDrawBuffer (GL_BACK);
|
|
qglReadBuffer (GL_BACK);
|
|
GL_EndRendering ();
|
|
GL_DoSwap();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
qboolean GenerateNormalisationCubeMap()
|
|
{
|
|
unsigned char data[32*32*3];
|
|
|
|
//some useful variables
|
|
int size=32;
|
|
float offset=0.5f;
|
|
float halfSize=16.0f;
|
|
vec3_t tempVector;
|
|
unsigned char * bytePtr;
|
|
|
|
int i, j;
|
|
|
|
//positive x
|
|
bytePtr=data;
|
|
|
|
for(j=0; j<size; j++)
|
|
{
|
|
for(i=0; i<size; i++)
|
|
{
|
|
tempVector[0] = halfSize;
|
|
tempVector[1] = -(j+offset-halfSize);
|
|
tempVector[2] = -(i+offset-halfSize);
|
|
|
|
VectorNormalize(tempVector);
|
|
|
|
bytePtr[0]=(unsigned char)((tempVector[0]/2 + 0.5)*255);
|
|
bytePtr[1]=(unsigned char)((tempVector[1]/2 + 0.5)*255);
|
|
bytePtr[2]=(unsigned char)((tempVector[2]/2 + 0.5)*255);
|
|
|
|
bytePtr+=3;
|
|
}
|
|
}
|
|
qglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
|
|
0, GL_RGBA8, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
|
|
|
|
//negative x
|
|
bytePtr=data;
|
|
|
|
for(j=0; j<size; j++)
|
|
{
|
|
for(i=0; i<size; i++)
|
|
{
|
|
tempVector[0] = (-halfSize);
|
|
tempVector[1] = (-(j+offset-halfSize));
|
|
tempVector[2] = ((i+offset-halfSize));
|
|
|
|
VectorNormalize(tempVector);
|
|
|
|
bytePtr[0]=(unsigned char)((tempVector[0]/2 + 0.5)*255);
|
|
bytePtr[1]=(unsigned char)((tempVector[1]/2 + 0.5)*255);
|
|
bytePtr[2]=(unsigned char)((tempVector[2]/2 + 0.5)*255);
|
|
|
|
bytePtr+=3;
|
|
}
|
|
}
|
|
qglTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
|
|
0, GL_RGBA8, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
|
|
|
|
//positive y
|
|
bytePtr=data;
|
|
|
|
for(j=0; j<size; j++)
|
|
{
|
|
for(i=0; i<size; i++)
|
|
{
|
|
tempVector[0] = (i+offset-halfSize);
|
|
tempVector[1] = (halfSize);
|
|
tempVector[2] = ((j+offset-halfSize));
|
|
|
|
VectorNormalize(tempVector);
|
|
|
|
bytePtr[0]=(unsigned char)((tempVector[0]/2 + 0.5)*255);
|
|
bytePtr[1]=(unsigned char)((tempVector[1]/2 + 0.5)*255);
|
|
bytePtr[2]=(unsigned char)((tempVector[2]/2 + 0.5)*255);
|
|
|
|
bytePtr+=3;
|
|
}
|
|
}
|
|
qglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
|
|
0, GL_RGBA8, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
|
|
|
|
//negative y
|
|
bytePtr=data;
|
|
|
|
for(j=0; j<size; j++)
|
|
{
|
|
for(i=0; i<size; i++)
|
|
{
|
|
tempVector[0] = (i+offset-halfSize);
|
|
tempVector[1] = (-halfSize);
|
|
tempVector[2] = (-(j+offset-halfSize));
|
|
|
|
VectorNormalize(tempVector);
|
|
|
|
bytePtr[0]=(unsigned char)((tempVector[0]/2 + 0.5)*255);
|
|
bytePtr[1]=(unsigned char)((tempVector[1]/2 + 0.5)*255);
|
|
bytePtr[2]=(unsigned char)((tempVector[2]/2 + 0.5)*255);
|
|
|
|
bytePtr+=3;
|
|
}
|
|
}
|
|
qglTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
|
|
0, GL_RGBA8, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
|
|
|
|
//positive z
|
|
bytePtr=data;
|
|
|
|
for(j=0; j<size; j++)
|
|
{
|
|
for(i=0; i<size; i++)
|
|
{
|
|
tempVector[0] = (i+offset-halfSize);
|
|
tempVector[1] = (-(j+offset-halfSize));
|
|
tempVector[2] = (halfSize);
|
|
|
|
VectorNormalize(tempVector);
|
|
|
|
bytePtr[0]=(unsigned char)((tempVector[0]/2 + 0.5)*255);
|
|
bytePtr[1]=(unsigned char)((tempVector[1]/2 + 0.5)*255);
|
|
bytePtr[2]=(unsigned char)((tempVector[2]/2 + 0.5)*255);
|
|
|
|
bytePtr+=3;
|
|
}
|
|
}
|
|
qglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
|
|
0, GL_RGBA8, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
|
|
|
|
//negative z
|
|
bytePtr=data;
|
|
|
|
for(j=0; j<size; j++)
|
|
{
|
|
for(i=0; i<size; i++)
|
|
{
|
|
tempVector[0] = (-(i+offset-halfSize));
|
|
tempVector[1] = (-(j+offset-halfSize));
|
|
tempVector[2] = (-halfSize);
|
|
|
|
VectorNormalize(tempVector);
|
|
|
|
bytePtr[0]=(unsigned char)((tempVector[0]/2 + 0.5)*255);
|
|
bytePtr[1]=(unsigned char)((tempVector[1]/2 + 0.5)*255);
|
|
bytePtr[2]=(unsigned char)((tempVector[2]/2 + 0.5)*255);
|
|
|
|
bytePtr+=3;
|
|
}
|
|
}
|
|
qglTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
|
|
0, GL_RGBA8, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
int normalisationCubeMap;
|
|
/*
|
|
===============
|
|
R_Init
|
|
===============
|
|
*/
|
|
void GLR_ReInit (void)
|
|
{
|
|
extern int gl_bumpmappingpossible;
|
|
R_InitParticleTexture ();
|
|
|
|
#ifdef GLTEST
|
|
Test_Init ();
|
|
#endif
|
|
|
|
netgraphtexture = texture_extension_number;
|
|
texture_extension_number++;
|
|
|
|
playertextures = texture_extension_number;
|
|
texture_extension_number += MAX_CLIENTS;
|
|
|
|
if (gl_bumpmappingpossible)
|
|
{
|
|
//Create normalisation cube map
|
|
normalisationCubeMap = texture_extension_number++;
|
|
GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
|
|
GenerateNormalisationCubeMap();
|
|
qglTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
qglTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
qglTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
qglTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
qglTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
|
}
|
|
else
|
|
normalisationCubeMap = 0;
|
|
|
|
}
|
|
/*
|
|
typedef struct
|
|
{
|
|
long offset; // Position of the entry in WAD
|
|
long dsize; // Size of the entry in WAD file
|
|
long size; // Size of the entry in memory
|
|
char type; // type of entry
|
|
char cmprs; // Compression. 0 if none.
|
|
short dummy; // Not used
|
|
char name[16]; // we use only first 8
|
|
} wad2entry_t;
|
|
typedef struct
|
|
{
|
|
char magic[4]; //should be WAD2
|
|
long num; //number of entries
|
|
long offset; //location of directory
|
|
} wad2_t;
|
|
void R_MakeTexWad_f(void)
|
|
{
|
|
miptex_t dummymip = {"", 0, 0, {0, 0, 0, 0}};
|
|
wad2_t wad2 = {"WAD2",0,0};
|
|
wad2entry_t entry[2048];
|
|
int entries = 0, i;
|
|
FILE *f;
|
|
char base[128];
|
|
char *texname;
|
|
// qbyte b;
|
|
float scale;
|
|
int width, height;
|
|
|
|
qbyte *buf, *outmip;
|
|
qbyte *mip, *stack;
|
|
|
|
// WIN32_FIND_DATA fd;
|
|
// HANDLE h;
|
|
|
|
scale = atof(Cmd_Argv(2));
|
|
if (!scale)
|
|
scale = 2;
|
|
|
|
// h = FindFirstFile(va("%s/textures/ *.tga", com_gamedir), &fd); //if this is uncommented, clear that space... (gcc warning fix)
|
|
if (!shader)
|
|
return;
|
|
mip = BZ_Malloc(1024*1024);
|
|
// initbuf = BZ_Malloc(1024*1024*4);
|
|
stack = BZ_Malloc(1024*1024*4+1024);
|
|
f=fopen(va("%s/shadrtex.wad", com_gamedir), "wb");
|
|
fwrite(&wad2, 1, sizeof(wad2_t), f);
|
|
|
|
for (shad = shader; shad; shad=shad->next)
|
|
{
|
|
texname = shad->editorname;
|
|
if (!*texname)
|
|
continue;
|
|
COM_StripExtension(shad->name, base);
|
|
base[15]=0;
|
|
for (i =0; i < entries; i++)
|
|
if (!strcmp(entry[entries].name, base))
|
|
break;
|
|
if (i != entries)
|
|
{
|
|
Con_Printf("Skipped %s - duplicated shrunken name\n", texname);
|
|
continue;
|
|
}
|
|
entry[entries].offset = ftell(f);
|
|
entry[entries].dsize = entry[entries].size = 0;
|
|
entry[entries].type = TYP_MIPTEX;
|
|
entry[entries].cmprs = 0;
|
|
entry[entries].dummy = 0;
|
|
strcpy(entry[entries].name, base);
|
|
|
|
strcpy(dummymip.name, base);
|
|
|
|
{
|
|
|
|
qbyte *data;
|
|
int h;
|
|
float x, xi;
|
|
float y, yi;
|
|
|
|
char *path[] ={
|
|
"%s",
|
|
"override/%s.tga",
|
|
"override/%s.pcx",
|
|
"%s.tga",
|
|
"progs/%s"};
|
|
for (h = 0, buf=NULL; h < sizeof(path)/sizeof(char *); h++)
|
|
{
|
|
buf = COM_LoadStackFile(va(path[h], texname), stack, 1024*1024*4+1024);
|
|
if (buf)
|
|
break;
|
|
}
|
|
if (!buf)
|
|
{
|
|
Con_Printf("Failed to find texture \"%s\"\n", texname);
|
|
continue;
|
|
}
|
|
|
|
|
|
data = ReadTargaFile(buf, com_filesize, &width, &height, false);
|
|
if (!data)
|
|
{
|
|
BZ_Free(data);
|
|
Con_Printf("Skipped %s - file type not supported (bad bpp?)\n", texname);
|
|
continue;
|
|
}
|
|
|
|
dummymip.width = (int)(width/scale) & ~0xf;
|
|
dummymip.height = (int)(height/scale) & ~0xf;
|
|
if (dummymip.width<=0)
|
|
dummymip.width=16;
|
|
if (dummymip.height<=0)
|
|
dummymip.height=16;
|
|
|
|
dummymip.offsets[0] = sizeof(dummymip);
|
|
dummymip.offsets[1] = dummymip.offsets[0]+dummymip.width*dummymip.height;
|
|
dummymip.offsets[2] = dummymip.offsets[1]+dummymip.width/2*dummymip.height/2;
|
|
dummymip.offsets[3] = dummymip.offsets[2]+dummymip.width/4*dummymip.height/4;
|
|
entry[entries].dsize = entry[entries].size = dummymip.offsets[3]+dummymip.width/8*dummymip.height/8;
|
|
|
|
xi = (float)width/dummymip.width;
|
|
yi = (float)height/dummymip.height;
|
|
|
|
|
|
fwrite(&dummymip, 1, sizeof(dummymip), f);
|
|
outmip=mip;
|
|
for (outmip=mip, y = 0; y < height; y+=yi)
|
|
for (x = 0; x < width; x+=xi)
|
|
{
|
|
*outmip++ = GetPalette( data[(int)(x+y*width)*4+0],
|
|
data[(int)(x+y*width)*4+1],
|
|
data[(int)(x+y*width)*4+2]);
|
|
}
|
|
fwrite(mip, dummymip.width, dummymip.height, f);
|
|
for (outmip=mip, y = 0; y < height; y+=yi*2)
|
|
for (x = 0; x < width; x+=xi*2)
|
|
{
|
|
*outmip++ = GetPalette( data[(int)(x+y*width)*4+0],
|
|
data[(int)(x+y*width)*4+1],
|
|
data[(int)(x+y*width)*4+2]);
|
|
}
|
|
fwrite(mip, dummymip.width/2, dummymip.height/2, f);
|
|
for (outmip=mip, y = 0; y < height; y+=yi*4)
|
|
for (x = 0; x < width; x+=xi*4)
|
|
{
|
|
*outmip++ = GetPalette( data[(int)(x+y*width)*4+0],
|
|
data[(int)(x+y*width)*4+1],
|
|
data[(int)(x+y*width)*4+2]);
|
|
}
|
|
fwrite(mip, dummymip.width/4, dummymip.height/4, f);
|
|
for (outmip=mip, y = 0; y < height; y+=yi*8)
|
|
for (x = 0; x < width; x+=xi*8)
|
|
{
|
|
*outmip++ = GetPalette( data[(int)(x+y*width)*4+0],
|
|
data[(int)(x+y*width)*4+1],
|
|
data[(int)(x+y*width)*4+2]);
|
|
}
|
|
fwrite(mip, dummymip.width/8, dummymip.height/8, f);
|
|
|
|
BZ_Free(data);
|
|
}
|
|
entries++;
|
|
Con_Printf("Added %s\n", base);
|
|
GLSCR_UpdateScreen();
|
|
}
|
|
|
|
wad2.offset = ftell(f);
|
|
wad2.num = entries;
|
|
fwrite(entry, entries, sizeof(wad2entry_t), f);
|
|
fseek(f, 0, SEEK_SET);
|
|
fwrite(&wad2, 1, sizeof(wad2_t), f);
|
|
fclose(f);
|
|
|
|
|
|
BZ_Free(mip);
|
|
// BZ_Free(initbuf);
|
|
BZ_Free(stack);
|
|
|
|
Con_Printf("Written %i mips to textures.wad\n", entries);
|
|
}
|
|
*/
|
|
void GLR_TimeRefresh_f (void);
|
|
|
|
extern cvar_t gl_bump;
|
|
extern cvar_t r_stains, r_stainfadetime, r_stainfadeammount;
|
|
|
|
void GLR_DeInit (void)
|
|
{
|
|
Cmd_RemoveCommand ("timerefresh");
|
|
Cmd_RemoveCommand ("envmap");
|
|
Cmd_RemoveCommand ("pointfile");
|
|
|
|
Cmd_RemoveCommand ("makewad");
|
|
|
|
GLDraw_DeInit();
|
|
|
|
GLSurf_DeInit();
|
|
}
|
|
|
|
void GLR_Init (void)
|
|
{
|
|
Cmd_AddRemCommand ("timerefresh", GLR_TimeRefresh_f);
|
|
Cmd_AddRemCommand ("envmap", R_Envmap_f);
|
|
|
|
// Cmd_AddRemCommand ("makewad", R_MakeTexWad_f);
|
|
|
|
R_InitBubble();
|
|
|
|
GLR_ReInit();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
R_TranslatePlayerSkin
|
|
|
|
Translates a skin texture by the per-player color lookup
|
|
===============
|
|
*/
|
|
/*
|
|
void R_TranslatePlayerSkin (int playernum)
|
|
{
|
|
int top, bottom;
|
|
qbyte translate[256];
|
|
unsigned translate32[256];
|
|
int i, j;
|
|
qbyte *original;
|
|
unsigned pixels[512*256], *out;
|
|
unsigned scaled_width, scaled_height;
|
|
int inwidth, inheight;
|
|
int tinwidth, tinheight;
|
|
qbyte *inrow;
|
|
unsigned frac, fracstep;
|
|
player_info_t *player;
|
|
extern qbyte *player_8bit_texels;
|
|
char s[512];
|
|
|
|
GL_DisableMultitexture();
|
|
|
|
player = &cl.players[playernum];
|
|
if (!player->name[0])
|
|
return;
|
|
|
|
strcpy(s, Info_ValueForKey(player->userinfo, "skin"));
|
|
COM_StripExtension(s, s);
|
|
if (player->skin && !stricmp(s, player->skin->name))
|
|
player->skin = NULL;
|
|
|
|
if (player->_topcolor != player->topcolor ||
|
|
player->_bottomcolor != player->bottomcolor || !player->skin) {
|
|
player->_topcolor = player->topcolor;
|
|
player->_bottomcolor = player->bottomcolor;
|
|
|
|
top = player->topcolor;
|
|
bottom = player->bottomcolor;
|
|
top = (top < 0) ? 0 : ((top > 13) ? 13 : top);
|
|
bottom = (bottom < 0) ? 0 : ((bottom > 13) ? 13 : bottom);
|
|
top *= 16;
|
|
bottom *= 16;
|
|
|
|
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
|
|
//
|
|
// real model width
|
|
tinwidth = 296;
|
|
tinheight = 194;
|
|
|
|
if (!player->skin)
|
|
Skin_Find(player);
|
|
if ((original = Skin_Cache8(player->skin)) != NULL) {
|
|
//skin data width
|
|
inwidth = player->skin->width;
|
|
inheight = player->skin->height;
|
|
} else {
|
|
original = player_8bit_texels;
|
|
inwidth = 296;
|
|
inheight = 194;
|
|
}
|
|
//tinwidth = 251&~3;
|
|
//tinheight = 194&~3;
|
|
//tinwidth = 319&~3;
|
|
//tinheight = 199&~3;
|
|
|
|
if (!original) //can't.
|
|
return;
|
|
|
|
|
|
// because this happens during gameplay, do it fast
|
|
// instead of sending it through gl_upload 8
|
|
GL_Bind(playertextures + playernum);
|
|
|
|
#if 0
|
|
s = 320*200;
|
|
qbyte 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);
|
|
#endif
|
|
|
|
scaled_width = gl_max_size.value < 512 ? gl_max_size.value : 512;
|
|
scaled_height = 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;
|
|
|
|
if (scaled_width < 8)
|
|
scaled_width = 8;
|
|
if (scaled_height < 8)
|
|
scaled_height = 8;
|
|
#ifdef GL_USE8BITTEX
|
|
#ifdef GL_EXT_paletted_texture
|
|
if (GLVID_Is8bit())
|
|
{// 8bit texture upload
|
|
qbyte *out2;
|
|
|
|
out2 = (qbyte *)pixels;
|
|
memset(pixels, 0, sizeof(pixels));
|
|
fracstep = tinwidth*0x10000/scaled_width;
|
|
for (i=0 ; i<scaled_height ; i++, out2 += scaled_width)
|
|
{
|
|
inrow = original + inwidth*(i*tinheight/scaled_height);
|
|
frac = fracstep >> 1;
|
|
for (j=0 ; j<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 ((qbyte *)pixels, scaled_width, scaled_height, false, false);
|
|
return;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef Q2BSP
|
|
if (cls.q2server)
|
|
{
|
|
extern unsigned char d_q28to24table[768];
|
|
for (i=0 ; i<256 ; i++)
|
|
{
|
|
translate32[i] = d_q28to24table[i*3] |
|
|
(d_q28to24table[i*3+1]<<8) |
|
|
(d_q28to24table[i*3+2]<<16) |
|
|
255<<24;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
for (i=0 ; i<256 ; i++)
|
|
translate32[i] = d_8to24rgbtable[translate[i]];
|
|
|
|
out = pixels;
|
|
memset(pixels, 0, sizeof(pixels));
|
|
fracstep = tinwidth*0x10000/scaled_width;
|
|
for (i=0 ; i<scaled_height ; i++, out += scaled_width)
|
|
{
|
|
inrow = original + inwidth*(i*tinheight/scaled_height);
|
|
frac = fracstep >> 1;
|
|
for (j=0 ; j<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;
|
|
}
|
|
}
|
|
|
|
glTexImage2D (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);
|
|
}
|
|
}
|
|
*/
|
|
|
|
|
|
void R_LoadRTLights(void)
|
|
{
|
|
dlight_t *dl;
|
|
char fname[MAX_QPATH];
|
|
char *file;
|
|
char *end;
|
|
int i;
|
|
int style;
|
|
|
|
vec3_t org;
|
|
float radius;
|
|
vec3_t rgb;
|
|
|
|
for (i=0 ; i<MAX_DLIGHTS ; i++)
|
|
{
|
|
cl_dlights[i].radius = 0;
|
|
}
|
|
|
|
COM_StripExtension(cl.worldmodel->name, fname);
|
|
strncat(fname, ".rtlights", MAX_QPATH-1);
|
|
|
|
file = COM_LoadTempFile(fname);
|
|
if (!file)
|
|
return;
|
|
while(1)
|
|
{
|
|
end = strchr(file, '\n');
|
|
if (!end)
|
|
end = file + strlen(file);
|
|
if (end == file)
|
|
break;
|
|
*end = '\0';
|
|
|
|
file = COM_Parse(file);
|
|
org[0] = atof(com_token);
|
|
file = COM_Parse(file);
|
|
org[1] = atof(com_token);
|
|
file = COM_Parse(file);
|
|
org[2] = atof(com_token);
|
|
|
|
file = COM_Parse(file);
|
|
radius = atof(com_token);
|
|
|
|
file = COM_Parse(file);
|
|
rgb[0] = atof(com_token);
|
|
file = COM_Parse(file);
|
|
rgb[1] = atof(com_token);
|
|
file = COM_Parse(file);
|
|
rgb[2] = atof(com_token);
|
|
|
|
file = COM_Parse(file);
|
|
style = atoi(com_token);
|
|
|
|
if (!file)
|
|
break;
|
|
|
|
dl = CL_AllocDlight(0);
|
|
VectorCopy(org, dl->origin);
|
|
dl->radius = radius;
|
|
VectorCopy(rgb, dl->color);
|
|
dl->die = cl.time + 0x7fffffff;
|
|
dl->isstatic = true;
|
|
|
|
dl->nodynamic = true;
|
|
dl->noflash = true;
|
|
|
|
dl->style = style+1;
|
|
|
|
file = end+1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
R_NewMap
|
|
===============
|
|
*/
|
|
void GLR_NewMap (void)
|
|
{
|
|
extern cvar_t host_mapname;
|
|
int i;
|
|
/*
|
|
if (cl.worldmodel->fromgame == fg_quake3 && cls.netchan.remote_address.type != NA_LOOPBACK)
|
|
{
|
|
if (!cls.allow_cheats)
|
|
{
|
|
CL_Disconnect();
|
|
Host_EndGame("\n\nThe quake3 map implementation is still experimental and contains many bugs that could be considered cheats. Therefore, the engine is handicapped to quake3 maps only when hosting - it's single player only.\n\nYou can allow it on the server by activating cheats, at which point this check will be ignored\n");
|
|
return;
|
|
}
|
|
// Cbuf_AddText("disconnect\n", RESTRICT_LOCAL);
|
|
}
|
|
*/
|
|
|
|
for (i=0 ; i<256 ; i++)
|
|
d_lightstylevalue[i] = 264; // normal light value
|
|
|
|
memset (&r_worldentity, 0, sizeof(r_worldentity));
|
|
AngleVectors(r_worldentity.angles, r_worldentity.axis[0], r_worldentity.axis[1], r_worldentity.axis[2]);
|
|
VectorInverse(r_worldentity.axis[1]);
|
|
r_worldentity.model = cl.worldmodel;
|
|
|
|
Cvar_Set(&host_mapname, cl.worldmodel->name);
|
|
|
|
// 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_viewcluster = -1;
|
|
r_oldviewcluster = 0;
|
|
r_viewcluster2 = -1;
|
|
TRACE(("dbg: GLR_NewMap: clear particles\n"));
|
|
P_ClearParticles ();
|
|
TRACE(("dbg: GLR_NewMap: wiping them stains (getting the cloth out)\n"));
|
|
GLR_WipeStains();
|
|
TRACE(("dbg: GLR_NewMap: building lightmaps\n"));
|
|
GL_BuildLightmaps ();
|
|
TRACE(("dbg: GLR_NewMap: figuring out skys and mirrors\n"));
|
|
// identify sky texture
|
|
if (cl.worldmodel->fromgame != fg_quake2 && cl.worldmodel->fromgame != fg_quake3)
|
|
{
|
|
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;
|
|
}
|
|
TRACE(("dbg: GLR_NewMap: that skybox thang\n"));
|
|
//#ifdef QUAKE2
|
|
R_LoadSkys ();
|
|
//#endif
|
|
TRACE(("dbg: GLR_NewMap: ui\n"));
|
|
UI_Reset();
|
|
TRACE(("dbg: GLR_NewMap: tp\n"));
|
|
TP_NewMap();
|
|
|
|
|
|
if (r_shadows.value)
|
|
{
|
|
R_LoadRTLights();
|
|
}
|
|
}
|
|
|
|
void GLR_PreNewMap(void)
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
====================
|
|
R_TimeRefresh_f
|
|
|
|
For program optimization
|
|
====================
|
|
*/
|
|
void GLR_TimeRefresh_f (void)
|
|
{
|
|
int i;
|
|
float start, stop, time;
|
|
|
|
qglDrawBuffer (GL_FRONT);
|
|
qglFinish ();
|
|
|
|
start = Sys_DoubleTime ();
|
|
for (i=0 ; i<128 ; i++)
|
|
{
|
|
r_refdef.viewangles[1] = i/128.0*360.0;
|
|
R_RenderView ();
|
|
}
|
|
|
|
qglFinish ();
|
|
stop = Sys_DoubleTime ();
|
|
time = stop-start;
|
|
Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
|
|
|
|
qglDrawBuffer (GL_BACK);
|
|
GL_EndRendering ();
|
|
GL_DoSwap();
|
|
}
|
|
|
|
#ifndef SWQUAKE
|
|
void D_FlushCaches (void)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
#endif
|