📄 render.c
字号:
/* render.c, HAWK game engine
*
* Copyright 1997-1998 by Phil Frisbie, Jr.
* for Hawk Software
*
*/
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include <gl/gl.h>
#include "hawk.h"
#include "internal.h"
#include "load.h"
#include "particle.h"
#include "graphics.h"
#include "hardware.h"
#define MAX_TEXT_LINE_LENGTH 100
#define MAX_TEXT_LINES 50
#define NUMVERTEXNORMALS 162
float avertexnormals[NUMVERTEXNORMALS][3] = {
#include "anorms.h"
};
int surfdrawn;
int surfclipped;
int tridrawn;
char screen[MAX_TEXT_LINES][MAX_TEXT_LINE_LENGTH + 1];
static int maxlines = 0, maxchars = 0;
int fonttex = 0;
BOOL skytexture = FALSE; /* any sky textures? */
BOOL transtexture = FALSE; /* any translucent textures? */
BOOL warpedtexture = FALSE; /* any warped textures? */
int renGetAnimation(int texture, int ntextures)
{
int f;
if(ntextures < 8)
f = (Engine.gameframes / 30 ) % ntextures;
else
f = (((Engine.gameframes) >> 2) & ANIM_TEX_MASK);
return (f + texture);
}
void renDrawMessage(int size, int startX, int startY, char *string, ... )
{
va_list args;
char buf[256];
char *c;
float row, column;
static TPOINT p[4];
int incX, incY;
float incS, incT;
int i;
/* decode string */
va_start(args, string);
vsprintf(buf, string, args);
va_end(args);
/* initialize starting coordinate location */
incX = size;
incY = size * 2;
memset(&p, 0, sizeof(p));
p[3].v[X] = (float)startX;
p[3].v[Y] = (float)startY;
p[2].v[X] = (float)(startX+incX);
p[2].v[Y] = (float)startY ;
p[1].v[X] = (float)(startX+incX);
p[1].v[Y] = (float)(startY+incY) ;
p[0].v[X] = (float)startX;
p[0].v[Y] = (float)(startY+incY);
/* setup the graphics modes */
graphTexture(TRUE);
graphUseColor(255, 255, 255, 255);
graphBlend(FALSE);
if(0)
{
graphBlendFunc(G_ONE, G_ONE_MINUS_SRC_COLOR);
}
graphTextureFunc(G_MODULATE);
graphAlphaFunc(G_GREATER, 0.5f);
graphAlpha(TRUE);
graphUseTexture(fonttex);
/* traverse through each character */
c = buf;
incS = 8.0f/128.0f;
incT = 16.0f/128.0f;
while (*c)
{
/* render if not space */
if (*c != ' ')
{
int ch = *c - 32;
if((ch < 0)||(ch > 95))/* non-printable char */
goto nextchar;
/* calculate where character is within font */
row = ch/16;
column = ch - row*16;
p[0].t[S] = incS * column;
p[0].t[T] = 1.0f - incT * row;
p[1].t[S] = p[0].t[S] + incS;
p[1].t[T] = p[0].t[T];
p[2].t[S] = p[0].t[S] + incS;
p[2].t[T] = p[0].t[T] - incT;
p[3].t[S] = p[0].t[S];
p[3].t[T] = p[0].t[T] - incT;
/* render character */
graphDraw(G_QUADS, &p[0], 0, 4);
}
/* next character */
nextchar:
c++;
for (i=0; i<4; i++)
p[i].v[X] += incX+1.0f;
}
}
void renScreenDisplay(void)
{
int i, x = 10, y = Engine.h;
char temp[MAX_TEXT_LINE_LENGTH + 1];
for(i=0;i<maxlines;i++)
{
strcpy(temp, screen[i]);
renDrawMessage(8, x, y, temp);
y -= 15;
}
}
void renTextPrint(char *str, ...)
{
char buffer[256];
va_list args;
int i, len;
static int line = 0;
if(!maxlines) /* configure first time through */
{
TEXTURE t;
t.type = IS_FONT;
fonttex = loadTexture("font.bmp", &t);
maxlines = Engine.h / 15;
if(maxlines > MAX_TEXT_LINES)
maxlines = MAX_TEXT_LINES;
maxchars = Engine.w / 10;
if(maxchars > MAX_TEXT_LINE_LENGTH)
maxchars = MAX_TEXT_LINE_LENGTH;
}
va_start(args, str);
vsprintf(buffer, str, args);
va_end(args);
logf(buffer);
len=(int)strlen(buffer);
if(++line==maxlines)
{
for(i=0;i<maxlines;i++)
memcpy(screen[i], screen[i+1], maxchars + 1);
line--;
}
if(len > maxchars + 1)
{
memcpy(screen[line], buffer, maxchars);
screen[line][maxchars + 1] = 0; /* terminate with null */
}
else
{
memcpy(screen[line], buffer, len + 1);
}
if(!Engine.running)
{
graphSetClearColor(0, 0, 0, 0);
graphClearBuffers(G_COLOR_BUFFER_BIT);
graphClearMatrix(MODEL_MATRIX|PROJECTION_MATRIX);
graphBegin2D();
renScreenDisplay();
swapBuffers();
}
}
void renTextClear(void)
{
memset(screen, 0, sizeof(screen));
}
void renLogo(void)
{
int h = Engine.h;
int w = Engine.w;
TPOINT p[4];
memset(&p, 0, sizeof(p));
p[0].v[X] = w - 80;
p[0].v[Y] = h - 30;
p[0].t[S] = 0;
p[0].t[T] = 0;
p[1].v[X] = w - 80;
p[1].v[Y] = h ;
p[1].t[S] = 0;
p[1].t[T] = 1;
p[2].v[X] = w;
p[2].v[Y] = h ;
p[2].t[S] = 1;
p[2].t[T] = 1;
p[3].v[X] = w;
p[3].v[Y] = h - 30;
p[3].t[S] = 1;
p[3].t[T] = 0;
graphTexture(TRUE);
graphUseColor(255, 255, 255, 255);
graphTextureFunc(G_MODULATE);
graphAlphaFunc(G_GREATER, 0.5f);
graphAlpha(TRUE);
graphUseTexture(Engine.logotex);
graphDraw(G_QUADS, &p[0], 0, 4);
graphAlpha(FALSE);
}
void renDrawSight(void)
{
int x = Engine.w / 2;
int y = Engine.h / 2;
int o = 4;
TPOINT p[8];
memset(&p, 0, sizeof(p));
p[0].v[X] = x;
p[0].v[Y] = y + o;
p[1].v[X] = x;
p[1].v[Y] = y + 2 * o ;
p[2].v[X] = x + o;
p[2].v[Y] = y ;
p[3].v[X] = x + 2 * o;
p[3].v[Y] = y;
p[4].v[X] = x;
p[4].v[Y] = y - o;
p[5].v[X] = x;
p[5].v[Y] = y - 2 * o;
p[6].v[X] = x - o;
p[6].v[Y] = y;
p[7].v[X] = x - 2 * o;
p[7].v[Y] = y;
graphTexture(FALSE);
graphUseColor(255, 255, 255, 255);
graphDraw(G_LINES, &p[0], 0, 8);
}
int cursorw[9][2] = {0,0,13,-4,4,-13,
8,-3,17,-12,12,-17,
12,-17,3,-8,8,-3};
int cursorb[9][2] = {1,-1,11,-4,4,-11,
8,-5,15,-12,12,-15,
12,-15,5,-8,8,-5};
void renDrawCursor(void)
{
int i, j = 0;
int x = Mouse.x;
int y = Engine.h - Mouse.y;
TPOINT p[3];
memset(&p, 0, sizeof(p));
graphTexture(FALSE);
graphUseColor(255, 255, 255, 255);
for(i=0;i<3;i++)
{
p[0].v[X] = x + cursorw[j][X];
p[0].v[Y] = y + cursorw[j++][Y];
p[1].v[X] = x + cursorw[j][X];
p[1].v[Y] = y + cursorw[j++][Y];
p[2].v[X] = x + cursorw[j][X];
p[2].v[Y] = y + cursorw[j++][Y];
graphDraw(G_TRIANGLES, &p[0], 0, 3);
}
j = 0;
graphUseColor(0, 0, 0, 0);
for(i=0;i<3;i++)
{
p[0].v[X] = x + cursorb[j][X];
p[0].v[Y] = y + cursorb[j++][Y];
p[1].v[X] = x + cursorb[j][X];
p[1].v[Y] = y + cursorb[j++][Y];
p[2].v[X] = x + cursorb[j][X];
p[2].v[Y] = y + cursorb[j++][Y];
graphDraw(G_TRIANGLES, &p[0], 0, 3);
}
}
BOOL renClipSky(int side, VIEW *view)
{
return FALSE;
}
#define NEAR_0 0.002f
#define NEAR_1 0.998f
TPOINT sky[] = {
{-100,-100,100, NEAR_1,NEAR_0}, /* front */
{-100,-100,-100, NEAR_1,NEAR_1},
{100,-100,-100, NEAR_0,NEAR_1},
{100,-100,100, NEAR_0,NEAR_0},
{100,-100,100, NEAR_1,NEAR_0}, /* right */
{100,-100,-100, NEAR_1,NEAR_1},
{100,100,-100, NEAR_0,NEAR_1},
{100,100,100, NEAR_0,NEAR_0},
{100,100,100, NEAR_1,NEAR_0}, /* back */
{100,100,-100, NEAR_1,NEAR_1},
{-100,100,-100, NEAR_0,NEAR_1},
{-100,100,100, NEAR_0,NEAR_0},
{-100,100,100, NEAR_1,NEAR_0}, /* left */
{-100,100,-100, NEAR_1,NEAR_1},
{-100,-100,-100, NEAR_0,NEAR_1},
{-100,-100,100, NEAR_0,NEAR_0},
{-100,-100,100, NEAR_1,NEAR_0}, /* up */
{100,-100,100, NEAR_1,NEAR_1},
{100,100,100, NEAR_0,NEAR_1},
{-100,100,100, NEAR_0,NEAR_0},
{100,-100,-100, NEAR_0,NEAR_0}, /* down */
{-100,-100,-100, NEAR_0,NEAR_1},
{-100,100,-100, NEAR_1,NEAR_1},
{100,100,-100, NEAR_1,NEAR_0}
};
void renDrawBackground(VIEW *view)
{
if(!skytexture)
return;
if(Level.background && Engine.texture)
{
int i;
TPOINT p[4];
graphBeginObject();
graphTranslate(view->cam[X], view->cam[Y], view->cam[Z]);
graphScale(20,20,20);
graphRotate(GLevel.skyangle, GLevel.skyaxis[X], GLevel.skyaxis[Y], GLevel.skyaxis[Z]);
graphDepthTest(FALSE);
graphTexture(TRUE);
for(i=0;i<6;i++)
{
if(!renClipSky(i, view))
{
memcpy(&p, &sky[i*4], sizeof(p));
graphUseTexture(Level.background + i);
graphDraw(G_QUADS, &p[0], 0, 4);
}
}
graphDepthTest(TRUE);
}
return;
}
BOOL renClipLeaf(dleaf_t *leaf, VIEW *view)
{
vec3_t v;
float d;
/* clip to the right view clipping plane */
v[X] = (float)(view->clipr[X] > 0) ? leaf->maxs[X] : leaf->mins[X];
v[Y] = (float)(view->clipr[Y] > 0) ? leaf->maxs[Y] : leaf->mins[Y];
v[Z] = (float)(view->clipr[Z] > 0) ? leaf->maxs[Z] : leaf->mins[Z];
VectorSubtract(v, view->cam, v);
d = DotProduct(v, view->clipr);
if(d < 0)
return TRUE;
/* clip to the left view clipping plane */
v[X] = (float)(view->clipl[X] > 0) ? leaf->maxs[X] : leaf->mins[X];
v[Y] = (float)(view->clipl[Y] > 0) ? leaf->maxs[Y] : leaf->mins[Y];
v[Z] = (float)(view->clipl[Z] > 0) ? leaf->maxs[Z] : leaf->mins[Z];
VectorSubtract(v, view->cam, v);
d = DotProduct(v, view->clipl);
if(d < 0)
return TRUE;
/* clip to the top view clipping plane */
v[X] = (float)(view->clipt[X] > 0) ? leaf->maxs[X] : leaf->mins[X];
v[Y] = (float)(view->clipt[Y] > 0) ? leaf->maxs[Y] : leaf->mins[Y];
v[Z] = (float)(view->clipt[Z] > 0) ? leaf->maxs[Z] : leaf->mins[Z];
VectorSubtract(v, view->cam, v);
d = DotProduct(v, view->clipt);
if(d < 0)
return TRUE;
/* clip to the bottom view clipping plane */
v[X] = (float)(view->clipb[X] > 0) ? leaf->maxs[X] : leaf->mins[X];
v[Y] = (float)(view->clipb[Y] > 0) ? leaf->maxs[Y] : leaf->mins[Y];
v[Z] = (float)(view->clipb[Z] > 0) ? leaf->maxs[Z] : leaf->mins[Z];
VectorSubtract(v, view->cam, v);
d = DotProduct(v, view->clipb);
return(d < 0);
}
void renCreateSurflist(VIEW *view)
{
int i, j;
int inleaf;
int numsurf = 0;
dleaf_t *leaf;
memset(Level.surflist, 0, Level.nsurf);
surfdrawn = surfclipped = tridrawn = 0;
inleaf = bspPointInLeafnum(view->cam);
leaf = &BSP.dleafs[inleaf];
if(pvs[inleaf])
{
for(i=1;i<BSP.numleafs;i++)
{
dleaf_t *visleaf = &BSP.dleafs[i];
int cluster = visleaf->cluster;
unsigned char *vis = pvs[inleaf];
if (cluster==-1)
continue;
if (!(vis[cluster>>3] & (1<<(cluster&7))))
continue; /* not in pvs */
if (!renClipLeaf(visleaf, view))
{
int first = visleaf->firstleafface;
int last = first + visleaf->numleaffaces;
for (j=first;j<last;++j)
{
int s = BSP.dleaffaces[j];
Level.surflist[s] = 1;
if(!Level.lighttex[s].number)
loadLightmap(s);
}
}
else
surfclipped += visleaf->numleaffaces;
}
}
else /* add every surface */
{
for(i=0;i<BSP.numleafs;i++)
{
dleaf_t *leaf = &BSP.dleafs[i];
if(!renClipLeaf(leaf, view))
{
int first = leaf->firstleafface;
int last = first + leaf->numleaffaces;
for(j=first; j<last;j++)
{
int s = BSP.dleaffaces[j];
Level.surflist[s] = 1;
if(!Level.lighttex[s].number)
loadLightmap(s);
}
}
else
surfclipped += leaf->numleaffaces;
}
}
}
void renDrawLightmaps(VIEW *view)
{
if(Engine.light) /* if lighting is enabled */
{
int i, lasttexture = 0;
BOOL multilights = FALSE; /* any polys have multiple lights? */
graphBeginObject();
graphBlend(TRUE);
graphBlendFunc(G_ONE_MINUS_SRC_ALPHA, G_SRC_ALPHA);
graphTexture(TRUE);
graphUseColor(255, 255, 255, 192);
graphTextureFunc(G_MODULATE);
for(i=0;i<Level.nsurf;i++)
{
if(Level.surflist[i])
{
SURFACE *surf = &Level.surf[i];
LIGHTMAP *lighttex = &Level.lighttex[i];
int first = surf->firstpoint;
int last = surf->firstpoint + surf->numpoints;
if(lighttex->number)
{
if(lighttex->number != lasttexture)
{
graphUseTexture(lighttex->number);
lasttexture = lighttex->number;
}
graphDrawLightmap(surf->mode, &Level.points[0], first, surf->numpoints);
}
}
}
graphBlend(TRUE);
}
}
void renDrawSurfaces(VIEW *view)
{
int i, lasttexture = 0;
skytexture = FALSE;
transtexture = FALSE;
warpedtexture = FALSE;
graphBeginObject();
graphBlend(FALSE);
graphTexture(TRUE);
graphUseColor(255, 255, 255, 255);
renCreateSurflist(view);
graphTextureFunc(G_MODULATE);
if(Engine.texture) /* if texturing is enabled */
{
for(i=0;i<Level.nsurf;i++) /* draw plain textures */
{
if(Level.surflist[i])
{
SURFACE *surf = &Level.surf[i];
int first = surf->firstpoint;
int last = surf->firstpoint + surf->numpoints;
int texture = surf->texture;
int ntextures = surf->ntextures;
if(ntextures)
texture = renGetAnimation(texture, ntextures);
if(texture)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -