ew-engine/hq engine src/gl_env.c
2006-10-08 00:00:00 +00:00

616 lines
16 KiB
C

#include "quakedef.h"
#ifndef gl_mtextype
#define gl_mtextype GL_TEXTURE0_SGIS
#endif
/* SGIS_multitexture */
#define GL_SELECTED_TEXTURE_SGIS 0x835C
#define GL_MAX_TEXTURES_SGIS 0x835D
#define GL_TEXTURE0_SGIS 0x835E
#define GL_TEXTURE1_SGIS 0x835F
#define GL_TEXTURE2_SGIS 0x8360
#define GL_TEXTURE3_SGIS 0x8361
#define XMAX 514
#define YMAX XMAX
#define SYZE (YMAX*XMAX)
typedef struct env_s
{
char filename[MAX_QPATH]; //file path
vec3_t mins, maxs;
int width, height; //Number of x/y coords
byte heightdata[SYZE]; //The actual coordinates.
vec3_t rotation, origin, scale;
float texres, detailtexres;
int texture, detailtexture;
float waterheight, wavesize, waveheight; //At wat height should the (sine-wave) water be based, how broad should the waves be, and how big should they be?
float watertexres, waterdetailtexres;
int watertexture, waterdetailtexture; //Water textures
int numneighbours;
struct env_s *neighbours[1]; //neighbouring terrains
} env_t;
void ENV_Init(void);
void ENV_Load(model_t *mod, byte *buf);
void ENV_ClipMoveToEntity(edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *trace);
void ENV_CheckWater(edict_t *ent);
void ENV_SetContentsColor(vec3_t origin);
void ENV_DrawScene(void);
typedef struct
{
vec3_t rotation, origin;
vec3_t scale;
float terraintexres, terraindetailtexres;
float watertexres, waterdetailtexres;
float waterheight;
char heightmaptexture[32];
char terraintexture[32];
char terraindetailtexture[32];
char watertexture[32];
char waterdetailtexture[32];
int numneighbours;
} env0area_t;
//extern qboolean texcombineable;
cvar_t env_dist = {"env_dist", "8", true};
cvar_t env_detaildist = {"env_detaildist", "1", true};
cvar_t env_z = {"env_z", "-4096", true};
cvar_t env_x = {"env_x", "-4096", true};
cvar_t env_y = {"env_y", "-500", true};
cvar_t env_sx = {"env_sx", "20", true};
cvar_t env_sy = {"env_sy", "20", true};
cvar_t env_sz = {"env_sz", "4", true};
cvar_t env_sdetail = {"env_sdetail", "40", true};
cvar_t env_stex = {"env_stex", "1", true};
env_t terrain;
void R_SetEnvTerrain (char *name)
{
strcpy(terrain.filename, name);
ENV_Load(cl.worldmodel, COM_LoadTempFile(terrain.filename));//Tei: Load the env
}
void LoadEnv_f (void)
{
// int k;//,j,len;
switch (Cmd_Argc())
{
case 1:
if (terrain.filename[0])
Con_Printf("Current env: %s\n", terrain.filename);
else
Con_Printf("Error: No env has been set\n");
break;
case 2:
R_SetEnvTerrain(Cmd_Argv(1));
/*
for (j=0;j<XMAX;j++)
{
for (k=0;k<XMAX;k++) Con_Printf("%d ",terrain.heightdata[j+k*XMAX]);
Con_Printf("\n");
}
len = COM_OpenFile (Cmd_Argv(1), &j);
Con_Printf("len %d\n", len);
if(j)
close(j);*/
break;
default:
Con_Printf("Usage: loadenv envname\n");
break;
}
}
void ENV_Init(void)
{
//CVar initalisations and such
Cvar_RegisterVariable(&env_dist);
Cvar_RegisterVariable(&env_detaildist);
Cvar_RegisterVariable(&env_x);
Cvar_RegisterVariable(&env_y);
Cvar_RegisterVariable(&env_z);
Cvar_RegisterVariable(&env_sx);
Cvar_RegisterVariable(&env_sy);
Cvar_RegisterVariable(&env_sz);
Cvar_RegisterVariable(&env_sdetail);
Cvar_RegisterVariable(&env_stex);
Cmd_AddCommand ("loadenv",LoadEnv_f);
}
void ENV_LoadENV(model_t *mod, byte *buf)
{
// int j,k;
if(!buf)
return;
//Init
VectorCopy(vec3_origin, terrain.rotation);
VectorCopy(vec3_origin, terrain.origin);
terrain.width = XMAX;
terrain.height = YMAX;
terrain.texture = loadtextureimage("terra/terra1.tga", true,true);
terrain.detailtexture = loadtextureimage( "terra/Detail.tga", true,true);
//terrain.watertexture = loadtextureimage( "terra/water.jpg", true,true);
//terrain.waterdetailtexture = loadtextureimage( "terra/cubemap.tga", true,true);
terrain.texres = 128;//area->terraintexres;
terrain.detailtexres = 16;//area->terraindetailtexres/10;
terrain.watertexres = 8;//area->watertexres/80;
terrain.waterdetailtexres = 8;// area->waterdetailtexres/20;
terrain.waterheight = 25;//65//area->waterheight;
terrain.scale[0] = 256.0f;
terrain.scale[1] = 256.0f;
terrain.scale[2] = 4;//3.0f
//terrain.origin[0] = terrain.width * terrain.scale[0] * 0.5 * (-1) ;
//terrain.origin[1] = terrain.height * terrain.scale[1] * 0.5 * (-1) ;
VectorCopy(vec3_origin, terrain.mins);
terrain.maxs[0] = terrain.origin[0] + terrain.scale[0] * terrain.width;
terrain.maxs[1] = terrain.origin[1] + terrain.scale[1] * terrain.height;
terrain.maxs[2] = terrain.origin[2] + terrain.scale[2] * 256;
/*
for (j=0;j<XMAX;j++)
{
for (k=0;k<XMAX;k++) Con_Printf("%d ",buf[j+k*XMAX]);
Con_Printf("|\n");
}
*/
//Con_Printf("size: %d\n",SYZE);
//strncpy(terrain.heightdata,buf,SYZE);
memcpy(terrain.heightdata,buf,SYZE);
mod->environment = &terrain;
}
void ENV_Load(model_t *mod, byte *buf)
{
if(!buf)
{
Con_Printf("----- NO buff -----\n");
return;
}
ENV_LoadENV(mod, buf);
Con_Printf("----- ENV Environment loaded -----\n");
}
void ENV_ClipMoveToEntity(edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *trace)
{
env_t *env;
int pos[3], pos2[3];
int i;
int offset = 42;
if(!sv.worldmodel->environment)
return;
env = sv.worldmodel->environment;
for(i = 0; i < 3; i++)
pos[i] = (trace->endpos[i] - env->origin[i]-mins[i])/env->scale[i];
for(i = 0; i < 3; i++)
pos2[i] = (start[i] - env->origin[i]-mins[i])/env->scale[i];
if(pos[0] < 0 || pos[0] > env->width ||
pos[1] < 0 || pos[1] > env->height)
return;
trace->allsolid = false;
if(pos2[2] < env->heightdata[pos[0] * env->height + pos[1]]+offset)
{
trace->startsolid = true;
trace->allsolid = true;
}
if(pos[2] < env->heightdata[pos[0] * env->height + pos[1]]+offset)
{
trace->endpos[2] = (env->heightdata[pos[0] * env->height + pos[1]] + env->origin[2] + offset)*env->scale[2];
trace->fraction *= abs(start[2] - end[2]) * 1.0f / abs(start[2] - trace->endpos[2]);
trace->plane.normal[0] = 0;
trace->plane.normal[1] = 0;
trace->plane.normal[2] = 1;
}
else
trace->allsolid = false;
}
void ENV_CheckWater(edict_t *ent)
{
}
void ENV_SetContentsColor(vec3_t origin)
{
}
#if 0
extern int gl_mtexable;
void ENV_DrawPart(env_t *env, int xMin, int xMax, int yMin, int yMax, int stepsize)
{
int x, y, dx, dy;
float tex_x, tex_y;
float tex_dx, tex_dy;
float detailtex_x, detailtex_y;
float detailtex_dx, detailtex_dy;
int heightstep, usedetail;
byte *height;
#define lstep(a) {x = a%stepsize; if(x){a+=x;}else{a+=stepsize;}}
#define hstep(a) {x = a%stepsize; if(x){a-=x;}else{a-=stepsize;}}
lstep(xMin);
hstep(xMax);
lstep(yMin);
hstep(yMax);
dx = (xMax - xMin);
dy = (yMax - yMin);
if(dx <= 0 || dy <= 0)
return;
usedetail = true; //(gl_mtexable && (env_detaildist.value >= stepsize));
heightstep = env->height * stepsize;
height = env->heightdata + xMin*env->height;
//Terrain
tex_x = env->texres / env->width * xMin;
tex_dx = env->texres / env->width * stepsize;
tex_dy = env->texres / env->height * stepsize;
detailtex_x = xMin * env->detailtexres;
detailtex_dx = env->detailtexres * stepsize;
detailtex_dy = env->detailtexres * stepsize;
#define GL_ADD_SIGNED_EXT 0x8574
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD_SIGNED_EXT);
qglSelectTextureSGIS_ARB(TEXTURE0_SGIS_ARB);
glBindTexture (GL_TEXTURE_2D,env->texture);
qglSelectTextureSGIS_ARB(TEXTURE1_SGIS_ARB);//emulated enable multitexture
glBindTexture (GL_TEXTURE_2D,env->detailtexture);
for(x = xMin; x < xMax-stepsize; x+=stepsize, tex_x += tex_dx, detailtex_x += detailtex_dx, height+=heightstep)
{
tex_y = env->texres / env->height * yMin;
detailtex_y = yMin * env->detailtexres;
glBegin(GL_TRIANGLE_STRIP);
for(y = yMin; y < yMax; y+=stepsize, tex_y += tex_dy, detailtex_y += detailtex_dy)
{
qglMTexCoord2fSGIS_ARB(TEXTURE0_SGIS_ARB, tex_y, tex_x+tex_dx);
qglMTexCoord2fSGIS_ARB(TEXTURE1_SGIS_ARB, detailtex_y, (detailtex_x+detailtex_dx));
glVertex3f(x+stepsize, y, height[y+heightstep]);
qglMTexCoord2fSGIS_ARB(TEXTURE0_SGIS_ARB, tex_y, tex_x);
qglMTexCoord2fSGIS_ARB(TEXTURE1_SGIS_ARB, detailtex_y, detailtex_x);
glVertex3f(x, y, height[y]);
}
glEnd();
}
// glDepthMask(FALSE);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
#else
void ENV_DrawPart(env_t *env, int xMin, int xMax, int yMin, int yMax, int stepsize)
{
int x, y, dx, dy;
float tex_x, tex_y;
float tex_dx, tex_dy;
// float detailtex_x, detailtex_y;
// float detailtex_dx, detailtex_dy;
int heightstep;//, usedetail;
byte *height;
int oldxMin,oldxMax,oldyMin,oldyMax;
oldxMin = xMin;
oldxMax = xMax;
oldyMax = yMax;
oldyMin = yMin;
#define lstep(a) {x = a%stepsize; if(x){a+=x;}else{a+=stepsize;}}
#define hstep(a) {x = a%stepsize; if(x){a-=x;}else{a-=stepsize;}}
lstep(xMin);
hstep(xMax);
lstep(yMin);
hstep(yMax);
dx = (xMax - xMin);
dy = (yMax - yMin);
if(dx <= 0 || dy <= 0)
return;
//heightstep =512 * stepsize;
heightstep = env->height * stepsize;
height = env->heightdata + xMin*env->height;
//Terrain
tex_x = env->texres / env->width * xMin;
tex_dx = env->texres / env->width * stepsize;
tex_dy = env->texres / env->height * stepsize;
//detailtex_x = xMin * env->detailtexres;
//detailtex_dx = env->detailtexres * stepsize;
//detailtex_dy = env->detailtexres * stepsize;
glBindTexture (GL_TEXTURE_2D,env->texture);
for(x = xMin; x < xMax-stepsize; x+=stepsize, tex_x += tex_dx, height+=heightstep)
{
tex_y = env->texres / env->height * yMin;
//detailtex_y = yMin * env->detailtexres;
glBegin(GL_TRIANGLE_STRIP);
for(y = yMin; y < yMax; y+=stepsize, tex_y += tex_dy)
{
// glColor3f(1,1,1);
/*
qglMTexCoord2fSGIS(gl_mtextype, tex_y, tex_x+tex_dx);
qglMTexCoord2fSGIS(gl_mtextype+1, detailtex_y, (detailtex_x+detailtex_dx));
glVertex3f(x+stepsize, y, height[y+heightstep]);
qglMTexCoord2fSGIS(gl_mtextype, tex_y, tex_x);
qglMTexCoord2fSGIS(gl_mtextype+1, detailtex_y, detailtex_x);
glVertex3f(x, y, height[y]);
*/
glTexCoord2f( tex_y, tex_x+tex_dx);
//glTexCoord2f( detailtex_y, (detailtex_x+detailtex_dx));
glVertex3f(x+stepsize, y, height[y+heightstep]);
glTexCoord2f( tex_y, tex_x);
//glTexCoord2f( detailtex_y, detailtex_x);
glVertex3f(x, y, height[y]);
}
glEnd();
}
//if (stepsize>1)
// return;
xMin = oldxMin ;
xMax = oldxMax ;
yMax = oldyMax ;
yMin = oldyMin ;
lstep(xMin);
hstep(xMax);
lstep(yMin);
hstep(yMax);
dx = (xMax - xMin);
dy = (yMax - yMin);
//heightstep =512 * stepsize;
heightstep =env->height * stepsize;
height = env->heightdata + xMin*env->height;
//Terrain
tex_x = env->detailtexres / env->width * xMin;
tex_dx = env->detailtexres / env->width * stepsize;
tex_dy = env->detailtexres / env->height * stepsize;
glColor4f (1,1,1,1);
glBindTexture (GL_TEXTURE_2D,env->detailtexture);
glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
for(x = xMin; x < xMax-stepsize; x+=stepsize, tex_x += tex_dx, height+=heightstep)
{
tex_y = env->detailtexres / env->height * yMin;
glBegin(GL_TRIANGLE_STRIP);
for(y = yMin; y < yMax; y+=stepsize, tex_y += tex_dy)
{
glTexCoord2f( tex_y, tex_x+tex_dx);
glVertex3f(x+stepsize, y, height[y+heightstep]);
glTexCoord2f( tex_y, tex_x);
glVertex3f(x, y, height[y]);
}
glEnd();
}
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f (1,1,1,1);
}
#endif
int ENV_Clamp(int x, int xclamp)
{
if(x < 0) x = 0;
if(x > xclamp) x = xclamp;
return x;
}
extern cvar_t r_cloudz,temp1;
void ENV_DrawScene(void)
{
env_t *env;
int i;
// int xMin, xMax, yMin, yMax;
// int dx, dy, dx2, dy2, dx3, dy3, dx4, dy4;
//double plane_eqn[4];
vec3_t origin, angles;
vec3_t originmid, originleft, originright;//Frustrum origins.
vec3_t forward, right, up;
if(!cl.worldmodel->environment)
return;
env = cl.worldmodel->environment;
env->origin[0] = env_x.value;
env->origin[1] = env_y.value;
env->origin[2] = env_z.value;
env->scale[0] = env_sx.value;
env->scale[1] = env_sy.value;
env->scale[2] = env_sz.value;
env->detailtexres = env_sdetail.value;
env->texres = env_stex.value;
/*
Basically, we get a rectangle that encompasses the visible area and use that to clamp
distance-based LOD rectangles. It is also clamped against the heightmap size.
Easy, but low processing cost and still a high level of clipped triangles.
*/
//get the frustrum rectangle : first calculate the origin and two points along the FOV triangle.
for(i = 0; i < 3; i++)
origin[i] = (r_refdef.vieworg[i] - env->origin[i])/env->scale[i];
VectorSubtract(r_refdef.viewangles, env->rotation, angles);
angles[PITCH] = 0;
AngleVectors(angles, forward, right, up);
if(forward[0])
origin[0] -= forward[0]/fabs(forward[0]);
if(forward[1])
origin[1] -= forward[1]/fabs(forward[1]);
VectorCopy(origin, originmid);
VectorMA(originmid, (env_dist.value), forward, originleft);
VectorMA(originleft, env_dist.value*r_refdef.fov_x/90.0f, right, originright);
VectorMA(originleft, -env_dist.value*r_refdef.fov_x/90.0f, right, originleft);
//then determine which points create the largest rectangle, and use that rectangle.
/*
xMin = (int)floor(min(min(originmid[0], originleft[0]), min(originmid[0], originright[0])));
xMax = (int)ceil(max(max(originmid[0], originleft[0]), max(originmid[0], originright[0])));
yMin = (int)floor(min(min(originmid[1], originleft[1]), min(originmid[1], originright[1])));
yMax = (int)ceil(max(max(originmid[1], originleft[1]), max(originmid[1], originright[1])));
*/
//get the LOD distances :
#define stepclamp(x, y) (x-(x%y))
/*
dx = stepclamp(32, 2);
dy = stepclamp(32, 2);
dx2 = stepclamp(64, 4);
dy2 = stepclamp(64, 4);
dx3 = stepclamp(128, 8);
dy3 = stepclamp(128, 8);
dx4 = stepclamp(256, 16);
dy4 = stepclamp(256, 16);
*/
//setup OpenGL
glPushMatrix();
glTranslatef(env->origin[0], env->origin[1], env->origin[2]);
glRotatef (env->rotation[1], 0, 0, 1);
glRotatef (env->rotation[0], 0, 1, 0);
glRotatef (env->rotation[2], 1, 0, 0);
glScalef(env->scale[0], env->scale[1], env->scale[2]);
glColor3f(1,1,1);
//This is where the view and LOD rects are clamped against each other.
//#define wl(d) ENV_Clamp(min(xMin, originmid[0]-d), env->width-1)
//#define wh(d) ENV_Clamp(max(xMax, originmid[0]+d), env->width-1)
//#define hl(d) ENV_Clamp(min(yMin, originmid[1]-d), env->height-1)
//#define hh(d) ENV_Clamp(max(yMax, origin[1]+d), env->height-1)
#define wl(d) ENV_Clamp(max(xMin, originmid[0]-d), env->width-1)
#define wh(d) ENV_Clamp(min(xMax, originmid[0]+d), env->width-1)
#define hl(d) ENV_Clamp(max(yMin, originmid[1]-d), env->height-1)
#define hh(d) ENV_Clamp(min(yMax, origin[1]+d), env->height-1)
/*
//LOD 1 : direct environment.
ENV_DrawPart(env, wl(dx), wh(dx), hl(dy), hh(dy), 1);//[-1, 1]x[-1, 1]
//LOD 4 : medium distance
ENV_DrawPart(env, wl(dx3), wl(dx2), hl(dy3), hh(dy2), 4);//[-3, -2]x[-3, 2]
ENV_DrawPart(env, wl(dx3), wh(dx2), hh(dy2), hh(dy3), 4);//[-3, 2]x[ 2, 3]
ENV_DrawPart(env, wh(dx2), wh(dx3), hl(dy2), hh(dy3), 4);//[ 2, 3]x[-2, 3]
ENV_DrawPart(env, wl(dx2), wh(dx3), hl(dy3), hl(dy2), 4);//[-2, 3]x[-3, -2]
//LOD 8 : long distance
ENV_DrawPart(env, wl(dx4), wl(dx3), hl(dy4), hh(dy3), 8);//[-2, -1]x[-2, 1]
ENV_DrawPart(env, wl(dx4), wh(dx3), hh(dy3), hh(dy4), 8);//[-2, 1]x[ 1, 2]
ENV_DrawPart(env, wh(dx3), wh(dx4), hl(dy3), hh(dy4), 8);//[ 1, 2]x[-1, 2]
ENV_DrawPart(env, wl(dx3), wh(dx4), hl(dy4), hl(dy3), 8);//[-1, 2]x[-2, -1]
//Total
//ENV_DrawPart(env, 0, 512, 0, 512, 16);//[-1, 1]x[-1, 1]
*/
//Custom draw
ENV_DrawPart(env, 0, env->width, 0, env->height, env_dist.value);//[-1, 1]x[-1, 1]
glPopMatrix();
}