📄 graphics.c
字号:
/* graphics.c, HAWK game engine
*
* This is the entry to the 3D specific routines.
*
* 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 "bmp.h"
#include "particle.h"
#include "graphics.h"
float modelmatrix[16];
GLubyte pointTex[] =
{
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, 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, 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, 64, 64, 64, 64, 128, 128, 128, 128, 128, 128, 128, 128, 64, 64, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 255, 255, 255, 255, 255, 255, 255, 255, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 255, 255, 255, 255, 255, 255, 255, 255, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 64, 64, 64, 64, 128, 128, 128, 128, 128, 128, 128, 128, 64, 64, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0};
/*
* Check name in the GL_EXTENSIONS string
*
* Returns TRUE if found
*/
BOOL checkEXT(char *name)
{
int len = strlen(name);
char *list = (char *)glGetString(GL_EXTENSIONS);
while(*list)
{
if(strncmp(list, name, len) == 0)
return TRUE;
while(*list && !isspace(*list))
++list;
while(*list && isspace(*list))
++list;
}
return FALSE;
}
#ifdef WIN32
static void (APIENTRY *glPointParameterfWIN)(GLenum pname, GLfloat param);
static void (APIENTRY *glPointParameterfvWIN)(GLenum pname, const GLfloat *params);
#endif
#ifndef GL_EXT_point_parameters
#define GL_POINT_SIZE_MIN_EXT 0x8126
#define GL_POINT_SIZE_MAX_EXT 0x8127
#define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128
#define GL_DISTANCE_ATTENUATION_EXT 0x8129
#endif
/*
* Main init code, must be called before any other graph* function
*
* Return TRUE when done, no failure at this time
*/
BOOL graphInit(void)
{
char *ext;
// GLfloat attenuation[3] = { 0.0f, 0.2f, 0.0f };
GLfloat attenuation[3] = { 0.0f, 0.2f, 0.0f };
/* init any arrays, vars, etc. */
Engine.GLvendor = (char *)glGetString(GL_VENDOR);
Engine.GLrenderer = (char *)glGetString(GL_RENDERER);
Engine.pointEXT = checkEXT("GL_EXT_point_parameters");
Engine.multitexEXT = checkEXT("GL_ARB_multitexture");
ext = (char *)glGetString(GL_EXTENSIONS);
logf("Extensions: %s\n", ext);
/* init OpenGL environment */
glDisable(GL_LIGHTING);
glDisable(GL_COLOR_MATERIAL);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDrawBuffer(GL_BACK);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glPointSize(16.0);
glEnable(GL_POINT_SMOOTH);
if(Engine.pointEXT)
{
#ifdef WIN32
glPointParameterfWIN = (void *)wglGetProcAddress("glPointParameterfEXT");
glPointParameterfvWIN = (void *)wglGetProcAddress("glPointParameterfvEXT");
if(!glPointParameterfWIN || !glPointParameterfvWIN)
{
Engine.pointEXT = FALSE;
Engine.pointtex = texBuildTex(RGBA_TEXTURE, 8, 8, pointTex);
}
else
{
glPointParameterfvWIN(GL_DISTANCE_ATTENUATION_EXT, attenuation);
// glPointParameterfWIN(GL_POINT_FADE_THRESHOLD_SIZE_EXT, 2.0);
// glPointParameterfWIN(GL_POINT_SIZE_MIN_EXT, 2.0);
}
#else
#ifdef GL_EXT_point_parameters
glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, linear);
glPointParameterfEXT(GL_POINT_FADE_THRESHOLD_SIZE_EXT, 1.0);
glPointParameterfEXT(GL_POINT_SIZE_MIN_EXT, 2.0);
#endif
#endif
}
else /* create point texture */
{
Engine.pointtex = texBuildTex(RGBA_TEXTURE, 8, 8, pointTex);
}
return TRUE;
}
/*
* called to shutdown graphics
*/
void graphStop(void)
{
}
/*
* Enable/disable Z-buffer
*/
void graphDepthTest(BOOL a)
{
if(a)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
}
/*
* Set the depth function
*/
void graphDepthFunc(int f)
{
glDepthFunc(f);
}
/*
* Enable/disable blending
*/
void graphBlend(BOOL a)
{
if(a)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
}
/*
* Set the blend function
*/
void graphBlendFunc(int s, int d)
{
glBlendFunc(s, d);
}
/*
* Enable/disable texturing
*/
void graphTexture(BOOL a)
{
if(a)
glEnable(GL_TEXTURE_2D);
else
glDisable(GL_TEXTURE_2D);
}
/*
* Set the texture function
*/
void graphTextureFunc(int f)
{
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, f);
}
/*
* Enable/disable texturing
*/
void graphAlpha(BOOL a)
{
if(a)
glEnable(GL_ALPHA_TEST);
else
glDisable(GL_ALPHA_TEST);
}
/*
* Set the alpha test function
*/
void graphAlphaFunc(int f, float v)
{
glAlphaFunc(f, v);
}
/*
* Returns the next texture number
*/
int graphNextTex(void)
{
static GLuint tex = 1;
/* glGenTextures(1, &tex); */
return tex++;
}
/*
* Use the tex texture
*/
void graphUseTexture(int tex)
{
glBindTexture(GL_TEXTURE_2D, tex);
}
/*
* Use color for blends
*/
void graphUseColor(unsigned char r, unsigned char g,
unsigned char b, unsigned char a)
{
glColor4ub(r, g, b, a);
}
/*
* Set the texture wrap mode
*/
void graphSetTexWrap(BOOL wrap)
{
if(wrap)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
}
}
/*
* Set the texture filtering mode. Called when loading textures.
*/
void graphSetTexFilter(BOOL mipmap)
{
if(mipmap)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
/*
* Returns the max texture size for the hardware
*/
int graphGetMaxTexSize(void)
{
int maxsize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
return maxsize;
}
/*
* Creates a texture
*/
void graphCreateTex(int level, int components, int w, int h, unsigned char *image)
{
glTexImage2D(GL_TEXTURE_2D, level, components, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
}
char basename[] = "hawkshot";
/*
* Dumps the front buffer to a 24 bit BMP file
*/
void graphCaptureScreen(void)
{
static int count = 0;
char file[1024];
int length;
int i, w, h;
char *buffer;
BMP_HEADER *bmp;
if(!count) /* init count to next free filename */
{
do
{
count++;
sprintf(file, "%s%d.bmp", basename, count);
}while(fileSize(file));
}
else
{
count++;
sprintf(file, "%s%d.bmp", basename, count);
}
w = Engine.w - Engine.w%4;
h = Engine.h;
length = w * h * 3;
buffer = TempMalloc(length + sizeof(BMP_HEADER) - 1);
bmp = (BMP_HEADER *)buffer;
bmp->type = 0x4D42; /* BM */
bmp->fsize = 54 + length;
bmp->reserved1 = 0;
bmp->reserved2 = 0;
bmp->offBits = 54;
bmp->hsize = 40;
bmp->width = w;
bmp->height = h;
bmp->planes = 1;
bmp->bitCount = 24;
bmp->compression = 0;
bmp->sizeImage = length;
bmp->XPelsPerMeter = 0;
bmp->YPelsPerMeter = 0;
bmp->ClrUsed = 0;
bmp->ClrImportant = 0;
glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, bmp->data);
for(i=0;i<length;i+=3) /* convert RGB to BGR Windows format */
{
unsigned char t = bmp->data[i];
bmp->data[i] = bmp->data[i+2];
bmp->data[i+2] = t;
}
length += sizeof(BMP_HEADER) - 1;
saveFile(file, length, buffer);
TempFree(buffer);
}
/*
* Sets up a perspective viewport
*/
void graphSetViewport(float angle, int x, int y, int w, int h)
{
float xmin, xmax, ymin, ymax, ratio,
zNear = 5.0, zFar = 5000.0;
ymax = zNear * tan(angle * (float)M_PI / 360.0);
ymin = -ymax;
if(w>h)
ratio = w / h;
else
ratio = h / w;
xmin = ymin * ratio;
xmax = ymax * ratio;
glViewport(x, y, w, h);
glMatrixMode(GL_PROJECTION);
glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
}
void graphLookAt(float eyex, float eyey, float eyez,
float centerx, float centery, float centerz,
float upx, float upy, float upz)
{
float m[16];
float x[3], y[3], z[3];
float mag;
glMatrixMode(GL_MODELVIEW);
/* Make rotation matrix */
/* Z vector */
z[0] = eyex - centerx;
z[1] = eyey - centery;
z[2] = eyez - centerz;
mag = sqrt( z[0]*z[0] + z[1]*z[1] + z[2]*z[2] );
if (mag)
{
z[0] /= mag;
z[1] /= mag;
z[2] /= mag;
}
/* Y vector */
y[0] = upx;
y[1] = upy;
y[2] = upz;
/* X vector = Y cross Z */
x[0] = y[1]*z[2] - y[2]*z[1];
x[1] = -y[0]*z[2] + y[2]*z[0];
x[2] = y[0]*z[1] - y[1]*z[0];
/* Recompute Y = Z cross X */
y[0] = z[1]*x[2] - z[2]*x[1];
y[1] = -z[0]*x[2] + z[2]*x[0];
y[2] = z[0]*x[1] - z[1]*x[0];
/* cross product gives area of parallelogram, which is < 1.0 for
* non-perpendicular unit-length vectors; so normalize x, y here
*/
mag = sqrt( x[0]*x[0] + x[1]*x[1] + x[2]*x[2] );
if (mag)
{
x[0] /= mag;
x[1] /= mag;
x[2] /= mag;
}
mag = sqrt( y[0]*y[0] + y[1]*y[1] + y[2]*y[2] );
if (mag)
{
y[0] /= mag;
y[1] /= mag;
y[2] /= mag;
}
#define M(row,col) m[col*4+row]
M(0,0) = x[0]; M(0,1) = x[1]; M(0,2) = x[2]; M(0,3) = 0.0;
M(1,0) = y[0]; M(1,1) = y[1]; M(1,2) = y[2]; M(1,3) = 0.0;
M(2,0) = z[0]; M(2,1) = z[1]; M(2,2) = z[2]; M(2,3) = 0.0;
M(3,0) = 0.0; M(3,1) = 0.0; M(3,2) = 0.0; M(3,3) = 1.0;
#undef M
glMultMatrixf(m);
glTranslatef(-eyex, -eyey, -eyez);
glGetFloatv(GL_MODELVIEW_MATRIX, modelmatrix);
}
void graphBegin2D(void)
{
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glViewport(0, 0, Engine.w, Engine.h);
glMatrixMode(GL_PROJECTION);
glOrtho(0.0, Engine.w, 0.0, Engine.h, -1.0, 1.0 );
glMatrixMode(GL_MODELVIEW);
}
/*
* Rotate an object
*/
void graphRotate(float angle, float x, float y, float z)
{
glMatrixMode(GL_MODELVIEW);
glRotatef(angle, x, y, z);
}
/*
* Scale an object
*/
void graphScale(float x, float y, float z)
{
glMatrixMode(GL_MODELVIEW);
glScalef(x, y, z);
}
/*
* Translate an object
*/
void graphTranslate(float x, float y, float z)
{
glMatrixMode(GL_MODELVIEW);
glTranslatef(x, y, z);
}
/*
* Generic draw function for most level surfaces
*/
void graphDraw(int mode, TPOINT *points, int start, int number)
{
int i;
TPOINT *p = &points[start];
glBegin(mode);
for(i=0;i<number;i++)
{
glTexCoord2fv(p[i].t);
glVertex3fv(p[i].v);
}
glEnd();
}
/*
* Special draw function for surface lightmaps
*/
void graphDrawLightmap(int mode, TPOINT *points, int start, int number)
{
int i;
TPOINT *p = &points[start];
glBegin(mode);
for(i=0;i<number;i++)
{
glTexCoord2fv(p[i].lm);
glVertex3fv(p[i].v);
}
glEnd();
}
/*
* Special draw function for particles
*/
void graphDrawParticles(void)
{
/* for now, just draw all particles in the level */
PARTICLE *p;
p = firstparticle;
glColor3f(1.0, 1.0, 1.0);
if(Engine.pointEXT)
{
vec_t lastsize = p->size;
glAlphaFunc(GL_GREATER, 0.5f);
glEnable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPointSize(lastsize);
glBegin(GL_POINTS);
do
{
if(lastsize != p->size)
{
glEnd();
lastsize = p->size;
glPointSize(lastsize);
glBegin(GL_POINTS);
}
glColor3fv(p->color);
glVertex3fv(p->center);
p = p->next;
}while(p);
glEnd();
glDisable(GL_ALPHA_TEST);
}
else
{
vec3_t tv, rv, lv, top;
vec_t angle = GLevel.view[0]->hangle + GLevel.view[0]->object->angles[Z] + 90.0;
vec_t pitch = GLevel.view[0]->object->pitch;
vec_t x, y, temp;
x = cos(RAD(angle));
y = sin(RAD(angle));
temp = cos(RAD(pitch + 90.0));
top[X] = y * temp;
top[Y] = x * temp;
top[Z] = sin(RAD(pitch + 90.0));
VectorNormalize(top, top);
x *= 0.5;
y *= 0.5;
/* setup to render the translucent particles */
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, Engine.pointtex);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glAlphaFunc(GL_GREATER, 0.5f);
glEnable(GL_ALPHA_TEST);
glBegin(GL_TRIANGLES);
do
{
vec_t size;
if(p->solid)
{
p = p->next;
continue;
}
size = p->size / 16;
glColor3fv(p->color);
VectorCopy(p->center, tv);
VectorCopy(tv, rv);
VectorCopy(tv, lv);
tv[X] += top[X] * size;
tv[Y] -= top[Y] * size;
tv[Z] += top[Z] * size;
rv[X] += x * size;
rv[Y] += y * size;
lv[X] -= x * size;
lv[Y] -= y * size;
glTexCoord2f(0.5, 0.2);
glVertex3fv(tv);
glTexCoord2f(0.0, 1.0);
glVertex3fv(lv);
glTexCoord2f(1.0, 1.0);
glVertex3fv(rv);
p = p->next;
}while(p);
glEnd();
/* setup to render solid particles */
glDisable(GL_BLEND);
p = firstparticle;
glBegin(GL_TRIANGLES);
do
{
vec_t size;
if(!p->solid)
{
p = p->next;
continue;
}
size = p->size / 16;
glColor3fv(p->color);
VectorCopy(p->center, tv);
VectorCopy(tv, rv);
VectorCopy(tv, lv);
tv[X] += top[X] * size;
tv[Y] -= top[Y] * size;
tv[Z] += top[Z] * size;
rv[X] += x * size;
rv[Y] += y * size;
lv[X] -= x * size;
lv[Y] -= y * size;
glTexCoord2f(0.5, 0.2);
glVertex3fv(tv);
glTexCoord2f(0.0, 1.0);
glVertex3fv(lv);
glTexCoord2f(1.0, 1.0);
glVertex3fv(rv);
p = p->next;
}while(p);
glEnd();
graphAlpha(FALSE);
}
}
void graphClearBuffers(int buffer)
{
glClear(buffer);
}
void graphSetClearColor(unsigned char r, unsigned char g,
unsigned char b, unsigned char a)
{
glClearColor(r, g, b, a);
}
void graphClearMatrix(int m)
{
if(m&MODEL_MATRIX)
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
if(m&PROJECTION_MATRIX)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
}
}
void graphBeginObject(void)
{
glLoadMatrixf(modelmatrix);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -