diff --git a/linux/q_shlinux.c b/linux/q_shlinux.c new file mode 100644 index 000000000..eeeef7253 --- /dev/null +++ b/linux/q_shlinux.c @@ -0,0 +1,205 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../linux/glob.h" + +#include "../qcommon/qcommon.h" + +//=============================================================================== + +byte *membase; +int maxhunksize; +int curhunksize; + +void *Hunk_Begin (int maxsize) +{ + // reserve a huge chunk of memory, but don't commit any yet + maxhunksize = maxsize + sizeof(int); + curhunksize = 0; + membase = mmap(0, maxhunksize, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (membase == NULL || membase == (byte *)-1) + Sys_Error("unable to virtual allocate %d bytes", maxsize); + + *((int *)membase) = curhunksize; + + return membase + sizeof(int); +} + +void *Hunk_Alloc (int size) +{ + byte *buf; + + // round to cacheline + size = (size+31)&~31; + if (curhunksize + size > maxhunksize) + Sys_Error("Hunk_Alloc overflow"); + buf = membase + sizeof(int) + curhunksize; + curhunksize += size; + return buf; +} + +int Hunk_End (void) +{ + byte *n; + + n = mremap(membase, maxhunksize, curhunksize + sizeof(int), 0); + if (n != membase) + Sys_Error("Hunk_End: Could not remap virtual block (%d)", errno); + *((int *)membase) = curhunksize + sizeof(int); + + return curhunksize; +} + +void Hunk_Free (void *base) +{ + byte *m; + + if (base) { + m = ((byte *)base) - sizeof(int); + if (munmap(m, *((int *)m))) + Sys_Error("Hunk_Free: munmap failed (%d)", errno); + } +} + +//=============================================================================== + + +/* +================ +Sys_Milliseconds +================ +*/ +int curtime; +int Sys_Milliseconds (void) +{ + struct timeval tp; + struct timezone tzp; + static int secbase; + + gettimeofday(&tp, &tzp); + + if (!secbase) + { + secbase = tp.tv_sec; + return tp.tv_usec/1000; + } + + curtime = (tp.tv_sec - secbase)*1000 + tp.tv_usec/1000; + + return curtime; +} + +void Sys_Mkdir (char *path) +{ + mkdir (path, 0777); +} + +char *strlwr (char *s) +{ + while (*s) { + *s = tolower(*s); + s++; + } +} + +//============================================ + +static char findbase[MAX_OSPATH]; +static char findpath[MAX_OSPATH]; +static char findpattern[MAX_OSPATH]; +static DIR *fdir; + +static qboolean CompareAttributes(char *path, char *name, + unsigned musthave, unsigned canthave ) +{ + struct stat st; + char fn[MAX_OSPATH]; + +// . and .. never match + if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) + return false; + + sprintf(fn, "%s/%s", path, name); + if (stat(fn, &st) == -1) + return false; // shouldn't happen + + if ( ( st.st_mode & S_IFDIR ) && ( canthave & SFF_SUBDIR ) ) + return false; + + if ( ( musthave & SFF_SUBDIR ) && !( st.st_mode & S_IFDIR ) ) + return false; + + return true; +} + +char *Sys_FindFirst (char *path, unsigned musthave, unsigned canhave) +{ + struct dirent *d; + char *p; + + if (fdir) + Sys_Error ("Sys_BeginFind without close"); + +// COM_FilePath (path, findbase); + strcpy(findbase, path); + + if ((p = strrchr(findbase, '/')) != NULL) { + *p = 0; + strcpy(findpattern, p + 1); + } else + strcpy(findpattern, "*"); + + if (strcmp(findpattern, "*.*") == 0) + strcpy(findpattern, "*"); + + if ((fdir = opendir(findbase)) == NULL) + return NULL; + while ((d = readdir(fdir)) != NULL) { + if (!*findpattern || glob_match(findpattern, d->d_name)) { +// if (*findpattern) +// printf("%s matched %s\n", findpattern, d->d_name); + if (CompareAttributes(findbase, d->d_name, musthave, canhave)) { + sprintf (findpath, "%s/%s", findbase, d->d_name); + return findpath; + } + } + } + return NULL; +} + +char *Sys_FindNext (unsigned musthave, unsigned canhave) +{ + struct dirent *d; + + if (fdir == NULL) + return NULL; + while ((d = readdir(fdir)) != NULL) { + if (!*findpattern || glob_match(findpattern, d->d_name)) { +// if (*findpattern) +// printf("%s matched %s\n", findpattern, d->d_name); + if (CompareAttributes(findbase, d->d_name, musthave, canhave)) { + sprintf (findpath, "%s/%s", findbase, d->d_name); + return findpath; + } + } + } + return NULL; +} + +void Sys_FindClose (void) +{ + if (fdir != NULL) + closedir(fdir); + fdir = NULL; +} + + +//============================================ + diff --git a/linux/qasm.h b/linux/qasm.h new file mode 100644 index 000000000..6931bd7ef --- /dev/null +++ b/linux/qasm.h @@ -0,0 +1,459 @@ +#ifndef __ASM_I386__ +#define __ASM_I386__ + +#ifdef ELF +#define C(label) label +#else +#define C(label) _##label +#endif + + +//#define GLQUAKE 1 + +#if defined(_WIN32) && !defined(WINDED) + +#if defined(_M_IX86) +#define __i386__ 1 +#endif + +#endif + +#ifdef __i386__ +#define id386 1 +#else +#define id386 0 +#endif + +// !!! must be kept the same as in d_iface.h !!! +#define TRANSPARENT_COLOR 255 + +#ifndef GLQUAKE + .extern C(d_zistepu) + .extern C(d_pzbuffer) + .extern C(d_zistepv) + .extern C(d_zrowbytes) + .extern C(d_ziorigin) + .extern C(r_turb_s) + .extern C(r_turb_t) + .extern C(r_turb_pdest) + .extern C(r_turb_spancount) + .extern C(r_turb_turb) + .extern C(r_turb_pbase) + .extern C(r_turb_sstep) + .extern C(r_turb_tstep) + .extern C(r_bmodelactive) + .extern C(d_sdivzstepu) + .extern C(d_tdivzstepu) + .extern C(d_sdivzstepv) + .extern C(d_tdivzstepv) + .extern C(d_sdivzorigin) + .extern C(d_tdivzorigin) + .extern C(sadjust) + .extern C(tadjust) + .extern C(bbextents) + .extern C(bbextentt) + .extern C(cacheblock) + .extern C(d_viewbuffer) + .extern C(cachewidth) + .extern C(d_pzbuffer) + .extern C(d_zrowbytes) + .extern C(d_zwidth) + .extern C(d_scantable) + .extern C(r_lightptr) + .extern C(r_numvblocks) + .extern C(prowdestbase) + .extern C(pbasesource) + .extern C(r_lightwidth) + .extern C(lightright) + .extern C(lightrightstep) + .extern C(lightdeltastep) + .extern C(lightdelta) + .extern C(lightright) + .extern C(lightdelta) + .extern C(sourcetstep) + .extern C(surfrowbytes) + .extern C(lightrightstep) + .extern C(lightdeltastep) + .extern C(r_sourcemax) + .extern C(r_stepback) + .extern C(colormap) + .extern C(blocksize) + .extern C(sourcesstep) + .extern C(lightleft) + .extern C(blockdivshift) + .extern C(blockdivmask) + .extern C(lightleftstep) + .extern C(r_origin) + .extern C(r_ppn) + .extern C(r_pup) + .extern C(r_pright) + .extern C(ycenter) + .extern C(xcenter) + .extern C(d_vrectbottom_particle) + .extern C(d_vrectright_particle) + .extern C(d_vrecty) + .extern C(d_vrectx) + .extern C(d_pix_shift) + .extern C(d_pix_min) + .extern C(d_pix_max) + .extern C(d_y_aspect_shift) + .extern C(screenwidth) + .extern C(r_leftclipped) + .extern C(r_leftenter) + .extern C(r_rightclipped) + .extern C(r_rightenter) + .extern C(modelorg) + .extern C(xscale) + .extern C(r_refdef) + .extern C(yscale) + .extern C(r_leftexit) + .extern C(r_rightexit) + .extern C(r_lastvertvalid) + .extern C(cacheoffset) + .extern C(newedges) + .extern C(removeedges) + .extern C(r_pedge) + .extern C(r_framecount) + .extern C(r_u1) + .extern C(r_emitted) + .extern C(edge_p) + .extern C(surface_p) + .extern C(surfaces) + .extern C(r_lzi1) + .extern C(r_v1) + .extern C(r_ceilv1) + .extern C(r_nearzi) + .extern C(r_nearzionly) + .extern C(edge_aftertail) + .extern C(edge_tail) + .extern C(current_iv) + .extern C(edge_head_u_shift20) + .extern C(span_p) + .extern C(edge_head) + .extern C(fv) + .extern C(edge_tail_u_shift20) + .extern C(r_apverts) + .extern C(r_anumverts) + .extern C(aliastransform) + .extern C(r_avertexnormals) + .extern C(r_plightvec) + .extern C(r_ambientlight) + .extern C(r_shadelight) + .extern C(aliasxcenter) + .extern C(aliasycenter) + .extern C(a_sstepxfrac) + .extern C(r_affinetridesc) + .extern C(acolormap) + .extern C(d_pcolormap) + .extern C(r_affinetridesc) + .extern C(d_sfrac) + .extern C(d_ptex) + .extern C(d_pedgespanpackage) + .extern C(d_tfrac) + .extern C(d_light) + .extern C(d_zi) + .extern C(d_pdest) + .extern C(d_pz) + .extern C(d_aspancount) + .extern C(erroradjustup) + .extern C(errorterm) + .extern C(d_xdenom) + .extern C(r_p0) + .extern C(r_p1) + .extern C(r_p2) + .extern C(a_tstepxfrac) + .extern C(r_sstepx) + .extern C(r_tstepx) + .extern C(a_ststepxwhole) + .extern C(zspantable) + .extern C(skintable) + .extern C(r_zistepx) + .extern C(erroradjustdown) + .extern C(d_countextrastep) + .extern C(ubasestep) + .extern C(a_ststepxwhole) + .extern C(a_tstepxfrac) + .extern C(r_lstepx) + .extern C(a_spans) + .extern C(erroradjustdown) + .extern C(d_pdestextrastep) + .extern C(d_pzextrastep) + .extern C(d_sfracextrastep) + .extern C(d_ptexextrastep) + .extern C(d_countextrastep) + .extern C(d_tfracextrastep) + .extern C(d_lightextrastep) + .extern C(d_ziextrastep) + .extern C(d_pdestbasestep) + .extern C(d_pzbasestep) + .extern C(d_sfracbasestep) + .extern C(d_ptexbasestep) + .extern C(ubasestep) + .extern C(d_tfracbasestep) + .extern C(d_lightbasestep) + .extern C(d_zibasestep) + .extern C(zspantable) + .extern C(r_lstepy) + .extern C(r_sstepy) + .extern C(r_tstepy) + .extern C(r_zistepy) + .extern C(D_PolysetSetEdgeTable) + .extern C(D_RasterizeAliasPolySmooth) + + .extern float_point5 + .extern Float2ToThe31nd + .extern izistep + .extern izi + .extern FloatMinus2ToThe31nd + .extern float_1 + .extern float_particle_z_clip + .extern float_minus_1 + .extern float_0 + .extern fp_16 + .extern fp_64k + .extern fp_1m + .extern fp_1m_minus_1 + .extern fp_8 + .extern entryvec_table + .extern advancetable + .extern sstep + .extern tstep + .extern pspantemp + .extern counttemp + .extern jumptemp + .extern reciprocal_table + .extern DP_Count + .extern DP_u + .extern DP_v + .extern DP_32768 + .extern DP_Color + .extern DP_Pix + .extern DP_EntryTable + .extern pbase + .extern s + .extern t + .extern sfracf + .extern tfracf + .extern snext + .extern tnext + .extern spancountminus1 + .extern zi16stepu + .extern sdivz16stepu + .extern tdivz16stepu + .extern zi8stepu + .extern sdivz8stepu + .extern tdivz8stepu + .extern reciprocal_table_16 + .extern entryvec_table_16 + .extern ceil_cw + .extern single_cw + .extern fp_64kx64k + .extern pz + .extern spr8entryvec_table +#endif + + .extern C(snd_scaletable) + .extern C(paintbuffer) + .extern C(snd_linear_count) + .extern C(snd_p) + .extern C(snd_vol) + .extern C(snd_out) + .extern C(vright) + .extern C(vup) + .extern C(vpn) + .extern C(BOPS_Error) + +// +// !!! note that this file must match the corresponding C structures at all +// times !!! +// + +// plane_t structure +// !!! if this is changed, it must be changed in model.h too !!! +// !!! if the size of this is changed, the array lookup in SV_HullPointContents +// must be changed too !!! +#define pl_normal 0 +#define pl_dist 12 +#define pl_type 16 +#define pl_signbits 17 +#define pl_pad 18 +#define pl_size 20 + +// hull_t structure +// !!! if this is changed, it must be changed in model.h too !!! +#define hu_clipnodes 0 +#define hu_planes 4 +#define hu_firstclipnode 8 +#define hu_lastclipnode 12 +#define hu_clip_mins 16 +#define hu_clip_maxs 28 +#define hu_size 40 + +// dnode_t structure +// !!! if this is changed, it must be changed in bspfile.h too !!! +#define nd_planenum 0 +#define nd_children 4 +#define nd_mins 8 +#define nd_maxs 20 +#define nd_firstface 32 +#define nd_numfaces 36 +#define nd_size 40 + +// sfxcache_t structure +// !!! if this is changed, it much be changed in sound.h too !!! +#define sfxc_length 0 +#define sfxc_loopstart 4 +#define sfxc_speed 8 +#define sfxc_width 12 +#define sfxc_stereo 16 +#define sfxc_data 20 + +// channel_t structure +// !!! if this is changed, it much be changed in sound.h too !!! +#define ch_sfx 0 +#define ch_leftvol 4 +#define ch_rightvol 8 +#define ch_end 12 +#define ch_pos 16 +#define ch_looping 20 +#define ch_entnum 24 +#define ch_entchannel 28 +#define ch_origin 32 +#define ch_dist_mult 44 +#define ch_master_vol 48 +#define ch_size 52 + +// portable_samplepair_t structure +// !!! if this is changed, it much be changed in sound.h too !!! +#define psp_left 0 +#define psp_right 4 +#define psp_size 8 + + +// +// !!! note that this file must match the corresponding C structures at all +// times !!! +// + +// !!! if this is changed, it must be changed in r_local.h too !!! +#define NEAR_CLIP 0.01 + +// !!! if this is changed, it must be changed in r_local.h too !!! +#define CYCLE 128 + +// espan_t structure +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define espan_t_u 0 +#define espan_t_v 4 +#define espan_t_count 8 +#define espan_t_pnext 12 +#define espan_t_size 16 + +// sspan_t structure +// !!! if this is changed, it must be changed in d_local.h too !!! +#define sspan_t_u 0 +#define sspan_t_v 4 +#define sspan_t_count 8 +#define sspan_t_size 12 + +// spanpackage_t structure +// !!! if this is changed, it must be changed in d_polyset.c too !!! +#define spanpackage_t_pdest 0 +#define spanpackage_t_pz 4 +#define spanpackage_t_count 8 +#define spanpackage_t_ptex 12 +#define spanpackage_t_sfrac 16 +#define spanpackage_t_tfrac 20 +#define spanpackage_t_light 24 +#define spanpackage_t_zi 28 +#define spanpackage_t_size 32 + +// edge_t structure +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define et_u 0 +#define et_u_step 4 +#define et_prev 8 +#define et_next 12 +#define et_surfs 16 +#define et_nextremove 20 +#define et_nearzi 24 +#define et_owner 28 +#define et_size 32 + +// surf_t structure +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define SURF_T_SHIFT 6 +#define st_next 0 +#define st_prev 4 +#define st_spans 8 +#define st_key 12 +#define st_last_u 16 +#define st_spanstate 20 +#define st_flags 24 +#define st_data 28 +#define st_entity 32 +#define st_nearzi 36 +#define st_insubmodel 40 +#define st_d_ziorigin 44 +#define st_d_zistepu 48 +#define st_d_zistepv 52 +#define st_pad 56 +#define st_size 64 + +// clipplane_t structure +// !!! if this is changed, it must be changed in r_local.h too !!! +#define cp_normal 0 +#define cp_dist 12 +#define cp_next 16 +#define cp_leftedge 20 +#define cp_rightedge 21 +#define cp_reserved 22 +#define cp_size 24 + +// medge_t structure +// !!! if this is changed, it must be changed in model.h too !!! +#define me_v 0 +#define me_cachededgeoffset 4 +#define me_size 8 + +// mvertex_t structure +// !!! if this is changed, it must be changed in model.h too !!! +#define mv_position 0 +#define mv_size 12 + +// refdef_t structure +// !!! if this is changed, it must be changed in render.h too !!! +#define rd_vrect 0 +#define rd_aliasvrect 20 +#define rd_vrectright 40 +#define rd_vrectbottom 44 +#define rd_aliasvrectright 48 +#define rd_aliasvrectbottom 52 +#define rd_vrectrightedge 56 +#define rd_fvrectx 60 +#define rd_fvrecty 64 +#define rd_fvrectx_adj 68 +#define rd_fvrecty_adj 72 +#define rd_vrect_x_adj_shift20 76 +#define rd_vrectright_adj_shift20 80 +#define rd_fvrectright_adj 84 +#define rd_fvrectbottom_adj 88 +#define rd_fvrectright 92 +#define rd_fvrectbottom 96 +#define rd_horizontalFieldOfView 100 +#define rd_xOrigin 104 +#define rd_yOrigin 108 +#define rd_vieworg 112 +#define rd_viewangles 124 +#define rd_ambientlight 136 +#define rd_size 140 + +// mtriangle_t structure +// !!! if this is changed, it must be changed in model.h too !!! +#define mtri_facesfront 0 +#define mtri_vertindex 4 +#define mtri_size 16 // !!! if this changes, array indexing in !!! + // !!! d_polysa.s must be changed to match !!! +#define mtri_shift 4 + +#endif diff --git a/linux/qgl_linux.c b/linux/qgl_linux.c new file mode 100644 index 000000000..d545632bf --- /dev/null +++ b/linux/qgl_linux.c @@ -0,0 +1,3994 @@ +/* +** QGL_WIN.C +** +** This file implements the operating system binding of GL to QGL function +** pointers. When doing a port of Quake2 you must implement the following +** two functions: +** +** QGL_Init() - loads libraries, assigns function pointers, etc. +** QGL_Shutdown() - unloads libraries, NULLs function pointers +*/ +#define QGL +#include "../ref_gl/gl_local.h" + +static FILE *log_fp = NULL; + +void ( APIENTRY * qglAccum )(GLenum op, GLfloat value); +void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref); +GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); +void ( APIENTRY * qglArrayElement )(GLint i); +void ( APIENTRY * qglBegin )(GLenum mode); +void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture); +void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor); +void ( APIENTRY * qglCallList )(GLuint list); +void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists); +void ( APIENTRY * qglClear )(GLbitfield mask); +void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +void ( APIENTRY * qglClearDepth )(GLclampd depth); +void ( APIENTRY * qglClearIndex )(GLfloat c); +void ( APIENTRY * qglClearStencil )(GLint s); +void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation); +void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue); +void ( APIENTRY * qglColor3bv )(const GLbyte *v); +void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue); +void ( APIENTRY * qglColor3dv )(const GLdouble *v); +void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue); +void ( APIENTRY * qglColor3fv )(const GLfloat *v); +void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue); +void ( APIENTRY * qglColor3iv )(const GLint *v); +void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue); +void ( APIENTRY * qglColor3sv )(const GLshort *v); +void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue); +void ( APIENTRY * qglColor3ubv )(const GLubyte *v); +void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue); +void ( APIENTRY * qglColor3uiv )(const GLuint *v); +void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue); +void ( APIENTRY * qglColor3usv )(const GLushort *v); +void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +void ( APIENTRY * qglColor4bv )(const GLbyte *v); +void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +void ( APIENTRY * qglColor4dv )(const GLdouble *v); +void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void ( APIENTRY * qglColor4fv )(const GLfloat *v); +void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha); +void ( APIENTRY * qglColor4iv )(const GLint *v); +void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha); +void ( APIENTRY * qglColor4sv )(const GLshort *v); +void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +void ( APIENTRY * qglColor4ubv )(const GLubyte *v); +void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha); +void ( APIENTRY * qglColor4uiv )(const GLuint *v); +void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha); +void ( APIENTRY * qglColor4usv )(const GLushort *v); +void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode); +void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); +void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +void ( APIENTRY * qglCullFace )(GLenum mode); +void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range); +void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures); +void ( APIENTRY * qglDepthFunc )(GLenum func); +void ( APIENTRY * qglDepthMask )(GLboolean flag); +void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar); +void ( APIENTRY * qglDisable )(GLenum cap); +void ( APIENTRY * qglDisableClientState )(GLenum array); +void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count); +void ( APIENTRY * qglDrawBuffer )(GLenum mode); +void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglEdgeFlag )(GLboolean flag); +void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag); +void ( APIENTRY * qglEnable )(GLenum cap); +void ( APIENTRY * qglEnableClientState )(GLenum array); +void ( APIENTRY * qglEnd )(void); +void ( APIENTRY * qglEndList )(void); +void ( APIENTRY * qglEvalCoord1d )(GLdouble u); +void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u); +void ( APIENTRY * qglEvalCoord1f )(GLfloat u); +void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u); +void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v); +void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u); +void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v); +void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u); +void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2); +void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +void ( APIENTRY * qglEvalPoint1 )(GLint i); +void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j); +void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer); +void ( APIENTRY * qglFinish )(void); +void ( APIENTRY * qglFlush )(void); +void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params); +void ( APIENTRY * qglFogi )(GLenum pname, GLint param); +void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params); +void ( APIENTRY * qglFrontFace )(GLenum mode); +void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLuint ( APIENTRY * qglGenLists )(GLsizei range); +void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures); +void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params); +void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation); +void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params); +GLenum ( APIENTRY * qglGetError )(void); +void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params); +void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params); +void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v); +void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v); +void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v); +void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params); +void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values); +void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values); +void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values); +void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params); +void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask); +const GLubyte * ( APIENTRY * qglGetString )(GLenum name); +void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params); +void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params); +void ( APIENTRY * qglHint )(GLenum target, GLenum mode); +void ( APIENTRY * qglIndexMask )(GLuint mask); +void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglIndexd )(GLdouble c); +void ( APIENTRY * qglIndexdv )(const GLdouble *c); +void ( APIENTRY * qglIndexf )(GLfloat c); +void ( APIENTRY * qglIndexfv )(const GLfloat *c); +void ( APIENTRY * qglIndexi )(GLint c); +void ( APIENTRY * qglIndexiv )(const GLint *c); +void ( APIENTRY * qglIndexs )(GLshort c); +void ( APIENTRY * qglIndexsv )(const GLshort *c); +void ( APIENTRY * qglIndexub )(GLubyte c); +void ( APIENTRY * qglIndexubv )(const GLubyte *c); +void ( APIENTRY * qglInitNames )(void); +void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); +GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap); +GLboolean ( APIENTRY * qglIsList )(GLuint list); +GLboolean ( APIENTRY * qglIsTexture )(GLuint texture); +void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params); +void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param); +void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params); +void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param); +void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param); +void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params); +void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern); +void ( APIENTRY * qglLineWidth )(GLfloat width); +void ( APIENTRY * qglListBase )(GLuint base); +void ( APIENTRY * qglLoadIdentity )(void); +void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m); +void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m); +void ( APIENTRY * qglLoadName )(GLuint name); +void ( APIENTRY * qglLogicOp )(GLenum opcode); +void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2); +void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2); +void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param); +void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param); +void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params); +void ( APIENTRY * qglMatrixMode )(GLenum mode); +void ( APIENTRY * qglMultMatrixd )(const GLdouble *m); +void ( APIENTRY * qglMultMatrixf )(const GLfloat *m); +void ( APIENTRY * qglNewList )(GLuint list, GLenum mode); +void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz); +void ( APIENTRY * qglNormal3bv )(const GLbyte *v); +void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz); +void ( APIENTRY * qglNormal3dv )(const GLdouble *v); +void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz); +void ( APIENTRY * qglNormal3fv )(const GLfloat *v); +void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz); +void ( APIENTRY * qglNormal3iv )(const GLint *v); +void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz); +void ( APIENTRY * qglNormal3sv )(const GLshort *v); +void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +void ( APIENTRY * qglPassThrough )(GLfloat token); +void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values); +void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values); +void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values); +void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param); +void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param); +void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param); +void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor); +void ( APIENTRY * qglPointSize )(GLfloat size); +void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode); +void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units); +void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask); +void ( APIENTRY * qglPopAttrib )(void); +void ( APIENTRY * qglPopClientAttrib )(void); +void ( APIENTRY * qglPopMatrix )(void); +void ( APIENTRY * qglPopName )(void); +void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); +void ( APIENTRY * qglPushAttrib )(GLbitfield mask); +void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask); +void ( APIENTRY * qglPushMatrix )(void); +void ( APIENTRY * qglPushName )(GLuint name); +void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y); +void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y); +void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y); +void ( APIENTRY * qglRasterPos2iv )(const GLint *v); +void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y); +void ( APIENTRY * qglRasterPos2sv )(const GLshort *v); +void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z); +void ( APIENTRY * qglRasterPos3iv )(const GLint *v); +void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z); +void ( APIENTRY * qglRasterPos3sv )(const GLshort *v); +void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w); +void ( APIENTRY * qglRasterPos4iv )(const GLint *v); +void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w); +void ( APIENTRY * qglRasterPos4sv )(const GLshort *v); +void ( APIENTRY * qglReadBuffer )(GLenum mode); +void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2); +void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2); +void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2); +void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2); +void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2); +GLint ( APIENTRY * qglRenderMode )(GLenum mode); +void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height); +void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer); +void ( APIENTRY * qglShadeModel )(GLenum mode); +void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask); +void ( APIENTRY * qglStencilMask )(GLuint mask); +void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass); +void ( APIENTRY * qglTexCoord1d )(GLdouble s); +void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord1f )(GLfloat s); +void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord1i )(GLint s); +void ( APIENTRY * qglTexCoord1iv )(const GLint *v); +void ( APIENTRY * qglTexCoord1s )(GLshort s); +void ( APIENTRY * qglTexCoord1sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t); +void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t); +void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t); +void ( APIENTRY * qglTexCoord2iv )(const GLint *v); +void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t); +void ( APIENTRY * qglTexCoord2sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r); +void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r); +void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r); +void ( APIENTRY * qglTexCoord3iv )(const GLint *v); +void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r); +void ( APIENTRY * qglTexCoord3sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q); +void ( APIENTRY * qglTexCoord4iv )(const GLint *v); +void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q); +void ( APIENTRY * qglTexCoord4sv )(const GLshort *v); +void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param); +void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param); +void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params); +void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param); +void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param); +void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y); +void ( APIENTRY * qglVertex2dv )(const GLdouble *v); +void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y); +void ( APIENTRY * qglVertex2fv )(const GLfloat *v); +void ( APIENTRY * qglVertex2i )(GLint x, GLint y); +void ( APIENTRY * qglVertex2iv )(const GLint *v); +void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y); +void ( APIENTRY * qglVertex2sv )(const GLshort *v); +void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglVertex3dv )(const GLdouble *v); +void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglVertex3fv )(const GLfloat *v); +void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z); +void ( APIENTRY * qglVertex3iv )(const GLint *v); +void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z); +void ( APIENTRY * qglVertex3sv )(const GLshort *v); +void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void ( APIENTRY * qglVertex4dv )(const GLdouble *v); +void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void ( APIENTRY * qglVertex4fv )(const GLfloat *v); +void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w); +void ( APIENTRY * qglVertex4iv )(const GLint *v); +void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w); +void ( APIENTRY * qglVertex4sv )(const GLshort *v); +void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height); + +void ( APIENTRY * qglLockArraysEXT)( int, int); +void ( APIENTRY * qglUnlockArraysEXT) ( void ); + +void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value ); +void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value ); +void ( APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * ); +void ( APIENTRY * qglSelectTextureSGIS)( GLenum ); +void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat ); + +static void ( APIENTRY * dllAccum )(GLenum op, GLfloat value); +static void ( APIENTRY * dllAlphaFunc )(GLenum func, GLclampf ref); +GLboolean ( APIENTRY * dllAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); +static void ( APIENTRY * dllArrayElement )(GLint i); +static void ( APIENTRY * dllBegin )(GLenum mode); +static void ( APIENTRY * dllBindTexture )(GLenum target, GLuint texture); +static void ( APIENTRY * dllBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +static void ( APIENTRY * dllBlendFunc )(GLenum sfactor, GLenum dfactor); +static void ( APIENTRY * dllCallList )(GLuint list); +static void ( APIENTRY * dllCallLists )(GLsizei n, GLenum type, const GLvoid *lists); +static void ( APIENTRY * dllClear )(GLbitfield mask); +static void ( APIENTRY * dllClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +static void ( APIENTRY * dllClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +static void ( APIENTRY * dllClearDepth )(GLclampd depth); +static void ( APIENTRY * dllClearIndex )(GLfloat c); +static void ( APIENTRY * dllClearStencil )(GLint s); +static void ( APIENTRY * dllClipPlane )(GLenum plane, const GLdouble *equation); +static void ( APIENTRY * dllColor3b )(GLbyte red, GLbyte green, GLbyte blue); +static void ( APIENTRY * dllColor3bv )(const GLbyte *v); +static void ( APIENTRY * dllColor3d )(GLdouble red, GLdouble green, GLdouble blue); +static void ( APIENTRY * dllColor3dv )(const GLdouble *v); +static void ( APIENTRY * dllColor3f )(GLfloat red, GLfloat green, GLfloat blue); +static void ( APIENTRY * dllColor3fv )(const GLfloat *v); +static void ( APIENTRY * dllColor3i )(GLint red, GLint green, GLint blue); +static void ( APIENTRY * dllColor3iv )(const GLint *v); +static void ( APIENTRY * dllColor3s )(GLshort red, GLshort green, GLshort blue); +static void ( APIENTRY * dllColor3sv )(const GLshort *v); +static void ( APIENTRY * dllColor3ub )(GLubyte red, GLubyte green, GLubyte blue); +static void ( APIENTRY * dllColor3ubv )(const GLubyte *v); +static void ( APIENTRY * dllColor3ui )(GLuint red, GLuint green, GLuint blue); +static void ( APIENTRY * dllColor3uiv )(const GLuint *v); +static void ( APIENTRY * dllColor3us )(GLushort red, GLushort green, GLushort blue); +static void ( APIENTRY * dllColor3usv )(const GLushort *v); +static void ( APIENTRY * dllColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +static void ( APIENTRY * dllColor4bv )(const GLbyte *v); +static void ( APIENTRY * dllColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +static void ( APIENTRY * dllColor4dv )(const GLdouble *v); +static void ( APIENTRY * dllColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +static void ( APIENTRY * dllColor4fv )(const GLfloat *v); +static void ( APIENTRY * dllColor4i )(GLint red, GLint green, GLint blue, GLint alpha); +static void ( APIENTRY * dllColor4iv )(const GLint *v); +static void ( APIENTRY * dllColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha); +static void ( APIENTRY * dllColor4sv )(const GLshort *v); +static void ( APIENTRY * dllColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +static void ( APIENTRY * dllColor4ubv )(const GLubyte *v); +static void ( APIENTRY * dllColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha); +static void ( APIENTRY * dllColor4uiv )(const GLuint *v); +static void ( APIENTRY * dllColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha); +static void ( APIENTRY * dllColor4usv )(const GLushort *v); +static void ( APIENTRY * dllColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +static void ( APIENTRY * dllColorMaterial )(GLenum face, GLenum mode); +static void ( APIENTRY * dllColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +static void ( APIENTRY * dllCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); +static void ( APIENTRY * dllCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +static void ( APIENTRY * dllCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +static void ( APIENTRY * dllCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +static void ( APIENTRY * dllCullFace )(GLenum mode); +static void ( APIENTRY * dllDeleteLists )(GLuint list, GLsizei range); +static void ( APIENTRY * dllDeleteTextures )(GLsizei n, const GLuint *textures); +static void ( APIENTRY * dllDepthFunc )(GLenum func); +static void ( APIENTRY * dllDepthMask )(GLboolean flag); +static void ( APIENTRY * dllDepthRange )(GLclampd zNear, GLclampd zFar); +static void ( APIENTRY * dllDisable )(GLenum cap); +static void ( APIENTRY * dllDisableClientState )(GLenum array); +static void ( APIENTRY * dllDrawArrays )(GLenum mode, GLint first, GLsizei count); +static void ( APIENTRY * dllDrawBuffer )(GLenum mode); +static void ( APIENTRY * dllDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +static void ( APIENTRY * dllDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllEdgeFlag )(GLboolean flag); +static void ( APIENTRY * dllEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllEdgeFlagv )(const GLboolean *flag); +static void ( APIENTRY * dllEnable )(GLenum cap); +static void ( APIENTRY * dllEnableClientState )(GLenum array); +static void ( APIENTRY * dllEnd )(void); +static void ( APIENTRY * dllEndList )(void); +static void ( APIENTRY * dllEvalCoord1d )(GLdouble u); +static void ( APIENTRY * dllEvalCoord1dv )(const GLdouble *u); +static void ( APIENTRY * dllEvalCoord1f )(GLfloat u); +static void ( APIENTRY * dllEvalCoord1fv )(const GLfloat *u); +static void ( APIENTRY * dllEvalCoord2d )(GLdouble u, GLdouble v); +static void ( APIENTRY * dllEvalCoord2dv )(const GLdouble *u); +static void ( APIENTRY * dllEvalCoord2f )(GLfloat u, GLfloat v); +static void ( APIENTRY * dllEvalCoord2fv )(const GLfloat *u); +static void ( APIENTRY * dllEvalMesh1 )(GLenum mode, GLint i1, GLint i2); +static void ( APIENTRY * dllEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +static void ( APIENTRY * dllEvalPoint1 )(GLint i); +static void ( APIENTRY * dllEvalPoint2 )(GLint i, GLint j); +static void ( APIENTRY * dllFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer); +static void ( APIENTRY * dllFinish )(void); +static void ( APIENTRY * dllFlush )(void); +static void ( APIENTRY * dllFogf )(GLenum pname, GLfloat param); +static void ( APIENTRY * dllFogfv )(GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllFogi )(GLenum pname, GLint param); +static void ( APIENTRY * dllFogiv )(GLenum pname, const GLint *params); +static void ( APIENTRY * dllFrontFace )(GLenum mode); +static void ( APIENTRY * dllFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLuint ( APIENTRY * dllGenLists )(GLsizei range); +static void ( APIENTRY * dllGenTextures )(GLsizei n, GLuint *textures); +static void ( APIENTRY * dllGetBooleanv )(GLenum pname, GLboolean *params); +static void ( APIENTRY * dllGetClipPlane )(GLenum plane, GLdouble *equation); +static void ( APIENTRY * dllGetDoublev )(GLenum pname, GLdouble *params); +GLenum ( APIENTRY * dllGetError )(void); +static void ( APIENTRY * dllGetFloatv )(GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetIntegerv )(GLenum pname, GLint *params); +static void ( APIENTRY * dllGetLightfv )(GLenum light, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetLightiv )(GLenum light, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetMapdv )(GLenum target, GLenum query, GLdouble *v); +static void ( APIENTRY * dllGetMapfv )(GLenum target, GLenum query, GLfloat *v); +static void ( APIENTRY * dllGetMapiv )(GLenum target, GLenum query, GLint *v); +static void ( APIENTRY * dllGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetMaterialiv )(GLenum face, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetPixelMapfv )(GLenum map, GLfloat *values); +static void ( APIENTRY * dllGetPixelMapuiv )(GLenum map, GLuint *values); +static void ( APIENTRY * dllGetPixelMapusv )(GLenum map, GLushort *values); +static void ( APIENTRY * dllGetPointerv )(GLenum pname, GLvoid* *params); +static void ( APIENTRY * dllGetPolygonStipple )(GLubyte *mask); +const GLubyte * ( APIENTRY * dllGetString )(GLenum name); +static void ( APIENTRY * dllGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetTexEnviv )(GLenum target, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params); +static void ( APIENTRY * dllGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetTexGeniv )(GLenum coord, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +static void ( APIENTRY * dllGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetTexParameteriv )(GLenum target, GLenum pname, GLint *params); +static void ( APIENTRY * dllHint )(GLenum target, GLenum mode); +static void ( APIENTRY * dllIndexMask )(GLuint mask); +static void ( APIENTRY * dllIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllIndexd )(GLdouble c); +static void ( APIENTRY * dllIndexdv )(const GLdouble *c); +static void ( APIENTRY * dllIndexf )(GLfloat c); +static void ( APIENTRY * dllIndexfv )(const GLfloat *c); +static void ( APIENTRY * dllIndexi )(GLint c); +static void ( APIENTRY * dllIndexiv )(const GLint *c); +static void ( APIENTRY * dllIndexs )(GLshort c); +static void ( APIENTRY * dllIndexsv )(const GLshort *c); +static void ( APIENTRY * dllIndexub )(GLubyte c); +static void ( APIENTRY * dllIndexubv )(const GLubyte *c); +static void ( APIENTRY * dllInitNames )(void); +static void ( APIENTRY * dllInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); +GLboolean ( APIENTRY * dllIsEnabled )(GLenum cap); +GLboolean ( APIENTRY * dllIsList )(GLuint list); +GLboolean ( APIENTRY * dllIsTexture )(GLuint texture); +static void ( APIENTRY * dllLightModelf )(GLenum pname, GLfloat param); +static void ( APIENTRY * dllLightModelfv )(GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllLightModeli )(GLenum pname, GLint param); +static void ( APIENTRY * dllLightModeliv )(GLenum pname, const GLint *params); +static void ( APIENTRY * dllLightf )(GLenum light, GLenum pname, GLfloat param); +static void ( APIENTRY * dllLightfv )(GLenum light, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllLighti )(GLenum light, GLenum pname, GLint param); +static void ( APIENTRY * dllLightiv )(GLenum light, GLenum pname, const GLint *params); +static void ( APIENTRY * dllLineStipple )(GLint factor, GLushort pattern); +static void ( APIENTRY * dllLineWidth )(GLfloat width); +static void ( APIENTRY * dllListBase )(GLuint base); +static void ( APIENTRY * dllLoadIdentity )(void); +static void ( APIENTRY * dllLoadMatrixd )(const GLdouble *m); +static void ( APIENTRY * dllLoadMatrixf )(const GLfloat *m); +static void ( APIENTRY * dllLoadName )(GLuint name); +static void ( APIENTRY * dllLogicOp )(GLenum opcode); +static void ( APIENTRY * dllMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +static void ( APIENTRY * dllMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +static void ( APIENTRY * dllMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +static void ( APIENTRY * dllMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +static void ( APIENTRY * dllMapGrid1d )(GLint un, GLdouble u1, GLdouble u2); +static void ( APIENTRY * dllMapGrid1f )(GLint un, GLfloat u1, GLfloat u2); +static void ( APIENTRY * dllMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +static void ( APIENTRY * dllMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +static void ( APIENTRY * dllMaterialf )(GLenum face, GLenum pname, GLfloat param); +static void ( APIENTRY * dllMaterialfv )(GLenum face, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllMateriali )(GLenum face, GLenum pname, GLint param); +static void ( APIENTRY * dllMaterialiv )(GLenum face, GLenum pname, const GLint *params); +static void ( APIENTRY * dllMatrixMode )(GLenum mode); +static void ( APIENTRY * dllMultMatrixd )(const GLdouble *m); +static void ( APIENTRY * dllMultMatrixf )(const GLfloat *m); +static void ( APIENTRY * dllNewList )(GLuint list, GLenum mode); +static void ( APIENTRY * dllNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz); +static void ( APIENTRY * dllNormal3bv )(const GLbyte *v); +static void ( APIENTRY * dllNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz); +static void ( APIENTRY * dllNormal3dv )(const GLdouble *v); +static void ( APIENTRY * dllNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz); +static void ( APIENTRY * dllNormal3fv )(const GLfloat *v); +static void ( APIENTRY * dllNormal3i )(GLint nx, GLint ny, GLint nz); +static void ( APIENTRY * dllNormal3iv )(const GLint *v); +static void ( APIENTRY * dllNormal3s )(GLshort nx, GLshort ny, GLshort nz); +static void ( APIENTRY * dllNormal3sv )(const GLshort *v); +static void ( APIENTRY * dllNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +static void ( APIENTRY * dllPassThrough )(GLfloat token); +static void ( APIENTRY * dllPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values); +static void ( APIENTRY * dllPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values); +static void ( APIENTRY * dllPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values); +static void ( APIENTRY * dllPixelStoref )(GLenum pname, GLfloat param); +static void ( APIENTRY * dllPixelStorei )(GLenum pname, GLint param); +static void ( APIENTRY * dllPixelTransferf )(GLenum pname, GLfloat param); +static void ( APIENTRY * dllPixelTransferi )(GLenum pname, GLint param); +static void ( APIENTRY * dllPixelZoom )(GLfloat xfactor, GLfloat yfactor); +static void ( APIENTRY * dllPointSize )(GLfloat size); +static void ( APIENTRY * dllPolygonMode )(GLenum face, GLenum mode); +static void ( APIENTRY * dllPolygonOffset )(GLfloat factor, GLfloat units); +static void ( APIENTRY * dllPolygonStipple )(const GLubyte *mask); +static void ( APIENTRY * dllPopAttrib )(void); +static void ( APIENTRY * dllPopClientAttrib )(void); +static void ( APIENTRY * dllPopMatrix )(void); +static void ( APIENTRY * dllPopName )(void); +static void ( APIENTRY * dllPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); +static void ( APIENTRY * dllPushAttrib )(GLbitfield mask); +static void ( APIENTRY * dllPushClientAttrib )(GLbitfield mask); +static void ( APIENTRY * dllPushMatrix )(void); +static void ( APIENTRY * dllPushName )(GLuint name); +static void ( APIENTRY * dllRasterPos2d )(GLdouble x, GLdouble y); +static void ( APIENTRY * dllRasterPos2dv )(const GLdouble *v); +static void ( APIENTRY * dllRasterPos2f )(GLfloat x, GLfloat y); +static void ( APIENTRY * dllRasterPos2fv )(const GLfloat *v); +static void ( APIENTRY * dllRasterPos2i )(GLint x, GLint y); +static void ( APIENTRY * dllRasterPos2iv )(const GLint *v); +static void ( APIENTRY * dllRasterPos2s )(GLshort x, GLshort y); +static void ( APIENTRY * dllRasterPos2sv )(const GLshort *v); +static void ( APIENTRY * dllRasterPos3d )(GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllRasterPos3dv )(const GLdouble *v); +static void ( APIENTRY * dllRasterPos3f )(GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllRasterPos3fv )(const GLfloat *v); +static void ( APIENTRY * dllRasterPos3i )(GLint x, GLint y, GLint z); +static void ( APIENTRY * dllRasterPos3iv )(const GLint *v); +static void ( APIENTRY * dllRasterPos3s )(GLshort x, GLshort y, GLshort z); +static void ( APIENTRY * dllRasterPos3sv )(const GLshort *v); +static void ( APIENTRY * dllRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +static void ( APIENTRY * dllRasterPos4dv )(const GLdouble *v); +static void ( APIENTRY * dllRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +static void ( APIENTRY * dllRasterPos4fv )(const GLfloat *v); +static void ( APIENTRY * dllRasterPos4i )(GLint x, GLint y, GLint z, GLint w); +static void ( APIENTRY * dllRasterPos4iv )(const GLint *v); +static void ( APIENTRY * dllRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w); +static void ( APIENTRY * dllRasterPos4sv )(const GLshort *v); +static void ( APIENTRY * dllReadBuffer )(GLenum mode); +static void ( APIENTRY * dllReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +static void ( APIENTRY * dllRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +static void ( APIENTRY * dllRectdv )(const GLdouble *v1, const GLdouble *v2); +static void ( APIENTRY * dllRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +static void ( APIENTRY * dllRectfv )(const GLfloat *v1, const GLfloat *v2); +static void ( APIENTRY * dllRecti )(GLint x1, GLint y1, GLint x2, GLint y2); +static void ( APIENTRY * dllRectiv )(const GLint *v1, const GLint *v2); +static void ( APIENTRY * dllRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +static void ( APIENTRY * dllRectsv )(const GLshort *v1, const GLshort *v2); +GLint ( APIENTRY * dllRenderMode )(GLenum mode); +static void ( APIENTRY * dllRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllScaled )(GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllScalef )(GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllScissor )(GLint x, GLint y, GLsizei width, GLsizei height); +static void ( APIENTRY * dllSelectBuffer )(GLsizei size, GLuint *buffer); +static void ( APIENTRY * dllShadeModel )(GLenum mode); +static void ( APIENTRY * dllStencilFunc )(GLenum func, GLint ref, GLuint mask); +static void ( APIENTRY * dllStencilMask )(GLuint mask); +static void ( APIENTRY * dllStencilOp )(GLenum fail, GLenum zfail, GLenum zpass); +static void ( APIENTRY * dllTexCoord1d )(GLdouble s); +static void ( APIENTRY * dllTexCoord1dv )(const GLdouble *v); +static void ( APIENTRY * dllTexCoord1f )(GLfloat s); +static void ( APIENTRY * dllTexCoord1fv )(const GLfloat *v); +static void ( APIENTRY * dllTexCoord1i )(GLint s); +static void ( APIENTRY * dllTexCoord1iv )(const GLint *v); +static void ( APIENTRY * dllTexCoord1s )(GLshort s); +static void ( APIENTRY * dllTexCoord1sv )(const GLshort *v); +static void ( APIENTRY * dllTexCoord2d )(GLdouble s, GLdouble t); +static void ( APIENTRY * dllTexCoord2dv )(const GLdouble *v); +static void ( APIENTRY * dllTexCoord2f )(GLfloat s, GLfloat t); +static void ( APIENTRY * dllTexCoord2fv )(const GLfloat *v); +static void ( APIENTRY * dllTexCoord2i )(GLint s, GLint t); +static void ( APIENTRY * dllTexCoord2iv )(const GLint *v); +static void ( APIENTRY * dllTexCoord2s )(GLshort s, GLshort t); +static void ( APIENTRY * dllTexCoord2sv )(const GLshort *v); +static void ( APIENTRY * dllTexCoord3d )(GLdouble s, GLdouble t, GLdouble r); +static void ( APIENTRY * dllTexCoord3dv )(const GLdouble *v); +static void ( APIENTRY * dllTexCoord3f )(GLfloat s, GLfloat t, GLfloat r); +static void ( APIENTRY * dllTexCoord3fv )(const GLfloat *v); +static void ( APIENTRY * dllTexCoord3i )(GLint s, GLint t, GLint r); +static void ( APIENTRY * dllTexCoord3iv )(const GLint *v); +static void ( APIENTRY * dllTexCoord3s )(GLshort s, GLshort t, GLshort r); +static void ( APIENTRY * dllTexCoord3sv )(const GLshort *v); +static void ( APIENTRY * dllTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +static void ( APIENTRY * dllTexCoord4dv )(const GLdouble *v); +static void ( APIENTRY * dllTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +static void ( APIENTRY * dllTexCoord4fv )(const GLfloat *v); +static void ( APIENTRY * dllTexCoord4i )(GLint s, GLint t, GLint r, GLint q); +static void ( APIENTRY * dllTexCoord4iv )(const GLint *v); +static void ( APIENTRY * dllTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q); +static void ( APIENTRY * dllTexCoord4sv )(const GLshort *v); +static void ( APIENTRY * dllTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllTexEnvf )(GLenum target, GLenum pname, GLfloat param); +static void ( APIENTRY * dllTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllTexEnvi )(GLenum target, GLenum pname, GLint param); +static void ( APIENTRY * dllTexEnviv )(GLenum target, GLenum pname, const GLint *params); +static void ( APIENTRY * dllTexGend )(GLenum coord, GLenum pname, GLdouble param); +static void ( APIENTRY * dllTexGendv )(GLenum coord, GLenum pname, const GLdouble *params); +static void ( APIENTRY * dllTexGenf )(GLenum coord, GLenum pname, GLfloat param); +static void ( APIENTRY * dllTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllTexGeni )(GLenum coord, GLenum pname, GLint param); +static void ( APIENTRY * dllTexGeniv )(GLenum coord, GLenum pname, const GLint *params); +static void ( APIENTRY * dllTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllTexParameterf )(GLenum target, GLenum pname, GLfloat param); +static void ( APIENTRY * dllTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllTexParameteri )(GLenum target, GLenum pname, GLint param); +static void ( APIENTRY * dllTexParameteriv )(GLenum target, GLenum pname, const GLint *params); +static void ( APIENTRY * dllTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllTranslated )(GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllTranslatef )(GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllVertex2d )(GLdouble x, GLdouble y); +static void ( APIENTRY * dllVertex2dv )(const GLdouble *v); +static void ( APIENTRY * dllVertex2f )(GLfloat x, GLfloat y); +static void ( APIENTRY * dllVertex2fv )(const GLfloat *v); +static void ( APIENTRY * dllVertex2i )(GLint x, GLint y); +static void ( APIENTRY * dllVertex2iv )(const GLint *v); +static void ( APIENTRY * dllVertex2s )(GLshort x, GLshort y); +static void ( APIENTRY * dllVertex2sv )(const GLshort *v); +static void ( APIENTRY * dllVertex3d )(GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllVertex3dv )(const GLdouble *v); +static void ( APIENTRY * dllVertex3f )(GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllVertex3fv )(const GLfloat *v); +static void ( APIENTRY * dllVertex3i )(GLint x, GLint y, GLint z); +static void ( APIENTRY * dllVertex3iv )(const GLint *v); +static void ( APIENTRY * dllVertex3s )(GLshort x, GLshort y, GLshort z); +static void ( APIENTRY * dllVertex3sv )(const GLshort *v); +static void ( APIENTRY * dllVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +static void ( APIENTRY * dllVertex4dv )(const GLdouble *v); +static void ( APIENTRY * dllVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +static void ( APIENTRY * dllVertex4fv )(const GLfloat *v); +static void ( APIENTRY * dllVertex4i )(GLint x, GLint y, GLint z, GLint w); +static void ( APIENTRY * dllVertex4iv )(const GLint *v); +static void ( APIENTRY * dllVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w); +static void ( APIENTRY * dllVertex4sv )(const GLshort *v); +static void ( APIENTRY * dllVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllViewport )(GLint x, GLint y, GLsizei width, GLsizei height); + +static void APIENTRY logAccum(GLenum op, GLfloat value) +{ + fprintf( log_fp, "glAccum\n" ); + dllAccum( op, value ); +} + +static void APIENTRY logAlphaFunc(GLenum func, GLclampf ref) +{ + fprintf( log_fp, "glAlphaFunc( 0x%x, %f )\n", func, ref ); + dllAlphaFunc( func, ref ); +} + +static GLboolean APIENTRY logAreTexturesResident(GLsizei n, const GLuint *textures, GLboolean *residences) +{ + fprintf( log_fp, "glAreTexturesResident\n" ); + return dllAreTexturesResident( n, textures, residences ); +} + +static void APIENTRY logArrayElement(GLint i) +{ + fprintf( log_fp, "glArrayElement\n" ); + dllArrayElement( i ); +} + +static void APIENTRY logBegin(GLenum mode) +{ + fprintf( log_fp, "glBegin( 0x%x )\n", mode ); + dllBegin( mode ); +} + +static void APIENTRY logBindTexture(GLenum target, GLuint texture) +{ + fprintf( log_fp, "glBindTexture( 0x%x, %u )\n", target, texture ); + dllBindTexture( target, texture ); +} + +static void APIENTRY logBitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap) +{ + fprintf( log_fp, "glBitmap\n" ); + dllBitmap( width, height, xorig, yorig, xmove, ymove, bitmap ); +} + +static void APIENTRY logBlendFunc(GLenum sfactor, GLenum dfactor) +{ + fprintf( log_fp, "glBlendFunc( 0x%x, 0x%x )\n", sfactor, dfactor ); + dllBlendFunc( sfactor, dfactor ); +} + +static void APIENTRY logCallList(GLuint list) +{ + fprintf( log_fp, "glCallList( %u )\n", list ); + dllCallList( list ); +} + +static void APIENTRY logCallLists(GLsizei n, GLenum type, const void *lists) +{ + fprintf( log_fp, "glCallLists\n" ); + dllCallLists( n, type, lists ); +} + +static void APIENTRY logClear(GLbitfield mask) +{ + fprintf( log_fp, "glClear\n" ); + dllClear( mask ); +} + +static void APIENTRY logClearAccum(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + fprintf( log_fp, "glClearAccum\n" ); + dllClearAccum( red, green, blue, alpha ); +} + +static void APIENTRY logClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + fprintf( log_fp, "glClearColor\n" ); + dllClearColor( red, green, blue, alpha ); +} + +static void APIENTRY logClearDepth(GLclampd depth) +{ + fprintf( log_fp, "glClearDepth\n" ); + dllClearDepth( depth ); +} + +static void APIENTRY logClearIndex(GLfloat c) +{ + fprintf( log_fp, "glClearIndex\n" ); + dllClearIndex( c ); +} + +static void APIENTRY logClearStencil(GLint s) +{ + fprintf( log_fp, "glClearStencil\n" ); + dllClearStencil( s ); +} + +static void APIENTRY logClipPlane(GLenum plane, const GLdouble *equation) +{ + fprintf( log_fp, "glClipPlane\n" ); + dllClipPlane( plane, equation ); +} + +static void APIENTRY logColor3b(GLbyte red, GLbyte green, GLbyte blue) +{ + fprintf( log_fp, "glColor3b\n" ); + dllColor3b( red, green, blue ); +} + +static void APIENTRY logColor3bv(const GLbyte *v) +{ + fprintf( log_fp, "glColor3bv\n" ); + dllColor3bv( v ); +} + +static void APIENTRY logColor3d(GLdouble red, GLdouble green, GLdouble blue) +{ + fprintf( log_fp, "glColor3d\n" ); + dllColor3d( red, green, blue ); +} + +static void APIENTRY logColor3dv(const GLdouble *v) +{ + fprintf( log_fp, "glColor3dv\n" ); + dllColor3dv( v ); +} + +static void APIENTRY logColor3f(GLfloat red, GLfloat green, GLfloat blue) +{ + fprintf( log_fp, "glColor3f\n" ); + dllColor3f( red, green, blue ); +} + +static void APIENTRY logColor3fv(const GLfloat *v) +{ + fprintf( log_fp, "glColor3fv\n" ); + dllColor3fv( v ); +} + +static void APIENTRY logColor3i(GLint red, GLint green, GLint blue) +{ + fprintf( log_fp, "glColor3i\n" ); + dllColor3i( red, green, blue ); +} + +static void APIENTRY logColor3iv(const GLint *v) +{ + fprintf( log_fp, "glColor3iv\n" ); + dllColor3iv( v ); +} + +static void APIENTRY logColor3s(GLshort red, GLshort green, GLshort blue) +{ + fprintf( log_fp, "glColor3s\n" ); + dllColor3s( red, green, blue ); +} + +static void APIENTRY logColor3sv(const GLshort *v) +{ + fprintf( log_fp, "glColor3sv\n" ); + dllColor3sv( v ); +} + +static void APIENTRY logColor3ub(GLubyte red, GLubyte green, GLubyte blue) +{ + fprintf( log_fp, "glColor3ub\n" ); + dllColor3ub( red, green, blue ); +} + +static void APIENTRY logColor3ubv(const GLubyte *v) +{ + fprintf( log_fp, "glColor3ubv\n" ); + dllColor3ubv( v ); +} + +#define SIG( x ) fprintf( log_fp, x "\n" ) + +static void APIENTRY logColor3ui(GLuint red, GLuint green, GLuint blue) +{ + SIG( "glColor3ui" ); + dllColor3ui( red, green, blue ); +} + +static void APIENTRY logColor3uiv(const GLuint *v) +{ + SIG( "glColor3uiv" ); + dllColor3uiv( v ); +} + +static void APIENTRY logColor3us(GLushort red, GLushort green, GLushort blue) +{ + SIG( "glColor3us" ); + dllColor3us( red, green, blue ); +} + +static void APIENTRY logColor3usv(const GLushort *v) +{ + SIG( "glColor3usv" ); + dllColor3usv( v ); +} + +static void APIENTRY logColor4b(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha) +{ + SIG( "glColor4b" ); + dllColor4b( red, green, blue, alpha ); +} + +static void APIENTRY logColor4bv(const GLbyte *v) +{ + SIG( "glColor4bv" ); + dllColor4bv( v ); +} + +static void APIENTRY logColor4d(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha) +{ + SIG( "glColor4d" ); + dllColor4d( red, green, blue, alpha ); +} +static void APIENTRY logColor4dv(const GLdouble *v) +{ + SIG( "glColor4dv" ); + dllColor4dv( v ); +} +static void APIENTRY logColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + SIG( "glColor4f" ); + dllColor4f( red, green, blue, alpha ); +} +static void APIENTRY logColor4fv(const GLfloat *v) +{ + SIG( "glColor4fv" ); + dllColor4fv( v ); +} +static void APIENTRY logColor4i(GLint red, GLint green, GLint blue, GLint alpha) +{ + SIG( "glColor4i" ); + dllColor4i( red, green, blue, alpha ); +} +static void APIENTRY logColor4iv(const GLint *v) +{ + SIG( "glColor4iv" ); + dllColor4iv( v ); +} +static void APIENTRY logColor4s(GLshort red, GLshort green, GLshort blue, GLshort alpha) +{ + SIG( "glColor4s" ); + dllColor4s( red, green, blue, alpha ); +} +static void APIENTRY logColor4sv(const GLshort *v) +{ + SIG( "glColor4sv" ); + dllColor4sv( v ); +} +static void APIENTRY logColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) +{ + SIG( "glColor4b" ); + dllColor4b( red, green, blue, alpha ); +} +static void APIENTRY logColor4ubv(const GLubyte *v) +{ + SIG( "glColor4ubv" ); + dllColor4ubv( v ); +} +static void APIENTRY logColor4ui(GLuint red, GLuint green, GLuint blue, GLuint alpha) +{ + SIG( "glColor4ui" ); + dllColor4ui( red, green, blue, alpha ); +} +static void APIENTRY logColor4uiv(const GLuint *v) +{ + SIG( "glColor4uiv" ); + dllColor4uiv( v ); +} +static void APIENTRY logColor4us(GLushort red, GLushort green, GLushort blue, GLushort alpha) +{ + SIG( "glColor4us" ); + dllColor4us( red, green, blue, alpha ); +} +static void APIENTRY logColor4usv(const GLushort *v) +{ + SIG( "glColor4usv" ); + dllColor4usv( v ); +} +static void APIENTRY logColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + SIG( "glColorMask" ); + dllColorMask( red, green, blue, alpha ); +} +static void APIENTRY logColorMaterial(GLenum face, GLenum mode) +{ + SIG( "glColorMaterial" ); + dllColorMaterial( face, mode ); +} + +static void APIENTRY logColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glColorPointer" ); + dllColorPointer( size, type, stride, pointer ); +} + +static void APIENTRY logCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type) +{ + SIG( "glCopyPixels" ); + dllCopyPixels( x, y, width, height, type ); +} + +static void APIENTRY logCopyTexImage1D(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border) +{ + SIG( "glCopyTexImage1D" ); + dllCopyTexImage1D( target, level, internalFormat, x, y, width, border ); +} + +static void APIENTRY logCopyTexImage2D(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + SIG( "glCopyTexImage2D" ); + dllCopyTexImage2D( target, level, internalFormat, x, y, width, height, border ); +} + +static void APIENTRY logCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) +{ + SIG( "glCopyTexSubImage1D" ); + dllCopyTexSubImage1D( target, level, xoffset, x, y, width ); +} + +static void APIENTRY logCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + SIG( "glCopyTexSubImage2D" ); + dllCopyTexSubImage2D( target, level, xoffset, yoffset, x, y, width, height ); +} + +static void APIENTRY logCullFace(GLenum mode) +{ + SIG( "glCullFace" ); + dllCullFace( mode ); +} + +static void APIENTRY logDeleteLists(GLuint list, GLsizei range) +{ + SIG( "glDeleteLists" ); + dllDeleteLists( list, range ); +} + +static void APIENTRY logDeleteTextures(GLsizei n, const GLuint *textures) +{ + SIG( "glDeleteTextures" ); + dllDeleteTextures( n, textures ); +} + +static void APIENTRY logDepthFunc(GLenum func) +{ + SIG( "glDepthFunc" ); + dllDepthFunc( func ); +} + +static void APIENTRY logDepthMask(GLboolean flag) +{ + SIG( "glDepthMask" ); + dllDepthMask( flag ); +} + +static void APIENTRY logDepthRange(GLclampd zNear, GLclampd zFar) +{ + SIG( "glDepthRange" ); + dllDepthRange( zNear, zFar ); +} + +static void APIENTRY logDisable(GLenum cap) +{ + fprintf( log_fp, "glDisable( 0x%x )\n", cap ); + dllDisable( cap ); +} + +static void APIENTRY logDisableClientState(GLenum array) +{ + SIG( "glDisableClientState" ); + dllDisableClientState( array ); +} + +static void APIENTRY logDrawArrays(GLenum mode, GLint first, GLsizei count) +{ + SIG( "glDrawArrays" ); + dllDrawArrays( mode, first, count ); +} + +static void APIENTRY logDrawBuffer(GLenum mode) +{ + SIG( "glDrawBuffer" ); + dllDrawBuffer( mode ); +} + +static void APIENTRY logDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) +{ + SIG( "glDrawElements" ); + dllDrawElements( mode, count, type, indices ); +} + +static void APIENTRY logDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glDrawPixels" ); + dllDrawPixels( width, height, format, type, pixels ); +} + +static void APIENTRY logEdgeFlag(GLboolean flag) +{ + SIG( "glEdgeFlag" ); + dllEdgeFlag( flag ); +} + +static void APIENTRY logEdgeFlagPointer(GLsizei stride, const void *pointer) +{ + SIG( "glEdgeFlagPointer" ); + dllEdgeFlagPointer( stride, pointer ); +} + +static void APIENTRY logEdgeFlagv(const GLboolean *flag) +{ + SIG( "glEdgeFlagv" ); + dllEdgeFlagv( flag ); +} + +static void APIENTRY logEnable(GLenum cap) +{ + fprintf( log_fp, "glEnable( 0x%x )\n", cap ); + dllEnable( cap ); +} + +static void APIENTRY logEnableClientState(GLenum array) +{ + SIG( "glEnableClientState" ); + dllEnableClientState( array ); +} + +static void APIENTRY logEnd(void) +{ + SIG( "glEnd" ); + dllEnd(); +} + +static void APIENTRY logEndList(void) +{ + SIG( "glEndList" ); + dllEndList(); +} + +static void APIENTRY logEvalCoord1d(GLdouble u) +{ + SIG( "glEvalCoord1d" ); + dllEvalCoord1d( u ); +} + +static void APIENTRY logEvalCoord1dv(const GLdouble *u) +{ + SIG( "glEvalCoord1dv" ); + dllEvalCoord1dv( u ); +} + +static void APIENTRY logEvalCoord1f(GLfloat u) +{ + SIG( "glEvalCoord1f" ); + dllEvalCoord1f( u ); +} + +static void APIENTRY logEvalCoord1fv(const GLfloat *u) +{ + SIG( "glEvalCoord1fv" ); + dllEvalCoord1fv( u ); +} +static void APIENTRY logEvalCoord2d(GLdouble u, GLdouble v) +{ + SIG( "glEvalCoord2d" ); + dllEvalCoord2d( u, v ); +} +static void APIENTRY logEvalCoord2dv(const GLdouble *u) +{ + SIG( "glEvalCoord2dv" ); + dllEvalCoord2dv( u ); +} +static void APIENTRY logEvalCoord2f(GLfloat u, GLfloat v) +{ + SIG( "glEvalCoord2f" ); + dllEvalCoord2f( u, v ); +} +static void APIENTRY logEvalCoord2fv(const GLfloat *u) +{ + SIG( "glEvalCoord2fv" ); + dllEvalCoord2fv( u ); +} + +static void APIENTRY logEvalMesh1(GLenum mode, GLint i1, GLint i2) +{ + SIG( "glEvalMesh1" ); + dllEvalMesh1( mode, i1, i2 ); +} +static void APIENTRY logEvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2) +{ + SIG( "glEvalMesh2" ); + dllEvalMesh2( mode, i1, i2, j1, j2 ); +} +static void APIENTRY logEvalPoint1(GLint i) +{ + SIG( "glEvalPoint1" ); + dllEvalPoint1( i ); +} +static void APIENTRY logEvalPoint2(GLint i, GLint j) +{ + SIG( "glEvalPoint2" ); + dllEvalPoint2( i, j ); +} + +static void APIENTRY logFeedbackBuffer(GLsizei size, GLenum type, GLfloat *buffer) +{ + SIG( "glFeedbackBuffer" ); + dllFeedbackBuffer( size, type, buffer ); +} + +static void APIENTRY logFinish(void) +{ + SIG( "glFinish" ); + dllFinish(); +} + +static void APIENTRY logFlush(void) +{ + SIG( "glFlush" ); + dllFlush(); +} + +static void APIENTRY logFogf(GLenum pname, GLfloat param) +{ + SIG( "glFogf" ); + dllFogf( pname, param ); +} + +static void APIENTRY logFogfv(GLenum pname, const GLfloat *params) +{ + SIG( "glFogfv" ); + dllFogfv( pname, params ); +} + +static void APIENTRY logFogi(GLenum pname, GLint param) +{ + SIG( "glFogi" ); + dllFogi( pname, param ); +} + +static void APIENTRY logFogiv(GLenum pname, const GLint *params) +{ + SIG( "glFogiv" ); + dllFogiv( pname, params ); +} + +static void APIENTRY logFrontFace(GLenum mode) +{ + SIG( "glFrontFace" ); + dllFrontFace( mode ); +} + +static void APIENTRY logFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) +{ + SIG( "glFrustum" ); + dllFrustum( left, right, bottom, top, zNear, zFar ); +} + +static GLuint APIENTRY logGenLists(GLsizei range) +{ + SIG( "glGenLists" ); + return dllGenLists( range ); +} + +static void APIENTRY logGenTextures(GLsizei n, GLuint *textures) +{ + SIG( "glGenTextures" ); + dllGenTextures( n, textures ); +} + +static void APIENTRY logGetBooleanv(GLenum pname, GLboolean *params) +{ + SIG( "glGetBooleanv" ); + dllGetBooleanv( pname, params ); +} + +static void APIENTRY logGetClipPlane(GLenum plane, GLdouble *equation) +{ + SIG( "glGetClipPlane" ); + dllGetClipPlane( plane, equation ); +} + +static void APIENTRY logGetDoublev(GLenum pname, GLdouble *params) +{ + SIG( "glGetDoublev" ); + dllGetDoublev( pname, params ); +} + +static GLenum APIENTRY logGetError(void) +{ + SIG( "glGetError" ); + return dllGetError(); +} + +static void APIENTRY logGetFloatv(GLenum pname, GLfloat *params) +{ + SIG( "glGetFloatv" ); + dllGetFloatv( pname, params ); +} + +static void APIENTRY logGetIntegerv(GLenum pname, GLint *params) +{ + SIG( "glGetIntegerv" ); + dllGetIntegerv( pname, params ); +} + +static void APIENTRY logGetLightfv(GLenum light, GLenum pname, GLfloat *params) +{ + SIG( "glGetLightfv" ); + dllGetLightfv( light, pname, params ); +} + +static void APIENTRY logGetLightiv(GLenum light, GLenum pname, GLint *params) +{ + SIG( "glGetLightiv" ); + dllGetLightiv( light, pname, params ); +} + +static void APIENTRY logGetMapdv(GLenum target, GLenum query, GLdouble *v) +{ + SIG( "glGetMapdv" ); + dllGetMapdv( target, query, v ); +} + +static void APIENTRY logGetMapfv(GLenum target, GLenum query, GLfloat *v) +{ + SIG( "glGetMapfv" ); + dllGetMapfv( target, query, v ); +} + +static void APIENTRY logGetMapiv(GLenum target, GLenum query, GLint *v) +{ + SIG( "glGetMapiv" ); + dllGetMapiv( target, query, v ); +} + +static void APIENTRY logGetMaterialfv(GLenum face, GLenum pname, GLfloat *params) +{ + SIG( "glGetMaterialfv" ); + dllGetMaterialfv( face, pname, params ); +} + +static void APIENTRY logGetMaterialiv(GLenum face, GLenum pname, GLint *params) +{ + SIG( "glGetMaterialiv" ); + dllGetMaterialiv( face, pname, params ); +} + +static void APIENTRY logGetPixelMapfv(GLenum map, GLfloat *values) +{ + SIG( "glGetPixelMapfv" ); + dllGetPixelMapfv( map, values ); +} + +static void APIENTRY logGetPixelMapuiv(GLenum map, GLuint *values) +{ + SIG( "glGetPixelMapuiv" ); + dllGetPixelMapuiv( map, values ); +} + +static void APIENTRY logGetPixelMapusv(GLenum map, GLushort *values) +{ + SIG( "glGetPixelMapusv" ); + dllGetPixelMapusv( map, values ); +} + +static void APIENTRY logGetPointerv(GLenum pname, GLvoid* *params) +{ + SIG( "glGetPointerv" ); + dllGetPointerv( pname, params ); +} + +static void APIENTRY logGetPolygonStipple(GLubyte *mask) +{ + SIG( "glGetPolygonStipple" ); + dllGetPolygonStipple( mask ); +} + +static const GLubyte * APIENTRY logGetString(GLenum name) +{ + SIG( "glGetString" ); + return dllGetString( name ); +} + +static void APIENTRY logGetTexEnvfv(GLenum target, GLenum pname, GLfloat *params) +{ + SIG( "glGetTexEnvfv" ); + dllGetTexEnvfv( target, pname, params ); +} + +static void APIENTRY logGetTexEnviv(GLenum target, GLenum pname, GLint *params) +{ + SIG( "glGetTexEnviv" ); + dllGetTexEnviv( target, pname, params ); +} + +static void APIENTRY logGetTexGendv(GLenum coord, GLenum pname, GLdouble *params) +{ + SIG( "glGetTexGendv" ); + dllGetTexGendv( coord, pname, params ); +} + +static void APIENTRY logGetTexGenfv(GLenum coord, GLenum pname, GLfloat *params) +{ + SIG( "glGetTexGenfv" ); + dllGetTexGenfv( coord, pname, params ); +} + +static void APIENTRY logGetTexGeniv(GLenum coord, GLenum pname, GLint *params) +{ + SIG( "glGetTexGeniv" ); + dllGetTexGeniv( coord, pname, params ); +} + +static void APIENTRY logGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void *pixels) +{ + SIG( "glGetTexImage" ); + dllGetTexImage( target, level, format, type, pixels ); +} +static void APIENTRY logGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params ) +{ + SIG( "glGetTexLevelParameterfv" ); + dllGetTexLevelParameterfv( target, level, pname, params ); +} + +static void APIENTRY logGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) +{ + SIG( "glGetTexLevelParameteriv" ); + dllGetTexLevelParameteriv( target, level, pname, params ); +} + +static void APIENTRY logGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params) +{ + SIG( "glGetTexParameterfv" ); + dllGetTexParameterfv( target, pname, params ); +} + +static void APIENTRY logGetTexParameteriv(GLenum target, GLenum pname, GLint *params) +{ + SIG( "glGetTexParameteriv" ); + dllGetTexParameteriv( target, pname, params ); +} + +static void APIENTRY logHint(GLenum target, GLenum mode) +{ + fprintf( log_fp, "glHint( 0x%x, 0x%x )\n", target, mode ); + dllHint( target, mode ); +} + +static void APIENTRY logIndexMask(GLuint mask) +{ + SIG( "glIndexMask" ); + dllIndexMask( mask ); +} + +static void APIENTRY logIndexPointer(GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glIndexPointer" ); + dllIndexPointer( type, stride, pointer ); +} + +static void APIENTRY logIndexd(GLdouble c) +{ + SIG( "glIndexd" ); + dllIndexd( c ); +} + +static void APIENTRY logIndexdv(const GLdouble *c) +{ + SIG( "glIndexdv" ); + dllIndexdv( c ); +} + +static void APIENTRY logIndexf(GLfloat c) +{ + SIG( "glIndexf" ); + dllIndexf( c ); +} + +static void APIENTRY logIndexfv(const GLfloat *c) +{ + SIG( "glIndexfv" ); + dllIndexfv( c ); +} + +static void APIENTRY logIndexi(GLint c) +{ + SIG( "glIndexi" ); + dllIndexi( c ); +} + +static void APIENTRY logIndexiv(const GLint *c) +{ + SIG( "glIndexiv" ); + dllIndexiv( c ); +} + +static void APIENTRY logIndexs(GLshort c) +{ + SIG( "glIndexs" ); + dllIndexs( c ); +} + +static void APIENTRY logIndexsv(const GLshort *c) +{ + SIG( "glIndexsv" ); + dllIndexsv( c ); +} + +static void APIENTRY logIndexub(GLubyte c) +{ + SIG( "glIndexub" ); + dllIndexub( c ); +} + +static void APIENTRY logIndexubv(const GLubyte *c) +{ + SIG( "glIndexubv" ); + dllIndexubv( c ); +} + +static void APIENTRY logInitNames(void) +{ + SIG( "glInitNames" ); + dllInitNames(); +} + +static void APIENTRY logInterleavedArrays(GLenum format, GLsizei stride, const void *pointer) +{ + SIG( "glInterleavedArrays" ); + dllInterleavedArrays( format, stride, pointer ); +} + +static GLboolean APIENTRY logIsEnabled(GLenum cap) +{ + SIG( "glIsEnabled" ); + return dllIsEnabled( cap ); +} +static GLboolean APIENTRY logIsList(GLuint list) +{ + SIG( "glIsList" ); + return dllIsList( list ); +} +static GLboolean APIENTRY logIsTexture(GLuint texture) +{ + SIG( "glIsTexture" ); + return dllIsTexture( texture ); +} + +static void APIENTRY logLightModelf(GLenum pname, GLfloat param) +{ + SIG( "glLightModelf" ); + dllLightModelf( pname, param ); +} + +static void APIENTRY logLightModelfv(GLenum pname, const GLfloat *params) +{ + SIG( "glLightModelfv" ); + dllLightModelfv( pname, params ); +} + +static void APIENTRY logLightModeli(GLenum pname, GLint param) +{ + SIG( "glLightModeli" ); + dllLightModeli( pname, param ); + +} + +static void APIENTRY logLightModeliv(GLenum pname, const GLint *params) +{ + SIG( "glLightModeliv" ); + dllLightModeliv( pname, params ); +} + +static void APIENTRY logLightf(GLenum light, GLenum pname, GLfloat param) +{ + SIG( "glLightf" ); + dllLightf( light, pname, param ); +} + +static void APIENTRY logLightfv(GLenum light, GLenum pname, const GLfloat *params) +{ + SIG( "glLightfv" ); + dllLightfv( light, pname, params ); +} + +static void APIENTRY logLighti(GLenum light, GLenum pname, GLint param) +{ + SIG( "glLighti" ); + dllLighti( light, pname, param ); +} + +static void APIENTRY logLightiv(GLenum light, GLenum pname, const GLint *params) +{ + SIG( "glLightiv" ); + dllLightiv( light, pname, params ); +} + +static void APIENTRY logLineStipple(GLint factor, GLushort pattern) +{ + SIG( "glLineStipple" ); + dllLineStipple( factor, pattern ); +} + +static void APIENTRY logLineWidth(GLfloat width) +{ + SIG( "glLineWidth" ); + dllLineWidth( width ); +} + +static void APIENTRY logListBase(GLuint base) +{ + SIG( "glListBase" ); + dllListBase( base ); +} + +static void APIENTRY logLoadIdentity(void) +{ + SIG( "glLoadIdentity" ); + dllLoadIdentity(); +} + +static void APIENTRY logLoadMatrixd(const GLdouble *m) +{ + SIG( "glLoadMatrixd" ); + dllLoadMatrixd( m ); +} + +static void APIENTRY logLoadMatrixf(const GLfloat *m) +{ + SIG( "glLoadMatrixf" ); + dllLoadMatrixf( m ); +} + +static void APIENTRY logLoadName(GLuint name) +{ + SIG( "glLoadName" ); + dllLoadName( name ); +} + +static void APIENTRY logLogicOp(GLenum opcode) +{ + SIG( "glLogicOp" ); + dllLogicOp( opcode ); +} + +static void APIENTRY logMap1d(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points) +{ + SIG( "glMap1d" ); + dllMap1d( target, u1, u2, stride, order, points ); +} + +static void APIENTRY logMap1f(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points) +{ + SIG( "glMap1f" ); + dllMap1f( target, u1, u2, stride, order, points ); +} + +static void APIENTRY logMap2d(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points) +{ + SIG( "glMap2d" ); + dllMap2d( target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points ); +} + +static void APIENTRY logMap2f(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points) +{ + SIG( "glMap2f" ); + dllMap2f( target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points ); +} + +static void APIENTRY logMapGrid1d(GLint un, GLdouble u1, GLdouble u2) +{ + SIG( "glMapGrid1d" ); + dllMapGrid1d( un, u1, u2 ); +} + +static void APIENTRY logMapGrid1f(GLint un, GLfloat u1, GLfloat u2) +{ + SIG( "glMapGrid1f" ); + dllMapGrid1f( un, u1, u2 ); +} + +static void APIENTRY logMapGrid2d(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2) +{ + SIG( "glMapGrid2d" ); + dllMapGrid2d( un, u1, u2, vn, v1, v2 ); +} +static void APIENTRY logMapGrid2f(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2) +{ + SIG( "glMapGrid2f" ); + dllMapGrid2f( un, u1, u2, vn, v1, v2 ); +} +static void APIENTRY logMaterialf(GLenum face, GLenum pname, GLfloat param) +{ + SIG( "glMaterialf" ); + dllMaterialf( face, pname, param ); +} +static void APIENTRY logMaterialfv(GLenum face, GLenum pname, const GLfloat *params) +{ + SIG( "glMaterialfv" ); + dllMaterialfv( face, pname, params ); +} + +static void APIENTRY logMateriali(GLenum face, GLenum pname, GLint param) +{ + SIG( "glMateriali" ); + dllMateriali( face, pname, param ); +} + +static void APIENTRY logMaterialiv(GLenum face, GLenum pname, const GLint *params) +{ + SIG( "glMaterialiv" ); + dllMaterialiv( face, pname, params ); +} + +static void APIENTRY logMatrixMode(GLenum mode) +{ + SIG( "glMatrixMode" ); + dllMatrixMode( mode ); +} + +static void APIENTRY logMultMatrixd(const GLdouble *m) +{ + SIG( "glMultMatrixd" ); + dllMultMatrixd( m ); +} + +static void APIENTRY logMultMatrixf(const GLfloat *m) +{ + SIG( "glMultMatrixf" ); + dllMultMatrixf( m ); +} + +static void APIENTRY logNewList(GLuint list, GLenum mode) +{ + SIG( "glNewList" ); + dllNewList( list, mode ); +} + +static void APIENTRY logNormal3b(GLbyte nx, GLbyte ny, GLbyte nz) +{ + SIG ("glNormal3b" ); + dllNormal3b( nx, ny, nz ); +} + +static void APIENTRY logNormal3bv(const GLbyte *v) +{ + SIG( "glNormal3bv" ); + dllNormal3bv( v ); +} + +static void APIENTRY logNormal3d(GLdouble nx, GLdouble ny, GLdouble nz) +{ + SIG( "glNormal3d" ); + dllNormal3d( nx, ny, nz ); +} + +static void APIENTRY logNormal3dv(const GLdouble *v) +{ + SIG( "glNormal3dv" ); + dllNormal3dv( v ); +} + +static void APIENTRY logNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) +{ + SIG( "glNormal3f" ); + dllNormal3f( nx, ny, nz ); +} + +static void APIENTRY logNormal3fv(const GLfloat *v) +{ + SIG( "glNormal3fv" ); + dllNormal3fv( v ); +} +static void APIENTRY logNormal3i(GLint nx, GLint ny, GLint nz) +{ + SIG( "glNormal3i" ); + dllNormal3i( nx, ny, nz ); +} +static void APIENTRY logNormal3iv(const GLint *v) +{ + SIG( "glNormal3iv" ); + dllNormal3iv( v ); +} +static void APIENTRY logNormal3s(GLshort nx, GLshort ny, GLshort nz) +{ + SIG( "glNormal3s" ); + dllNormal3s( nx, ny, nz ); +} +static void APIENTRY logNormal3sv(const GLshort *v) +{ + SIG( "glNormal3sv" ); + dllNormal3sv( v ); +} +static void APIENTRY logNormalPointer(GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glNormalPointer" ); + dllNormalPointer( type, stride, pointer ); +} +static void APIENTRY logOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) +{ + SIG( "glOrtho" ); + dllOrtho( left, right, bottom, top, zNear, zFar ); +} + +static void APIENTRY logPassThrough(GLfloat token) +{ + SIG( "glPassThrough" ); + dllPassThrough( token ); +} + +static void APIENTRY logPixelMapfv(GLenum map, GLsizei mapsize, const GLfloat *values) +{ + SIG( "glPixelMapfv" ); + dllPixelMapfv( map, mapsize, values ); +} + +static void APIENTRY logPixelMapuiv(GLenum map, GLsizei mapsize, const GLuint *values) +{ + SIG( "glPixelMapuiv" ); + dllPixelMapuiv( map, mapsize, values ); +} + +static void APIENTRY logPixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values) +{ + SIG( "glPixelMapusv" ); + dllPixelMapusv( map, mapsize, values ); +} +static void APIENTRY logPixelStoref(GLenum pname, GLfloat param) +{ + SIG( "glPixelStoref" ); + dllPixelStoref( pname, param ); +} +static void APIENTRY logPixelStorei(GLenum pname, GLint param) +{ + SIG( "glPixelStorei" ); + dllPixelStorei( pname, param ); +} +static void APIENTRY logPixelTransferf(GLenum pname, GLfloat param) +{ + SIG( "glPixelTransferf" ); + dllPixelTransferf( pname, param ); +} + +static void APIENTRY logPixelTransferi(GLenum pname, GLint param) +{ + SIG( "glPixelTransferi" ); + dllPixelTransferi( pname, param ); +} + +static void APIENTRY logPixelZoom(GLfloat xfactor, GLfloat yfactor) +{ + SIG( "glPixelZoom" ); + dllPixelZoom( xfactor, yfactor ); +} + +static void APIENTRY logPointSize(GLfloat size) +{ + SIG( "glPointSize" ); + dllPointSize( size ); +} + +static void APIENTRY logPolygonMode(GLenum face, GLenum mode) +{ + fprintf( log_fp, "glPolygonMode( 0x%x, 0x%x )\n", face, mode ); + dllPolygonMode( face, mode ); +} + +static void APIENTRY logPolygonOffset(GLfloat factor, GLfloat units) +{ + SIG( "glPolygonOffset" ); + dllPolygonOffset( factor, units ); +} +static void APIENTRY logPolygonStipple(const GLubyte *mask ) +{ + SIG( "glPolygonStipple" ); + dllPolygonStipple( mask ); +} +static void APIENTRY logPopAttrib(void) +{ + SIG( "glPopAttrib" ); + dllPopAttrib(); +} + +static void APIENTRY logPopClientAttrib(void) +{ + SIG( "glPopClientAttrib" ); + dllPopClientAttrib(); +} + +static void APIENTRY logPopMatrix(void) +{ + SIG( "glPopMatrix" ); + dllPopMatrix(); +} + +static void APIENTRY logPopName(void) +{ + SIG( "glPopName" ); + dllPopName(); +} + +static void APIENTRY logPrioritizeTextures(GLsizei n, const GLuint *textures, const GLclampf *priorities) +{ + SIG( "glPrioritizeTextures" ); + dllPrioritizeTextures( n, textures, priorities ); +} + +static void APIENTRY logPushAttrib(GLbitfield mask) +{ + SIG( "glPushAttrib" ); + dllPushAttrib( mask ); +} + +static void APIENTRY logPushClientAttrib(GLbitfield mask) +{ + SIG( "glPushClientAttrib" ); + dllPushClientAttrib( mask ); +} + +static void APIENTRY logPushMatrix(void) +{ + SIG( "glPushMatrix" ); + dllPushMatrix(); +} + +static void APIENTRY logPushName(GLuint name) +{ + SIG( "glPushName" ); + dllPushName( name ); +} + +static void APIENTRY logRasterPos2d(GLdouble x, GLdouble y) +{ + SIG ("glRasterPot2d" ); + dllRasterPos2d( x, y ); +} + +static void APIENTRY logRasterPos2dv(const GLdouble *v) +{ + SIG( "glRasterPos2dv" ); + dllRasterPos2dv( v ); +} + +static void APIENTRY logRasterPos2f(GLfloat x, GLfloat y) +{ + SIG( "glRasterPos2f" ); + dllRasterPos2f( x, y ); +} +static void APIENTRY logRasterPos2fv(const GLfloat *v) +{ + SIG( "glRasterPos2dv" ); + dllRasterPos2fv( v ); +} +static void APIENTRY logRasterPos2i(GLint x, GLint y) +{ + SIG( "glRasterPos2if" ); + dllRasterPos2i( x, y ); +} +static void APIENTRY logRasterPos2iv(const GLint *v) +{ + SIG( "glRasterPos2iv" ); + dllRasterPos2iv( v ); +} +static void APIENTRY logRasterPos2s(GLshort x, GLshort y) +{ + SIG( "glRasterPos2s" ); + dllRasterPos2s( x, y ); +} +static void APIENTRY logRasterPos2sv(const GLshort *v) +{ + SIG( "glRasterPos2sv" ); + dllRasterPos2sv( v ); +} +static void APIENTRY logRasterPos3d(GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glRasterPos3d" ); + dllRasterPos3d( x, y, z ); +} +static void APIENTRY logRasterPos3dv(const GLdouble *v) +{ + SIG( "glRasterPos3dv" ); + dllRasterPos3dv( v ); +} +static void APIENTRY logRasterPos3f(GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glRasterPos3f" ); + dllRasterPos3f( x, y, z ); +} +static void APIENTRY logRasterPos3fv(const GLfloat *v) +{ + SIG( "glRasterPos3fv" ); + dllRasterPos3fv( v ); +} +static void APIENTRY logRasterPos3i(GLint x, GLint y, GLint z) +{ + SIG( "glRasterPos3i" ); + dllRasterPos3i( x, y, z ); +} +static void APIENTRY logRasterPos3iv(const GLint *v) +{ + SIG( "glRasterPos3iv" ); + dllRasterPos3iv( v ); +} +static void APIENTRY logRasterPos3s(GLshort x, GLshort y, GLshort z) +{ + SIG( "glRasterPos3s" ); + dllRasterPos3s( x, y, z ); +} +static void APIENTRY logRasterPos3sv(const GLshort *v) +{ + SIG( "glRasterPos3sv" ); + dllRasterPos3sv( v ); +} +static void APIENTRY logRasterPos4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + SIG( "glRasterPos4d" ); + dllRasterPos4d( x, y, z, w ); +} +static void APIENTRY logRasterPos4dv(const GLdouble *v) +{ + SIG( "glRasterPos4dv" ); + dllRasterPos4dv( v ); +} +static void APIENTRY logRasterPos4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + SIG( "glRasterPos4f" ); + dllRasterPos4f( x, y, z, w ); +} +static void APIENTRY logRasterPos4fv(const GLfloat *v) +{ + SIG( "glRasterPos4fv" ); + dllRasterPos4fv( v ); +} +static void APIENTRY logRasterPos4i(GLint x, GLint y, GLint z, GLint w) +{ + SIG( "glRasterPos4i" ); + dllRasterPos4i( x, y, z, w ); +} +static void APIENTRY logRasterPos4iv(const GLint *v) +{ + SIG( "glRasterPos4iv" ); + dllRasterPos4iv( v ); +} +static void APIENTRY logRasterPos4s(GLshort x, GLshort y, GLshort z, GLshort w) +{ + SIG( "glRasterPos4s" ); + dllRasterPos4s( x, y, z, w ); +} +static void APIENTRY logRasterPos4sv(const GLshort *v) +{ + SIG( "glRasterPos4sv" ); + dllRasterPos4sv( v ); +} +static void APIENTRY logReadBuffer(GLenum mode) +{ + SIG( "glReadBuffer" ); + dllReadBuffer( mode ); +} +static void APIENTRY logReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) +{ + SIG( "glReadPixels" ); + dllReadPixels( x, y, width, height, format, type, pixels ); +} + +static void APIENTRY logRectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2) +{ + SIG( "glRectd" ); + dllRectd( x1, y1, x2, y2 ); +} + +static void APIENTRY logRectdv(const GLdouble *v1, const GLdouble *v2) +{ + SIG( "glRectdv" ); + dllRectdv( v1, v2 ); +} + +static void APIENTRY logRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) +{ + SIG( "glRectf" ); + dllRectf( x1, y1, x2, y2 ); +} + +static void APIENTRY logRectfv(const GLfloat *v1, const GLfloat *v2) +{ + SIG( "glRectfv" ); + dllRectfv( v1, v2 ); +} +static void APIENTRY logRecti(GLint x1, GLint y1, GLint x2, GLint y2) +{ + SIG( "glRecti" ); + dllRecti( x1, y1, x2, y2 ); +} +static void APIENTRY logRectiv(const GLint *v1, const GLint *v2) +{ + SIG( "glRectiv" ); + dllRectiv( v1, v2 ); +} +static void APIENTRY logRects(GLshort x1, GLshort y1, GLshort x2, GLshort y2) +{ + SIG( "glRects" ); + dllRects( x1, y1, x2, y2 ); +} +static void APIENTRY logRectsv(const GLshort *v1, const GLshort *v2) +{ + SIG( "glRectsv" ); + dllRectsv( v1, v2 ); +} +static GLint APIENTRY logRenderMode(GLenum mode) +{ + SIG( "glRenderMode" ); + return dllRenderMode( mode ); +} +static void APIENTRY logRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glRotated" ); + dllRotated( angle, x, y, z ); +} + +static void APIENTRY logRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glRotatef" ); + dllRotatef( angle, x, y, z ); +} + +static void APIENTRY logScaled(GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glScaled" ); + dllScaled( x, y, z ); +} + +static void APIENTRY logScalef(GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glScalef" ); + dllScalef( x, y, z ); +} + +static void APIENTRY logScissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ + SIG( "glScissor" ); + dllScissor( x, y, width, height ); +} + +static void APIENTRY logSelectBuffer(GLsizei size, GLuint *buffer) +{ + SIG( "glSelectBuffer" ); + dllSelectBuffer( size, buffer ); +} + +static void APIENTRY logShadeModel(GLenum mode) +{ + SIG( "glShadeModel" ); + dllShadeModel( mode ); +} + +static void APIENTRY logStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + SIG( "glStencilFunc" ); + dllStencilFunc( func, ref, mask ); +} + +static void APIENTRY logStencilMask(GLuint mask) +{ + SIG( "glStencilMask" ); + dllStencilMask( mask ); +} + +static void APIENTRY logStencilOp(GLenum fail, GLenum zfail, GLenum zpass) +{ + SIG( "glStencilOp" ); + dllStencilOp( fail, zfail, zpass ); +} + +static void APIENTRY logTexCoord1d(GLdouble s) +{ + SIG( "glTexCoord1d" ); + dllTexCoord1d( s ); +} + +static void APIENTRY logTexCoord1dv(const GLdouble *v) +{ + SIG( "glTexCoord1dv" ); + dllTexCoord1dv( v ); +} + +static void APIENTRY logTexCoord1f(GLfloat s) +{ + SIG( "glTexCoord1f" ); + dllTexCoord1f( s ); +} +static void APIENTRY logTexCoord1fv(const GLfloat *v) +{ + SIG( "glTexCoord1fv" ); + dllTexCoord1fv( v ); +} +static void APIENTRY logTexCoord1i(GLint s) +{ + SIG( "glTexCoord1i" ); + dllTexCoord1i( s ); +} +static void APIENTRY logTexCoord1iv(const GLint *v) +{ + SIG( "glTexCoord1iv" ); + dllTexCoord1iv( v ); +} +static void APIENTRY logTexCoord1s(GLshort s) +{ + SIG( "glTexCoord1s" ); + dllTexCoord1s( s ); +} +static void APIENTRY logTexCoord1sv(const GLshort *v) +{ + SIG( "glTexCoord1sv" ); + dllTexCoord1sv( v ); +} +static void APIENTRY logTexCoord2d(GLdouble s, GLdouble t) +{ + SIG( "glTexCoord2d" ); + dllTexCoord2d( s, t ); +} + +static void APIENTRY logTexCoord2dv(const GLdouble *v) +{ + SIG( "glTexCoord2dv" ); + dllTexCoord2dv( v ); +} +static void APIENTRY logTexCoord2f(GLfloat s, GLfloat t) +{ + SIG( "glTexCoord2f" ); + dllTexCoord2f( s, t ); +} +static void APIENTRY logTexCoord2fv(const GLfloat *v) +{ + SIG( "glTexCoord2fv" ); + dllTexCoord2fv( v ); +} +static void APIENTRY logTexCoord2i(GLint s, GLint t) +{ + SIG( "glTexCoord2i" ); + dllTexCoord2i( s, t ); +} +static void APIENTRY logTexCoord2iv(const GLint *v) +{ + SIG( "glTexCoord2iv" ); + dllTexCoord2iv( v ); +} +static void APIENTRY logTexCoord2s(GLshort s, GLshort t) +{ + SIG( "glTexCoord2s" ); + dllTexCoord2s( s, t ); +} +static void APIENTRY logTexCoord2sv(const GLshort *v) +{ + SIG( "glTexCoord2sv" ); + dllTexCoord2sv( v ); +} +static void APIENTRY logTexCoord3d(GLdouble s, GLdouble t, GLdouble r) +{ + SIG( "glTexCoord3d" ); + dllTexCoord3d( s, t, r ); +} +static void APIENTRY logTexCoord3dv(const GLdouble *v) +{ + SIG( "glTexCoord3dv" ); + dllTexCoord3dv( v ); +} +static void APIENTRY logTexCoord3f(GLfloat s, GLfloat t, GLfloat r) +{ + SIG( "glTexCoord3f" ); + dllTexCoord3f( s, t, r ); +} +static void APIENTRY logTexCoord3fv(const GLfloat *v) +{ + SIG( "glTexCoord3fv" ); + dllTexCoord3fv( v ); +} +static void APIENTRY logTexCoord3i(GLint s, GLint t, GLint r) +{ + SIG( "glTexCoord3i" ); + dllTexCoord3i( s, t, r ); +} +static void APIENTRY logTexCoord3iv(const GLint *v) +{ + SIG( "glTexCoord3iv" ); + dllTexCoord3iv( v ); +} +static void APIENTRY logTexCoord3s(GLshort s, GLshort t, GLshort r) +{ + SIG( "glTexCoord3s" ); + dllTexCoord3s( s, t, r ); +} +static void APIENTRY logTexCoord3sv(const GLshort *v) +{ + SIG( "glTexCoord3sv" ); + dllTexCoord3sv( v ); +} +static void APIENTRY logTexCoord4d(GLdouble s, GLdouble t, GLdouble r, GLdouble q) +{ + SIG( "glTexCoord4d" ); + dllTexCoord4d( s, t, r, q ); +} +static void APIENTRY logTexCoord4dv(const GLdouble *v) +{ + SIG( "glTexCoord4dv" ); + dllTexCoord4dv( v ); +} +static void APIENTRY logTexCoord4f(GLfloat s, GLfloat t, GLfloat r, GLfloat q) +{ + SIG( "glTexCoord4f" ); + dllTexCoord4f( s, t, r, q ); +} +static void APIENTRY logTexCoord4fv(const GLfloat *v) +{ + SIG( "glTexCoord4fv" ); + dllTexCoord4fv( v ); +} +static void APIENTRY logTexCoord4i(GLint s, GLint t, GLint r, GLint q) +{ + SIG( "glTexCoord4i" ); + dllTexCoord4i( s, t, r, q ); +} +static void APIENTRY logTexCoord4iv(const GLint *v) +{ + SIG( "glTexCoord4iv" ); + dllTexCoord4iv( v ); +} +static void APIENTRY logTexCoord4s(GLshort s, GLshort t, GLshort r, GLshort q) +{ + SIG( "glTexCoord4s" ); + dllTexCoord4s( s, t, r, q ); +} +static void APIENTRY logTexCoord4sv(const GLshort *v) +{ + SIG( "glTexCoord4sv" ); + dllTexCoord4sv( v ); +} +static void APIENTRY logTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glTexCoordPointer" ); + dllTexCoordPointer( size, type, stride, pointer ); +} + +static void APIENTRY logTexEnvf(GLenum target, GLenum pname, GLfloat param) +{ + fprintf( log_fp, "glTexEnvf( 0x%x, 0x%x, %f )\n", target, pname, param ); + dllTexEnvf( target, pname, param ); +} + +static void APIENTRY logTexEnvfv(GLenum target, GLenum pname, const GLfloat *params) +{ + SIG( "glTexEnvfv" ); + dllTexEnvfv( target, pname, params ); +} + +static void APIENTRY logTexEnvi(GLenum target, GLenum pname, GLint param) +{ + fprintf( log_fp, "glTexEnvi( 0x%x, 0x%x, 0x%x )\n", target, pname, param ); + dllTexEnvi( target, pname, param ); +} +static void APIENTRY logTexEnviv(GLenum target, GLenum pname, const GLint *params) +{ + SIG( "glTexEnviv" ); + dllTexEnviv( target, pname, params ); +} + +static void APIENTRY logTexGend(GLenum coord, GLenum pname, GLdouble param) +{ + SIG( "glTexGend" ); + dllTexGend( coord, pname, param ); +} + +static void APIENTRY logTexGendv(GLenum coord, GLenum pname, const GLdouble *params) +{ + SIG( "glTexGendv" ); + dllTexGendv( coord, pname, params ); +} + +static void APIENTRY logTexGenf(GLenum coord, GLenum pname, GLfloat param) +{ + SIG( "glTexGenf" ); + dllTexGenf( coord, pname, param ); +} +static void APIENTRY logTexGenfv(GLenum coord, GLenum pname, const GLfloat *params) +{ + SIG( "glTexGenfv" ); + dllTexGenfv( coord, pname, params ); +} +static void APIENTRY logTexGeni(GLenum coord, GLenum pname, GLint param) +{ + SIG( "glTexGeni" ); + dllTexGeni( coord, pname, param ); +} +static void APIENTRY logTexGeniv(GLenum coord, GLenum pname, const GLint *params) +{ + SIG( "glTexGeniv" ); + dllTexGeniv( coord, pname, params ); +} +static void APIENTRY logTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glTexImage1D" ); + dllTexImage1D( target, level, internalformat, width, border, format, type, pixels ); +} +static void APIENTRY logTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glTexImage2D" ); + dllTexImage2D( target, level, internalformat, width, height, border, format, type, pixels ); +} + +static void APIENTRY logTexParameterf(GLenum target, GLenum pname, GLfloat param) +{ + fprintf( log_fp, "glTexParameterf( 0x%x, 0x%x, %f )\n", target, pname, param ); + dllTexParameterf( target, pname, param ); +} + +static void APIENTRY logTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) +{ + SIG( "glTexParameterfv" ); + dllTexParameterfv( target, pname, params ); +} +static void APIENTRY logTexParameteri(GLenum target, GLenum pname, GLint param) +{ + fprintf( log_fp, "glTexParameteri( 0x%x, 0x%x, 0x%x )\n", target, pname, param ); + dllTexParameteri( target, pname, param ); +} +static void APIENTRY logTexParameteriv(GLenum target, GLenum pname, const GLint *params) +{ + SIG( "glTexParameteriv" ); + dllTexParameteriv( target, pname, params ); +} +static void APIENTRY logTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glTexSubImage1D" ); + dllTexSubImage1D( target, level, xoffset, width, format, type, pixels ); +} +static void APIENTRY logTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glTexSubImage2D" ); + dllTexSubImage2D( target, level, xoffset, yoffset, width, height, format, type, pixels ); +} +static void APIENTRY logTranslated(GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glTranslated" ); + dllTranslated( x, y, z ); +} + +static void APIENTRY logTranslatef(GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glTranslatef" ); + dllTranslatef( x, y, z ); +} + +static void APIENTRY logVertex2d(GLdouble x, GLdouble y) +{ + SIG( "glVertex2d" ); + dllVertex2d( x, y ); +} + +static void APIENTRY logVertex2dv(const GLdouble *v) +{ + SIG( "glVertex2dv" ); + dllVertex2dv( v ); +} +static void APIENTRY logVertex2f(GLfloat x, GLfloat y) +{ + SIG( "glVertex2f" ); + dllVertex2f( x, y ); +} +static void APIENTRY logVertex2fv(const GLfloat *v) +{ + SIG( "glVertex2fv" ); + dllVertex2fv( v ); +} +static void APIENTRY logVertex2i(GLint x, GLint y) +{ + SIG( "glVertex2i" ); + dllVertex2i( x, y ); +} +static void APIENTRY logVertex2iv(const GLint *v) +{ + SIG( "glVertex2iv" ); + dllVertex2iv( v ); +} +static void APIENTRY logVertex2s(GLshort x, GLshort y) +{ + SIG( "glVertex2s" ); + dllVertex2s( x, y ); +} +static void APIENTRY logVertex2sv(const GLshort *v) +{ + SIG( "glVertex2sv" ); + dllVertex2sv( v ); +} +static void APIENTRY logVertex3d(GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glVertex3d" ); + dllVertex3d( x, y, z ); +} +static void APIENTRY logVertex3dv(const GLdouble *v) +{ + SIG( "glVertex3dv" ); + dllVertex3dv( v ); +} +static void APIENTRY logVertex3f(GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glVertex3f" ); + dllVertex3f( x, y, z ); +} +static void APIENTRY logVertex3fv(const GLfloat *v) +{ + SIG( "glVertex3fv" ); + dllVertex3fv( v ); +} +static void APIENTRY logVertex3i(GLint x, GLint y, GLint z) +{ + SIG( "glVertex3i" ); + dllVertex3i( x, y, z ); +} +static void APIENTRY logVertex3iv(const GLint *v) +{ + SIG( "glVertex3iv" ); + dllVertex3iv( v ); +} +static void APIENTRY logVertex3s(GLshort x, GLshort y, GLshort z) +{ + SIG( "glVertex3s" ); + dllVertex3s( x, y, z ); +} +static void APIENTRY logVertex3sv(const GLshort *v) +{ + SIG( "glVertex3sv" ); + dllVertex3sv( v ); +} +static void APIENTRY logVertex4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + SIG( "glVertex4d" ); + dllVertex4d( x, y, z, w ); +} +static void APIENTRY logVertex4dv(const GLdouble *v) +{ + SIG( "glVertex4dv" ); + dllVertex4dv( v ); +} +static void APIENTRY logVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + SIG( "glVertex4f" ); + dllVertex4f( x, y, z, w ); +} +static void APIENTRY logVertex4fv(const GLfloat *v) +{ + SIG( "glVertex4fv" ); + dllVertex4fv( v ); +} +static void APIENTRY logVertex4i(GLint x, GLint y, GLint z, GLint w) +{ + SIG( "glVertex4i" ); + dllVertex4i( x, y, z, w ); +} +static void APIENTRY logVertex4iv(const GLint *v) +{ + SIG( "glVertex4iv" ); + dllVertex4iv( v ); +} +static void APIENTRY logVertex4s(GLshort x, GLshort y, GLshort z, GLshort w) +{ + SIG( "glVertex4s" ); + dllVertex4s( x, y, z, w ); +} +static void APIENTRY logVertex4sv(const GLshort *v) +{ + SIG( "glVertex4sv" ); + dllVertex4sv( v ); +} +static void APIENTRY logVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glVertexPointer" ); + dllVertexPointer( size, type, stride, pointer ); +} +static void APIENTRY logViewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + SIG( "glViewport" ); + dllViewport( x, y, width, height ); +} + +/* +** QGL_Shutdown +** +** Unloads the specified DLL then nulls out all the proc pointers. +*/ +void QGL_Shutdown( void ) +{ + qglAccum = NULL; + qglAlphaFunc = NULL; + qglAreTexturesResident = NULL; + qglArrayElement = NULL; + qglBegin = NULL; + qglBindTexture = NULL; + qglBitmap = NULL; + qglBlendFunc = NULL; + qglCallList = NULL; + qglCallLists = NULL; + qglClear = NULL; + qglClearAccum = NULL; + qglClearColor = NULL; + qglClearDepth = NULL; + qglClearIndex = NULL; + qglClearStencil = NULL; + qglClipPlane = NULL; + qglColor3b = NULL; + qglColor3bv = NULL; + qglColor3d = NULL; + qglColor3dv = NULL; + qglColor3f = NULL; + qglColor3fv = NULL; + qglColor3i = NULL; + qglColor3iv = NULL; + qglColor3s = NULL; + qglColor3sv = NULL; + qglColor3ub = NULL; + qglColor3ubv = NULL; + qglColor3ui = NULL; + qglColor3uiv = NULL; + qglColor3us = NULL; + qglColor3usv = NULL; + qglColor4b = NULL; + qglColor4bv = NULL; + qglColor4d = NULL; + qglColor4dv = NULL; + qglColor4f = NULL; + qglColor4fv = NULL; + qglColor4i = NULL; + qglColor4iv = NULL; + qglColor4s = NULL; + qglColor4sv = NULL; + qglColor4ub = NULL; + qglColor4ubv = NULL; + qglColor4ui = NULL; + qglColor4uiv = NULL; + qglColor4us = NULL; + qglColor4usv = NULL; + qglColorMask = NULL; + qglColorMaterial = NULL; + qglColorPointer = NULL; + qglCopyPixels = NULL; + qglCopyTexImage1D = NULL; + qglCopyTexImage2D = NULL; + qglCopyTexSubImage1D = NULL; + qglCopyTexSubImage2D = NULL; + qglCullFace = NULL; + qglDeleteLists = NULL; + qglDeleteTextures = NULL; + qglDepthFunc = NULL; + qglDepthMask = NULL; + qglDepthRange = NULL; + qglDisable = NULL; + qglDisableClientState = NULL; + qglDrawArrays = NULL; + qglDrawBuffer = NULL; + qglDrawElements = NULL; + qglDrawPixels = NULL; + qglEdgeFlag = NULL; + qglEdgeFlagPointer = NULL; + qglEdgeFlagv = NULL; + qglEnable = NULL; + qglEnableClientState = NULL; + qglEnd = NULL; + qglEndList = NULL; + qglEvalCoord1d = NULL; + qglEvalCoord1dv = NULL; + qglEvalCoord1f = NULL; + qglEvalCoord1fv = NULL; + qglEvalCoord2d = NULL; + qglEvalCoord2dv = NULL; + qglEvalCoord2f = NULL; + qglEvalCoord2fv = NULL; + qglEvalMesh1 = NULL; + qglEvalMesh2 = NULL; + qglEvalPoint1 = NULL; + qglEvalPoint2 = NULL; + qglFeedbackBuffer = NULL; + qglFinish = NULL; + qglFlush = NULL; + qglFogf = NULL; + qglFogfv = NULL; + qglFogi = NULL; + qglFogiv = NULL; + qglFrontFace = NULL; + qglFrustum = NULL; + qglGenLists = NULL; + qglGenTextures = NULL; + qglGetBooleanv = NULL; + qglGetClipPlane = NULL; + qglGetDoublev = NULL; + qglGetError = NULL; + qglGetFloatv = NULL; + qglGetIntegerv = NULL; + qglGetLightfv = NULL; + qglGetLightiv = NULL; + qglGetMapdv = NULL; + qglGetMapfv = NULL; + qglGetMapiv = NULL; + qglGetMaterialfv = NULL; + qglGetMaterialiv = NULL; + qglGetPixelMapfv = NULL; + qglGetPixelMapuiv = NULL; + qglGetPixelMapusv = NULL; + qglGetPointerv = NULL; + qglGetPolygonStipple = NULL; + qglGetString = NULL; + qglGetTexEnvfv = NULL; + qglGetTexEnviv = NULL; + qglGetTexGendv = NULL; + qglGetTexGenfv = NULL; + qglGetTexGeniv = NULL; + qglGetTexImage = NULL; + qglGetTexLevelParameterfv = NULL; + qglGetTexLevelParameteriv = NULL; + qglGetTexParameterfv = NULL; + qglGetTexParameteriv = NULL; + qglHint = NULL; + qglIndexMask = NULL; + qglIndexPointer = NULL; + qglIndexd = NULL; + qglIndexdv = NULL; + qglIndexf = NULL; + qglIndexfv = NULL; + qglIndexi = NULL; + qglIndexiv = NULL; + qglIndexs = NULL; + qglIndexsv = NULL; + qglIndexub = NULL; + qglIndexubv = NULL; + qglInitNames = NULL; + qglInterleavedArrays = NULL; + qglIsEnabled = NULL; + qglIsList = NULL; + qglIsTexture = NULL; + qglLightModelf = NULL; + qglLightModelfv = NULL; + qglLightModeli = NULL; + qglLightModeliv = NULL; + qglLightf = NULL; + qglLightfv = NULL; + qglLighti = NULL; + qglLightiv = NULL; + qglLineStipple = NULL; + qglLineWidth = NULL; + qglListBase = NULL; + qglLoadIdentity = NULL; + qglLoadMatrixd = NULL; + qglLoadMatrixf = NULL; + qglLoadName = NULL; + qglLogicOp = NULL; + qglMap1d = NULL; + qglMap1f = NULL; + qglMap2d = NULL; + qglMap2f = NULL; + qglMapGrid1d = NULL; + qglMapGrid1f = NULL; + qglMapGrid2d = NULL; + qglMapGrid2f = NULL; + qglMaterialf = NULL; + qglMaterialfv = NULL; + qglMateriali = NULL; + qglMaterialiv = NULL; + qglMatrixMode = NULL; + qglMultMatrixd = NULL; + qglMultMatrixf = NULL; + qglNewList = NULL; + qglNormal3b = NULL; + qglNormal3bv = NULL; + qglNormal3d = NULL; + qglNormal3dv = NULL; + qglNormal3f = NULL; + qglNormal3fv = NULL; + qglNormal3i = NULL; + qglNormal3iv = NULL; + qglNormal3s = NULL; + qglNormal3sv = NULL; + qglNormalPointer = NULL; + qglOrtho = NULL; + qglPassThrough = NULL; + qglPixelMapfv = NULL; + qglPixelMapuiv = NULL; + qglPixelMapusv = NULL; + qglPixelStoref = NULL; + qglPixelStorei = NULL; + qglPixelTransferf = NULL; + qglPixelTransferi = NULL; + qglPixelZoom = NULL; + qglPointSize = NULL; + qglPolygonMode = NULL; + qglPolygonOffset = NULL; + qglPolygonStipple = NULL; + qglPopAttrib = NULL; + qglPopClientAttrib = NULL; + qglPopMatrix = NULL; + qglPopName = NULL; + qglPrioritizeTextures = NULL; + qglPushAttrib = NULL; + qglPushClientAttrib = NULL; + qglPushMatrix = NULL; + qglPushName = NULL; + qglRasterPos2d = NULL; + qglRasterPos2dv = NULL; + qglRasterPos2f = NULL; + qglRasterPos2fv = NULL; + qglRasterPos2i = NULL; + qglRasterPos2iv = NULL; + qglRasterPos2s = NULL; + qglRasterPos2sv = NULL; + qglRasterPos3d = NULL; + qglRasterPos3dv = NULL; + qglRasterPos3f = NULL; + qglRasterPos3fv = NULL; + qglRasterPos3i = NULL; + qglRasterPos3iv = NULL; + qglRasterPos3s = NULL; + qglRasterPos3sv = NULL; + qglRasterPos4d = NULL; + qglRasterPos4dv = NULL; + qglRasterPos4f = NULL; + qglRasterPos4fv = NULL; + qglRasterPos4i = NULL; + qglRasterPos4iv = NULL; + qglRasterPos4s = NULL; + qglRasterPos4sv = NULL; + qglReadBuffer = NULL; + qglReadPixels = NULL; + qglRectd = NULL; + qglRectdv = NULL; + qglRectf = NULL; + qglRectfv = NULL; + qglRecti = NULL; + qglRectiv = NULL; + qglRects = NULL; + qglRectsv = NULL; + qglRenderMode = NULL; + qglRotated = NULL; + qglRotatef = NULL; + qglScaled = NULL; + qglScalef = NULL; + qglScissor = NULL; + qglSelectBuffer = NULL; + qglShadeModel = NULL; + qglStencilFunc = NULL; + qglStencilMask = NULL; + qglStencilOp = NULL; + qglTexCoord1d = NULL; + qglTexCoord1dv = NULL; + qglTexCoord1f = NULL; + qglTexCoord1fv = NULL; + qglTexCoord1i = NULL; + qglTexCoord1iv = NULL; + qglTexCoord1s = NULL; + qglTexCoord1sv = NULL; + qglTexCoord2d = NULL; + qglTexCoord2dv = NULL; + qglTexCoord2f = NULL; + qglTexCoord2fv = NULL; + qglTexCoord2i = NULL; + qglTexCoord2iv = NULL; + qglTexCoord2s = NULL; + qglTexCoord2sv = NULL; + qglTexCoord3d = NULL; + qglTexCoord3dv = NULL; + qglTexCoord3f = NULL; + qglTexCoord3fv = NULL; + qglTexCoord3i = NULL; + qglTexCoord3iv = NULL; + qglTexCoord3s = NULL; + qglTexCoord3sv = NULL; + qglTexCoord4d = NULL; + qglTexCoord4dv = NULL; + qglTexCoord4f = NULL; + qglTexCoord4fv = NULL; + qglTexCoord4i = NULL; + qglTexCoord4iv = NULL; + qglTexCoord4s = NULL; + qglTexCoord4sv = NULL; + qglTexCoordPointer = NULL; + qglTexEnvf = NULL; + qglTexEnvfv = NULL; + qglTexEnvi = NULL; + qglTexEnviv = NULL; + qglTexGend = NULL; + qglTexGendv = NULL; + qglTexGenf = NULL; + qglTexGenfv = NULL; + qglTexGeni = NULL; + qglTexGeniv = NULL; + qglTexImage1D = NULL; + qglTexImage2D = NULL; + qglTexParameterf = NULL; + qglTexParameterfv = NULL; + qglTexParameteri = NULL; + qglTexParameteriv = NULL; + qglTexSubImage1D = NULL; + qglTexSubImage2D = NULL; + qglTranslated = NULL; + qglTranslatef = NULL; + qglVertex2d = NULL; + qglVertex2dv = NULL; + qglVertex2f = NULL; + qglVertex2fv = NULL; + qglVertex2i = NULL; + qglVertex2iv = NULL; + qglVertex2s = NULL; + qglVertex2sv = NULL; + qglVertex3d = NULL; + qglVertex3dv = NULL; + qglVertex3f = NULL; + qglVertex3fv = NULL; + qglVertex3i = NULL; + qglVertex3iv = NULL; + qglVertex3s = NULL; + qglVertex3sv = NULL; + qglVertex4d = NULL; + qglVertex4dv = NULL; + qglVertex4f = NULL; + qglVertex4fv = NULL; + qglVertex4i = NULL; + qglVertex4iv = NULL; + qglVertex4s = NULL; + qglVertex4sv = NULL; + qglVertexPointer = NULL; + qglViewport = NULL; +} + +/* +** QGL_Init +** +** This is responsible for binding our qgl function pointers to +** the appropriate GL stuff. In Windows this means doing a +** LoadLibrary and a bunch of calls to GetProcAddress. On other +** operating systems we need to do the right thing, whatever that +** might be. +** +*/ +qboolean QGL_Init( const char *dllname ) +{ + qglAccum = dllAccum = glAccum; + qglAlphaFunc = dllAlphaFunc = glAlphaFunc; + qglAreTexturesResident = dllAreTexturesResident = glAreTexturesResident; + qglArrayElement = dllArrayElement = glArrayElement; + qglBegin = dllBegin = glBegin; + qglBindTexture = dllBindTexture = glBindTexture; + qglBitmap = dllBitmap = glBitmap; + qglBlendFunc = dllBlendFunc = glBlendFunc; + qglCallList = dllCallList = glCallList; + qglCallLists = dllCallLists = glCallLists; + qglClear = dllClear = glClear; + qglClearAccum = dllClearAccum = glClearAccum; + qglClearColor = dllClearColor = glClearColor; + qglClearDepth = dllClearDepth = glClearDepth; + qglClearIndex = dllClearIndex = glClearIndex; + qglClearStencil = dllClearStencil = glClearStencil; + qglClipPlane = dllClipPlane = glClipPlane; + qglColor3b = dllColor3b = glColor3b; + qglColor3bv = dllColor3bv = glColor3bv; + qglColor3d = dllColor3d = glColor3d; + qglColor3dv = dllColor3dv = glColor3dv; + qglColor3f = dllColor3f = glColor3f; + qglColor3fv = dllColor3fv = glColor3fv; + qglColor3i = dllColor3i = glColor3i; + qglColor3iv = dllColor3iv = glColor3iv; + qglColor3s = dllColor3s = glColor3s; + qglColor3sv = dllColor3sv = glColor3sv; + qglColor3ub = dllColor3ub = glColor3ub; + qglColor3ubv = dllColor3ubv = glColor3ubv; + qglColor3ui = dllColor3ui = glColor3ui; + qglColor3uiv = dllColor3uiv = glColor3uiv; + qglColor3us = dllColor3us = glColor3us; + qglColor3usv = dllColor3usv = glColor3usv; + qglColor4b = dllColor4b = glColor4b; + qglColor4bv = dllColor4bv = glColor4bv; + qglColor4d = dllColor4d = glColor4d; + qglColor4dv = dllColor4dv = glColor4dv; + qglColor4f = dllColor4f = glColor4f; + qglColor4fv = dllColor4fv = glColor4fv; + qglColor4i = dllColor4i = glColor4i; + qglColor4iv = dllColor4iv = glColor4iv; + qglColor4s = dllColor4s = glColor4s; + qglColor4sv = dllColor4sv = glColor4sv; + qglColor4ub = dllColor4ub = glColor4ub; + qglColor4ubv = dllColor4ubv = glColor4ubv; + qglColor4ui = dllColor4ui = glColor4ui; + qglColor4uiv = dllColor4uiv = glColor4uiv; + qglColor4us = dllColor4us = glColor4us; + qglColor4usv = dllColor4usv = glColor4usv; + qglColorMask = dllColorMask = glColorMask; + qglColorMaterial = dllColorMaterial = glColorMaterial; + qglColorPointer = dllColorPointer = glColorPointer; + qglCopyPixels = dllCopyPixels = glCopyPixels; + qglCopyTexImage1D = dllCopyTexImage1D = glCopyTexImage1D; + qglCopyTexImage2D = dllCopyTexImage2D = glCopyTexImage2D; + qglCopyTexSubImage1D = dllCopyTexSubImage1D = glCopyTexSubImage1D; + qglCopyTexSubImage2D = dllCopyTexSubImage2D = glCopyTexSubImage2D; + qglCullFace = dllCullFace = glCullFace; + qglDeleteLists = dllDeleteLists = glDeleteLists; + qglDeleteTextures = dllDeleteTextures = glDeleteTextures; + qglDepthFunc = dllDepthFunc = glDepthFunc; + qglDepthMask = dllDepthMask = glDepthMask; + qglDepthRange = dllDepthRange = glDepthRange; + qglDisable = dllDisable = glDisable; + qglDisableClientState = dllDisableClientState = glDisableClientState; + qglDrawArrays = dllDrawArrays = glDrawArrays; + qglDrawBuffer = dllDrawBuffer = glDrawBuffer; + qglDrawElements = dllDrawElements = glDrawElements; + qglDrawPixels = dllDrawPixels = glDrawPixels; + qglEdgeFlag = dllEdgeFlag = glEdgeFlag; + qglEdgeFlagPointer = dllEdgeFlagPointer = glEdgeFlagPointer; + qglEdgeFlagv = dllEdgeFlagv = glEdgeFlagv; + qglEnable = dllEnable = glEnable; + qglEnableClientState = dllEnableClientState = glEnableClientState; + qglEnd = dllEnd = glEnd; + qglEndList = dllEndList = glEndList; + qglEvalCoord1d = dllEvalCoord1d = glEvalCoord1d; + qglEvalCoord1dv = dllEvalCoord1dv = glEvalCoord1dv; + qglEvalCoord1f = dllEvalCoord1f = glEvalCoord1f; + qglEvalCoord1fv = dllEvalCoord1fv = glEvalCoord1fv; + qglEvalCoord2d = dllEvalCoord2d = glEvalCoord2d; + qglEvalCoord2dv = dllEvalCoord2dv = glEvalCoord2dv; + qglEvalCoord2f = dllEvalCoord2f = glEvalCoord2f; + qglEvalCoord2fv = dllEvalCoord2fv = glEvalCoord2fv; + qglEvalMesh1 = dllEvalMesh1 = glEvalMesh1; + qglEvalMesh2 = dllEvalMesh2 = glEvalMesh2; + qglEvalPoint1 = dllEvalPoint1 = glEvalPoint1; + qglEvalPoint2 = dllEvalPoint2 = glEvalPoint2; + qglFeedbackBuffer = dllFeedbackBuffer = glFeedbackBuffer; + qglFinish = dllFinish = glFinish; + qglFlush = dllFlush = glFlush; + qglFogf = dllFogf = glFogf; + qglFogfv = dllFogfv = glFogfv; + qglFogi = dllFogi = glFogi; + qglFogiv = dllFogiv = glFogiv; + qglFrontFace = dllFrontFace = glFrontFace; + qglFrustum = dllFrustum = glFrustum; + qglGenLists = dllGenLists = glGenLists; + qglGenTextures = dllGenTextures = glGenTextures; + qglGetBooleanv = dllGetBooleanv = glGetBooleanv; + qglGetClipPlane = dllGetClipPlane = glGetClipPlane; + qglGetDoublev = dllGetDoublev = glGetDoublev; + qglGetError = dllGetError = glGetError; + qglGetFloatv = dllGetFloatv = glGetFloatv; + qglGetIntegerv = dllGetIntegerv = glGetIntegerv; + qglGetLightfv = dllGetLightfv = glGetLightfv; + qglGetLightiv = dllGetLightiv = glGetLightiv; + qglGetMapdv = dllGetMapdv = glGetMapdv; + qglGetMapfv = dllGetMapfv = glGetMapfv; + qglGetMapiv = dllGetMapiv = glGetMapiv; + qglGetMaterialfv = dllGetMaterialfv = glGetMaterialfv; + qglGetMaterialiv = dllGetMaterialiv = glGetMaterialiv; + qglGetPixelMapfv = dllGetPixelMapfv = glGetPixelMapfv; + qglGetPixelMapuiv = dllGetPixelMapuiv = glGetPixelMapuiv; + qglGetPixelMapusv = dllGetPixelMapusv = glGetPixelMapusv; + qglGetPointerv = dllGetPointerv = glGetPointerv; + qglGetPolygonStipple = dllGetPolygonStipple = glGetPolygonStipple; + qglGetString = dllGetString = glGetString; + qglGetTexEnvfv = dllGetTexEnvfv = glGetTexEnvfv; + qglGetTexEnviv = dllGetTexEnviv = glGetTexEnviv; + qglGetTexGendv = dllGetTexGendv = glGetTexGendv; + qglGetTexGenfv = dllGetTexGenfv = glGetTexGenfv; + qglGetTexGeniv = dllGetTexGeniv = glGetTexGeniv; + qglGetTexImage = dllGetTexImage = glGetTexImage; +// qglGetTexLevelParameterfv = dllGetTexLevelParameterfv = glGetLevelParameterfv; +// qglGetTexLevelParameteriv = dllGetTexLevelParameteriv = glGetLevelParameteriv; + qglGetTexParameterfv = dllGetTexParameterfv = glGetTexParameterfv; + qglGetTexParameteriv = dllGetTexParameteriv = glGetTexParameteriv; + qglHint = dllHint = glHint; + qglIndexMask = dllIndexMask = glIndexMask; + qglIndexPointer = dllIndexPointer = glIndexPointer; + qglIndexd = dllIndexd = glIndexd; + qglIndexdv = dllIndexdv = glIndexdv; + qglIndexf = dllIndexf = glIndexf; + qglIndexfv = dllIndexfv = glIndexfv; + qglIndexi = dllIndexi = glIndexi; + qglIndexiv = dllIndexiv = glIndexiv; + qglIndexs = dllIndexs = glIndexs; + qglIndexsv = dllIndexsv = glIndexsv; + qglIndexub = dllIndexub = glIndexub; + qglIndexubv = dllIndexubv = glIndexubv; + qglInitNames = dllInitNames = glInitNames; + qglInterleavedArrays = dllInterleavedArrays = glInterleavedArrays; + qglIsEnabled = dllIsEnabled = glIsEnabled; + qglIsList = dllIsList = glIsList; + qglIsTexture = dllIsTexture = glIsTexture; + qglLightModelf = dllLightModelf = glLightModelf; + qglLightModelfv = dllLightModelfv = glLightModelfv; + qglLightModeli = dllLightModeli = glLightModeli; + qglLightModeliv = dllLightModeliv = glLightModeliv; + qglLightf = dllLightf = glLightf; + qglLightfv = dllLightfv = glLightfv; + qglLighti = dllLighti = glLighti; + qglLightiv = dllLightiv = glLightiv; + qglLineStipple = dllLineStipple = glLineStipple; + qglLineWidth = dllLineWidth = glLineWidth; + qglListBase = dllListBase = glListBase; + qglLoadIdentity = dllLoadIdentity = glLoadIdentity; + qglLoadMatrixd = dllLoadMatrixd = glLoadMatrixd; + qglLoadMatrixf = dllLoadMatrixf = glLoadMatrixf; + qglLoadName = dllLoadName = glLoadName; + qglLogicOp = dllLogicOp = glLogicOp; + qglMap1d = dllMap1d = glMap1d; + qglMap1f = dllMap1f = glMap1f; + qglMap2d = dllMap2d = glMap2d; + qglMap2f = dllMap2f = glMap2f; + qglMapGrid1d = dllMapGrid1d = glMapGrid1d; + qglMapGrid1f = dllMapGrid1f = glMapGrid1f; + qglMapGrid2d = dllMapGrid2d = glMapGrid2d; + qglMapGrid2f = dllMapGrid2f = glMapGrid2f; + qglMaterialf = dllMaterialf = glMaterialf; + qglMaterialfv = dllMaterialfv = glMaterialfv; + qglMateriali = dllMateriali = glMateriali; + qglMaterialiv = dllMaterialiv = glMaterialiv; + qglMatrixMode = dllMatrixMode = glMatrixMode; + qglMultMatrixd = dllMultMatrixd = glMultMatrixd; + qglMultMatrixf = dllMultMatrixf = glMultMatrixf; + qglNewList = dllNewList = glNewList; + qglNormal3b = dllNormal3b = glNormal3b; + qglNormal3bv = dllNormal3bv = glNormal3bv; + qglNormal3d = dllNormal3d = glNormal3d; + qglNormal3dv = dllNormal3dv = glNormal3dv; + qglNormal3f = dllNormal3f = glNormal3f; + qglNormal3fv = dllNormal3fv = glNormal3fv; + qglNormal3i = dllNormal3i = glNormal3i; + qglNormal3iv = dllNormal3iv = glNormal3iv; + qglNormal3s = dllNormal3s = glNormal3s; + qglNormal3sv = dllNormal3sv = glNormal3sv; + qglNormalPointer = dllNormalPointer = glNormalPointer; + qglOrtho = dllOrtho = glOrtho; + qglPassThrough = dllPassThrough = glPassThrough; + qglPixelMapfv = dllPixelMapfv = glPixelMapfv; + qglPixelMapuiv = dllPixelMapuiv = glPixelMapuiv; + qglPixelMapusv = dllPixelMapusv = glPixelMapusv; + qglPixelStoref = dllPixelStoref = glPixelStoref; + qglPixelStorei = dllPixelStorei = glPixelStorei; + qglPixelTransferf = dllPixelTransferf = glPixelTransferf; + qglPixelTransferi = dllPixelTransferi = glPixelTransferi; + qglPixelZoom = dllPixelZoom = glPixelZoom; + qglPointSize = dllPointSize = glPointSize; + qglPolygonMode = dllPolygonMode = glPolygonMode; + qglPolygonOffset = dllPolygonOffset = glPolygonOffset; + qglPolygonStipple = dllPolygonStipple = glPolygonStipple; + qglPopAttrib = dllPopAttrib = glPopAttrib; + qglPopClientAttrib = dllPopClientAttrib = glPopClientAttrib; + qglPopMatrix = dllPopMatrix = glPopMatrix; + qglPopName = dllPopName = glPopName; + qglPrioritizeTextures = dllPrioritizeTextures = glPrioritizeTextures; + qglPushAttrib = dllPushAttrib = glPushAttrib; + qglPushClientAttrib = dllPushClientAttrib = glPushClientAttrib; + qglPushMatrix = dllPushMatrix = glPushMatrix; + qglPushName = dllPushName = glPushName; + qglRasterPos2d = dllRasterPos2d = glRasterPos2d; + qglRasterPos2dv = dllRasterPos2dv = glRasterPos2dv; + qglRasterPos2f = dllRasterPos2f = glRasterPos2f; + qglRasterPos2fv = dllRasterPos2fv = glRasterPos2fv; + qglRasterPos2i = dllRasterPos2i = glRasterPos2i; + qglRasterPos2iv = dllRasterPos2iv = glRasterPos2iv; + qglRasterPos2s = dllRasterPos2s = glRasterPos2s; + qglRasterPos2sv = dllRasterPos2sv = glRasterPos2sv; + qglRasterPos3d = dllRasterPos3d = glRasterPos3d; + qglRasterPos3dv = dllRasterPos3dv = glRasterPos3dv; + qglRasterPos3f = dllRasterPos3f = glRasterPos3f; + qglRasterPos3fv = dllRasterPos3fv = glRasterPos3fv; + qglRasterPos3i = dllRasterPos3i = glRasterPos3i; + qglRasterPos3iv = dllRasterPos3iv = glRasterPos3iv; + qglRasterPos3s = dllRasterPos3s = glRasterPos3s; + qglRasterPos3sv = dllRasterPos3sv = glRasterPos3sv; + qglRasterPos4d = dllRasterPos4d = glRasterPos4d; + qglRasterPos4dv = dllRasterPos4dv = glRasterPos4dv; + qglRasterPos4f = dllRasterPos4f = glRasterPos4f; + qglRasterPos4fv = dllRasterPos4fv = glRasterPos4fv; + qglRasterPos4i = dllRasterPos4i = glRasterPos4i; + qglRasterPos4iv = dllRasterPos4iv = glRasterPos4iv; + qglRasterPos4s = dllRasterPos4s = glRasterPos4s; + qglRasterPos4sv = dllRasterPos4sv = glRasterPos4sv; + qglReadBuffer = dllReadBuffer = glReadBuffer; + qglReadPixels = dllReadPixels = glReadPixels; + qglRectd = dllRectd = glRectd; + qglRectdv = dllRectdv = glRectdv; + qglRectf = dllRectf = glRectf; + qglRectfv = dllRectfv = glRectfv; + qglRecti = dllRecti = glRecti; + qglRectiv = dllRectiv = glRectiv; + qglRects = dllRects = glRects; + qglRectsv = dllRectsv = glRectsv; + qglRenderMode = dllRenderMode = glRenderMode; + qglRotated = dllRotated = glRotated; + qglRotatef = dllRotatef = glRotatef; + qglScaled = dllScaled = glScaled; + qglScalef = dllScalef = glScalef; + qglScissor = dllScissor = glScissor; + qglSelectBuffer = dllSelectBuffer = glSelectBuffer; + qglShadeModel = dllShadeModel = glShadeModel; + qglStencilFunc = dllStencilFunc = glStencilFunc; + qglStencilMask = dllStencilMask = glStencilMask; + qglStencilOp = dllStencilOp = glStencilOp; + qglTexCoord1d = dllTexCoord1d = glTexCoord1d; + qglTexCoord1dv = dllTexCoord1dv = glTexCoord1dv; + qglTexCoord1f = dllTexCoord1f = glTexCoord1f; + qglTexCoord1fv = dllTexCoord1fv = glTexCoord1fv; + qglTexCoord1i = dllTexCoord1i = glTexCoord1i; + qglTexCoord1iv = dllTexCoord1iv = glTexCoord1iv; + qglTexCoord1s = dllTexCoord1s = glTexCoord1s; + qglTexCoord1sv = dllTexCoord1sv = glTexCoord1sv; + qglTexCoord2d = dllTexCoord2d = glTexCoord2d; + qglTexCoord2dv = dllTexCoord2dv = glTexCoord2dv; + qglTexCoord2f = dllTexCoord2f = glTexCoord2f; + qglTexCoord2fv = dllTexCoord2fv = glTexCoord2fv; + qglTexCoord2i = dllTexCoord2i = glTexCoord2i; + qglTexCoord2iv = dllTexCoord2iv = glTexCoord2iv; + qglTexCoord2s = dllTexCoord2s = glTexCoord2s; + qglTexCoord2sv = dllTexCoord2sv = glTexCoord2sv; + qglTexCoord3d = dllTexCoord3d = glTexCoord3d; + qglTexCoord3dv = dllTexCoord3dv = glTexCoord3dv; + qglTexCoord3f = dllTexCoord3f = glTexCoord3f; + qglTexCoord3fv = dllTexCoord3fv = glTexCoord3fv; + qglTexCoord3i = dllTexCoord3i = glTexCoord3i; + qglTexCoord3iv = dllTexCoord3iv = glTexCoord3iv; + qglTexCoord3s = dllTexCoord3s = glTexCoord3s; + qglTexCoord3sv = dllTexCoord3sv = glTexCoord3sv; + qglTexCoord4d = dllTexCoord4d = glTexCoord4d; + qglTexCoord4dv = dllTexCoord4dv = glTexCoord4dv; + qglTexCoord4f = dllTexCoord4f = glTexCoord4f; + qglTexCoord4fv = dllTexCoord4fv = glTexCoord4fv; + qglTexCoord4i = dllTexCoord4i = glTexCoord4i; + qglTexCoord4iv = dllTexCoord4iv = glTexCoord4iv; + qglTexCoord4s = dllTexCoord4s = glTexCoord4s; + qglTexCoord4sv = dllTexCoord4sv = glTexCoord4sv; + qglTexCoordPointer = dllTexCoordPointer = glTexCoordPointer; + qglTexEnvf = dllTexEnvf = glTexEnvf; + qglTexEnvfv = dllTexEnvfv = glTexEnvfv; + qglTexEnvi = dllTexEnvi = glTexEnvi; + qglTexEnviv = dllTexEnviv = glTexEnviv; + qglTexGend = dllTexGend = glTexGend; + qglTexGendv = dllTexGendv = glTexGendv; + qglTexGenf = dllTexGenf = glTexGenf; + qglTexGenfv = dllTexGenfv = glTexGenfv; + qglTexGeni = dllTexGeni = glTexGeni; + qglTexGeniv = dllTexGeniv = glTexGeniv; + qglTexImage1D = dllTexImage1D = glTexImage1D; + qglTexImage2D = dllTexImage2D = glTexImage2D; + qglTexParameterf = dllTexParameterf = glTexParameterf; + qglTexParameterfv = dllTexParameterfv = glTexParameterfv; + qglTexParameteri = dllTexParameteri = glTexParameteri; + qglTexParameteriv = dllTexParameteriv = glTexParameteriv; + qglTexSubImage1D = dllTexSubImage1D = glTexSubImage1D; + qglTexSubImage2D = dllTexSubImage2D = glTexSubImage2D; + qglTranslated = dllTranslated = glTranslated; + qglTranslatef = dllTranslatef = glTranslatef; + qglVertex2d = dllVertex2d = glVertex2d; + qglVertex2dv = dllVertex2dv = glVertex2dv; + qglVertex2f = dllVertex2f = glVertex2f; + qglVertex2fv = dllVertex2fv = glVertex2fv; + qglVertex2i = dllVertex2i = glVertex2i; + qglVertex2iv = dllVertex2iv = glVertex2iv; + qglVertex2s = dllVertex2s = glVertex2s; + qglVertex2sv = dllVertex2sv = glVertex2sv; + qglVertex3d = dllVertex3d = glVertex3d; + qglVertex3dv = dllVertex3dv = glVertex3dv; + qglVertex3f = dllVertex3f = glVertex3f; + qglVertex3fv = dllVertex3fv = glVertex3fv; + qglVertex3i = dllVertex3i = glVertex3i; + qglVertex3iv = dllVertex3iv = glVertex3iv; + qglVertex3s = dllVertex3s = glVertex3s; + qglVertex3sv = dllVertex3sv = glVertex3sv; + qglVertex4d = dllVertex4d = glVertex4d; + qglVertex4dv = dllVertex4dv = glVertex4dv; + qglVertex4f = dllVertex4f = glVertex4f; + qglVertex4fv = dllVertex4fv = glVertex4fv; + qglVertex4i = dllVertex4i = glVertex4i; + qglVertex4iv = dllVertex4iv = glVertex4iv; + qglVertex4s = dllVertex4s = glVertex4s; + qglVertex4sv = dllVertex4sv = glVertex4sv; + qglVertexPointer = dllVertexPointer = glVertexPointer; + qglViewport = dllViewport = glViewport; + + qglPointParameterfEXT = 0; + qglPointParameterfvEXT = 0; + qglColorTableEXT = 0; + qglSelectTextureSGIS = 0; + qglMTexCoord2fSGIS = 0; + + return true; +} + +void GLimp_EnableLogging( qboolean enable ) +{ + if ( enable ) + { + if ( !log_fp ) + { + struct tm *newtime; + time_t aclock; + char buffer[1024]; + + time( &aclock ); + newtime = localtime( &aclock ); + + asctime( newtime ); + + sprintf( buffer, "%s/gl.log", ri.FS_Gamedir() ); + log_fp = fopen( buffer, "wt"); + + fprintf( log_fp, "%s\n", asctime( newtime ) ); + } + + qglAccum = logAccum; + qglAlphaFunc = logAlphaFunc; + qglAreTexturesResident = logAreTexturesResident; + qglArrayElement = logArrayElement; + qglBegin = logBegin; + qglBindTexture = logBindTexture; + qglBitmap = logBitmap; + qglBlendFunc = logBlendFunc; + qglCallList = logCallList; + qglCallLists = logCallLists; + qglClear = logClear; + qglClearAccum = logClearAccum; + qglClearColor = logClearColor; + qglClearDepth = logClearDepth; + qglClearIndex = logClearIndex; + qglClearStencil = logClearStencil; + qglClipPlane = logClipPlane; + qglColor3b = logColor3b; + qglColor3bv = logColor3bv; + qglColor3d = logColor3d; + qglColor3dv = logColor3dv; + qglColor3f = logColor3f; + qglColor3fv = logColor3fv; + qglColor3i = logColor3i; + qglColor3iv = logColor3iv; + qglColor3s = logColor3s; + qglColor3sv = logColor3sv; + qglColor3ub = logColor3ub; + qglColor3ubv = logColor3ubv; + qglColor3ui = logColor3ui; + qglColor3uiv = logColor3uiv; + qglColor3us = logColor3us; + qglColor3usv = logColor3usv; + qglColor4b = logColor4b; + qglColor4bv = logColor4bv; + qglColor4d = logColor4d; + qglColor4dv = logColor4dv; + qglColor4f = logColor4f; + qglColor4fv = logColor4fv; + qglColor4i = logColor4i; + qglColor4iv = logColor4iv; + qglColor4s = logColor4s; + qglColor4sv = logColor4sv; + qglColor4ub = logColor4ub; + qglColor4ubv = logColor4ubv; + qglColor4ui = logColor4ui; + qglColor4uiv = logColor4uiv; + qglColor4us = logColor4us; + qglColor4usv = logColor4usv; + qglColorMask = logColorMask; + qglColorMaterial = logColorMaterial; + qglColorPointer = logColorPointer; + qglCopyPixels = logCopyPixels; + qglCopyTexImage1D = logCopyTexImage1D; + qglCopyTexImage2D = logCopyTexImage2D; + qglCopyTexSubImage1D = logCopyTexSubImage1D; + qglCopyTexSubImage2D = logCopyTexSubImage2D; + qglCullFace = logCullFace; + qglDeleteLists = logDeleteLists ; + qglDeleteTextures = logDeleteTextures ; + qglDepthFunc = logDepthFunc ; + qglDepthMask = logDepthMask ; + qglDepthRange = logDepthRange ; + qglDisable = logDisable ; + qglDisableClientState = logDisableClientState ; + qglDrawArrays = logDrawArrays ; + qglDrawBuffer = logDrawBuffer ; + qglDrawElements = logDrawElements ; + qglDrawPixels = logDrawPixels ; + qglEdgeFlag = logEdgeFlag ; + qglEdgeFlagPointer = logEdgeFlagPointer ; + qglEdgeFlagv = logEdgeFlagv ; + qglEnable = logEnable ; + qglEnableClientState = logEnableClientState ; + qglEnd = logEnd ; + qglEndList = logEndList ; + qglEvalCoord1d = logEvalCoord1d ; + qglEvalCoord1dv = logEvalCoord1dv ; + qglEvalCoord1f = logEvalCoord1f ; + qglEvalCoord1fv = logEvalCoord1fv ; + qglEvalCoord2d = logEvalCoord2d ; + qglEvalCoord2dv = logEvalCoord2dv ; + qglEvalCoord2f = logEvalCoord2f ; + qglEvalCoord2fv = logEvalCoord2fv ; + qglEvalMesh1 = logEvalMesh1 ; + qglEvalMesh2 = logEvalMesh2 ; + qglEvalPoint1 = logEvalPoint1 ; + qglEvalPoint2 = logEvalPoint2 ; + qglFeedbackBuffer = logFeedbackBuffer ; + qglFinish = logFinish ; + qglFlush = logFlush ; + qglFogf = logFogf ; + qglFogfv = logFogfv ; + qglFogi = logFogi ; + qglFogiv = logFogiv ; + qglFrontFace = logFrontFace ; + qglFrustum = logFrustum ; + qglGenLists = logGenLists ; + qglGenTextures = logGenTextures ; + qglGetBooleanv = logGetBooleanv ; + qglGetClipPlane = logGetClipPlane ; + qglGetDoublev = logGetDoublev ; + qglGetError = logGetError ; + qglGetFloatv = logGetFloatv ; + qglGetIntegerv = logGetIntegerv ; + qglGetLightfv = logGetLightfv ; + qglGetLightiv = logGetLightiv ; + qglGetMapdv = logGetMapdv ; + qglGetMapfv = logGetMapfv ; + qglGetMapiv = logGetMapiv ; + qglGetMaterialfv = logGetMaterialfv ; + qglGetMaterialiv = logGetMaterialiv ; + qglGetPixelMapfv = logGetPixelMapfv ; + qglGetPixelMapuiv = logGetPixelMapuiv ; + qglGetPixelMapusv = logGetPixelMapusv ; + qglGetPointerv = logGetPointerv ; + qglGetPolygonStipple = logGetPolygonStipple ; + qglGetString = logGetString ; + qglGetTexEnvfv = logGetTexEnvfv ; + qglGetTexEnviv = logGetTexEnviv ; + qglGetTexGendv = logGetTexGendv ; + qglGetTexGenfv = logGetTexGenfv ; + qglGetTexGeniv = logGetTexGeniv ; + qglGetTexImage = logGetTexImage ; +// qglGetTexLevelParameterfv = logGetTexLevelParameterfv ; +// qglGetTexLevelParameteriv = logGetTexLevelParameteriv ; + qglGetTexParameterfv = logGetTexParameterfv ; + qglGetTexParameteriv = logGetTexParameteriv ; + qglHint = logHint ; + qglIndexMask = logIndexMask ; + qglIndexPointer = logIndexPointer ; + qglIndexd = logIndexd ; + qglIndexdv = logIndexdv ; + qglIndexf = logIndexf ; + qglIndexfv = logIndexfv ; + qglIndexi = logIndexi ; + qglIndexiv = logIndexiv ; + qglIndexs = logIndexs ; + qglIndexsv = logIndexsv ; + qglIndexub = logIndexub ; + qglIndexubv = logIndexubv ; + qglInitNames = logInitNames ; + qglInterleavedArrays = logInterleavedArrays ; + qglIsEnabled = logIsEnabled ; + qglIsList = logIsList ; + qglIsTexture = logIsTexture ; + qglLightModelf = logLightModelf ; + qglLightModelfv = logLightModelfv ; + qglLightModeli = logLightModeli ; + qglLightModeliv = logLightModeliv ; + qglLightf = logLightf ; + qglLightfv = logLightfv ; + qglLighti = logLighti ; + qglLightiv = logLightiv ; + qglLineStipple = logLineStipple ; + qglLineWidth = logLineWidth ; + qglListBase = logListBase ; + qglLoadIdentity = logLoadIdentity ; + qglLoadMatrixd = logLoadMatrixd ; + qglLoadMatrixf = logLoadMatrixf ; + qglLoadName = logLoadName ; + qglLogicOp = logLogicOp ; + qglMap1d = logMap1d ; + qglMap1f = logMap1f ; + qglMap2d = logMap2d ; + qglMap2f = logMap2f ; + qglMapGrid1d = logMapGrid1d ; + qglMapGrid1f = logMapGrid1f ; + qglMapGrid2d = logMapGrid2d ; + qglMapGrid2f = logMapGrid2f ; + qglMaterialf = logMaterialf ; + qglMaterialfv = logMaterialfv ; + qglMateriali = logMateriali ; + qglMaterialiv = logMaterialiv ; + qglMatrixMode = logMatrixMode ; + qglMultMatrixd = logMultMatrixd ; + qglMultMatrixf = logMultMatrixf ; + qglNewList = logNewList ; + qglNormal3b = logNormal3b ; + qglNormal3bv = logNormal3bv ; + qglNormal3d = logNormal3d ; + qglNormal3dv = logNormal3dv ; + qglNormal3f = logNormal3f ; + qglNormal3fv = logNormal3fv ; + qglNormal3i = logNormal3i ; + qglNormal3iv = logNormal3iv ; + qglNormal3s = logNormal3s ; + qglNormal3sv = logNormal3sv ; + qglNormalPointer = logNormalPointer ; + qglOrtho = logOrtho ; + qglPassThrough = logPassThrough ; + qglPixelMapfv = logPixelMapfv ; + qglPixelMapuiv = logPixelMapuiv ; + qglPixelMapusv = logPixelMapusv ; + qglPixelStoref = logPixelStoref ; + qglPixelStorei = logPixelStorei ; + qglPixelTransferf = logPixelTransferf ; + qglPixelTransferi = logPixelTransferi ; + qglPixelZoom = logPixelZoom ; + qglPointSize = logPointSize ; + qglPolygonMode = logPolygonMode ; + qglPolygonOffset = logPolygonOffset ; + qglPolygonStipple = logPolygonStipple ; + qglPopAttrib = logPopAttrib ; + qglPopClientAttrib = logPopClientAttrib ; + qglPopMatrix = logPopMatrix ; + qglPopName = logPopName ; + qglPrioritizeTextures = logPrioritizeTextures ; + qglPushAttrib = logPushAttrib ; + qglPushClientAttrib = logPushClientAttrib ; + qglPushMatrix = logPushMatrix ; + qglPushName = logPushName ; + qglRasterPos2d = logRasterPos2d ; + qglRasterPos2dv = logRasterPos2dv ; + qglRasterPos2f = logRasterPos2f ; + qglRasterPos2fv = logRasterPos2fv ; + qglRasterPos2i = logRasterPos2i ; + qglRasterPos2iv = logRasterPos2iv ; + qglRasterPos2s = logRasterPos2s ; + qglRasterPos2sv = logRasterPos2sv ; + qglRasterPos3d = logRasterPos3d ; + qglRasterPos3dv = logRasterPos3dv ; + qglRasterPos3f = logRasterPos3f ; + qglRasterPos3fv = logRasterPos3fv ; + qglRasterPos3i = logRasterPos3i ; + qglRasterPos3iv = logRasterPos3iv ; + qglRasterPos3s = logRasterPos3s ; + qglRasterPos3sv = logRasterPos3sv ; + qglRasterPos4d = logRasterPos4d ; + qglRasterPos4dv = logRasterPos4dv ; + qglRasterPos4f = logRasterPos4f ; + qglRasterPos4fv = logRasterPos4fv ; + qglRasterPos4i = logRasterPos4i ; + qglRasterPos4iv = logRasterPos4iv ; + qglRasterPos4s = logRasterPos4s ; + qglRasterPos4sv = logRasterPos4sv ; + qglReadBuffer = logReadBuffer ; + qglReadPixels = logReadPixels ; + qglRectd = logRectd ; + qglRectdv = logRectdv ; + qglRectf = logRectf ; + qglRectfv = logRectfv ; + qglRecti = logRecti ; + qglRectiv = logRectiv ; + qglRects = logRects ; + qglRectsv = logRectsv ; + qglRenderMode = logRenderMode ; + qglRotated = logRotated ; + qglRotatef = logRotatef ; + qglScaled = logScaled ; + qglScalef = logScalef ; + qglScissor = logScissor ; + qglSelectBuffer = logSelectBuffer ; + qglShadeModel = logShadeModel ; + qglStencilFunc = logStencilFunc ; + qglStencilMask = logStencilMask ; + qglStencilOp = logStencilOp ; + qglTexCoord1d = logTexCoord1d ; + qglTexCoord1dv = logTexCoord1dv ; + qglTexCoord1f = logTexCoord1f ; + qglTexCoord1fv = logTexCoord1fv ; + qglTexCoord1i = logTexCoord1i ; + qglTexCoord1iv = logTexCoord1iv ; + qglTexCoord1s = logTexCoord1s ; + qglTexCoord1sv = logTexCoord1sv ; + qglTexCoord2d = logTexCoord2d ; + qglTexCoord2dv = logTexCoord2dv ; + qglTexCoord2f = logTexCoord2f ; + qglTexCoord2fv = logTexCoord2fv ; + qglTexCoord2i = logTexCoord2i ; + qglTexCoord2iv = logTexCoord2iv ; + qglTexCoord2s = logTexCoord2s ; + qglTexCoord2sv = logTexCoord2sv ; + qglTexCoord3d = logTexCoord3d ; + qglTexCoord3dv = logTexCoord3dv ; + qglTexCoord3f = logTexCoord3f ; + qglTexCoord3fv = logTexCoord3fv ; + qglTexCoord3i = logTexCoord3i ; + qglTexCoord3iv = logTexCoord3iv ; + qglTexCoord3s = logTexCoord3s ; + qglTexCoord3sv = logTexCoord3sv ; + qglTexCoord4d = logTexCoord4d ; + qglTexCoord4dv = logTexCoord4dv ; + qglTexCoord4f = logTexCoord4f ; + qglTexCoord4fv = logTexCoord4fv ; + qglTexCoord4i = logTexCoord4i ; + qglTexCoord4iv = logTexCoord4iv ; + qglTexCoord4s = logTexCoord4s ; + qglTexCoord4sv = logTexCoord4sv ; + qglTexCoordPointer = logTexCoordPointer ; + qglTexEnvf = logTexEnvf ; + qglTexEnvfv = logTexEnvfv ; + qglTexEnvi = logTexEnvi ; + qglTexEnviv = logTexEnviv ; + qglTexGend = logTexGend ; + qglTexGendv = logTexGendv ; + qglTexGenf = logTexGenf ; + qglTexGenfv = logTexGenfv ; + qglTexGeni = logTexGeni ; + qglTexGeniv = logTexGeniv ; + qglTexImage1D = logTexImage1D ; + qglTexImage2D = logTexImage2D ; + qglTexParameterf = logTexParameterf ; + qglTexParameterfv = logTexParameterfv ; + qglTexParameteri = logTexParameteri ; + qglTexParameteriv = logTexParameteriv ; + qglTexSubImage1D = logTexSubImage1D ; + qglTexSubImage2D = logTexSubImage2D ; + qglTranslated = logTranslated ; + qglTranslatef = logTranslatef ; + qglVertex2d = logVertex2d ; + qglVertex2dv = logVertex2dv ; + qglVertex2f = logVertex2f ; + qglVertex2fv = logVertex2fv ; + qglVertex2i = logVertex2i ; + qglVertex2iv = logVertex2iv ; + qglVertex2s = logVertex2s ; + qglVertex2sv = logVertex2sv ; + qglVertex3d = logVertex3d ; + qglVertex3dv = logVertex3dv ; + qglVertex3f = logVertex3f ; + qglVertex3fv = logVertex3fv ; + qglVertex3i = logVertex3i ; + qglVertex3iv = logVertex3iv ; + qglVertex3s = logVertex3s ; + qglVertex3sv = logVertex3sv ; + qglVertex4d = logVertex4d ; + qglVertex4dv = logVertex4dv ; + qglVertex4f = logVertex4f ; + qglVertex4fv = logVertex4fv ; + qglVertex4i = logVertex4i ; + qglVertex4iv = logVertex4iv ; + qglVertex4s = logVertex4s ; + qglVertex4sv = logVertex4sv ; + qglVertexPointer = logVertexPointer ; + qglViewport = logViewport ; + } + else + { + qglAccum = dllAccum; + qglAlphaFunc = dllAlphaFunc; + qglAreTexturesResident = dllAreTexturesResident; + qglArrayElement = dllArrayElement; + qglBegin = dllBegin; + qglBindTexture = dllBindTexture; + qglBitmap = dllBitmap; + qglBlendFunc = dllBlendFunc; + qglCallList = dllCallList; + qglCallLists = dllCallLists; + qglClear = dllClear; + qglClearAccum = dllClearAccum; + qglClearColor = dllClearColor; + qglClearDepth = dllClearDepth; + qglClearIndex = dllClearIndex; + qglClearStencil = dllClearStencil; + qglClipPlane = dllClipPlane; + qglColor3b = dllColor3b; + qglColor3bv = dllColor3bv; + qglColor3d = dllColor3d; + qglColor3dv = dllColor3dv; + qglColor3f = dllColor3f; + qglColor3fv = dllColor3fv; + qglColor3i = dllColor3i; + qglColor3iv = dllColor3iv; + qglColor3s = dllColor3s; + qglColor3sv = dllColor3sv; + qglColor3ub = dllColor3ub; + qglColor3ubv = dllColor3ubv; + qglColor3ui = dllColor3ui; + qglColor3uiv = dllColor3uiv; + qglColor3us = dllColor3us; + qglColor3usv = dllColor3usv; + qglColor4b = dllColor4b; + qglColor4bv = dllColor4bv; + qglColor4d = dllColor4d; + qglColor4dv = dllColor4dv; + qglColor4f = dllColor4f; + qglColor4fv = dllColor4fv; + qglColor4i = dllColor4i; + qglColor4iv = dllColor4iv; + qglColor4s = dllColor4s; + qglColor4sv = dllColor4sv; + qglColor4ub = dllColor4ub; + qglColor4ubv = dllColor4ubv; + qglColor4ui = dllColor4ui; + qglColor4uiv = dllColor4uiv; + qglColor4us = dllColor4us; + qglColor4usv = dllColor4usv; + qglColorMask = dllColorMask; + qglColorMaterial = dllColorMaterial; + qglColorPointer = dllColorPointer; + qglCopyPixels = dllCopyPixels; + qglCopyTexImage1D = dllCopyTexImage1D; + qglCopyTexImage2D = dllCopyTexImage2D; + qglCopyTexSubImage1D = dllCopyTexSubImage1D; + qglCopyTexSubImage2D = dllCopyTexSubImage2D; + qglCullFace = dllCullFace; + qglDeleteLists = dllDeleteLists ; + qglDeleteTextures = dllDeleteTextures ; + qglDepthFunc = dllDepthFunc ; + qglDepthMask = dllDepthMask ; + qglDepthRange = dllDepthRange ; + qglDisable = dllDisable ; + qglDisableClientState = dllDisableClientState ; + qglDrawArrays = dllDrawArrays ; + qglDrawBuffer = dllDrawBuffer ; + qglDrawElements = dllDrawElements ; + qglDrawPixels = dllDrawPixels ; + qglEdgeFlag = dllEdgeFlag ; + qglEdgeFlagPointer = dllEdgeFlagPointer ; + qglEdgeFlagv = dllEdgeFlagv ; + qglEnable = dllEnable ; + qglEnableClientState = dllEnableClientState ; + qglEnd = dllEnd ; + qglEndList = dllEndList ; + qglEvalCoord1d = dllEvalCoord1d ; + qglEvalCoord1dv = dllEvalCoord1dv ; + qglEvalCoord1f = dllEvalCoord1f ; + qglEvalCoord1fv = dllEvalCoord1fv ; + qglEvalCoord2d = dllEvalCoord2d ; + qglEvalCoord2dv = dllEvalCoord2dv ; + qglEvalCoord2f = dllEvalCoord2f ; + qglEvalCoord2fv = dllEvalCoord2fv ; + qglEvalMesh1 = dllEvalMesh1 ; + qglEvalMesh2 = dllEvalMesh2 ; + qglEvalPoint1 = dllEvalPoint1 ; + qglEvalPoint2 = dllEvalPoint2 ; + qglFeedbackBuffer = dllFeedbackBuffer ; + qglFinish = dllFinish ; + qglFlush = dllFlush ; + qglFogf = dllFogf ; + qglFogfv = dllFogfv ; + qglFogi = dllFogi ; + qglFogiv = dllFogiv ; + qglFrontFace = dllFrontFace ; + qglFrustum = dllFrustum ; + qglGenLists = dllGenLists ; + qglGenTextures = dllGenTextures ; + qglGetBooleanv = dllGetBooleanv ; + qglGetClipPlane = dllGetClipPlane ; + qglGetDoublev = dllGetDoublev ; + qglGetError = dllGetError ; + qglGetFloatv = dllGetFloatv ; + qglGetIntegerv = dllGetIntegerv ; + qglGetLightfv = dllGetLightfv ; + qglGetLightiv = dllGetLightiv ; + qglGetMapdv = dllGetMapdv ; + qglGetMapfv = dllGetMapfv ; + qglGetMapiv = dllGetMapiv ; + qglGetMaterialfv = dllGetMaterialfv ; + qglGetMaterialiv = dllGetMaterialiv ; + qglGetPixelMapfv = dllGetPixelMapfv ; + qglGetPixelMapuiv = dllGetPixelMapuiv ; + qglGetPixelMapusv = dllGetPixelMapusv ; + qglGetPointerv = dllGetPointerv ; + qglGetPolygonStipple = dllGetPolygonStipple ; + qglGetString = dllGetString ; + qglGetTexEnvfv = dllGetTexEnvfv ; + qglGetTexEnviv = dllGetTexEnviv ; + qglGetTexGendv = dllGetTexGendv ; + qglGetTexGenfv = dllGetTexGenfv ; + qglGetTexGeniv = dllGetTexGeniv ; + qglGetTexImage = dllGetTexImage ; + qglGetTexLevelParameterfv = dllGetTexLevelParameterfv ; + qglGetTexLevelParameteriv = dllGetTexLevelParameteriv ; + qglGetTexParameterfv = dllGetTexParameterfv ; + qglGetTexParameteriv = dllGetTexParameteriv ; + qglHint = dllHint ; + qglIndexMask = dllIndexMask ; + qglIndexPointer = dllIndexPointer ; + qglIndexd = dllIndexd ; + qglIndexdv = dllIndexdv ; + qglIndexf = dllIndexf ; + qglIndexfv = dllIndexfv ; + qglIndexi = dllIndexi ; + qglIndexiv = dllIndexiv ; + qglIndexs = dllIndexs ; + qglIndexsv = dllIndexsv ; + qglIndexub = dllIndexub ; + qglIndexubv = dllIndexubv ; + qglInitNames = dllInitNames ; + qglInterleavedArrays = dllInterleavedArrays ; + qglIsEnabled = dllIsEnabled ; + qglIsList = dllIsList ; + qglIsTexture = dllIsTexture ; + qglLightModelf = dllLightModelf ; + qglLightModelfv = dllLightModelfv ; + qglLightModeli = dllLightModeli ; + qglLightModeliv = dllLightModeliv ; + qglLightf = dllLightf ; + qglLightfv = dllLightfv ; + qglLighti = dllLighti ; + qglLightiv = dllLightiv ; + qglLineStipple = dllLineStipple ; + qglLineWidth = dllLineWidth ; + qglListBase = dllListBase ; + qglLoadIdentity = dllLoadIdentity ; + qglLoadMatrixd = dllLoadMatrixd ; + qglLoadMatrixf = dllLoadMatrixf ; + qglLoadName = dllLoadName ; + qglLogicOp = dllLogicOp ; + qglMap1d = dllMap1d ; + qglMap1f = dllMap1f ; + qglMap2d = dllMap2d ; + qglMap2f = dllMap2f ; + qglMapGrid1d = dllMapGrid1d ; + qglMapGrid1f = dllMapGrid1f ; + qglMapGrid2d = dllMapGrid2d ; + qglMapGrid2f = dllMapGrid2f ; + qglMaterialf = dllMaterialf ; + qglMaterialfv = dllMaterialfv ; + qglMateriali = dllMateriali ; + qglMaterialiv = dllMaterialiv ; + qglMatrixMode = dllMatrixMode ; + qglMultMatrixd = dllMultMatrixd ; + qglMultMatrixf = dllMultMatrixf ; + qglNewList = dllNewList ; + qglNormal3b = dllNormal3b ; + qglNormal3bv = dllNormal3bv ; + qglNormal3d = dllNormal3d ; + qglNormal3dv = dllNormal3dv ; + qglNormal3f = dllNormal3f ; + qglNormal3fv = dllNormal3fv ; + qglNormal3i = dllNormal3i ; + qglNormal3iv = dllNormal3iv ; + qglNormal3s = dllNormal3s ; + qglNormal3sv = dllNormal3sv ; + qglNormalPointer = dllNormalPointer ; + qglOrtho = dllOrtho ; + qglPassThrough = dllPassThrough ; + qglPixelMapfv = dllPixelMapfv ; + qglPixelMapuiv = dllPixelMapuiv ; + qglPixelMapusv = dllPixelMapusv ; + qglPixelStoref = dllPixelStoref ; + qglPixelStorei = dllPixelStorei ; + qglPixelTransferf = dllPixelTransferf ; + qglPixelTransferi = dllPixelTransferi ; + qglPixelZoom = dllPixelZoom ; + qglPointSize = dllPointSize ; + qglPolygonMode = dllPolygonMode ; + qglPolygonOffset = dllPolygonOffset ; + qglPolygonStipple = dllPolygonStipple ; + qglPopAttrib = dllPopAttrib ; + qglPopClientAttrib = dllPopClientAttrib ; + qglPopMatrix = dllPopMatrix ; + qglPopName = dllPopName ; + qglPrioritizeTextures = dllPrioritizeTextures ; + qglPushAttrib = dllPushAttrib ; + qglPushClientAttrib = dllPushClientAttrib ; + qglPushMatrix = dllPushMatrix ; + qglPushName = dllPushName ; + qglRasterPos2d = dllRasterPos2d ; + qglRasterPos2dv = dllRasterPos2dv ; + qglRasterPos2f = dllRasterPos2f ; + qglRasterPos2fv = dllRasterPos2fv ; + qglRasterPos2i = dllRasterPos2i ; + qglRasterPos2iv = dllRasterPos2iv ; + qglRasterPos2s = dllRasterPos2s ; + qglRasterPos2sv = dllRasterPos2sv ; + qglRasterPos3d = dllRasterPos3d ; + qglRasterPos3dv = dllRasterPos3dv ; + qglRasterPos3f = dllRasterPos3f ; + qglRasterPos3fv = dllRasterPos3fv ; + qglRasterPos3i = dllRasterPos3i ; + qglRasterPos3iv = dllRasterPos3iv ; + qglRasterPos3s = dllRasterPos3s ; + qglRasterPos3sv = dllRasterPos3sv ; + qglRasterPos4d = dllRasterPos4d ; + qglRasterPos4dv = dllRasterPos4dv ; + qglRasterPos4f = dllRasterPos4f ; + qglRasterPos4fv = dllRasterPos4fv ; + qglRasterPos4i = dllRasterPos4i ; + qglRasterPos4iv = dllRasterPos4iv ; + qglRasterPos4s = dllRasterPos4s ; + qglRasterPos4sv = dllRasterPos4sv ; + qglReadBuffer = dllReadBuffer ; + qglReadPixels = dllReadPixels ; + qglRectd = dllRectd ; + qglRectdv = dllRectdv ; + qglRectf = dllRectf ; + qglRectfv = dllRectfv ; + qglRecti = dllRecti ; + qglRectiv = dllRectiv ; + qglRects = dllRects ; + qglRectsv = dllRectsv ; + qglRenderMode = dllRenderMode ; + qglRotated = dllRotated ; + qglRotatef = dllRotatef ; + qglScaled = dllScaled ; + qglScalef = dllScalef ; + qglScissor = dllScissor ; + qglSelectBuffer = dllSelectBuffer ; + qglShadeModel = dllShadeModel ; + qglStencilFunc = dllStencilFunc ; + qglStencilMask = dllStencilMask ; + qglStencilOp = dllStencilOp ; + qglTexCoord1d = dllTexCoord1d ; + qglTexCoord1dv = dllTexCoord1dv ; + qglTexCoord1f = dllTexCoord1f ; + qglTexCoord1fv = dllTexCoord1fv ; + qglTexCoord1i = dllTexCoord1i ; + qglTexCoord1iv = dllTexCoord1iv ; + qglTexCoord1s = dllTexCoord1s ; + qglTexCoord1sv = dllTexCoord1sv ; + qglTexCoord2d = dllTexCoord2d ; + qglTexCoord2dv = dllTexCoord2dv ; + qglTexCoord2f = dllTexCoord2f ; + qglTexCoord2fv = dllTexCoord2fv ; + qglTexCoord2i = dllTexCoord2i ; + qglTexCoord2iv = dllTexCoord2iv ; + qglTexCoord2s = dllTexCoord2s ; + qglTexCoord2sv = dllTexCoord2sv ; + qglTexCoord3d = dllTexCoord3d ; + qglTexCoord3dv = dllTexCoord3dv ; + qglTexCoord3f = dllTexCoord3f ; + qglTexCoord3fv = dllTexCoord3fv ; + qglTexCoord3i = dllTexCoord3i ; + qglTexCoord3iv = dllTexCoord3iv ; + qglTexCoord3s = dllTexCoord3s ; + qglTexCoord3sv = dllTexCoord3sv ; + qglTexCoord4d = dllTexCoord4d ; + qglTexCoord4dv = dllTexCoord4dv ; + qglTexCoord4f = dllTexCoord4f ; + qglTexCoord4fv = dllTexCoord4fv ; + qglTexCoord4i = dllTexCoord4i ; + qglTexCoord4iv = dllTexCoord4iv ; + qglTexCoord4s = dllTexCoord4s ; + qglTexCoord4sv = dllTexCoord4sv ; + qglTexCoordPointer = dllTexCoordPointer ; + qglTexEnvf = dllTexEnvf ; + qglTexEnvfv = dllTexEnvfv ; + qglTexEnvi = dllTexEnvi ; + qglTexEnviv = dllTexEnviv ; + qglTexGend = dllTexGend ; + qglTexGendv = dllTexGendv ; + qglTexGenf = dllTexGenf ; + qglTexGenfv = dllTexGenfv ; + qglTexGeni = dllTexGeni ; + qglTexGeniv = dllTexGeniv ; + qglTexImage1D = dllTexImage1D ; + qglTexImage2D = dllTexImage2D ; + qglTexParameterf = dllTexParameterf ; + qglTexParameterfv = dllTexParameterfv ; + qglTexParameteri = dllTexParameteri ; + qglTexParameteriv = dllTexParameteriv ; + qglTexSubImage1D = dllTexSubImage1D ; + qglTexSubImage2D = dllTexSubImage2D ; + qglTranslated = dllTranslated ; + qglTranslatef = dllTranslatef ; + qglVertex2d = dllVertex2d ; + qglVertex2dv = dllVertex2dv ; + qglVertex2f = dllVertex2f ; + qglVertex2fv = dllVertex2fv ; + qglVertex2i = dllVertex2i ; + qglVertex2iv = dllVertex2iv ; + qglVertex2s = dllVertex2s ; + qglVertex2sv = dllVertex2sv ; + qglVertex3d = dllVertex3d ; + qglVertex3dv = dllVertex3dv ; + qglVertex3f = dllVertex3f ; + qglVertex3fv = dllVertex3fv ; + qglVertex3i = dllVertex3i ; + qglVertex3iv = dllVertex3iv ; + qglVertex3s = dllVertex3s ; + qglVertex3sv = dllVertex3sv ; + qglVertex4d = dllVertex4d ; + qglVertex4dv = dllVertex4dv ; + qglVertex4f = dllVertex4f ; + qglVertex4fv = dllVertex4fv ; + qglVertex4i = dllVertex4i ; + qglVertex4iv = dllVertex4iv ; + qglVertex4s = dllVertex4s ; + qglVertex4sv = dllVertex4sv ; + qglVertexPointer = dllVertexPointer ; + qglViewport = dllViewport ; + } +} + + +void GLimp_LogNewFrame( void ) +{ + fprintf( log_fp, "*** R_BeginFrame ***\n"); +} + + diff --git a/linux/r_aclipa.s b/linux/r_aclipa.s new file mode 100644 index 000000000..74eb74b73 --- /dev/null +++ b/linux/r_aclipa.s @@ -0,0 +1,195 @@ +// +// r_aliasa.s +// x86 assembly-language Alias model transform and project code. +// + +#include "qasm.h" +#include "d_ifacea.h" + +#if id386 + + .data +Ltemp0: .long 0 +Ltemp1: .long 0 + + .text + +#define pfv0 8+4 +#define pfv1 8+8 +#define out 8+12 + +.globl C(R_Alias_clip_bottom) +C(R_Alias_clip_bottom): + pushl %esi + pushl %edi + + movl pfv0(%esp),%esi + movl pfv1(%esp),%edi + + movl C(r_refdef)+rd_aliasvrectbottom,%eax + +LDoForwardOrBackward: + + movl fv_v+4(%esi),%edx + movl fv_v+4(%edi),%ecx + + cmpl %ecx,%edx + jl LDoForward + + movl fv_v+4(%esi),%ecx + movl fv_v+4(%edi),%edx + movl pfv0(%esp),%edi + movl pfv1(%esp),%esi + +LDoForward: + + subl %edx,%ecx + subl %edx,%eax + movl %ecx,Ltemp1 + movl %eax,Ltemp0 + fildl Ltemp1 + fildl Ltemp0 + movl out(%esp),%edx + movl $2,%eax + + fdivp %st(0),%st(1) // scale + +LDo3Forward: + fildl fv_v+0(%esi) // fv0v0 | scale + fildl fv_v+0(%edi) // fv1v0 | fv0v0 | scale + fildl fv_v+4(%esi) // fv0v1 | fv1v0 | fv0v0 | scale + fildl fv_v+4(%edi) // fv1v1 | fv0v1 | fv1v0 | fv0v0 | scale + fildl fv_v+8(%esi) // fv0v2 | fv1v1 | fv0v1 | fv1v0 | fv0v0 | scale + fildl fv_v+8(%edi) // fv1v2 | fv0v2 | fv1v1 | fv0v1 | fv1v0 | fv0v0 | + // scale + fxch %st(5) // fv0v0 | fv0v2 | fv1v1 | fv0v1 | fv1v0 | fv1v2 | + // scale + fsubr %st(0),%st(4) // fv0v0 | fv0v2 | fv1v1 | fv0v1 | fv1v0-fv0v0 | + // fv1v2 | scale + fxch %st(3) // fv0v1 | fv0v2 | fv1v1 | fv0v0 | fv1v0-fv0v0 | + // fv1v2 | scale + fsubr %st(0),%st(2) // fv0v1 | fv0v2 | fv1v1-fv0v1 | fv0v0 | + // fv1v0-fv0v0 | fv1v2 | scale + fxch %st(1) // fv0v2 | fv0v1 | fv1v1-fv0v1 | fv0v0 | + // fv1v0-fv0v0 | fv1v2 | scale + fsubr %st(0),%st(5) // fv0v2 | fv0v1 | fv1v1-fv0v1 | fv0v0 | + // fv1v0-fv0v0 | fv1v2-fv0v2 | scale + fxch %st(6) // scale | fv0v1 | fv1v1-fv0v1 | fv0v0 | + // fv1v0-fv0v0 | fv1v2-fv0v2 | fv0v2 + fmul %st(0),%st(4) // scale | fv0v1 | fv1v1-fv0v1 | fv0v0 | + // (fv1v0-fv0v0)*scale | fv1v2-fv0v2 | fv0v2 + addl $12,%edi + fmul %st(0),%st(2) // scale | fv0v1 | (fv1v1-fv0v1)*scale | fv0v0 | + // (fv1v0-fv0v0)*scale | fv1v2-fv0v2 | fv0v2 + addl $12,%esi + addl $12,%edx + fmul %st(0),%st(5) // scale | fv0v1 | (fv1v1-fv0v1)*scale | fv0v0 | + // (fv1v0-fv0v0)*scale | (fv1v2-fv0v2)*scale | + // fv0v2 + fxch %st(3) // fv0v0 | fv0v1 | (fv1v1-fv0v1)*scale | scale | + // (fv1v0-fv0v0)*scale | (fv1v2-fv0v2)*scale | + // fv0v2 + faddp %st(0),%st(4) // fv0v1 | (fv1v1-fv0v1)*scale | scale | + // fv0v0+(fv1v0-fv0v0)*scale | + // (fv1v2-fv0v2)*scale | fv0v2 + faddp %st(0),%st(1) // fv0v1+(fv1v1-fv0v1)*scale | scale | + // fv0v0+(fv1v0-fv0v0)*scale | + // (fv1v2-fv0v2)*scale | fv0v2 + fxch %st(4) // fv0v2 | scale | fv0v0+(fv1v0-fv0v0)*scale | + // (fv1v2-fv0v2)*scale | fv0v1+(fv1v1-fv0v1)*scale + faddp %st(0),%st(3) // scale | fv0v0+(fv1v0-fv0v0)*scale | + // fv0v2+(fv1v2-fv0v2)*scale | + // fv0v1+(fv1v1-fv0v1)*scale + fxch %st(1) // fv0v0+(fv1v0-fv0v0)*scale | scale | + // fv0v2+(fv1v2-fv0v2)*scale | + // fv0v1+(fv1v1-fv0v1)*scale + fadds float_point5 + fxch %st(3) // fv0v1+(fv1v1-fv0v1)*scale | scale | + // fv0v2+(fv1v2-fv0v2)*scale | + // fv0v0+(fv1v0-fv0v0)*scale + fadds float_point5 + fxch %st(2) // fv0v2+(fv1v2-fv0v2)*scale | scale | + // fv0v1+(fv1v1-fv0v1)*scale | + // fv0v0+(fv1v0-fv0v0)*scale + fadds float_point5 + fxch %st(3) // fv0v0+(fv1v0-fv0v0)*scale | scale | + // fv0v1+(fv1v1-fv0v1)*scale | + // fv0v2+(fv1v2-fv0v2)*scale + fistpl fv_v+0-12(%edx) // scale | fv0v1+(fv1v1-fv0v1)*scale | + // fv0v2+(fv1v2-fv0v2)*scale + fxch %st(1) // fv0v1+(fv1v1-fv0v1)*scale | scale | + // fv0v2+(fv1v2-fv0v2)*scale | scale + fistpl fv_v+4-12(%edx) // scale | fv0v2+(fv1v2-fv0v2)*scale + fxch %st(1) // fv0v2+(fv1v2-fv0v2)*sc | scale + fistpl fv_v+8-12(%edx) // scale + + decl %eax + jnz LDo3Forward + + fstp %st(0) + + popl %edi + popl %esi + + ret + + +.globl C(R_Alias_clip_top) +C(R_Alias_clip_top): + pushl %esi + pushl %edi + + movl pfv0(%esp),%esi + movl pfv1(%esp),%edi + + movl C(r_refdef)+rd_aliasvrect+4,%eax + jmp LDoForwardOrBackward + + + +.globl C(R_Alias_clip_right) +C(R_Alias_clip_right): + pushl %esi + pushl %edi + + movl pfv0(%esp),%esi + movl pfv1(%esp),%edi + + movl C(r_refdef)+rd_aliasvrectright,%eax + +LRightLeftEntry: + + + movl fv_v+4(%esi),%edx + movl fv_v+4(%edi),%ecx + + cmpl %ecx,%edx + movl fv_v+0(%esi),%edx + + movl fv_v+0(%edi),%ecx + jl LDoForward2 + + movl fv_v+0(%esi),%ecx + movl fv_v+0(%edi),%edx + movl pfv0(%esp),%edi + movl pfv1(%esp),%esi + +LDoForward2: + + jmp LDoForward + + +.globl C(R_Alias_clip_left) +C(R_Alias_clip_left): + pushl %esi + pushl %edi + + movl pfv0(%esp),%esi + movl pfv1(%esp),%edi + + movl C(r_refdef)+rd_aliasvrect+0,%eax + jmp LRightLeftEntry + + +#endif // id386 + diff --git a/linux/r_draw16.s b/linux/r_draw16.s new file mode 100644 index 000000000..2c774514e --- /dev/null +++ b/linux/r_draw16.s @@ -0,0 +1,1227 @@ +// +// d_draw16.s +// x86 assembly-language horizontal 8-bpp span-drawing code, with 16-pixel +// subdivision. +// + +#include "qasm.h" +#include "d_ifacea.h" + +#if id386 + +//---------------------------------------------------------------------- +// 8-bpp horizontal span drawing code for polygons, with no transparency and +// 16-pixel subdivision. +// +// Assumes there is at least one span in pspans, and that every span +// contains at least one pixel +//---------------------------------------------------------------------- + + .data + + .text + +// out-of-line, rarely-needed clamping code + +LClampHigh0: + movl C(bbextents),%esi + jmp LClampReentry0 +LClampHighOrLow0: + jg LClampHigh0 + xorl %esi,%esi + jmp LClampReentry0 + +LClampHigh1: + movl C(bbextentt),%edx + jmp LClampReentry1 +LClampHighOrLow1: + jg LClampHigh1 + xorl %edx,%edx + jmp LClampReentry1 + +LClampLow2: + movl $4096,%ebp + jmp LClampReentry2 +LClampHigh2: + movl C(bbextents),%ebp + jmp LClampReentry2 + +LClampLow3: + movl $4096,%ecx + jmp LClampReentry3 +LClampHigh3: + movl C(bbextentt),%ecx + jmp LClampReentry3 + +LClampLow4: + movl $4096,%eax + jmp LClampReentry4 +LClampHigh4: + movl C(bbextents),%eax + jmp LClampReentry4 + +LClampLow5: + movl $4096,%ebx + jmp LClampReentry5 +LClampHigh5: + movl C(bbextentt),%ebx + jmp LClampReentry5 + + +#define pspans 4+16 + + .align 4 +.globl C(D_DrawSpans16) +C(D_DrawSpans16): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// +// set up scaled-by-16 steps, for 16-long segments; also set up cacheblock +// and span list pointers +// +// TODO: any overlap from rearranging? + flds C(d_sdivzstepu) + fmuls fp_16 + movl C(cacheblock),%edx + flds C(d_tdivzstepu) + fmuls fp_16 + movl pspans(%esp),%ebx // point to the first span descriptor + flds C(d_zistepu) + fmuls fp_16 + movl %edx,pbase // pbase = cacheblock + fstps zi16stepu + fstps tdivz16stepu + fstps sdivz16stepu + +LSpanLoop: +// +// set up the initial s/z, t/z, and 1/z on the FP stack, and generate the +// initial s and t values +// +// FIXME: pipeline FILD? + fildl espan_t_v(%ebx) + fildl espan_t_u(%ebx) + + fld %st(1) // dv | du | dv + fmuls C(d_sdivzstepv) // dv*d_sdivzstepv | du | dv + fld %st(1) // du | dv*d_sdivzstepv | du | dv + fmuls C(d_sdivzstepu) // du*d_sdivzstepu | dv*d_sdivzstepv | du | dv + fld %st(2) // du | du*d_sdivzstepu | dv*d_sdivzstepv | du | dv + fmuls C(d_tdivzstepu) // du*d_tdivzstepu | du*d_sdivzstepu | + // dv*d_sdivzstepv | du | dv + fxch %st(1) // du*d_sdivzstepu | du*d_tdivzstepu | + // dv*d_sdivzstepv | du | dv + faddp %st(0),%st(2) // du*d_tdivzstepu | + // du*d_sdivzstepu + dv*d_sdivzstepv | du | dv + fxch %st(1) // du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fld %st(3) // dv | du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fmuls C(d_tdivzstepv) // dv*d_tdivzstepv | + // du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fxch %st(1) // du*d_sdivzstepu + dv*d_sdivzstepv | + // dv*d_tdivzstepv | du*d_tdivzstepu | du | dv + fadds C(d_sdivzorigin) // sdivz = d_sdivzorigin + dv*d_sdivzstepv + + // du*d_sdivzstepu; stays in %st(2) at end + fxch %st(4) // dv | dv*d_tdivzstepv | du*d_tdivzstepu | du | + // s/z + fmuls C(d_zistepv) // dv*d_zistepv | dv*d_tdivzstepv | + // du*d_tdivzstepu | du | s/z + fxch %st(1) // dv*d_tdivzstepv | dv*d_zistepv | + // du*d_tdivzstepu | du | s/z + faddp %st(0),%st(2) // dv*d_zistepv | + // dv*d_tdivzstepv + du*d_tdivzstepu | du | s/z + fxch %st(2) // du | dv*d_tdivzstepv + du*d_tdivzstepu | + // dv*d_zistepv | s/z + fmuls C(d_zistepu) // du*d_zistepu | + // dv*d_tdivzstepv + du*d_tdivzstepu | + // dv*d_zistepv | s/z + fxch %st(1) // dv*d_tdivzstepv + du*d_tdivzstepu | + // du*d_zistepu | dv*d_zistepv | s/z + fadds C(d_tdivzorigin) // tdivz = d_tdivzorigin + dv*d_tdivzstepv + + // du*d_tdivzstepu; stays in %st(1) at end + fxch %st(2) // dv*d_zistepv | du*d_zistepu | t/z | s/z + faddp %st(0),%st(1) // dv*d_zistepv + du*d_zistepu | t/z | s/z + + flds fp_64k // fp_64k | dv*d_zistepv + du*d_zistepu | t/z | s/z + fxch %st(1) // dv*d_zistepv + du*d_zistepu | fp_64k | t/z | s/z + fadds C(d_ziorigin) // zi = d_ziorigin + dv*d_zistepv + + // du*d_zistepu; stays in %st(0) at end + // 1/z | fp_64k | t/z | s/z +// +// calculate and clamp s & t +// + fdivr %st(0),%st(1) // 1/z | z*64k | t/z | s/z + +// +// point %edi to the first pixel in the span +// + movl C(d_viewbuffer),%ecx + movl espan_t_v(%ebx),%eax + movl %ebx,pspantemp // preserve spans pointer + + movl C(tadjust),%edx + movl C(sadjust),%esi + movl C(d_scantable)(,%eax,4),%edi // v * screenwidth + addl %ecx,%edi + movl espan_t_u(%ebx),%ecx + addl %ecx,%edi // pdest = &pdestspan[scans->u]; + movl espan_t_count(%ebx),%ecx + +// +// now start the FDIV for the end of the span +// + cmpl $16,%ecx + ja LSetupNotLast1 + + decl %ecx + jz LCleanup1 // if only one pixel, no need to start an FDIV + movl %ecx,spancountminus1 + +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + + fildl spancountminus1 + + flds C(d_tdivzstepu) // C(d_tdivzstepu) | spancountminus1 + flds C(d_zistepu) // C(d_zistepu) | C(d_tdivzstepu) | spancountminus1 + fmul %st(2),%st(0) // C(d_zistepu)*scm1 | C(d_tdivzstepu) | scm1 + fxch %st(1) // C(d_tdivzstepu) | C(d_zistepu)*scm1 | scm1 + fmul %st(2),%st(0) // C(d_tdivzstepu)*scm1 | C(d_zistepu)*scm1 | scm1 + fxch %st(2) // scm1 | C(d_zistepu)*scm1 | C(d_tdivzstepu)*scm1 + fmuls C(d_sdivzstepu) // C(d_sdivzstepu)*scm1 | C(d_zistepu)*scm1 | + // C(d_tdivzstepu)*scm1 + fxch %st(1) // C(d_zistepu)*scm1 | C(d_sdivzstepu)*scm1 | + // C(d_tdivzstepu)*scm1 + faddp %st(0),%st(3) // C(d_sdivzstepu)*scm1 | C(d_tdivzstepu)*scm1 + fxch %st(1) // C(d_tdivzstepu)*scm1 | C(d_sdivzstepu)*scm1 + faddp %st(0),%st(3) // C(d_sdivzstepu)*scm1 + faddp %st(0),%st(3) + + flds fp_64k + fdiv %st(1),%st(0) // this is what we've gone to all this trouble to + // overlap + jmp LFDIVInFlight1 + +LCleanup1: +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + jmp LFDIVInFlight1 + + .align 4 +LSetupNotLast1: +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + + fadds zi16stepu + fxch %st(2) + fadds sdivz16stepu + fxch %st(2) + flds tdivz16stepu + faddp %st(0),%st(2) + flds fp_64k + fdiv %st(1),%st(0) // z = 1/1/z + // this is what we've gone to all this trouble to + // overlap +LFDIVInFlight1: + + addl s,%esi + addl t,%edx + movl C(bbextents),%ebx + movl C(bbextentt),%ebp + cmpl %ebx,%esi + ja LClampHighOrLow0 +LClampReentry0: + movl %esi,s + movl pbase,%ebx + shll $16,%esi + cmpl %ebp,%edx + movl %esi,sfracf + ja LClampHighOrLow1 +LClampReentry1: + movl %edx,t + movl s,%esi // sfrac = scans->sfrac; + shll $16,%edx + movl t,%eax // tfrac = scans->tfrac; + sarl $16,%esi + movl %edx,tfracf + +// +// calculate the texture starting address +// + sarl $16,%eax + movl C(cachewidth),%edx + imull %edx,%eax // (tfrac >> 16) * cachewidth + addl %ebx,%esi + addl %eax,%esi // psource = pbase + (sfrac >> 16) + + // ((tfrac >> 16) * cachewidth); +// +// determine whether last span or not +// + cmpl $16,%ecx + jna LLastSegment + +// +// not the last segment; do full 16-wide segment +// +LNotLastSegment: + +// +// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to +// get there +// + +// pick up after the FDIV that was left in flight previously + + fld %st(0) // duplicate it + fmul %st(4),%st(0) // s = s/z * z + fxch %st(1) + fmul %st(3),%st(0) // t = t/z * z + fxch %st(1) + fistpl snext + fistpl tnext + movl snext,%eax + movl tnext,%edx + + movb (%esi),%bl // get first source texel + subl $16,%ecx // count off this segments' pixels + movl C(sadjust),%ebp + movl %ecx,counttemp // remember count of remaining pixels + + movl C(tadjust),%ecx + movb %bl,(%edi) // store first dest pixel + + addl %eax,%ebp + addl %edx,%ecx + + movl C(bbextents),%eax + movl C(bbextentt),%edx + + cmpl $4096,%ebp + jl LClampLow2 + cmpl %eax,%ebp + ja LClampHigh2 +LClampReentry2: + + cmpl $4096,%ecx + jl LClampLow3 + cmpl %edx,%ecx + ja LClampHigh3 +LClampReentry3: + + movl %ebp,snext + movl %ecx,tnext + + subl s,%ebp + subl t,%ecx + +// +// set up advancetable +// + movl %ecx,%eax + movl %ebp,%edx + sarl $20,%eax // tstep >>= 16; + jz LZero + sarl $20,%edx // sstep >>= 16; + movl C(cachewidth),%ebx + imull %ebx,%eax + jmp LSetUp1 + +LZero: + sarl $20,%edx // sstep >>= 16; + movl C(cachewidth),%ebx + +LSetUp1: + + addl %edx,%eax // add in sstep + // (tstep >> 16) * cachewidth + (sstep >> 16); + movl tfracf,%edx + movl %eax,advancetable+4 // advance base in t + addl %ebx,%eax // ((tstep >> 16) + 1) * cachewidth + + // (sstep >> 16); + shll $12,%ebp // left-justify sstep fractional part + movl sfracf,%ebx + shll $12,%ecx // left-justify tstep fractional part + movl %eax,advancetable // advance extra in t + + movl %ecx,tstep + addl %ecx,%edx // advance tfrac fractional part by tstep frac + + sbbl %ecx,%ecx // turn tstep carry into -1 (0 if none) + addl %ebp,%ebx // advance sfrac fractional part by sstep frac + adcl advancetable+4(,%ecx,4),%esi // point to next source texel + + addl tstep,%edx + sbbl %ecx,%ecx + movb (%esi),%al + addl %ebp,%ebx + movb %al,1(%edi) + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,2(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,3(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,4(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,5(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,6(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,7(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + +// +// start FDIV for end of next segment in flight, so it can overlap +// + movl counttemp,%ecx + cmpl $16,%ecx // more than one segment after this? + ja LSetupNotLast2 // yes + + decl %ecx + jz LFDIVInFlight2 // if only one pixel, no need to start an FDIV + movl %ecx,spancountminus1 + fildl spancountminus1 + + flds C(d_zistepu) // C(d_zistepu) | spancountminus1 + fmul %st(1),%st(0) // C(d_zistepu)*scm1 | scm1 + flds C(d_tdivzstepu) // C(d_tdivzstepu) | C(d_zistepu)*scm1 | scm1 + fmul %st(2),%st(0) // C(d_tdivzstepu)*scm1 | C(d_zistepu)*scm1 | scm1 + fxch %st(1) // C(d_zistepu)*scm1 | C(d_tdivzstepu)*scm1 | scm1 + faddp %st(0),%st(3) // C(d_tdivzstepu)*scm1 | scm1 + fxch %st(1) // scm1 | C(d_tdivzstepu)*scm1 + fmuls C(d_sdivzstepu) // C(d_sdivzstepu)*scm1 | C(d_tdivzstepu)*scm1 + fxch %st(1) // C(d_tdivzstepu)*scm1 | C(d_sdivzstepu)*scm1 + faddp %st(0),%st(3) // C(d_sdivzstepu)*scm1 + flds fp_64k // 64k | C(d_sdivzstepu)*scm1 + fxch %st(1) // C(d_sdivzstepu)*scm1 | 64k + faddp %st(0),%st(4) // 64k + + fdiv %st(1),%st(0) // this is what we've gone to all this trouble to + // overlap + jmp LFDIVInFlight2 + + .align 4 +LSetupNotLast2: + fadds zi16stepu + fxch %st(2) + fadds sdivz16stepu + fxch %st(2) + flds tdivz16stepu + faddp %st(0),%st(2) + flds fp_64k + fdiv %st(1),%st(0) // z = 1/1/z + // this is what we've gone to all this trouble to + // overlap +LFDIVInFlight2: + movl %ecx,counttemp + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,8(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,9(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,10(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,11(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,12(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,13(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,14(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + + addl $16,%edi + movl %edx,tfracf + movl snext,%edx + movl %ebx,sfracf + movl tnext,%ebx + movl %edx,s + movl %ebx,t + + movl counttemp,%ecx // retrieve count + +// +// determine whether last span or not +// + cmpl $16,%ecx // are there multiple segments remaining? + movb %al,-1(%edi) + ja LNotLastSegment // yes + +// +// last segment of scan +// +LLastSegment: + +// +// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to +// get there. The number of pixels left is variable, and we want to land on the +// last pixel, not step one past it, so we can't run into arithmetic problems +// + testl %ecx,%ecx + jz LNoSteps // just draw the last pixel and we're done + +// pick up after the FDIV that was left in flight previously + + + fld %st(0) // duplicate it + fmul %st(4),%st(0) // s = s/z * z + fxch %st(1) + fmul %st(3),%st(0) // t = t/z * z + fxch %st(1) + fistpl snext + fistpl tnext + + movb (%esi),%al // load first texel in segment + movl C(tadjust),%ebx + movb %al,(%edi) // store first pixel in segment + movl C(sadjust),%eax + + addl snext,%eax + addl tnext,%ebx + + movl C(bbextents),%ebp + movl C(bbextentt),%edx + + cmpl $4096,%eax + jl LClampLow4 + cmpl %ebp,%eax + ja LClampHigh4 +LClampReentry4: + movl %eax,snext + + cmpl $4096,%ebx + jl LClampLow5 + cmpl %edx,%ebx + ja LClampHigh5 +LClampReentry5: + + cmpl $1,%ecx // don't bother + je LOnlyOneStep // if two pixels in segment, there's only one step, + // of the segment length + subl s,%eax + subl t,%ebx + + addl %eax,%eax // convert to 15.17 format so multiply by 1.31 + addl %ebx,%ebx // reciprocal yields 16.48 + + imull reciprocal_table_16-8(,%ecx,4) // sstep = (snext - s) / + // (spancount-1) + movl %edx,%ebp + + movl %ebx,%eax + imull reciprocal_table_16-8(,%ecx,4) // tstep = (tnext - t) / + // (spancount-1) +LSetEntryvec: +// +// set up advancetable +// + movl entryvec_table_16(,%ecx,4),%ebx + movl %edx,%eax + movl %ebx,jumptemp // entry point into code for RET later + movl %ebp,%ecx + sarl $16,%edx // tstep >>= 16; + movl C(cachewidth),%ebx + sarl $16,%ecx // sstep >>= 16; + imull %ebx,%edx + + addl %ecx,%edx // add in sstep + // (tstep >> 16) * cachewidth + (sstep >> 16); + movl tfracf,%ecx + movl %edx,advancetable+4 // advance base in t + addl %ebx,%edx // ((tstep >> 16) + 1) * cachewidth + + // (sstep >> 16); + shll $16,%ebp // left-justify sstep fractional part + movl sfracf,%ebx + shll $16,%eax // left-justify tstep fractional part + movl %edx,advancetable // advance extra in t + + movl %eax,tstep + movl %ecx,%edx + addl %eax,%edx + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + + jmp *jumptemp // jump to the number-of-pixels handler + +//---------------------------------------- + +LNoSteps: + movb (%esi),%al // load first texel in segment + subl $15,%edi // adjust for hardwired offset + jmp LEndSpan + + +LOnlyOneStep: + subl s,%eax + subl t,%ebx + movl %eax,%ebp + movl %ebx,%edx + jmp LSetEntryvec + +//---------------------------------------- + +.globl Entry2_16, Entry3_16, Entry4_16, Entry5_16 +.globl Entry6_16, Entry7_16, Entry8_16, Entry9_16 +.globl Entry10_16, Entry11_16, Entry12_16, Entry13_16 +.globl Entry14_16, Entry15_16, Entry16_16 + +Entry2_16: + subl $14,%edi // adjust for hardwired offsets + movb (%esi),%al + jmp LEntry2_16 + +//---------------------------------------- + +Entry3_16: + subl $13,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + jmp LEntry3_16 + +//---------------------------------------- + +Entry4_16: + subl $12,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry4_16 + +//---------------------------------------- + +Entry5_16: + subl $11,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry5_16 + +//---------------------------------------- + +Entry6_16: + subl $10,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry6_16 + +//---------------------------------------- + +Entry7_16: + subl $9,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry7_16 + +//---------------------------------------- + +Entry8_16: + subl $8,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry8_16 + +//---------------------------------------- + +Entry9_16: + subl $7,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry9_16 + +//---------------------------------------- + +Entry10_16: + subl $6,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry10_16 + +//---------------------------------------- + +Entry11_16: + subl $5,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry11_16 + +//---------------------------------------- + +Entry12_16: + subl $4,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry12_16 + +//---------------------------------------- + +Entry13_16: + subl $3,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry13_16 + +//---------------------------------------- + +Entry14_16: + subl $2,%edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry14_16 + +//---------------------------------------- + +Entry15_16: + decl %edi // adjust for hardwired offsets + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx + jmp LEntry15_16 + +//---------------------------------------- + +Entry16_16: + addl %eax,%edx + movb (%esi),%al + sbbl %ecx,%ecx + addl %ebp,%ebx + adcl advancetable+4(,%ecx,4),%esi + + addl tstep,%edx + sbbl %ecx,%ecx + movb %al,1(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry15_16: + sbbl %ecx,%ecx + movb %al,2(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry14_16: + sbbl %ecx,%ecx + movb %al,3(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry13_16: + sbbl %ecx,%ecx + movb %al,4(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry12_16: + sbbl %ecx,%ecx + movb %al,5(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry11_16: + sbbl %ecx,%ecx + movb %al,6(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry10_16: + sbbl %ecx,%ecx + movb %al,7(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry9_16: + sbbl %ecx,%ecx + movb %al,8(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry8_16: + sbbl %ecx,%ecx + movb %al,9(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry7_16: + sbbl %ecx,%ecx + movb %al,10(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry6_16: + sbbl %ecx,%ecx + movb %al,11(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry5_16: + sbbl %ecx,%ecx + movb %al,12(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi + addl tstep,%edx +LEntry4_16: + sbbl %ecx,%ecx + movb %al,13(%edi) + addl %ebp,%ebx + movb (%esi),%al + adcl advancetable+4(,%ecx,4),%esi +LEntry3_16: + movb %al,14(%edi) + movb (%esi),%al +LEntry2_16: + +LEndSpan: + +// +// clear s/z, t/z, 1/z from FP stack +// + fstp %st(0) + fstp %st(0) + fstp %st(0) + + movl pspantemp,%ebx // restore spans pointer + movl espan_t_pnext(%ebx),%ebx // point to next span + testl %ebx,%ebx // any more spans? + movb %al,15(%edi) + jnz LSpanLoop // more spans + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + +//---------------------------------------------------------------------- +// 8-bpp horizontal span z drawing codefor polygons, with no transparency. +// +// Assumes there is at least one span in pzspans, and that every span +// contains at least one pixel +//---------------------------------------------------------------------- + + .text + +// z-clamp on a non-negative gradient span +LClamp: + movl $0x40000000,%edx + xorl %ebx,%ebx + fstp %st(0) + jmp LZDraw + +// z-clamp on a negative gradient span +LClampNeg: + movl $0x40000000,%edx + xorl %ebx,%ebx + fstp %st(0) + jmp LZDrawNeg + + +#define pzspans 4+16 + +.globl C(D_DrawZSpans) +C(D_DrawZSpans): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + + flds C(d_zistepu) + movl C(d_zistepu),%eax + movl pzspans(%esp),%esi + testl %eax,%eax + jz LFNegSpan + + fmuls Float2ToThe31nd + fistpl izistep // note: we are relying on FP exceptions being turned + // off here to avoid range problems + movl izistep,%ebx // remains loaded for all spans + +LFSpanLoop: +// set up the initial 1/z value + fildl espan_t_v(%esi) + fildl espan_t_u(%esi) + movl espan_t_v(%esi),%ecx + movl C(d_pzbuffer),%edi + fmuls C(d_zistepu) + fxch %st(1) + fmuls C(d_zistepv) + fxch %st(1) + fadds C(d_ziorigin) + imull C(d_zrowbytes),%ecx + faddp %st(0),%st(1) + +// clamp if z is nearer than 2 (1/z > 0.5) + fcoms float_point5 + addl %ecx,%edi + movl espan_t_u(%esi),%edx + addl %edx,%edx // word count + movl espan_t_count(%esi),%ecx + addl %edx,%edi // pdest = &pdestspan[scans->u]; + pushl %esi // preserve spans pointer + fnstsw %ax + testb $0x45,%ah + jz LClamp + + fmuls Float2ToThe31nd + fistpl izi // note: we are relying on FP exceptions being turned + // off here to avoid problems when the span is closer + // than 1/(2**31) + movl izi,%edx + +// at this point: +// %ebx = izistep +// %ecx = count +// %edx = izi +// %edi = pdest + +LZDraw: + +// do a single pixel up front, if necessary to dword align the destination + testl $2,%edi + jz LFMiddle + movl %edx,%eax + addl %ebx,%edx + shrl $16,%eax + decl %ecx + movw %ax,(%edi) + addl $2,%edi + +// do middle a pair of aligned dwords at a time +LFMiddle: + pushl %ecx + shrl $1,%ecx // count / 2 + jz LFLast // no aligned dwords to do + shrl $1,%ecx // (count / 2) / 2 + jnc LFMiddleLoop // even number of aligned dwords to do + + movl %edx,%eax + addl %ebx,%edx + shrl $16,%eax + movl %edx,%esi + addl %ebx,%edx + andl $0xFFFF0000,%esi + orl %esi,%eax + movl %eax,(%edi) + addl $4,%edi + andl %ecx,%ecx + jz LFLast + +LFMiddleLoop: + movl %edx,%eax + addl %ebx,%edx + shrl $16,%eax + movl %edx,%esi + addl %ebx,%edx + andl $0xFFFF0000,%esi + orl %esi,%eax + movl %edx,%ebp + movl %eax,(%edi) + addl %ebx,%edx + shrl $16,%ebp + movl %edx,%esi + addl %ebx,%edx + andl $0xFFFF0000,%esi + orl %esi,%ebp + movl %ebp,4(%edi) // FIXME: eliminate register contention + addl $8,%edi + + decl %ecx + jnz LFMiddleLoop + +LFLast: + popl %ecx // retrieve count + popl %esi // retrieve span pointer + +// do the last, unaligned pixel, if there is one + andl $1,%ecx // is there an odd pixel left to do? + jz LFSpanDone // no + shrl $16,%edx + movw %dx,(%edi) // do the final pixel's z + +LFSpanDone: + movl espan_t_pnext(%esi),%esi + testl %esi,%esi + jnz LFSpanLoop + + jmp LFDone + +LFNegSpan: + fmuls FloatMinus2ToThe31nd + fistpl izistep // note: we are relying on FP exceptions being turned + // off here to avoid range problems + movl izistep,%ebx // remains loaded for all spans + +LFNegSpanLoop: +// set up the initial 1/z value + fildl espan_t_v(%esi) + fildl espan_t_u(%esi) + movl espan_t_v(%esi),%ecx + movl C(d_pzbuffer),%edi + fmuls C(d_zistepu) + fxch %st(1) + fmuls C(d_zistepv) + fxch %st(1) + fadds C(d_ziorigin) + imull C(d_zrowbytes),%ecx + faddp %st(0),%st(1) + +// clamp if z is nearer than 2 (1/z > 0.5) + fcoms float_point5 + addl %ecx,%edi + movl espan_t_u(%esi),%edx + addl %edx,%edx // word count + movl espan_t_count(%esi),%ecx + addl %edx,%edi // pdest = &pdestspan[scans->u]; + pushl %esi // preserve spans pointer + fnstsw %ax + testb $0x45,%ah + jz LClampNeg + + fmuls Float2ToThe31nd + fistpl izi // note: we are relying on FP exceptions being turned + // off here to avoid problems when the span is closer + // than 1/(2**31) + movl izi,%edx + +// at this point: +// %ebx = izistep +// %ecx = count +// %edx = izi +// %edi = pdest + +LZDrawNeg: + +// do a single pixel up front, if necessary to dword align the destination + testl $2,%edi + jz LFNegMiddle + movl %edx,%eax + subl %ebx,%edx + shrl $16,%eax + decl %ecx + movw %ax,(%edi) + addl $2,%edi + +// do middle a pair of aligned dwords at a time +LFNegMiddle: + pushl %ecx + shrl $1,%ecx // count / 2 + jz LFNegLast // no aligned dwords to do + shrl $1,%ecx // (count / 2) / 2 + jnc LFNegMiddleLoop // even number of aligned dwords to do + + movl %edx,%eax + subl %ebx,%edx + shrl $16,%eax + movl %edx,%esi + subl %ebx,%edx + andl $0xFFFF0000,%esi + orl %esi,%eax + movl %eax,(%edi) + addl $4,%edi + andl %ecx,%ecx + jz LFNegLast + +LFNegMiddleLoop: + movl %edx,%eax + subl %ebx,%edx + shrl $16,%eax + movl %edx,%esi + subl %ebx,%edx + andl $0xFFFF0000,%esi + orl %esi,%eax + movl %edx,%ebp + movl %eax,(%edi) + subl %ebx,%edx + shrl $16,%ebp + movl %edx,%esi + subl %ebx,%edx + andl $0xFFFF0000,%esi + orl %esi,%ebp + movl %ebp,4(%edi) // FIXME: eliminate register contention + addl $8,%edi + + decl %ecx + jnz LFNegMiddleLoop + +LFNegLast: + popl %ecx // retrieve count + popl %esi // retrieve span pointer + +// do the last, unaligned pixel, if there is one + andl $1,%ecx // is there an odd pixel left to do? + jz LFNegSpanDone // no + shrl $16,%edx + movw %dx,(%edi) // do the final pixel's z + +LFNegSpanDone: + movl espan_t_pnext(%esi),%esi + testl %esi,%esi + jnz LFNegSpanLoop + +LFDone: + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + +#endif // id386 + diff --git a/linux/r_drawa.s b/linux/r_drawa.s new file mode 100644 index 000000000..4406afdce --- /dev/null +++ b/linux/r_drawa.s @@ -0,0 +1,817 @@ +// +// r_drawa.s +// x86 assembly-language edge clipping and emission code +// + +#include "qasm.h" +#include "d_ifacea.h" + +#if id386 + +// !!! if these are changed, they must be changed in r_draw.c too !!! +#define FULLY_CLIPPED_CACHED 0x80000000 +#define FRAMECOUNT_MASK 0x7FFFFFFF + + .data + +Ld0: .single 0.0 +Ld1: .single 0.0 +Lstack: .long 0 +Lfp_near_clip: .single NEAR_CLIP +Lceilv0: .long 0 +Lv: .long 0 +Lu0: .long 0 +Lv0: .long 0 +Lzi0: .long 0 + + .text + +//---------------------------------------------------------------------- +// edge clipping code +//---------------------------------------------------------------------- + +#define pv0 4+12 +#define pv1 8+12 +#define clip 12+12 + + .align 4 +.globl C(R_ClipEdge) +C(R_ClipEdge): + pushl %esi // preserve register variables + pushl %edi + pushl %ebx + movl %esp,Lstack // for clearing the stack later + +// float d0, d1, f; +// mvertex_t clipvert; + + movl clip(%esp),%ebx + movl pv0(%esp),%esi + movl pv1(%esp),%edx + +// if (clip) +// { + testl %ebx,%ebx + jz Lemit + +// do +// { + +Lcliploop: + +// d0 = DotProduct (pv0->position, clip->normal) - clip->dist; +// d1 = DotProduct (pv1->position, clip->normal) - clip->dist; + flds mv_position+0(%esi) + fmuls cp_normal+0(%ebx) + flds mv_position+4(%esi) + fmuls cp_normal+4(%ebx) + flds mv_position+8(%esi) + fmuls cp_normal+8(%ebx) + fxch %st(1) + faddp %st(0),%st(2) // d0mul2 | d0add0 + + flds mv_position+0(%edx) + fmuls cp_normal+0(%ebx) + flds mv_position+4(%edx) + fmuls cp_normal+4(%ebx) + flds mv_position+8(%edx) + fmuls cp_normal+8(%ebx) + fxch %st(1) + faddp %st(0),%st(2) // d1mul2 | d1add0 | d0mul2 | d0add0 + fxch %st(3) // d0add0 | d1add0 | d0mul2 | d1mul2 + + faddp %st(0),%st(2) // d1add0 | dot0 | d1mul2 + faddp %st(0),%st(2) // dot0 | dot1 + + fsubs cp_dist(%ebx) // d0 | dot1 + fxch %st(1) // dot1 | d0 + fsubs cp_dist(%ebx) // d1 | d0 + fxch %st(1) + fstps Ld0 + fstps Ld1 + +// if (d0 >= 0) +// { + movl Ld0,%eax + movl Ld1,%ecx + orl %eax,%ecx + js Lp2 + +// both points are unclipped + +Lcontinue: + +// +// R_ClipEdge (&clipvert, pv1, clip->next); +// return; +// } +// } while ((clip = clip->next) != NULL); + movl cp_next(%ebx),%ebx + testl %ebx,%ebx + jnz Lcliploop + +// } + +//// add the edge +// R_EmitEdge (pv0, pv1); +Lemit: + +// +// set integer rounding to ceil mode, set to single precision +// +// FIXME: do away with by manually extracting integers from floats? +// FIXME: set less often + fldcw ceil_cw + +// edge_t *edge, *pcheck; +// int u_check; +// float u, u_step; +// vec3_t local, transformed; +// float *world; +// int v, v2, ceilv0; +// float scale, lzi0, u0, v0; +// int side; + +// if (r_lastvertvalid) +// { + cmpl $0,C(r_lastvertvalid) + jz LCalcFirst + +// u0 = r_u1; +// v0 = r_v1; +// lzi0 = r_lzi1; +// ceilv0 = r_ceilv1; + movl C(r_lzi1),%eax + movl C(r_u1),%ecx + movl %eax,Lzi0 + movl %ecx,Lu0 + movl C(r_v1),%ecx + movl C(r_ceilv1),%eax + movl %ecx,Lv0 + movl %eax,Lceilv0 + jmp LCalcSecond + +// } + +LCalcFirst: + +// else +// { +// world = &pv0->position[0]; + + call LTransformAndProject // v0 | lzi0 | u0 + + fsts Lv0 + fxch %st(2) // u0 | lzi0 | v0 + fstps Lu0 // lzi0 | v0 + fstps Lzi0 // v0 + +// ceilv0 = (int)(v0 - 2000) + 2000; // ceil(v0); + fistpl Lceilv0 + +// } + +LCalcSecond: + +// world = &pv1->position[0]; + movl %edx,%esi + + call LTransformAndProject // v1 | lzi1 | u1 + + flds Lu0 // u0 | v1 | lzi1 | u1 + fxch %st(3) // u1 | v1 | lzi1 | u0 + flds Lzi0 // lzi0 | u1 | v1 | lzi1 | u0 + fxch %st(3) // lzi1 | u1 | v1 | lzi0 | u0 + flds Lv0 // v0 | lzi1 | u1 | v1 | lzi0 | u0 + fxch %st(3) // v1 | lzi1 | u1 | v0 | lzi0 | u0 + +// r_ceilv1 = (int)(r_v1 - 2000) + 2000; // ceil(r_v1); + fistl C(r_ceilv1) + + fldcw single_cw // put back normal floating-point state + + fsts C(r_v1) + fxch %st(4) // lzi0 | lzi1 | u1 | v0 | v1 | u0 + +// if (r_lzi1 > lzi0) +// lzi0 = r_lzi1; + fcom %st(1) + fnstsw %ax + testb $1,%ah + jz LP0 + fstp %st(0) + fld %st(0) +LP0: + + fxch %st(1) // lzi1 | lzi0 | u1 | v0 | v1 | u0 + fstps C(r_lzi1) // lzi0 | u1 | v0 | v1 | u0 + fxch %st(1) + fsts C(r_u1) + fxch %st(1) + +// if (lzi0 > r_nearzi) // for mipmap finding +// r_nearzi = lzi0; + fcoms C(r_nearzi) + fnstsw %ax + testb $0x45,%ah + jnz LP1 + fsts C(r_nearzi) +LP1: + +// // for right edges, all we want is the effect on 1/z +// if (r_nearzionly) +// return; + movl C(r_nearzionly),%eax + testl %eax,%eax + jz LP2 +LPop5AndDone: + movl C(cacheoffset),%eax + movl C(r_framecount),%edx + cmpl $0x7FFFFFFF,%eax + jz LDoPop + andl $(FRAMECOUNT_MASK),%edx + orl $(FULLY_CLIPPED_CACHED),%edx + movl %edx,C(cacheoffset) + +LDoPop: + fstp %st(0) // u1 | v0 | v1 | u0 + fstp %st(0) // v0 | v1 | u0 + fstp %st(0) // v1 | u0 + fstp %st(0) // u0 + fstp %st(0) + jmp Ldone + +LP2: + +// // create the edge +// if (ceilv0 == r_ceilv1) +// return; // horizontal edge + movl Lceilv0,%ebx + movl C(edge_p),%edi + movl C(r_ceilv1),%ecx + movl %edi,%edx + movl C(r_pedge),%esi + addl $(et_size),%edx + cmpl %ecx,%ebx + jz LPop5AndDone + + movl C(r_pedge),%eax + movl %eax,et_owner(%edi) + +// side = ceilv0 > r_ceilv1; +// +// edge->nearzi = lzi0; + fstps et_nearzi(%edi) // u1 | v0 | v1 | u0 + +// if (side == 1) +// { + jc LSide0 + +LSide1: + +// // leading edge (go from p2 to p1) + +// u_step = ((u0 - r_u1) / (v0 - r_v1)); + fsubrp %st(0),%st(3) // v0 | v1 | u0-u1 + fsub %st(1),%st(0) // v0-v1 | v1 | u0-u1 + fdivrp %st(0),%st(2) // v1 | ustep + +// r_emitted = 1; + movl $1,C(r_emitted) + +// edge = edge_p++; + movl %edx,C(edge_p) + +// pretouch next edge + movl (%edx),%eax + +// v2 = ceilv0 - 1; +// v = r_ceilv1; + movl %ecx,%eax + leal -1(%ebx),%ecx + movl %eax,%ebx + +// edge->surfs[0] = 0; +// edge->surfs[1] = surface_p - surfaces; + movl C(surface_p),%eax + movl C(surfaces),%esi + subl %edx,%edx + subl %esi,%eax + shrl $(SURF_T_SHIFT),%eax + movl %edx,et_surfs(%edi) + movl %eax,et_surfs+2(%edi) + + subl %esi,%esi + +// u = r_u1 + ((float)v - r_v1) * u_step; + movl %ebx,Lv + fildl Lv // v | v1 | ustep + fsubp %st(0),%st(1) // v-v1 | ustep + fmul %st(1),%st(0) // (v-v1)*ustep | ustep + fadds C(r_u1) // u | ustep + + jmp LSideDone + +// } + +LSide0: + +// else +// { +// // trailing edge (go from p1 to p2) + +// u_step = ((r_u1 - u0) / (r_v1 - v0)); + fsub %st(3),%st(0) // u1-u0 | v0 | v1 | u0 + fxch %st(2) // v1 | v0 | u1-u0 | u0 + fsub %st(1),%st(0) // v1-v0 | v0 | u1-u0 | u0 + fdivrp %st(0),%st(2) // v0 | ustep | u0 + +// r_emitted = 1; + movl $1,C(r_emitted) + +// edge = edge_p++; + movl %edx,C(edge_p) + +// pretouch next edge + movl (%edx),%eax + +// v = ceilv0; +// v2 = r_ceilv1 - 1; + decl %ecx + +// edge->surfs[0] = surface_p - surfaces; +// edge->surfs[1] = 0; + movl C(surface_p),%eax + movl C(surfaces),%esi + subl %edx,%edx + subl %esi,%eax + shrl $(SURF_T_SHIFT),%eax + movl %edx,et_surfs+2(%edi) + movl %eax,et_surfs(%edi) + + movl $1,%esi + +// u = u0 + ((float)v - v0) * u_step; + movl %ebx,Lv + fildl Lv // v | v0 | ustep | u0 + fsubp %st(0),%st(1) // v-v0 | ustep | u0 + fmul %st(1),%st(0) // (v-v0)*ustep | ustep | u0 + faddp %st(0),%st(2) // ustep | u + fxch %st(1) // u | ustep + +// } + +LSideDone: + +// edge->u_step = u_step*0x100000; +// edge->u = u*0x100000 + 0xFFFFF; + + fmuls fp_1m // u*0x100000 | ustep + fxch %st(1) // ustep | u*0x100000 + fmuls fp_1m // ustep*0x100000 | u*0x100000 + fxch %st(1) // u*0x100000 | ustep*0x100000 + fadds fp_1m_minus_1 // u*0x100000 + 0xFFFFF | ustep*0x100000 + fxch %st(1) // ustep*0x100000 | u*0x100000 + 0xFFFFF + fistpl et_u_step(%edi) // u*0x100000 + 0xFFFFF + fistpl et_u(%edi) + +// // we need to do this to avoid stepping off the edges if a very nearly +// // horizontal edge is less than epsilon above a scan, and numeric error +// // causes it to incorrectly extend to the scan, and the extension of the +// // line goes off the edge of the screen +// // FIXME: is this actually needed? +// if (edge->u < r_refdef.vrect_x_adj_shift20) +// edge->u = r_refdef.vrect_x_adj_shift20; +// if (edge->u > r_refdef.vrectright_adj_shift20) +// edge->u = r_refdef.vrectright_adj_shift20; + movl et_u(%edi),%eax + movl C(r_refdef)+rd_vrect_x_adj_shift20,%edx + cmpl %edx,%eax + jl LP4 + movl C(r_refdef)+rd_vrectright_adj_shift20,%edx + cmpl %edx,%eax + jng LP5 +LP4: + movl %edx,et_u(%edi) + movl %edx,%eax +LP5: + +// // sort the edge in normally +// u_check = edge->u; +// +// if (edge->surfs[0]) +// u_check++; // sort trailers after leaders + addl %esi,%eax + +// if (!newedges[v] || newedges[v]->u >= u_check) +// { + movl C(newedges)(,%ebx,4),%esi + testl %esi,%esi + jz LDoFirst + cmpl %eax,et_u(%esi) + jl LNotFirst +LDoFirst: + +// edge->next = newedges[v]; +// newedges[v] = edge; + movl %esi,et_next(%edi) + movl %edi,C(newedges)(,%ebx,4) + + jmp LSetRemove + +// } + +LNotFirst: + +// else +// { +// pcheck = newedges[v]; +// +// while (pcheck->next && pcheck->next->u < u_check) +// pcheck = pcheck->next; +LFindInsertLoop: + movl %esi,%edx + movl et_next(%esi),%esi + testl %esi,%esi + jz LInsertFound + cmpl %eax,et_u(%esi) + jl LFindInsertLoop + +LInsertFound: + +// edge->next = pcheck->next; +// pcheck->next = edge; + movl %esi,et_next(%edi) + movl %edi,et_next(%edx) + +// } + +LSetRemove: + +// edge->nextremove = removeedges[v2]; +// removeedges[v2] = edge; + movl C(removeedges)(,%ecx,4),%eax + movl %edi,C(removeedges)(,%ecx,4) + movl %eax,et_nextremove(%edi) + +Ldone: + movl Lstack,%esp // clear temporary variables from stack + + popl %ebx // restore register variables + popl %edi + popl %esi + ret + +// at least one point is clipped + +Lp2: + testl %eax,%eax + jns Lp1 + +// else +// { +// // point 0 is clipped + +// if (d1 < 0) +// { + movl Ld1,%eax + testl %eax,%eax + jns Lp3 + +// // both points are clipped +// // we do cache fully clipped edges +// if (!leftclipped) + movl C(r_leftclipped),%eax + movl C(r_pedge),%ecx + testl %eax,%eax + jnz Ldone + +// r_pedge->framecount = r_framecount; + movl C(r_framecount),%eax + andl $(FRAMECOUNT_MASK),%eax + orl $(FULLY_CLIPPED_CACHED),%eax + movl %eax,C(cacheoffset) + +// return; + jmp Ldone + +// } + +Lp1: + +// // point 0 is unclipped +// if (d1 >= 0) +// { +// // both points are unclipped +// continue; + +// // only point 1 is clipped + +// f = d0 / (d0 - d1); + flds Ld0 + flds Ld1 + fsubr %st(1),%st(0) + +// // we don't cache partially clipped edges + movl $0x7FFFFFFF,C(cacheoffset) + + fdivrp %st(0),%st(1) + + subl $(mv_size),%esp // allocate space for clipvert + +// clipvert.position[0] = pv0->position[0] + +// f * (pv1->position[0] - pv0->position[0]); +// clipvert.position[1] = pv0->position[1] + +// f * (pv1->position[1] - pv0->position[1]); +// clipvert.position[2] = pv0->position[2] + +// f * (pv1->position[2] - pv0->position[2]); + flds mv_position+8(%edx) + fsubs mv_position+8(%esi) + flds mv_position+4(%edx) + fsubs mv_position+4(%esi) + flds mv_position+0(%edx) + fsubs mv_position+0(%esi) // 0 | 1 | 2 + +// replace pv1 with the clip point + movl %esp,%edx + movl cp_leftedge(%ebx),%eax + testb %al,%al + + fmul %st(3),%st(0) + fxch %st(1) // 1 | 0 | 2 + fmul %st(3),%st(0) + fxch %st(2) // 2 | 0 | 1 + fmulp %st(0),%st(3) // 0 | 1 | 2 + fadds mv_position+0(%esi) + fxch %st(1) // 1 | 0 | 2 + fadds mv_position+4(%esi) + fxch %st(2) // 2 | 0 | 1 + fadds mv_position+8(%esi) + fxch %st(1) // 0 | 2 | 1 + fstps mv_position+0(%esp) // 2 | 1 + fstps mv_position+8(%esp) // 1 + fstps mv_position+4(%esp) + +// if (clip->leftedge) +// { + jz Ltestright + +// r_leftclipped = true; +// r_leftexit = clipvert; + movl $1,C(r_leftclipped) + movl mv_position+0(%esp),%eax + movl %eax,C(r_leftexit)+mv_position+0 + movl mv_position+4(%esp),%eax + movl %eax,C(r_leftexit)+mv_position+4 + movl mv_position+8(%esp),%eax + movl %eax,C(r_leftexit)+mv_position+8 + + jmp Lcontinue + +// } + +Ltestright: +// else if (clip->rightedge) +// { + testb %ah,%ah + jz Lcontinue + +// r_rightclipped = true; +// r_rightexit = clipvert; + movl $1,C(r_rightclipped) + movl mv_position+0(%esp),%eax + movl %eax,C(r_rightexit)+mv_position+0 + movl mv_position+4(%esp),%eax + movl %eax,C(r_rightexit)+mv_position+4 + movl mv_position+8(%esp),%eax + movl %eax,C(r_rightexit)+mv_position+8 + +// } +// +// R_ClipEdge (pv0, &clipvert, clip->next); +// return; +// } + jmp Lcontinue + +// } + +Lp3: + +// // only point 0 is clipped +// r_lastvertvalid = false; + + movl $0,C(r_lastvertvalid) + +// f = d0 / (d0 - d1); + flds Ld0 + flds Ld1 + fsubr %st(1),%st(0) + +// // we don't cache partially clipped edges + movl $0x7FFFFFFF,C(cacheoffset) + + fdivrp %st(0),%st(1) + + subl $(mv_size),%esp // allocate space for clipvert + +// clipvert.position[0] = pv0->position[0] + +// f * (pv1->position[0] - pv0->position[0]); +// clipvert.position[1] = pv0->position[1] + +// f * (pv1->position[1] - pv0->position[1]); +// clipvert.position[2] = pv0->position[2] + +// f * (pv1->position[2] - pv0->position[2]); + flds mv_position+8(%edx) + fsubs mv_position+8(%esi) + flds mv_position+4(%edx) + fsubs mv_position+4(%esi) + flds mv_position+0(%edx) + fsubs mv_position+0(%esi) // 0 | 1 | 2 + + movl cp_leftedge(%ebx),%eax + testb %al,%al + + fmul %st(3),%st(0) + fxch %st(1) // 1 | 0 | 2 + fmul %st(3),%st(0) + fxch %st(2) // 2 | 0 | 1 + fmulp %st(0),%st(3) // 0 | 1 | 2 + fadds mv_position+0(%esi) + fxch %st(1) // 1 | 0 | 2 + fadds mv_position+4(%esi) + fxch %st(2) // 2 | 0 | 1 + fadds mv_position+8(%esi) + fxch %st(1) // 0 | 2 | 1 + fstps mv_position+0(%esp) // 2 | 1 + fstps mv_position+8(%esp) // 1 + fstps mv_position+4(%esp) + +// replace pv0 with the clip point + movl %esp,%esi + +// if (clip->leftedge) +// { + jz Ltestright2 + +// r_leftclipped = true; +// r_leftenter = clipvert; + movl $1,C(r_leftclipped) + movl mv_position+0(%esp),%eax + movl %eax,C(r_leftenter)+mv_position+0 + movl mv_position+4(%esp),%eax + movl %eax,C(r_leftenter)+mv_position+4 + movl mv_position+8(%esp),%eax + movl %eax,C(r_leftenter)+mv_position+8 + + jmp Lcontinue + +// } + +Ltestright2: +// else if (clip->rightedge) +// { + testb %ah,%ah + jz Lcontinue + +// r_rightclipped = true; +// r_rightenter = clipvert; + movl $1,C(r_rightclipped) + movl mv_position+0(%esp),%eax + movl %eax,C(r_rightenter)+mv_position+0 + movl mv_position+4(%esp),%eax + movl %eax,C(r_rightenter)+mv_position+4 + movl mv_position+8(%esp),%eax + movl %eax,C(r_rightenter)+mv_position+8 + +// } + jmp Lcontinue + +// %esi = vec3_t point to transform and project +// %edx preserved +LTransformAndProject: + +// // transform and project +// VectorSubtract (world, modelorg, local); + flds mv_position+0(%esi) + fsubs C(modelorg)+0 + flds mv_position+4(%esi) + fsubs C(modelorg)+4 + flds mv_position+8(%esi) + fsubs C(modelorg)+8 + fxch %st(2) // local[0] | local[1] | local[2] + +// TransformVector (local, transformed); +// +// if (transformed[2] < NEAR_CLIP) +// transformed[2] = NEAR_CLIP; +// +// lzi0 = 1.0 / transformed[2]; + fld %st(0) // local[0] | local[0] | local[1] | local[2] + fmuls C(vpn)+0 // zm0 | local[0] | local[1] | local[2] + fld %st(1) // local[0] | zm0 | local[0] | local[1] | + // local[2] + fmuls C(vright)+0 // xm0 | zm0 | local[0] | local[1] | local[2] + fxch %st(2) // local[0] | zm0 | xm0 | local[1] | local[2] + fmuls C(vup)+0 // ym0 | zm0 | xm0 | local[1] | local[2] + fld %st(3) // local[1] | ym0 | zm0 | xm0 | local[1] | + // local[2] + fmuls C(vpn)+4 // zm1 | ym0 | zm0 | xm0 | local[1] | + // local[2] + fld %st(4) // local[1] | zm1 | ym0 | zm0 | xm0 | + // local[1] | local[2] + fmuls C(vright)+4 // xm1 | zm1 | ym0 | zm0 | xm0 | + // local[1] | local[2] + fxch %st(5) // local[1] | zm1 | ym0 | zm0 | xm0 | + // xm1 | local[2] + fmuls C(vup)+4 // ym1 | zm1 | ym0 | zm0 | xm0 | + // xm1 | local[2] + fxch %st(1) // zm1 | ym1 | ym0 | zm0 | xm0 | + // xm1 | local[2] + faddp %st(0),%st(3) // ym1 | ym0 | zm2 | xm0 | xm1 | local[2] + fxch %st(3) // xm0 | ym0 | zm2 | ym1 | xm1 | local[2] + faddp %st(0),%st(4) // ym0 | zm2 | ym1 | xm2 | local[2] + faddp %st(0),%st(2) // zm2 | ym2 | xm2 | local[2] + fld %st(3) // local[2] | zm2 | ym2 | xm2 | local[2] + fmuls C(vpn)+8 // zm3 | zm2 | ym2 | xm2 | local[2] + fld %st(4) // local[2] | zm3 | zm2 | ym2 | xm2 | local[2] + fmuls C(vright)+8 // xm3 | zm3 | zm2 | ym2 | xm2 | local[2] + fxch %st(5) // local[2] | zm3 | zm2 | ym2 | xm2 | xm3 + fmuls C(vup)+8 // ym3 | zm3 | zm2 | ym2 | xm2 | xm3 + fxch %st(1) // zm3 | ym3 | zm2 | ym2 | xm2 | xm3 + faddp %st(0),%st(2) // ym3 | zm4 | ym2 | xm2 | xm3 + fxch %st(4) // xm3 | zm4 | ym2 | xm2 | ym3 + faddp %st(0),%st(3) // zm4 | ym2 | xm4 | ym3 + fxch %st(1) // ym2 | zm4 | xm4 | ym3 + faddp %st(0),%st(3) // zm4 | xm4 | ym4 + + fcoms Lfp_near_clip + fnstsw %ax + testb $1,%ah + jz LNoClip + fstp %st(0) + flds Lfp_near_clip + +LNoClip: + + fdivrs float_1 // lzi0 | x | y + fxch %st(1) // x | lzi0 | y + +// // FIXME: build x/yscale into transform? +// scale = xscale * lzi0; +// u0 = (xcenter + scale*transformed[0]); + flds C(xscale) // xscale | x | lzi0 | y + fmul %st(2),%st(0) // scale | x | lzi0 | y + fmulp %st(0),%st(1) // scale*x | lzi0 | y + fadds C(xcenter) // u0 | lzi0 | y + +// if (u0 < r_refdef.fvrectx_adj) +// u0 = r_refdef.fvrectx_adj; +// if (u0 > r_refdef.fvrectright_adj) +// u0 = r_refdef.fvrectright_adj; +// FIXME: use integer compares of floats? + fcoms C(r_refdef)+rd_fvrectx_adj + fnstsw %ax + testb $1,%ah + jz LClampP0 + fstp %st(0) + flds C(r_refdef)+rd_fvrectx_adj +LClampP0: + fcoms C(r_refdef)+rd_fvrectright_adj + fnstsw %ax + testb $0x45,%ah + jnz LClampP1 + fstp %st(0) + flds C(r_refdef)+rd_fvrectright_adj +LClampP1: + + fld %st(1) // lzi0 | u0 | lzi0 | y + +// scale = yscale * lzi0; +// v0 = (ycenter - scale*transformed[1]); + fmuls C(yscale) // scale | u0 | lzi0 | y + fmulp %st(0),%st(3) // u0 | lzi0 | scale*y + fxch %st(2) // scale*y | lzi0 | u0 + fsubrs C(ycenter) // v0 | lzi0 | u0 + +// if (v0 < r_refdef.fvrecty_adj) +// v0 = r_refdef.fvrecty_adj; +// if (v0 > r_refdef.fvrectbottom_adj) +// v0 = r_refdef.fvrectbottom_adj; +// FIXME: use integer compares of floats? + fcoms C(r_refdef)+rd_fvrecty_adj + fnstsw %ax + testb $1,%ah + jz LClampP2 + fstp %st(0) + flds C(r_refdef)+rd_fvrecty_adj +LClampP2: + fcoms C(r_refdef)+rd_fvrectbottom_adj + fnstsw %ax + testb $0x45,%ah + jnz LClampP3 + fstp %st(0) + flds C(r_refdef)+rd_fvrectbottom_adj +LClampP3: + ret + +#endif // id386 + diff --git a/linux/r_edgea.s b/linux/r_edgea.s new file mode 100644 index 000000000..6b38251e8 --- /dev/null +++ b/linux/r_edgea.s @@ -0,0 +1,729 @@ +// +// r_edgea.s +// x86 assembly-language edge-processing code. +// + +#include "qasm.h" + +#if id386 + + .data +Ltemp: .long 0 +float_1_div_0100000h: .long 0x35800000 // 1.0/(float)0x100000 +float_point_999: .single 0.999 +float_1_point_001: .single 1.001 + + .text + +//-------------------------------------------------------------------- + +#define edgestoadd 4+8 // note odd stack offsets because of interleaving +#define edgelist 8+12 // with pushes + +.globl C(R_EdgeCodeStart) +C(R_EdgeCodeStart): + +.globl C(R_InsertNewEdges) +C(R_InsertNewEdges): + pushl %edi + pushl %esi // preserve register variables + movl edgestoadd(%esp),%edx + pushl %ebx + movl edgelist(%esp),%ecx + +LDoNextEdge: + movl et_u(%edx),%eax + movl %edx,%edi + +LContinueSearch: + movl et_u(%ecx),%ebx + movl et_next(%ecx),%esi + cmpl %ebx,%eax + jle LAddedge + movl et_u(%esi),%ebx + movl et_next(%esi),%ecx + cmpl %ebx,%eax + jle LAddedge2 + movl et_u(%ecx),%ebx + movl et_next(%ecx),%esi + cmpl %ebx,%eax + jle LAddedge + movl et_u(%esi),%ebx + movl et_next(%esi),%ecx + cmpl %ebx,%eax + jg LContinueSearch + +LAddedge2: + movl et_next(%edx),%edx + movl et_prev(%esi),%ebx + movl %esi,et_next(%edi) + movl %ebx,et_prev(%edi) + movl %edi,et_next(%ebx) + movl %edi,et_prev(%esi) + movl %esi,%ecx + + cmpl $0,%edx + jnz LDoNextEdge + jmp LDone + + .align 4 +LAddedge: + movl et_next(%edx),%edx + movl et_prev(%ecx),%ebx + movl %ecx,et_next(%edi) + movl %ebx,et_prev(%edi) + movl %edi,et_next(%ebx) + movl %edi,et_prev(%ecx) + + cmpl $0,%edx + jnz LDoNextEdge + +LDone: + popl %ebx // restore register variables + popl %esi + popl %edi + + ret + +//-------------------------------------------------------------------- + +#define predge 4+4 + +.globl C(R_RemoveEdges) +C(R_RemoveEdges): + pushl %ebx + movl predge(%esp),%eax + +Lre_loop: + movl et_next(%eax),%ecx + movl et_nextremove(%eax),%ebx + movl et_prev(%eax),%edx + testl %ebx,%ebx + movl %edx,et_prev(%ecx) + jz Lre_done + movl %ecx,et_next(%edx) + + movl et_next(%ebx),%ecx + movl et_prev(%ebx),%edx + movl et_nextremove(%ebx),%eax + movl %edx,et_prev(%ecx) + testl %eax,%eax + movl %ecx,et_next(%edx) + jnz Lre_loop + + popl %ebx + ret + +Lre_done: + movl %ecx,et_next(%edx) + popl %ebx + + ret + +//-------------------------------------------------------------------- + +#define pedgelist 4+4 // note odd stack offset because of interleaving + // with pushes + +.globl C(R_StepActiveU) +C(R_StepActiveU): + pushl %edi + movl pedgelist(%esp),%edx + pushl %esi // preserve register variables + pushl %ebx + + movl et_prev(%edx),%esi + +LNewEdge: + movl et_u(%esi),%edi + +LNextEdge: + movl et_u(%edx),%eax + movl et_u_step(%edx),%ebx + addl %ebx,%eax + movl et_next(%edx),%esi + movl %eax,et_u(%edx) + cmpl %edi,%eax + jl LPushBack + + movl et_u(%esi),%edi + movl et_u_step(%esi),%ebx + addl %ebx,%edi + movl et_next(%esi),%edx + movl %edi,et_u(%esi) + cmpl %eax,%edi + jl LPushBack2 + + movl et_u(%edx),%eax + movl et_u_step(%edx),%ebx + addl %ebx,%eax + movl et_next(%edx),%esi + movl %eax,et_u(%edx) + cmpl %edi,%eax + jl LPushBack + + movl et_u(%esi),%edi + movl et_u_step(%esi),%ebx + addl %ebx,%edi + movl et_next(%esi),%edx + movl %edi,et_u(%esi) + cmpl %eax,%edi + jnl LNextEdge + +LPushBack2: + movl %edx,%ebx + movl %edi,%eax + movl %esi,%edx + movl %ebx,%esi + +LPushBack: +// push it back to keep it sorted + movl et_prev(%edx),%ecx + movl et_next(%edx),%ebx + +// done if the -1 in edge_aftertail triggered this + cmpl $(C(edge_aftertail)),%edx + jz LUDone + +// pull the edge out of the edge list + movl et_prev(%ecx),%edi + movl %ecx,et_prev(%esi) + movl %ebx,et_next(%ecx) + +// find out where the edge goes in the edge list +LPushBackLoop: + movl et_prev(%edi),%ecx + movl et_u(%edi),%ebx + cmpl %ebx,%eax + jnl LPushBackFound + + movl et_prev(%ecx),%edi + movl et_u(%ecx),%ebx + cmpl %ebx,%eax + jl LPushBackLoop + + movl %ecx,%edi + +// put the edge back into the edge list +LPushBackFound: + movl et_next(%edi),%ebx + movl %edi,et_prev(%edx) + movl %ebx,et_next(%edx) + movl %edx,et_next(%edi) + movl %edx,et_prev(%ebx) + + movl %esi,%edx + movl et_prev(%esi),%esi + + cmpl $(C(edge_tail)),%edx + jnz LNewEdge + +LUDone: + popl %ebx // restore register variables + popl %esi + popl %edi + + ret + +//-------------------------------------------------------------------- + +#define surf 4 // note this is loaded before any pushes + + .align 4 +TrailingEdge: + movl st_spanstate(%esi),%eax // check for edge inversion + decl %eax + jnz LInverted + + movl %eax,st_spanstate(%esi) + movl st_insubmodel(%esi),%ecx + movl 0x12345678,%edx // surfaces[1].st_next +LPatch0: + movl C(r_bmodelactive),%eax + subl %ecx,%eax + cmpl %esi,%edx + movl %eax,C(r_bmodelactive) + jnz LNoEmit // surface isn't on top, just remove + +// emit a span (current top going away) + movl et_u(%ebx),%eax + shrl $20,%eax // iu = integral pixel u + movl st_last_u(%esi),%edx + movl st_next(%esi),%ecx + cmpl %edx,%eax + jle LNoEmit2 // iu <= surf->last_u, so nothing to emit + + movl %eax,st_last_u(%ecx) // surf->next->last_u = iu; + subl %edx,%eax + movl %edx,espan_t_u(%ebp) // span->u = surf->last_u; + + movl %eax,espan_t_count(%ebp) // span->count = iu - span->u; + movl C(current_iv),%eax + movl %eax,espan_t_v(%ebp) // span->v = current_iv; + movl st_spans(%esi),%eax + movl %eax,espan_t_pnext(%ebp) // span->pnext = surf->spans; + movl %ebp,st_spans(%esi) // surf->spans = span; + addl $(espan_t_size),%ebp + + movl st_next(%esi),%edx // remove the surface from the surface + movl st_prev(%esi),%esi // stack + + movl %edx,st_next(%esi) + movl %esi,st_prev(%edx) + ret + +LNoEmit2: + movl %eax,st_last_u(%ecx) // surf->next->last_u = iu; + movl st_next(%esi),%edx // remove the surface from the surface + movl st_prev(%esi),%esi // stack + + movl %edx,st_next(%esi) + movl %esi,st_prev(%edx) + ret + +LNoEmit: + movl st_next(%esi),%edx // remove the surface from the surface + movl st_prev(%esi),%esi // stack + + movl %edx,st_next(%esi) + movl %esi,st_prev(%edx) + ret + +LInverted: + movl %eax,st_spanstate(%esi) + ret + +//-------------------------------------------------------------------- + +// trailing edge only +Lgs_trailing: + pushl $Lgs_nextedge + jmp TrailingEdge + + +.globl C(R_GenerateSpans) +C(R_GenerateSpans): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// clear active surfaces to just the background surface + movl C(surfaces),%eax + movl C(edge_head_u_shift20),%edx + addl $(st_size),%eax +// %ebp = span_p throughout + movl C(span_p),%ebp + + movl $0,C(r_bmodelactive) + + movl %eax,st_next(%eax) + movl %eax,st_prev(%eax) + movl %edx,st_last_u(%eax) + movl C(edge_head)+et_next,%ebx // edge=edge_head.next + +// generate spans + cmpl $(C(edge_tail)),%ebx // done if empty list + jz Lgs_lastspan + +Lgs_edgeloop: + + movl et_surfs(%ebx),%edi + movl C(surfaces),%eax + movl %edi,%esi + andl $0xFFFF0000,%edi + andl $0xFFFF,%esi + jz Lgs_leading // not a trailing edge + +// it has a left surface, so a surface is going away for this span + shll $(SURF_T_SHIFT),%esi + addl %eax,%esi + testl %edi,%edi + jz Lgs_trailing + +// both leading and trailing + call TrailingEdge + movl C(surfaces),%eax + +// --------------------------------------------------------------- +// handle a leading edge +// --------------------------------------------------------------- + +Lgs_leading: + shrl $16-SURF_T_SHIFT,%edi + movl C(surfaces),%eax + addl %eax,%edi + movl 0x12345678,%esi // surf2 = surfaces[1].next; +LPatch2: + movl st_spanstate(%edi),%edx + movl st_insubmodel(%edi),%eax + testl %eax,%eax + jnz Lbmodel_leading + +// handle a leading non-bmodel edge + +// don't start a span if this is an inverted span, with the end edge preceding +// the start edge (that is, we've already seen the end edge) + testl %edx,%edx + jnz Lxl_done + + +// if (surf->key < surf2->key) +// goto newtop; + incl %edx + movl st_key(%edi),%eax + movl %edx,st_spanstate(%edi) + movl st_key(%esi),%ecx + cmpl %ecx,%eax + jl Lnewtop + +// main sorting loop to search through surface stack until insertion point +// found. Always terminates because background surface is sentinel +// do +// { +// surf2 = surf2->next; +// } while (surf->key >= surf2->key); +Lsortloopnb: + movl st_next(%esi),%esi + movl st_key(%esi),%ecx + cmpl %ecx,%eax + jge Lsortloopnb + + jmp LInsertAndExit + + +// handle a leading bmodel edge + .align 4 +Lbmodel_leading: + +// don't start a span if this is an inverted span, with the end edge preceding +// the start edge (that is, we've already seen the end edge) + testl %edx,%edx + jnz Lxl_done + + movl C(r_bmodelactive),%ecx + incl %edx + incl %ecx + movl %edx,st_spanstate(%edi) + movl %ecx,C(r_bmodelactive) + +// if (surf->key < surf2->key) +// goto newtop; + movl st_key(%edi),%eax + movl st_key(%esi),%ecx + cmpl %ecx,%eax + jl Lnewtop + +// if ((surf->key == surf2->key) && surf->insubmodel) +// { + jz Lzcheck_for_newtop + +// main sorting loop to search through surface stack until insertion point +// found. Always terminates because background surface is sentinel +// do +// { +// surf2 = surf2->next; +// } while (surf->key > surf2->key); +Lsortloop: + movl st_next(%esi),%esi + movl st_key(%esi),%ecx + cmpl %ecx,%eax + jg Lsortloop + + jne LInsertAndExit + +// Do 1/z sorting to see if we've arrived in the right position + movl et_u(%ebx),%eax + subl $0xFFFFF,%eax + movl %eax,Ltemp + fildl Ltemp + + fmuls float_1_div_0100000h // fu = (float)(edge->u - 0xFFFFF) * + // (1.0 / 0x100000); + + fld %st(0) // fu | fu + fmuls st_d_zistepu(%edi) // fu*surf->d_zistepu | fu + flds C(fv) // fv | fu*surf->d_zistepu | fu + fmuls st_d_zistepv(%edi) // fv*surf->d_zistepv | fu*surf->d_zistepu | fu + fxch %st(1) // fu*surf->d_zistepu | fv*surf->d_zistepv | fu + fadds st_d_ziorigin(%edi) // fu*surf->d_zistepu + surf->d_ziorigin | + // fv*surf->d_zistepv | fu + + flds st_d_zistepu(%esi) // surf2->d_zistepu | + // fu*surf->d_zistepu + surf->d_ziorigin | + // fv*surf->d_zistepv | fu + fmul %st(3),%st(0) // fu*surf2->d_zistepu | + // fu*surf->d_zistepu + surf->d_ziorigin | + // fv*surf->d_zistepv | fu + fxch %st(1) // fu*surf->d_zistepu + surf->d_ziorigin | + // fu*surf2->d_zistepu | + // fv*surf->d_zistepv | fu + faddp %st(0),%st(2) // fu*surf2->d_zistepu | newzi | fu + + flds C(fv) // fv | fu*surf2->d_zistepu | newzi | fu + fmuls st_d_zistepv(%esi) // fv*surf2->d_zistepv | + // fu*surf2->d_zistepu | newzi | fu + fld %st(2) // newzi | fv*surf2->d_zistepv | + // fu*surf2->d_zistepu | newzi | fu + fmuls float_point_999 // newzibottom | fv*surf2->d_zistepv | + // fu*surf2->d_zistepu | newzi | fu + + fxch %st(2) // fu*surf2->d_zistepu | fv*surf2->d_zistepv | + // newzibottom | newzi | fu + fadds st_d_ziorigin(%esi) // fu*surf2->d_zistepu + surf2->d_ziorigin | + // fv*surf2->d_zistepv | newzibottom | newzi | + // fu + faddp %st(0),%st(1) // testzi | newzibottom | newzi | fu + fxch %st(1) // newzibottom | testzi | newzi | fu + +// if (newzibottom >= testzi) +// goto Lgotposition; + + fcomp %st(1) // testzi | newzi | fu + + fxch %st(1) // newzi | testzi | fu + fmuls float_1_point_001 // newzitop | testzi | fu + fxch %st(1) // testzi | newzitop | fu + + fnstsw %ax + testb $0x01,%ah + jz Lgotposition_fpop3 + +// if (newzitop >= testzi) +// { + + fcomp %st(1) // newzitop | fu + fnstsw %ax + testb $0x45,%ah + jz Lsortloop_fpop2 + +// if (surf->d_zistepu >= surf2->d_zistepu) +// goto newtop; + + flds st_d_zistepu(%edi) // surf->d_zistepu | newzitop| fu + fcomps st_d_zistepu(%esi) // newzitop | fu + fnstsw %ax + testb $0x01,%ah + jz Lgotposition_fpop2 + + fstp %st(0) // clear the FPstack + fstp %st(0) + movl st_key(%edi),%eax + jmp Lsortloop + + +Lgotposition_fpop3: + fstp %st(0) +Lgotposition_fpop2: + fstp %st(0) + fstp %st(0) + jmp LInsertAndExit + + +// emit a span (obscures current top) + +Lnewtop_fpop3: + fstp %st(0) +Lnewtop_fpop2: + fstp %st(0) + fstp %st(0) + movl st_key(%edi),%eax // reload the sorting key + +Lnewtop: + movl et_u(%ebx),%eax + movl st_last_u(%esi),%edx + shrl $20,%eax // iu = integral pixel u + movl %eax,st_last_u(%edi) // surf->last_u = iu; + cmpl %edx,%eax + jle LInsertAndExit // iu <= surf->last_u, so nothing to emit + + subl %edx,%eax + movl %edx,espan_t_u(%ebp) // span->u = surf->last_u; + + movl %eax,espan_t_count(%ebp) // span->count = iu - span->u; + movl C(current_iv),%eax + movl %eax,espan_t_v(%ebp) // span->v = current_iv; + movl st_spans(%esi),%eax + movl %eax,espan_t_pnext(%ebp) // span->pnext = surf->spans; + movl %ebp,st_spans(%esi) // surf->spans = span; + addl $(espan_t_size),%ebp + +LInsertAndExit: +// insert before surf2 + movl %esi,st_next(%edi) // surf->next = surf2; + movl st_prev(%esi),%eax + movl %eax,st_prev(%edi) // surf->prev = surf2->prev; + movl %edi,st_prev(%esi) // surf2->prev = surf; + movl %edi,st_next(%eax) // surf2->prev->next = surf; + +// --------------------------------------------------------------- +// leading edge done +// --------------------------------------------------------------- + +// --------------------------------------------------------------- +// see if there are any more edges +// --------------------------------------------------------------- + +Lgs_nextedge: + movl et_next(%ebx),%ebx + cmpl $(C(edge_tail)),%ebx + jnz Lgs_edgeloop + +// clean up at the right edge +Lgs_lastspan: + +// now that we've reached the right edge of the screen, we're done with any +// unfinished surfaces, so emit a span for whatever's on top + movl 0x12345678,%esi // surfaces[1].st_next +LPatch3: + movl C(edge_tail_u_shift20),%eax + xorl %ecx,%ecx + movl st_last_u(%esi),%edx + subl %edx,%eax + jle Lgs_resetspanstate + + movl %edx,espan_t_u(%ebp) + movl %eax,espan_t_count(%ebp) + movl C(current_iv),%eax + movl %eax,espan_t_v(%ebp) + movl st_spans(%esi),%eax + movl %eax,espan_t_pnext(%ebp) + movl %ebp,st_spans(%esi) + addl $(espan_t_size),%ebp + +// reset spanstate for all surfaces in the surface stack +Lgs_resetspanstate: + movl %ecx,st_spanstate(%esi) + movl st_next(%esi),%esi + cmpl $0x12345678,%esi // &surfaces[1] +LPatch4: + jnz Lgs_resetspanstate + +// store the final span_p + movl %ebp,C(span_p) + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + + +// --------------------------------------------------------------- +// 1/z sorting for bmodels in the same leaf +// --------------------------------------------------------------- + .align 4 +Lxl_done: + incl %edx + movl %edx,st_spanstate(%edi) + + jmp Lgs_nextedge + + + .align 4 +Lzcheck_for_newtop: + movl et_u(%ebx),%eax + subl $0xFFFFF,%eax + movl %eax,Ltemp + fildl Ltemp + + fmuls float_1_div_0100000h // fu = (float)(edge->u - 0xFFFFF) * + // (1.0 / 0x100000); + + fld %st(0) // fu | fu + fmuls st_d_zistepu(%edi) // fu*surf->d_zistepu | fu + flds C(fv) // fv | fu*surf->d_zistepu | fu + fmuls st_d_zistepv(%edi) // fv*surf->d_zistepv | fu*surf->d_zistepu | fu + fxch %st(1) // fu*surf->d_zistepu | fv*surf->d_zistepv | fu + fadds st_d_ziorigin(%edi) // fu*surf->d_zistepu + surf->d_ziorigin | + // fv*surf->d_zistepv | fu + + flds st_d_zistepu(%esi) // surf2->d_zistepu | + // fu*surf->d_zistepu + surf->d_ziorigin | + // fv*surf->d_zistepv | fu + fmul %st(3),%st(0) // fu*surf2->d_zistepu | + // fu*surf->d_zistepu + surf->d_ziorigin | + // fv*surf->d_zistepv | fu + fxch %st(1) // fu*surf->d_zistepu + surf->d_ziorigin | + // fu*surf2->d_zistepu | + // fv*surf->d_zistepv | fu + faddp %st(0),%st(2) // fu*surf2->d_zistepu | newzi | fu + + flds C(fv) // fv | fu*surf2->d_zistepu | newzi | fu + fmuls st_d_zistepv(%esi) // fv*surf2->d_zistepv | + // fu*surf2->d_zistepu | newzi | fu + fld %st(2) // newzi | fv*surf2->d_zistepv | + // fu*surf2->d_zistepu | newzi | fu + fmuls float_point_999 // newzibottom | fv*surf2->d_zistepv | + // fu*surf2->d_zistepu | newzi | fu + + fxch %st(2) // fu*surf2->d_zistepu | fv*surf2->d_zistepv | + // newzibottom | newzi | fu + fadds st_d_ziorigin(%esi) // fu*surf2->d_zistepu + surf2->d_ziorigin | + // fv*surf2->d_zistepv | newzibottom | newzi | + // fu + faddp %st(0),%st(1) // testzi | newzibottom | newzi | fu + fxch %st(1) // newzibottom | testzi | newzi | fu + +// if (newzibottom >= testzi) +// goto newtop; + + fcomp %st(1) // testzi | newzi | fu + + fxch %st(1) // newzi | testzi | fu + fmuls float_1_point_001 // newzitop | testzi | fu + fxch %st(1) // testzi | newzitop | fu + + fnstsw %ax + testb $0x01,%ah + jz Lnewtop_fpop3 + +// if (newzitop >= testzi) +// { + + fcomp %st(1) // newzitop | fu + fnstsw %ax + testb $0x45,%ah + jz Lsortloop_fpop2 + +// if (surf->d_zistepu >= surf2->d_zistepu) +// goto newtop; + + flds st_d_zistepu(%edi) // surf->d_zistepu | newzitop | fu + fcomps st_d_zistepu(%esi) // newzitop | fu + fnstsw %ax + testb $0x01,%ah + jz Lnewtop_fpop2 + +Lsortloop_fpop2: + fstp %st(0) // clear the FP stack + fstp %st(0) + movl st_key(%edi),%eax + jmp Lsortloop + + +.globl C(R_EdgeCodeEnd) +C(R_EdgeCodeEnd): + + +//---------------------------------------------------------------------- +// Surface array address code patching routine +//---------------------------------------------------------------------- + + .align 4 +.globl C(R_SurfacePatch) +C(R_SurfacePatch): + + movl C(surfaces),%eax + addl $(st_size),%eax + movl %eax,LPatch4-4 + + addl $(st_next),%eax + movl %eax,LPatch0-4 + movl %eax,LPatch2-4 + movl %eax,LPatch3-4 + + ret + +#endif // id386 + diff --git a/linux/r_scana.s b/linux/r_scana.s new file mode 100644 index 000000000..f4ce68d37 --- /dev/null +++ b/linux/r_scana.s @@ -0,0 +1,68 @@ +// +// d_scana.s +// x86 assembly-language turbulent texture mapping code +// + +#include "qasm.h" +#include "d_ifacea.h" + +#if id386 + + .data + + .text + +//---------------------------------------------------------------------- +// turbulent texture mapping code +//---------------------------------------------------------------------- + + .align 4 +.globl C(D_DrawTurbulent8Span) +C(D_DrawTurbulent8Span): + pushl %ebp // preserve caller's stack frame pointer + pushl %esi // preserve register variables + pushl %edi + pushl %ebx + + movl C(r_turb_s),%esi + movl C(r_turb_t),%ecx + movl C(r_turb_pdest),%edi + movl C(r_turb_spancount),%ebx + +Llp: + movl %ecx,%eax + movl %esi,%edx + sarl $16,%eax + movl C(r_turb_turb),%ebp + sarl $16,%edx + andl $(CYCLE-1),%eax + andl $(CYCLE-1),%edx + movl (%ebp,%eax,4),%eax + movl (%ebp,%edx,4),%edx + addl %esi,%eax + sarl $16,%eax + addl %ecx,%edx + sarl $16,%edx + andl $(TURB_TEX_SIZE-1),%eax + andl $(TURB_TEX_SIZE-1),%edx + shll $6,%edx + movl C(r_turb_pbase),%ebp + addl %eax,%edx + incl %edi + addl C(r_turb_sstep),%esi + addl C(r_turb_tstep),%ecx + movb (%ebp,%edx,1),%dl + decl %ebx + movb %dl,-1(%edi) + jnz Llp + + movl %edi,C(r_turb_pdest) + + popl %ebx // restore register variables + popl %edi + popl %esi + popl %ebp // restore caller's stack frame pointer + ret + +#endif // id386 + diff --git a/linux/r_spr8.s b/linux/r_spr8.s new file mode 100644 index 000000000..d5fb01728 --- /dev/null +++ b/linux/r_spr8.s @@ -0,0 +1,879 @@ +// +// d_spr8.s +// x86 assembly-language horizontal 8-bpp transparent span-drawing code. +// + +#include "qasm.h" + +#if id386 + +//---------------------------------------------------------------------- +// 8-bpp horizontal span drawing code for polygons, with transparency. +//---------------------------------------------------------------------- + + .text + +// out-of-line, rarely-needed clamping code + +LClampHigh0: + movl C(bbextents),%esi + jmp LClampReentry0 +LClampHighOrLow0: + jg LClampHigh0 + xorl %esi,%esi + jmp LClampReentry0 + +LClampHigh1: + movl C(bbextentt),%edx + jmp LClampReentry1 +LClampHighOrLow1: + jg LClampHigh1 + xorl %edx,%edx + jmp LClampReentry1 + +LClampLow2: + movl $2048,%ebp + jmp LClampReentry2 +LClampHigh2: + movl C(bbextents),%ebp + jmp LClampReentry2 + +LClampLow3: + movl $2048,%ecx + jmp LClampReentry3 +LClampHigh3: + movl C(bbextentt),%ecx + jmp LClampReentry3 + +LClampLow4: + movl $2048,%eax + jmp LClampReentry4 +LClampHigh4: + movl C(bbextents),%eax + jmp LClampReentry4 + +LClampLow5: + movl $2048,%ebx + jmp LClampReentry5 +LClampHigh5: + movl C(bbextentt),%ebx + jmp LClampReentry5 + + +#define pspans 4+16 + + .align 4 +.globl C(D_SpriteDrawSpans) +C(D_SpriteDrawSpans): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// +// set up scaled-by-8 steps, for 8-long segments; also set up cacheblock +// and span list pointers, and 1/z step in 0.32 fixed-point +// +// FIXME: any overlap from rearranging? + flds C(d_sdivzstepu) + fmuls fp_8 + movl C(cacheblock),%edx + flds C(d_tdivzstepu) + fmuls fp_8 + movl pspans(%esp),%ebx // point to the first span descriptor + flds C(d_zistepu) + fmuls fp_8 + movl %edx,pbase // pbase = cacheblock + flds C(d_zistepu) + fmuls fp_64kx64k + fxch %st(3) + fstps sdivz8stepu + fstps zi8stepu + fstps tdivz8stepu + fistpl izistep + movl izistep,%eax + rorl $16,%eax // put upper 16 bits in low word + movl sspan_t_count(%ebx),%ecx + movl %eax,izistep + + cmpl $0,%ecx + jle LNextSpan + +LSpanLoop: + +// +// set up the initial s/z, t/z, and 1/z on the FP stack, and generate the +// initial s and t values +// +// FIXME: pipeline FILD? + fildl sspan_t_v(%ebx) + fildl sspan_t_u(%ebx) + + fld %st(1) // dv | du | dv + fmuls C(d_sdivzstepv) // dv*d_sdivzstepv | du | dv + fld %st(1) // du | dv*d_sdivzstepv | du | dv + fmuls C(d_sdivzstepu) // du*d_sdivzstepu | dv*d_sdivzstepv | du | dv + fld %st(2) // du | du*d_sdivzstepu | dv*d_sdivzstepv | du | dv + fmuls C(d_tdivzstepu) // du*d_tdivzstepu | du*d_sdivzstepu | + // dv*d_sdivzstepv | du | dv + fxch %st(1) // du*d_sdivzstepu | du*d_tdivzstepu | + // dv*d_sdivzstepv | du | dv + faddp %st(0),%st(2) // du*d_tdivzstepu | + // du*d_sdivzstepu + dv*d_sdivzstepv | du | dv + fxch %st(1) // du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fld %st(3) // dv | du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fmuls C(d_tdivzstepv) // dv*d_tdivzstepv | + // du*d_sdivzstepu + dv*d_sdivzstepv | + // du*d_tdivzstepu | du | dv + fxch %st(1) // du*d_sdivzstepu + dv*d_sdivzstepv | + // dv*d_tdivzstepv | du*d_tdivzstepu | du | dv + fadds C(d_sdivzorigin) // sdivz = d_sdivzorigin + dv*d_sdivzstepv + + // du*d_sdivzstepu; stays in %st(2) at end + fxch %st(4) // dv | dv*d_tdivzstepv | du*d_tdivzstepu | du | + // s/z + fmuls C(d_zistepv) // dv*d_zistepv | dv*d_tdivzstepv | + // du*d_tdivzstepu | du | s/z + fxch %st(1) // dv*d_tdivzstepv | dv*d_zistepv | + // du*d_tdivzstepu | du | s/z + faddp %st(0),%st(2) // dv*d_zistepv | + // dv*d_tdivzstepv + du*d_tdivzstepu | du | s/z + fxch %st(2) // du | dv*d_tdivzstepv + du*d_tdivzstepu | + // dv*d_zistepv | s/z + fmuls C(d_zistepu) // du*d_zistepu | + // dv*d_tdivzstepv + du*d_tdivzstepu | + // dv*d_zistepv | s/z + fxch %st(1) // dv*d_tdivzstepv + du*d_tdivzstepu | + // du*d_zistepu | dv*d_zistepv | s/z + fadds C(d_tdivzorigin) // tdivz = d_tdivzorigin + dv*d_tdivzstepv + + // du*d_tdivzstepu; stays in %st(1) at end + fxch %st(2) // dv*d_zistepv | du*d_zistepu | t/z | s/z + faddp %st(0),%st(1) // dv*d_zistepv + du*d_zistepu | t/z | s/z + + flds fp_64k // fp_64k | dv*d_zistepv + du*d_zistepu | t/z | s/z + fxch %st(1) // dv*d_zistepv + du*d_zistepu | fp_64k | t/z | s/z + fadds C(d_ziorigin) // zi = d_ziorigin + dv*d_zistepv + + // du*d_zistepu; stays in %st(0) at end + // 1/z | fp_64k | t/z | s/z + + fld %st(0) // FIXME: get rid of stall on FMUL? + fmuls fp_64kx64k + fxch %st(1) + +// +// calculate and clamp s & t +// + fdivr %st(0),%st(2) // 1/z | z*64k | t/z | s/z + fxch %st(1) + + fistpl izi // 0.32 fixed-point 1/z + movl izi,%ebp + +// +// set pz to point to the first z-buffer pixel in the span +// + rorl $16,%ebp // put upper 16 bits in low word + movl sspan_t_v(%ebx),%eax + movl %ebp,izi + movl sspan_t_u(%ebx),%ebp + imull C(d_zrowbytes) + shll $1,%ebp // a word per pixel + addl C(d_pzbuffer),%eax + addl %ebp,%eax + movl %eax,pz + +// +// point %edi to the first pixel in the span +// + movl C(d_viewbuffer),%ebp + movl sspan_t_v(%ebx),%eax + pushl %ebx // preserve spans pointer + movl C(tadjust),%edx + movl C(sadjust),%esi + movl C(d_scantable)(,%eax,4),%edi // v * screenwidth + addl %ebp,%edi + movl sspan_t_u(%ebx),%ebp + addl %ebp,%edi // pdest = &pdestspan[scans->u]; + +// +// now start the FDIV for the end of the span +// + cmpl $8,%ecx + ja LSetupNotLast1 + + decl %ecx + jz LCleanup1 // if only one pixel, no need to start an FDIV + movl %ecx,spancountminus1 + +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + + fildl spancountminus1 + + flds C(d_tdivzstepu) // _d_tdivzstepu | spancountminus1 + flds C(d_zistepu) // _d_zistepu | _d_tdivzstepu | spancountminus1 + fmul %st(2),%st(0) // _d_zistepu*scm1 | _d_tdivzstepu | scm1 + fxch %st(1) // _d_tdivzstepu | _d_zistepu*scm1 | scm1 + fmul %st(2),%st(0) // _d_tdivzstepu*scm1 | _d_zistepu*scm1 | scm1 + fxch %st(2) // scm1 | _d_zistepu*scm1 | _d_tdivzstepu*scm1 + fmuls C(d_sdivzstepu) // _d_sdivzstepu*scm1 | _d_zistepu*scm1 | + // _d_tdivzstepu*scm1 + fxch %st(1) // _d_zistepu*scm1 | _d_sdivzstepu*scm1 | + // _d_tdivzstepu*scm1 + faddp %st(0),%st(3) // _d_sdivzstepu*scm1 | _d_tdivzstepu*scm1 + fxch %st(1) // _d_tdivzstepu*scm1 | _d_sdivzstepu*scm1 + faddp %st(0),%st(3) // _d_sdivzstepu*scm1 + faddp %st(0),%st(3) + + flds fp_64k + fdiv %st(1),%st(0) // this is what we've gone to all this trouble to + // overlap + jmp LFDIVInFlight1 + +LCleanup1: +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + jmp LFDIVInFlight1 + + .align 4 +LSetupNotLast1: +// finish up the s and t calcs + fxch %st(1) // z*64k | 1/z | t/z | s/z + + fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z + fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z + fxch %st(1) // z*64k | s | 1/z | t/z | s/z + fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z + fxch %st(1) // s | t | 1/z | t/z | s/z + fistpl s // 1/z | t | t/z | s/z + fistpl t // 1/z | t/z | s/z + + fadds zi8stepu + fxch %st(2) + fadds sdivz8stepu + fxch %st(2) + flds tdivz8stepu + faddp %st(0),%st(2) + flds fp_64k + fdiv %st(1),%st(0) // z = 1/1/z + // this is what we've gone to all this trouble to + // overlap +LFDIVInFlight1: + + addl s,%esi + addl t,%edx + movl C(bbextents),%ebx + movl C(bbextentt),%ebp + cmpl %ebx,%esi + ja LClampHighOrLow0 +LClampReentry0: + movl %esi,s + movl pbase,%ebx + shll $16,%esi + cmpl %ebp,%edx + movl %esi,sfracf + ja LClampHighOrLow1 +LClampReentry1: + movl %edx,t + movl s,%esi // sfrac = scans->sfrac; + shll $16,%edx + movl t,%eax // tfrac = scans->tfrac; + sarl $16,%esi + movl %edx,tfracf + +// +// calculate the texture starting address +// + sarl $16,%eax + addl %ebx,%esi + imull C(cachewidth),%eax // (tfrac >> 16) * cachewidth + addl %eax,%esi // psource = pbase + (sfrac >> 16) + + // ((tfrac >> 16) * cachewidth); + +// +// determine whether last span or not +// + cmpl $8,%ecx + jna LLastSegment + +// +// not the last segment; do full 8-wide segment +// +LNotLastSegment: + +// +// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to +// get there +// + +// pick up after the FDIV that was left in flight previously + + fld %st(0) // duplicate it + fmul %st(4),%st(0) // s = s/z * z + fxch %st(1) + fmul %st(3),%st(0) // t = t/z * z + fxch %st(1) + fistpl snext + fistpl tnext + movl snext,%eax + movl tnext,%edx + + subl $8,%ecx // count off this segments' pixels + movl C(sadjust),%ebp + pushl %ecx // remember count of remaining pixels + movl C(tadjust),%ecx + + addl %eax,%ebp + addl %edx,%ecx + + movl C(bbextents),%eax + movl C(bbextentt),%edx + + cmpl $2048,%ebp + jl LClampLow2 + cmpl %eax,%ebp + ja LClampHigh2 +LClampReentry2: + + cmpl $2048,%ecx + jl LClampLow3 + cmpl %edx,%ecx + ja LClampHigh3 +LClampReentry3: + + movl %ebp,snext + movl %ecx,tnext + + subl s,%ebp + subl t,%ecx + +// +// set up advancetable +// + movl %ecx,%eax + movl %ebp,%edx + sarl $19,%edx // sstep >>= 16; + movl C(cachewidth),%ebx + sarl $19,%eax // tstep >>= 16; + jz LIsZero + imull %ebx,%eax // (tstep >> 16) * cachewidth; +LIsZero: + addl %edx,%eax // add in sstep + // (tstep >> 16) * cachewidth + (sstep >> 16); + movl tfracf,%edx + movl %eax,advancetable+4 // advance base in t + addl %ebx,%eax // ((tstep >> 16) + 1) * cachewidth + + // (sstep >> 16); + shll $13,%ebp // left-justify sstep fractional part + movl %ebp,sstep + movl sfracf,%ebx + shll $13,%ecx // left-justify tstep fractional part + movl %eax,advancetable // advance extra in t + movl %ecx,tstep + + movl pz,%ecx + movl izi,%ebp + + cmpw (%ecx),%bp + jl Lp1 + movb (%esi),%al // get first source texel + cmpb $(TRANSPARENT_COLOR),%al + jz Lp1 + movw %bp,(%ecx) + movb %al,(%edi) // store first dest pixel +Lp1: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx // advance tfrac fractional part by tstep frac + + sbbl %eax,%eax // turn tstep carry into -1 (0 if none) + addl sstep,%ebx // advance sfrac fractional part by sstep frac + adcl advancetable+4(,%eax,4),%esi // point to next source texel + + cmpw 2(%ecx),%bp + jl Lp2 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp2 + movw %bp,2(%ecx) + movb %al,1(%edi) +Lp2: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + + cmpw 4(%ecx),%bp + jl Lp3 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp3 + movw %bp,4(%ecx) + movb %al,2(%edi) +Lp3: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + + cmpw 6(%ecx),%bp + jl Lp4 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp4 + movw %bp,6(%ecx) + movb %al,3(%edi) +Lp4: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + + cmpw 8(%ecx),%bp + jl Lp5 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp5 + movw %bp,8(%ecx) + movb %al,4(%edi) +Lp5: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + +// +// start FDIV for end of next segment in flight, so it can overlap +// + popl %eax + cmpl $8,%eax // more than one segment after this? + ja LSetupNotLast2 // yes + + decl %eax + jz LFDIVInFlight2 // if only one pixel, no need to start an FDIV + movl %eax,spancountminus1 + fildl spancountminus1 + + flds C(d_zistepu) // _d_zistepu | spancountminus1 + fmul %st(1),%st(0) // _d_zistepu*scm1 | scm1 + flds C(d_tdivzstepu) // _d_tdivzstepu | _d_zistepu*scm1 | scm1 + fmul %st(2),%st(0) // _d_tdivzstepu*scm1 | _d_zistepu*scm1 | scm1 + fxch %st(1) // _d_zistepu*scm1 | _d_tdivzstepu*scm1 | scm1 + faddp %st(0),%st(3) // _d_tdivzstepu*scm1 | scm1 + fxch %st(1) // scm1 | _d_tdivzstepu*scm1 + fmuls C(d_sdivzstepu) // _d_sdivzstepu*scm1 | _d_tdivzstepu*scm1 + fxch %st(1) // _d_tdivzstepu*scm1 | _d_sdivzstepu*scm1 + faddp %st(0),%st(3) // _d_sdivzstepu*scm1 + flds fp_64k // 64k | _d_sdivzstepu*scm1 + fxch %st(1) // _d_sdivzstepu*scm1 | 64k + faddp %st(0),%st(4) // 64k + + fdiv %st(1),%st(0) // this is what we've gone to all this trouble to + // overlap + jmp LFDIVInFlight2 + + .align 4 +LSetupNotLast2: + fadds zi8stepu + fxch %st(2) + fadds sdivz8stepu + fxch %st(2) + flds tdivz8stepu + faddp %st(0),%st(2) + flds fp_64k + fdiv %st(1),%st(0) // z = 1/1/z + // this is what we've gone to all this trouble to + // overlap +LFDIVInFlight2: + pushl %eax + + cmpw 10(%ecx),%bp + jl Lp6 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp6 + movw %bp,10(%ecx) + movb %al,5(%edi) +Lp6: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + + cmpw 12(%ecx),%bp + jl Lp7 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp7 + movw %bp,12(%ecx) + movb %al,6(%edi) +Lp7: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + + cmpw 14(%ecx),%bp + jl Lp8 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp8 + movw %bp,14(%ecx) + movb %al,7(%edi) +Lp8: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + + addl $8,%edi + addl $16,%ecx + movl %edx,tfracf + movl snext,%edx + movl %ebx,sfracf + movl tnext,%ebx + movl %edx,s + movl %ebx,t + + movl %ecx,pz + movl %ebp,izi + + popl %ecx // retrieve count + +// +// determine whether last span or not +// + cmpl $8,%ecx // are there multiple segments remaining? + ja LNotLastSegment // yes + +// +// last segment of scan +// +LLastSegment: + +// +// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to +// get there. The number of pixels left is variable, and we want to land on the +// last pixel, not step one past it, so we can't run into arithmetic problems +// + testl %ecx,%ecx + jz LNoSteps // just draw the last pixel and we're done + +// pick up after the FDIV that was left in flight previously + + + fld %st(0) // duplicate it + fmul %st(4),%st(0) // s = s/z * z + fxch %st(1) + fmul %st(3),%st(0) // t = t/z * z + fxch %st(1) + fistpl snext + fistpl tnext + + movl C(tadjust),%ebx + movl C(sadjust),%eax + + addl snext,%eax + addl tnext,%ebx + + movl C(bbextents),%ebp + movl C(bbextentt),%edx + + cmpl $2048,%eax + jl LClampLow4 + cmpl %ebp,%eax + ja LClampHigh4 +LClampReentry4: + movl %eax,snext + + cmpl $2048,%ebx + jl LClampLow5 + cmpl %edx,%ebx + ja LClampHigh5 +LClampReentry5: + + cmpl $1,%ecx // don't bother + je LOnlyOneStep // if two pixels in segment, there's only one step, + // of the segment length + subl s,%eax + subl t,%ebx + + addl %eax,%eax // convert to 15.17 format so multiply by 1.31 + addl %ebx,%ebx // reciprocal yields 16.48 + imull reciprocal_table-8(,%ecx,4) // sstep = (snext - s) / (spancount-1) + movl %edx,%ebp + + movl %ebx,%eax + imull reciprocal_table-8(,%ecx,4) // tstep = (tnext - t) / (spancount-1) + +LSetEntryvec: +// +// set up advancetable +// + movl spr8entryvec_table(,%ecx,4),%ebx + movl %edx,%eax + pushl %ebx // entry point into code for RET later + movl %ebp,%ecx + sarl $16,%ecx // sstep >>= 16; + movl C(cachewidth),%ebx + sarl $16,%edx // tstep >>= 16; + jz LIsZeroLast + imull %ebx,%edx // (tstep >> 16) * cachewidth; +LIsZeroLast: + addl %ecx,%edx // add in sstep + // (tstep >> 16) * cachewidth + (sstep >> 16); + movl tfracf,%ecx + movl %edx,advancetable+4 // advance base in t + addl %ebx,%edx // ((tstep >> 16) + 1) * cachewidth + + // (sstep >> 16); + shll $16,%ebp // left-justify sstep fractional part + movl sfracf,%ebx + shll $16,%eax // left-justify tstep fractional part + movl %edx,advancetable // advance extra in t + + movl %eax,tstep + movl %ebp,sstep + movl %ecx,%edx + + movl pz,%ecx + movl izi,%ebp + + ret // jump to the number-of-pixels handler + +//---------------------------------------- + +LNoSteps: + movl pz,%ecx + subl $7,%edi // adjust for hardwired offset + subl $14,%ecx + jmp LEndSpan + + +LOnlyOneStep: + subl s,%eax + subl t,%ebx + movl %eax,%ebp + movl %ebx,%edx + jmp LSetEntryvec + +//---------------------------------------- + +.globl Spr8Entry2_8 +Spr8Entry2_8: + subl $6,%edi // adjust for hardwired offsets + subl $12,%ecx + movb (%esi),%al + jmp LLEntry2_8 + +//---------------------------------------- + +.globl Spr8Entry3_8 +Spr8Entry3_8: + subl $5,%edi // adjust for hardwired offsets + subl $10,%ecx + jmp LLEntry3_8 + +//---------------------------------------- + +.globl Spr8Entry4_8 +Spr8Entry4_8: + subl $4,%edi // adjust for hardwired offsets + subl $8,%ecx + jmp LLEntry4_8 + +//---------------------------------------- + +.globl Spr8Entry5_8 +Spr8Entry5_8: + subl $3,%edi // adjust for hardwired offsets + subl $6,%ecx + jmp LLEntry5_8 + +//---------------------------------------- + +.globl Spr8Entry6_8 +Spr8Entry6_8: + subl $2,%edi // adjust for hardwired offsets + subl $4,%ecx + jmp LLEntry6_8 + +//---------------------------------------- + +.globl Spr8Entry7_8 +Spr8Entry7_8: + decl %edi // adjust for hardwired offsets + subl $2,%ecx + jmp LLEntry7_8 + +//---------------------------------------- + +.globl Spr8Entry8_8 +Spr8Entry8_8: + cmpw (%ecx),%bp + jl Lp9 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp9 + movw %bp,(%ecx) + movb %al,(%edi) +Lp9: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi +LLEntry7_8: + cmpw 2(%ecx),%bp + jl Lp10 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp10 + movw %bp,2(%ecx) + movb %al,1(%edi) +Lp10: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi +LLEntry6_8: + cmpw 4(%ecx),%bp + jl Lp11 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp11 + movw %bp,4(%ecx) + movb %al,2(%edi) +Lp11: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi +LLEntry5_8: + cmpw 6(%ecx),%bp + jl Lp12 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp12 + movw %bp,6(%ecx) + movb %al,3(%edi) +Lp12: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi +LLEntry4_8: + cmpw 8(%ecx),%bp + jl Lp13 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp13 + movw %bp,8(%ecx) + movb %al,4(%edi) +Lp13: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi +LLEntry3_8: + cmpw 10(%ecx),%bp + jl Lp14 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp14 + movw %bp,10(%ecx) + movb %al,5(%edi) +Lp14: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi +LLEntry2_8: + cmpw 12(%ecx),%bp + jl Lp15 + movb (%esi),%al + cmpb $(TRANSPARENT_COLOR),%al + jz Lp15 + movw %bp,12(%ecx) + movb %al,6(%edi) +Lp15: + addl izistep,%ebp + adcl $0,%ebp + addl tstep,%edx + sbbl %eax,%eax + addl sstep,%ebx + adcl advancetable+4(,%eax,4),%esi + +LEndSpan: + cmpw 14(%ecx),%bp + jl Lp16 + movb (%esi),%al // load first texel in segment + cmpb $(TRANSPARENT_COLOR),%al + jz Lp16 + movw %bp,14(%ecx) + movb %al,7(%edi) +Lp16: + +// +// clear s/z, t/z, 1/z from FP stack +// + fstp %st(0) + fstp %st(0) + fstp %st(0) + + popl %ebx // restore spans pointer +LNextSpan: + addl $(sspan_t_size),%ebx // point to next span + movl sspan_t_count(%ebx),%ecx + cmpl $0,%ecx // any more spans? + jg LSpanLoop // yes + jz LNextSpan // yes, but this one's empty + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + +#endif // id386 diff --git a/linux/r_surf8.s b/linux/r_surf8.s new file mode 100644 index 000000000..2069cf3ef --- /dev/null +++ b/linux/r_surf8.s @@ -0,0 +1,762 @@ +// +// surf8.s +// x86 assembly-language 8 bpp surface block drawing code. +// + +#include "qasm.h" + +#if id386 + + .data + +sb_v: .long 0 + + .text + + .align 4 +.globl C(R_Surf8Start) +C(R_Surf8Start): + +//---------------------------------------------------------------------- +// Surface block drawer for mip level 0 +//---------------------------------------------------------------------- + + .align 4 +.globl C(R_DrawSurfaceBlock8_mip0) +C(R_DrawSurfaceBlock8_mip0): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// for (v=0 ; v> blockdivshift; +// lightrightstep = (lightptr[1] - lightright) >> blockdivshift; +// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) | +// 0xF0000000; + movl 4(%ebx),%ecx // lightptr[1] + movl (%ebx),%ebx // lightptr[0] + + subl %eax,%ebx + subl %edx,%ecx + + sarl $4,%ecx + orl $0xF0000000,%ebp + + sarl $4,%ebx + movl %ecx,C(lightrightstep) + + subl %ecx,%ebx + andl $0xFFFFF,%ebx + + orl $0xF0000000,%ebx + subl %ecx,%ecx // high word must be 0 in loop for addressing + + movl %ebx,C(lightdeltastep) + subl %ebx,%ebx // high word must be 0 in loop for addressing + +Lblockloop8_mip0: + movl %ebp,C(lightdelta) + movb 14(%esi),%cl + + sarl $4,%ebp + movb %dh,%bh + + movb 15(%esi),%bl + addl %ebp,%edx + + movb %dh,%ch + addl %ebp,%edx + + movb 0x12345678(%ebx),%ah +LBPatch0: + movb 13(%esi),%bl + + movb 0x12345678(%ecx),%al +LBPatch1: + movb 12(%esi),%cl + + movb %dh,%bh + addl %ebp,%edx + + rorl $16,%eax + movb %dh,%ch + + addl %ebp,%edx + movb 0x12345678(%ebx),%ah +LBPatch2: + + movb 11(%esi),%bl + movb 0x12345678(%ecx),%al +LBPatch3: + + movb 10(%esi),%cl + movl %eax,12(%edi) + + movb %dh,%bh + addl %ebp,%edx + + movb %dh,%ch + addl %ebp,%edx + + movb 0x12345678(%ebx),%ah +LBPatch4: + movb 9(%esi),%bl + + movb 0x12345678(%ecx),%al +LBPatch5: + movb 8(%esi),%cl + + movb %dh,%bh + addl %ebp,%edx + + rorl $16,%eax + movb %dh,%ch + + addl %ebp,%edx + movb 0x12345678(%ebx),%ah +LBPatch6: + + movb 7(%esi),%bl + movb 0x12345678(%ecx),%al +LBPatch7: + + movb 6(%esi),%cl + movl %eax,8(%edi) + + movb %dh,%bh + addl %ebp,%edx + + movb %dh,%ch + addl %ebp,%edx + + movb 0x12345678(%ebx),%ah +LBPatch8: + movb 5(%esi),%bl + + movb 0x12345678(%ecx),%al +LBPatch9: + movb 4(%esi),%cl + + movb %dh,%bh + addl %ebp,%edx + + rorl $16,%eax + movb %dh,%ch + + addl %ebp,%edx + movb 0x12345678(%ebx),%ah +LBPatch10: + + movb 3(%esi),%bl + movb 0x12345678(%ecx),%al +LBPatch11: + + movb 2(%esi),%cl + movl %eax,4(%edi) + + movb %dh,%bh + addl %ebp,%edx + + movb %dh,%ch + addl %ebp,%edx + + movb 0x12345678(%ebx),%ah +LBPatch12: + movb 1(%esi),%bl + + movb 0x12345678(%ecx),%al +LBPatch13: + movb (%esi),%cl + + movb %dh,%bh + addl %ebp,%edx + + rorl $16,%eax + movb %dh,%ch + + movb 0x12345678(%ebx),%ah +LBPatch14: + movl C(lightright),%edx + + movb 0x12345678(%ecx),%al +LBPatch15: + movl C(lightdelta),%ebp + + movl %eax,(%edi) + + addl C(sourcetstep),%esi + addl C(surfrowbytes),%edi + + addl C(lightrightstep),%edx + addl C(lightdeltastep),%ebp + + movl %edx,C(lightright) + jc Lblockloop8_mip0 + +// if (pbasesource >= r_sourcemax) +// pbasesource -= stepback; + + cmpl C(r_sourcemax),%esi + jb LSkip_mip0 + subl C(r_stepback),%esi +LSkip_mip0: + + movl C(r_lightptr),%ebx + decl sb_v + + jnz Lv_loop_mip0 + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + + +//---------------------------------------------------------------------- +// Surface block drawer for mip level 1 +//---------------------------------------------------------------------- + + .align 4 +.globl C(R_DrawSurfaceBlock8_mip1) +C(R_DrawSurfaceBlock8_mip1): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// for (v=0 ; v> blockdivshift; +// lightrightstep = (lightptr[1] - lightright) >> blockdivshift; +// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) | +// 0xF0000000; + movl 4(%ebx),%ecx // lightptr[1] + movl (%ebx),%ebx // lightptr[0] + + subl %eax,%ebx + subl %edx,%ecx + + sarl $3,%ecx + orl $0x70000000,%ebp + + sarl $3,%ebx + movl %ecx,C(lightrightstep) + + subl %ecx,%ebx + andl $0xFFFFF,%ebx + + orl $0xF0000000,%ebx + subl %ecx,%ecx // high word must be 0 in loop for addressing + + movl %ebx,C(lightdeltastep) + subl %ebx,%ebx // high word must be 0 in loop for addressing + +Lblockloop8_mip1: + movl %ebp,C(lightdelta) + movb 6(%esi),%cl + + sarl $3,%ebp + movb %dh,%bh + + movb 7(%esi),%bl + addl %ebp,%edx + + movb %dh,%ch + addl %ebp,%edx + + movb 0x12345678(%ebx),%ah +LBPatch22: + movb 5(%esi),%bl + + movb 0x12345678(%ecx),%al +LBPatch23: + movb 4(%esi),%cl + + movb %dh,%bh + addl %ebp,%edx + + rorl $16,%eax + movb %dh,%ch + + addl %ebp,%edx + movb 0x12345678(%ebx),%ah +LBPatch24: + + movb 3(%esi),%bl + movb 0x12345678(%ecx),%al +LBPatch25: + + movb 2(%esi),%cl + movl %eax,4(%edi) + + movb %dh,%bh + addl %ebp,%edx + + movb %dh,%ch + addl %ebp,%edx + + movb 0x12345678(%ebx),%ah +LBPatch26: + movb 1(%esi),%bl + + movb 0x12345678(%ecx),%al +LBPatch27: + movb (%esi),%cl + + movb %dh,%bh + addl %ebp,%edx + + rorl $16,%eax + movb %dh,%ch + + movb 0x12345678(%ebx),%ah +LBPatch28: + movl C(lightright),%edx + + movb 0x12345678(%ecx),%al +LBPatch29: + movl C(lightdelta),%ebp + + movl %eax,(%edi) + movl C(sourcetstep),%eax + + addl %eax,%esi + movl C(surfrowbytes),%eax + + addl %eax,%edi + movl C(lightrightstep),%eax + + addl %eax,%edx + movl C(lightdeltastep),%eax + + addl %eax,%ebp + movl %edx,C(lightright) + + jc Lblockloop8_mip1 + +// if (pbasesource >= r_sourcemax) +// pbasesource -= stepback; + + cmpl C(r_sourcemax),%esi + jb LSkip_mip1 + subl C(r_stepback),%esi +LSkip_mip1: + + movl C(r_lightptr),%ebx + decl sb_v + + jnz Lv_loop_mip1 + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + + +//---------------------------------------------------------------------- +// Surface block drawer for mip level 2 +//---------------------------------------------------------------------- + + .align 4 +.globl C(R_DrawSurfaceBlock8_mip2) +C(R_DrawSurfaceBlock8_mip2): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// for (v=0 ; v> blockdivshift; +// lightrightstep = (lightptr[1] - lightright) >> blockdivshift; +// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) | +// 0xF0000000; + movl 4(%ebx),%ecx // lightptr[1] + movl (%ebx),%ebx // lightptr[0] + + subl %eax,%ebx + subl %edx,%ecx + + sarl $2,%ecx + orl $0x30000000,%ebp + + sarl $2,%ebx + movl %ecx,C(lightrightstep) + + subl %ecx,%ebx + + andl $0xFFFFF,%ebx + + orl $0xF0000000,%ebx + subl %ecx,%ecx // high word must be 0 in loop for addressing + + movl %ebx,C(lightdeltastep) + subl %ebx,%ebx // high word must be 0 in loop for addressing + +Lblockloop8_mip2: + movl %ebp,C(lightdelta) + movb 2(%esi),%cl + + sarl $2,%ebp + movb %dh,%bh + + movb 3(%esi),%bl + addl %ebp,%edx + + movb %dh,%ch + addl %ebp,%edx + + movb 0x12345678(%ebx),%ah +LBPatch18: + movb 1(%esi),%bl + + movb 0x12345678(%ecx),%al +LBPatch19: + movb (%esi),%cl + + movb %dh,%bh + addl %ebp,%edx + + rorl $16,%eax + movb %dh,%ch + + movb 0x12345678(%ebx),%ah +LBPatch20: + movl C(lightright),%edx + + movb 0x12345678(%ecx),%al +LBPatch21: + movl C(lightdelta),%ebp + + movl %eax,(%edi) + movl C(sourcetstep),%eax + + addl %eax,%esi + movl C(surfrowbytes),%eax + + addl %eax,%edi + movl C(lightrightstep),%eax + + addl %eax,%edx + movl C(lightdeltastep),%eax + + addl %eax,%ebp + movl %edx,C(lightright) + + jc Lblockloop8_mip2 + +// if (pbasesource >= r_sourcemax) +// pbasesource -= stepback; + + cmpl C(r_sourcemax),%esi + jb LSkip_mip2 + subl C(r_stepback),%esi +LSkip_mip2: + + movl C(r_lightptr),%ebx + decl sb_v + + jnz Lv_loop_mip2 + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + + +//---------------------------------------------------------------------- +// Surface block drawer for mip level 3 +//---------------------------------------------------------------------- + + .align 4 +.globl C(R_DrawSurfaceBlock8_mip3) +C(R_DrawSurfaceBlock8_mip3): + pushl %ebp // preserve caller's stack frame + pushl %edi + pushl %esi // preserve register variables + pushl %ebx + +// for (v=0 ; v> blockdivshift; +// lightrightstep = (lightptr[1] - lightright) >> blockdivshift; +// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) | +// 0xF0000000; + movl 4(%ebx),%ecx // lightptr[1] + movl (%ebx),%ebx // lightptr[0] + + subl %eax,%ebx + subl %edx,%ecx + + sarl $1,%ecx + + sarl $1,%ebx + movl %ecx,C(lightrightstep) + + subl %ecx,%ebx + andl $0xFFFFF,%ebx + + sarl $1,%ebp + orl $0xF0000000,%ebx + + movl %ebx,C(lightdeltastep) + subl %ebx,%ebx // high word must be 0 in loop for addressing + + movb 1(%esi),%bl + subl %ecx,%ecx // high word must be 0 in loop for addressing + + movb %dh,%bh + movb (%esi),%cl + + addl %ebp,%edx + movb %dh,%ch + + movb 0x12345678(%ebx),%al +LBPatch16: + movl C(lightright),%edx + + movb %al,1(%edi) + movb 0x12345678(%ecx),%al +LBPatch17: + + movb %al,(%edi) + movl C(sourcetstep),%eax + + addl %eax,%esi + movl C(surfrowbytes),%eax + + addl %eax,%edi + movl C(lightdeltastep),%eax + + movl C(lightdelta),%ebp + movb (%esi),%cl + + addl %eax,%ebp + movl C(lightrightstep),%eax + + sarl $1,%ebp + addl %eax,%edx + + movb %dh,%bh + movb 1(%esi),%bl + + addl %ebp,%edx + movb %dh,%ch + + movb 0x12345678(%ebx),%al +LBPatch30: + movl C(sourcetstep),%edx + + movb %al,1(%edi) + movb 0x12345678(%ecx),%al +LBPatch31: + + movb %al,(%edi) + movl C(surfrowbytes),%ebp + + addl %edx,%esi + addl %ebp,%edi + +// if (pbasesource >= r_sourcemax) +// pbasesource -= stepback; + + cmpl C(r_sourcemax),%esi + jb LSkip_mip3 + subl C(r_stepback),%esi +LSkip_mip3: + + movl C(r_lightptr),%ebx + decl sb_v + + jnz Lv_loop_mip3 + + popl %ebx // restore register variables + popl %esi + popl %edi + popl %ebp // restore the caller's stack frame + ret + + +.globl C(R_Surf8End) +C(R_Surf8End): + +//---------------------------------------------------------------------- +// Code patching routines +//---------------------------------------------------------------------- + .data + + .align 4 +LPatchTable8: + .long LBPatch0-4 + .long LBPatch1-4 + .long LBPatch2-4 + .long LBPatch3-4 + .long LBPatch4-4 + .long LBPatch5-4 + .long LBPatch6-4 + .long LBPatch7-4 + .long LBPatch8-4 + .long LBPatch9-4 + .long LBPatch10-4 + .long LBPatch11-4 + .long LBPatch12-4 + .long LBPatch13-4 + .long LBPatch14-4 + .long LBPatch15-4 + .long LBPatch16-4 + .long LBPatch17-4 + .long LBPatch18-4 + .long LBPatch19-4 + .long LBPatch20-4 + .long LBPatch21-4 + .long LBPatch22-4 + .long LBPatch23-4 + .long LBPatch24-4 + .long LBPatch25-4 + .long LBPatch26-4 + .long LBPatch27-4 + .long LBPatch28-4 + .long LBPatch29-4 + .long LBPatch30-4 + .long LBPatch31-4 + + .text + + .align 4 +.globl C(R_Surf8Patch) +C(R_Surf8Patch): + pushl %ebx + + movl C(colormap),%eax + movl $LPatchTable8,%ebx + movl $32,%ecx +LPatchLoop8: + movl (%ebx),%edx + addl $4,%ebx + movl %eax,(%edx) + decl %ecx + jnz LPatchLoop8 + + popl %ebx + + ret + +#endif // id386 diff --git a/linux/r_varsa.s b/linux/r_varsa.s new file mode 100644 index 000000000..d951e4f2c --- /dev/null +++ b/linux/r_varsa.s @@ -0,0 +1,223 @@ +// +// r_varsa.s +// + +#include "qasm.h" +#include "d_ifacea.h" + +#if id386 + + .data + +//------------------------------------------------------- +// ASM-only variables +//------------------------------------------------------- +.globl float_1, float_particle_z_clip, float_point5 +.globl float_minus_1, float_0 +float_0: .single 0.0 +float_1: .single 1.0 +float_minus_1: .single -1.0 +float_particle_z_clip: .single PARTICLE_Z_CLIP +float_point5: .single 0.5 + +.globl fp_16, fp_64k, fp_1m, fp_64kx64k +.globl fp_1m_minus_1 +.globl fp_8 +fp_1m: .single 1048576.0 +fp_1m_minus_1: .single 1048575.0 +fp_64k: .single 65536.0 +fp_8: .single 8.0 +fp_16: .single 16.0 +fp_64kx64k: .long 0x4f000000 // (float)0x8000*0x10000 + + +.globl FloatZero, Float2ToThe31nd, FloatMinus2ToThe31nd +FloatZero: .long 0 +Float2ToThe31nd: .long 0x4f000000 +FloatMinus2ToThe31nd: .long 0xcf000000 + +.globl C(r_bmodelactive) +C(r_bmodelactive): .long 0 + +//------------------------------------------------------- +// global refresh variables +//------------------------------------------------------- + +// FIXME: put all refresh variables into one contiguous block. Make into one +// big structure, like cl or sv? + + .align 4 +.globl C(d_sdivzstepu) +.globl C(d_tdivzstepu) +.globl C(d_zistepu) +.globl C(d_sdivzstepv) +.globl C(d_tdivzstepv) +.globl C(d_zistepv) +.globl C(d_sdivzorigin) +.globl C(d_tdivzorigin) +.globl C(d_ziorigin) +C(d_sdivzstepu): .single 0 +C(d_tdivzstepu): .single 0 +C(d_zistepu): .single 0 +C(d_sdivzstepv): .single 0 +C(d_tdivzstepv): .single 0 +C(d_zistepv): .single 0 +C(d_sdivzorigin): .single 0 +C(d_tdivzorigin): .single 0 +C(d_ziorigin): .single 0 + +.globl C(sadjust) +.globl C(tadjust) +.globl C(bbextents) +.globl C(bbextentt) +C(sadjust): .long 0 +C(tadjust): .long 0 +C(bbextents): .long 0 +C(bbextentt): .long 0 + +.globl C(cacheblock) +.globl C(d_viewbuffer) +.globl C(cachewidth) +.globl C(d_pzbuffer) +.globl C(d_zrowbytes) +.globl C(d_zwidth) +C(cacheblock): .long 0 +C(cachewidth): .long 0 +C(d_viewbuffer): .long 0 +C(d_pzbuffer): .long 0 +C(d_zrowbytes): .long 0 +C(d_zwidth): .long 0 + + +//------------------------------------------------------- +// ASM-only variables +//------------------------------------------------------- +.globl izi +izi: .long 0 + +.globl pbase, s, t, sfracf, tfracf, snext, tnext +.globl spancountminus1, zi16stepu, sdivz16stepu, tdivz16stepu +.globl zi8stepu, sdivz8stepu, tdivz8stepu, pz +s: .long 0 +t: .long 0 +snext: .long 0 +tnext: .long 0 +sfracf: .long 0 +tfracf: .long 0 +pbase: .long 0 +zi8stepu: .long 0 +sdivz8stepu: .long 0 +tdivz8stepu: .long 0 +zi16stepu: .long 0 +sdivz16stepu: .long 0 +tdivz16stepu: .long 0 +spancountminus1: .long 0 +pz: .long 0 + +.globl izistep +izistep: .long 0 + +//------------------------------------------------------- +// local variables for d_draw16.s +//------------------------------------------------------- + +.globl reciprocal_table_16, entryvec_table_16 +// 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, 1/13, +// 1/14, and 1/15 in 0.32 form +reciprocal_table_16: .long 0x40000000, 0x2aaaaaaa, 0x20000000 + .long 0x19999999, 0x15555555, 0x12492492 + .long 0x10000000, 0xe38e38e, 0xccccccc, 0xba2e8ba + .long 0xaaaaaaa, 0x9d89d89, 0x9249249, 0x8888888 + +#ifndef NeXT + .extern Entry2_16 + .extern Entry3_16 + .extern Entry4_16 + .extern Entry5_16 + .extern Entry6_16 + .extern Entry7_16 + .extern Entry8_16 + .extern Entry9_16 + .extern Entry10_16 + .extern Entry11_16 + .extern Entry12_16 + .extern Entry13_16 + .extern Entry14_16 + .extern Entry15_16 + .extern Entry16_16 +#endif + +entryvec_table_16: .long 0, Entry2_16, Entry3_16, Entry4_16 + .long Entry5_16, Entry6_16, Entry7_16, Entry8_16 + .long Entry9_16, Entry10_16, Entry11_16, Entry12_16 + .long Entry13_16, Entry14_16, Entry15_16, Entry16_16 + +//------------------------------------------------------- +// local variables for d_parta.s +//------------------------------------------------------- +.globl DP_Count, DP_u, DP_v, DP_32768, DP_Color, DP_Pix, DP_EntryTable +DP_Count: .long 0 +DP_u: .long 0 +DP_v: .long 0 +DP_32768: .single 32768.0 +DP_Color: .long 0 +DP_Pix: .long 0 + + +#if 0 + .extern DP_1x1 + .extern DP_2x2 + .extern DP_3x3 + .extern DP_4x4 + +DP_EntryTable: .long DP_1x1, DP_2x2, DP_3x3, DP_4x4 +#endif + +// +// advancetable is 8 bytes, but points to the middle of that range so negative +// offsets will work +// +.globl advancetable, sstep, tstep, pspantemp, counttemp, jumptemp +advancetable: .long 0, 0 +sstep: .long 0 +tstep: .long 0 + +pspantemp: .long 0 +counttemp: .long 0 +jumptemp: .long 0 + +// 1/2, 1/3, 1/4, 1/5, 1/6, and 1/7 in 0.32 form +.globl reciprocal_table, entryvec_table +reciprocal_table: .long 0x40000000, 0x2aaaaaaa, 0x20000000 + .long 0x19999999, 0x15555555, 0x12492492 + +#if 0 + .extern Entry2_8 + .extern Entry3_8 + .extern Entry4_8 + .extern Entry5_8 + .extern Entry6_8 + .extern Entry7_8 + .extern Entry8_8 + +entryvec_table: .long 0, Entry2_8, Entry3_8, Entry4_8 + .long Entry5_8, Entry6_8, Entry7_8, Entry8_8 +#endif + +#ifndef NeXT + .extern Spr8Entry2_8 + .extern Spr8Entry3_8 + .extern Spr8Entry4_8 + .extern Spr8Entry5_8 + .extern Spr8Entry6_8 + .extern Spr8Entry7_8 + .extern Spr8Entry8_8 +#endif + +.globl spr8entryvec_table +spr8entryvec_table: .long 0, Spr8Entry2_8, Spr8Entry3_8, Spr8Entry4_8 + .long Spr8Entry5_8, Spr8Entry6_8, Spr8Entry7_8, Spr8Entry8_8 + +#endif // id386 + + diff --git a/linux/rw_in_svgalib.c b/linux/rw_in_svgalib.c new file mode 100644 index 000000000..31f5734f5 --- /dev/null +++ b/linux/rw_in_svgalib.c @@ -0,0 +1,374 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "vga.h" +#include "vgakeyboard.h" +#include "vgamouse.h" + +#include "../ref_soft/r_local.h" +#include "../client/keys.h" +#include "../linux/rw_linux.h" + +/*****************************************************************************/ +/* KEYBOARD */ +/*****************************************************************************/ + +static unsigned char scantokey[128]; +Key_Event_fp_t Key_Event_fp; + +static void keyhandler(int scancode, int state) +{ + int sc; + + sc = scancode & 0x7f; +//ri.Con_Printf(PRINT_ALL, "scancode=%x (%d%s)\n", scancode, sc, scancode&0x80?"+128":""); + Key_Event_fp(scantokey[sc], state == KEY_EVENTPRESS); +} + +void KBD_Init(Key_Event_fp_t fp) +{ + int i; + + Key_Event_fp = fp; + + for (i=0 ; i<128 ; i++) + scantokey[i] = ' '; + + scantokey[ 1] = K_ESCAPE; + scantokey[ 2] = '1'; + scantokey[ 3] = '2'; + scantokey[ 4] = '3'; + scantokey[ 5] = '4'; + scantokey[ 6] = '5'; + scantokey[ 7] = '6'; + scantokey[ 8] = '7'; + scantokey[ 9] = '8'; + scantokey[ 10] = '9'; + scantokey[ 11] = '0'; + scantokey[ 12] = '-'; + scantokey[ 13] = '='; + scantokey[ 14] = K_BACKSPACE; + scantokey[ 15] = K_TAB; + scantokey[ 16] = 'q'; + scantokey[ 17] = 'w'; + scantokey[ 18] = 'e'; + scantokey[ 19] = 'r'; + scantokey[ 20] = 't'; + scantokey[ 21] = 'y'; + scantokey[ 22] = 'u'; + scantokey[ 23] = 'i'; + scantokey[ 24] = 'o'; + scantokey[ 25] = 'p'; + scantokey[ 26] = '['; + scantokey[ 27] = ']'; + scantokey[ 28] = K_ENTER; + scantokey[ 29] = K_CTRL; //left + scantokey[ 30] = 'a'; + scantokey[ 31] = 's'; + scantokey[ 32] = 'd'; + scantokey[ 33] = 'f'; + scantokey[ 34] = 'g'; + scantokey[ 35] = 'h'; + scantokey[ 36] = 'j'; + scantokey[ 37] = 'k'; + scantokey[ 38] = 'l'; + scantokey[ 39] = ';'; + scantokey[ 40] = '\''; + scantokey[ 41] = '`'; + scantokey[ 42] = K_SHIFT; //left + scantokey[ 43] = '\\'; + scantokey[ 44] = 'z'; + scantokey[ 45] = 'x'; + scantokey[ 46] = 'c'; + scantokey[ 47] = 'v'; + scantokey[ 48] = 'b'; + scantokey[ 49] = 'n'; + scantokey[ 50] = 'm'; + scantokey[ 51] = ','; + scantokey[ 52] = '.'; + scantokey[ 53] = '/'; + scantokey[ 54] = K_SHIFT; //right + scantokey[ 55] = '*'; //keypad + scantokey[ 56] = K_ALT; //left + scantokey[ 57] = ' '; + // 58 caps lock + scantokey[ 59] = K_F1; + scantokey[ 60] = K_F2; + scantokey[ 61] = K_F3; + scantokey[ 62] = K_F4; + scantokey[ 63] = K_F5; + scantokey[ 64] = K_F6; + scantokey[ 65] = K_F7; + scantokey[ 66] = K_F8; + scantokey[ 67] = K_F9; + scantokey[ 68] = K_F10; + // 69 numlock + // 70 scrollock + scantokey[ 71] = K_KP_HOME; + scantokey[ 72] = K_KP_UPARROW; + scantokey[ 73] = K_KP_PGUP; + scantokey[ 74] = K_KP_MINUS; + scantokey[ 75] = K_KP_LEFTARROW; + scantokey[ 76] = K_KP_5; + scantokey[ 77] = K_KP_RIGHTARROW; + scantokey[ 79] = K_KP_END; + scantokey[ 78] = K_KP_PLUS; + scantokey[ 80] = K_KP_DOWNARROW; + scantokey[ 81] = K_KP_PGDN; + scantokey[ 82] = K_KP_INS; + scantokey[ 83] = K_KP_DEL; + // 84 to 86 not used + scantokey[ 87] = K_F11; + scantokey[ 88] = K_F12; + // 89 to 95 not used + scantokey[ 96] = K_KP_ENTER; //keypad enter + scantokey[ 97] = K_CTRL; //right + scantokey[ 98] = K_KP_SLASH; + scantokey[ 99] = K_F12; // print screen, bind to screenshot by default + scantokey[100] = K_ALT; // right + + scantokey[101] = K_PAUSE; // break + scantokey[102] = K_HOME; + scantokey[103] = K_UPARROW; + scantokey[104] = K_PGUP; + scantokey[105] = K_LEFTARROW; + scantokey[106] = K_RIGHTARROW; + scantokey[107] = K_END; + scantokey[108] = K_DOWNARROW; + scantokey[109] = K_PGDN; + scantokey[110] = K_INS; + scantokey[111] = K_DEL; + + scantokey[119] = K_PAUSE; + + if (keyboard_init()) + Sys_Error("keyboard_init() failed"); + keyboard_seteventhandler(keyhandler); + keyboard_translatekeys(DONT_CATCH_CTRLC); +} + +void KBD_Update(void) +{ + while (keyboard_update()) + ; +} + +void KBD_Close(void) +{ + keyboard_close(); +} + +/*****************************************************************************/ +/* MOUSE */ +/*****************************************************************************/ + +// this is inside the renderer shared lib, so these are called from vid_so + +static qboolean UseMouse = true; + +static int mouserate = MOUSE_DEFAULTSAMPLERATE; + +static int mouse_buttons; +static int mouse_buttonstate; +static int mouse_oldbuttonstate; +static float mouse_x, mouse_y; +static float old_mouse_x, old_mouse_y; +static int mx, my; + +static cvar_t *m_filter; +static cvar_t *in_mouse; + +static cvar_t *mdev; +static cvar_t *mrate; + +static qboolean mlooking; + +// state struct passed in Init +static in_state_t *in_state; + +static cvar_t *sensitivity; +static cvar_t *lookstrafe; +static cvar_t *m_side; +static cvar_t *m_yaw; +static cvar_t *m_pitch; +static cvar_t *m_forward; +static cvar_t *freelook; + +static void Force_CenterView_f (void) +{ + in_state->viewangles[PITCH] = 0; +} + +static void RW_IN_MLookDown (void) +{ + mlooking = true; +} + +static void RW_IN_MLookUp (void) +{ + mlooking = false; + in_state->IN_CenterView_fp (); +} + +static void mousehandler(int buttonstate, int dx, int dy) +{ + mouse_buttonstate = buttonstate; + mx += dx; + my += dy; +} + +void RW_IN_Init(in_state_t *in_state_p) +{ + int mtype; + int i; + + in_state = in_state_p; + + // mouse variables + m_filter = ri.Cvar_Get ("m_filter", "0", 0); + in_mouse = ri.Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE); + freelook = ri.Cvar_Get( "freelook", "0", 0 ); + lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0); + sensitivity = ri.Cvar_Get ("sensitivity", "3", 0); + m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0); + m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0); + m_forward = ri.Cvar_Get ("m_forward", "1", 0); + m_side = ri.Cvar_Get ("m_side", "0.8", 0); + + ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown); + ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp); + + ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f); + + mouse_buttons = 3; + + mtype = vga_getmousetype(); + + mdev = ri.Cvar_Get ("mdev", "/dev/mouse", 0); + mrate = ri.Cvar_Get ("mrate", "1200", 0); + +// printf("Mouse: dev=%s,type=%s,speed=%d\n", +// mousedev, mice[mtype].name, mouserate); + + if (mouse_init(mdev->string, mtype, (int)mrate->value)) + { + ri.Con_Printf(PRINT_ALL, "No mouse found\n"); + UseMouse = false; + } + else + mouse_seteventhandler(mousehandler); +} + +void RW_IN_Shutdown(void) +{ + mouse_close(); +} + +/* +=========== +IN_Commands +=========== +*/ +void RW_IN_Commands (void) +{ + if (!UseMouse) + return; + + // poll mouse values + mouse_update(); + + // perform button actions + if ((mouse_buttonstate & MOUSE_LEFTBUTTON) && + !(mouse_oldbuttonstate & MOUSE_LEFTBUTTON)) + in_state->Key_Event_fp (K_MOUSE1, true); + else if (!(mouse_buttonstate & MOUSE_LEFTBUTTON) && + (mouse_oldbuttonstate & MOUSE_LEFTBUTTON)) + in_state->Key_Event_fp (K_MOUSE1, false); + + if ((mouse_buttonstate & MOUSE_RIGHTBUTTON) && + !(mouse_oldbuttonstate & MOUSE_RIGHTBUTTON)) + in_state->Key_Event_fp (K_MOUSE2, true); + else if (!(mouse_buttonstate & MOUSE_RIGHTBUTTON) && + (mouse_oldbuttonstate & MOUSE_RIGHTBUTTON)) + in_state->Key_Event_fp (K_MOUSE2, false); + + if ((mouse_buttonstate & MOUSE_MIDDLEBUTTON) && + !(mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON)) + Key_Event_fp (K_MOUSE3, true); + else if (!(mouse_buttonstate & MOUSE_MIDDLEBUTTON) && + (mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON)) + in_state->Key_Event_fp (K_MOUSE3, false); + + mouse_oldbuttonstate = mouse_buttonstate; +} + +/* +=========== +IN_Move +=========== +*/ +void RW_IN_Move (usercmd_t *cmd) +{ + if (!UseMouse) + return; + + // poll mouse values + mouse_update(); + + if (m_filter->value) + { + mouse_x = (mx + old_mouse_x) * 0.5; + mouse_y = (my + old_mouse_y) * 0.5; + } + else + { + mouse_x = mx; + mouse_y = my; + } + old_mouse_x = mx; + old_mouse_y = my; + + if (!mx && !my) + return; + + mx = my = 0; // clear for next update + + mouse_x *= sensitivity->value; + mouse_y *= sensitivity->value; + +// add mouse X/Y movement to cmd + if ( (*in_state->in_strafe_state & 1) || + (lookstrafe->value && mlooking )) + cmd->sidemove += m_side->value * mouse_x; + else + in_state->viewangles[YAW] -= m_yaw->value * mouse_x; + + if ( (mlooking || freelook->value) && + !(*in_state->in_strafe_state & 1)) + { + in_state->viewangles[PITCH] += m_pitch->value * mouse_y; + } + else + { + cmd->forwardmove -= m_forward->value * mouse_y; + } +} + +void RW_IN_Frame (void) +{ +} + +void RW_IN_Activate(void) +{ +} + + + diff --git a/linux/rw_linux.h b/linux/rw_linux.h new file mode 100644 index 000000000..c9a59c11a --- /dev/null +++ b/linux/rw_linux.h @@ -0,0 +1,16 @@ + + +typedef void (*Key_Event_fp_t)(int key, qboolean down); + +extern void (*KBD_Update_fp)(void); +extern void (*KBD_Init_fp)(Key_Event_fp_t fp); +extern void (*KBD_Close_fp)(void); + +typedef struct in_state { + // Pointers to functions back in client, set by vid_so + void (*IN_CenterView_fp)(void); + Key_Event_fp_t Key_Event_fp; + vec_t *viewangles; + int *in_strafe_state; +} in_state_t; + diff --git a/linux/rw_svgalib.c b/linux/rw_svgalib.c new file mode 100644 index 000000000..37992745a --- /dev/null +++ b/linux/rw_svgalib.c @@ -0,0 +1,311 @@ +/* +** RW_SVGALBI.C +** +** This file contains ALL Linux specific stuff having to do with the +** software refresh. When a port is being made the following functions +** must be implemented by the port: +** +** SWimp_EndFrame +** SWimp_Init +** SWimp_InitGraphics +** SWimp_SetPalette +** SWimp_Shutdown +** SWimp_SwitchFullscreen +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "vga.h" +#include "vgakeyboard.h" +#include "vgamouse.h" + +#include "../ref_soft/r_local.h" +#include "../client/keys.h" +#include "../linux/rw_linux.h" + +/*****************************************************************************/ + +int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar; +byte *VGA_pagebase; +char *framebuffer_ptr; + +void VGA_UpdatePlanarScreen (void *srcbuffer); + +int num_modes; +vga_modeinfo *modes; +int current_mode; + +// Console variables that we need to access from this module + +/*****************************************************************************/ + +void VID_InitModes(void) +{ + +int i; + + // get complete information on all modes + + num_modes = vga_lastmodenumber()+1; + modes = malloc(num_modes * sizeof(vga_modeinfo)); + for (i=0 ; i0) +// framebuffer_ptr = (char *) vga_getgraphmem(); + if (!framebuffer_ptr) + Sys_Error("This mode isn't hapnin'\n"); + + vga_setpage(0); + + vid.buffer = malloc(vid.rowbytes * vid.height); + if (!vid.buffer) + Sys_Error("Unabled to alloc vid.buffer!\n"); + + return true; +} + +/* +** SWimp_EndFrame +** +** This does an implementation specific copy from the backbuffer to the +** front buffer. In the Win32 case it uses BitBlt or BltFast depending +** on whether we're using DIB sections/GDI or DDRAW. +*/ +void SWimp_EndFrame (void) +{ + if (!vga_oktowrite()) + return; // can't update screen if it's not active + +// if (vid_waitforrefresh.value) +// vga_waitretrace(); + + if (VGA_planar) + VGA_UpdatePlanarScreen (vid.buffer); + + else { + int total = vid.rowbytes * vid.height; + int offset; + + for (offset=0;offset0x10000)?0x10000:(total-offset))); + } + } +} + +/* +** SWimp_SetMode +*/ +rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen ) +{ + rserr_t retval = rserr_ok; + + ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode ); + + if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) ) + { + ri.Con_Printf( PRINT_ALL, " invalid mode\n" ); + return rserr_invalid_mode; + } + + ri.Con_Printf( PRINT_ALL, " %d %d\n", *pwidth, *pheight); + + if ( !SWimp_InitGraphics( false ) ) { + // failed to set a valid mode in windowed mode + return rserr_invalid_mode; + } + + R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table ); + + return retval; +} + +/* +** SWimp_SetPalette +** +** System specific palette setting routine. A NULL palette means +** to use the existing palette. The palette is expected to be in +** a padded 4-byte xRGB format. +*/ +void SWimp_SetPalette( const unsigned char *palette ) +{ + static int tmppal[256*3]; + const unsigned char *pal; + int *tp; + int i; + + if ( !palette ) + palette = ( const unsigned char * ) sw_state.currentpalette; + + if (vga_getcolors() == 256) + { + tp = tmppal; + pal = palette; + + for (i=0 ; i < 256 ; i++, pal += 4, tp += 3) { + tp[0] = pal[0] >> 2; + tp[1] = pal[1] >> 2; + tp[2] = pal[2] >> 2; + } + + if (vga_oktowrite()) + vga_setpalvec(0, 256, tmppal); + } +} + +/* +** SWimp_Shutdown +** +** System specific graphics subsystem shutdown routine. Destroys +** DIBs or DDRAW surfaces as appropriate. +*/ +void SWimp_Shutdown( void ) +{ + if (vid.buffer) { + free(vid.buffer); + vid.buffer = NULL; + } + vga_setmode(TEXT); +} + +/* +** SWimp_AppActivate +*/ +void SWimp_AppActivate( qboolean active ) +{ +} + +//=============================================================================== + +/* +================ +Sys_MakeCodeWriteable +================ +*/ +void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length) +{ + + int r; + unsigned long addr; + int psize = getpagesize(); + + addr = (startaddr & ~(psize-1)) - psize; + +// fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr, +// addr, startaddr+length, length); + + r = mprotect((char*)addr, length + startaddr - addr + psize, 7); + + if (r < 0) + Sys_Error("Protection change failed\n"); +} + diff --git a/linux/rw_x11.c b/linux/rw_x11.c new file mode 100644 index 000000000..f0c30e625 --- /dev/null +++ b/linux/rw_x11.c @@ -0,0 +1,1093 @@ +/* +** RW_X11.C +** +** This file contains ALL Linux specific stuff having to do with the +** software refresh. When a port is being made the following functions +** must be implemented by the port: +** +** SWimp_EndFrame +** SWimp_Init +** SWimp_InitGraphics +** SWimp_SetPalette +** SWimp_Shutdown +** SWimp_SwitchFullscreen +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../ref_soft/r_local.h" +#include "../client/keys.h" +#include "../linux/rw_linux.h" + +/*****************************************************************************/ + +static qboolean doShm; +static Display *x_disp; +static Colormap x_cmap; +static Window x_win; +static GC x_gc; +static Visual *x_vis; +static XVisualInfo *x_visinfo; +//static XImage *x_image; + +#define STD_EVENT_MASK (StructureNotifyMask | KeyPressMask \ + | KeyReleaseMask | ExposureMask | PointerMotionMask | \ + ButtonPressMask | ButtonReleaseMask) + +static int x_shmeventtype; +//static XShmSegmentInfo x_shminfo; + +static qboolean oktodraw = false; +static qboolean X11_active = false; + +int XShmQueryExtension(Display *); +int XShmGetEventBase(Display *); + +int current_framebuffer; +static XImage *x_framebuffer[2] = { 0, 0 }; +static XShmSegmentInfo x_shminfo[2]; + +struct +{ + int key; + int down; +} keyq[64]; +int keyq_head=0; +int keyq_tail=0; + +int config_notify=0; +int config_notify_width; +int config_notify_height; + +typedef unsigned short PIXEL; + +// Console variables that we need to access from this module + +/*****************************************************************************/ +/* MOUSE */ +/*****************************************************************************/ + +// this is inside the renderer shared lib, so these are called from vid_so + +static qboolean mouse_avail; +static int mouse_buttonstate; +static int mouse_oldbuttonstate; +static int mouse_x, mouse_y; +static int old_mouse_x, old_mouse_y; +static int mx, my; +static float old_windowed_mouse; +static int p_mouse_x, p_mouse_y; + +static cvar_t *_windowed_mouse; +static cvar_t *m_filter; +static cvar_t *in_mouse; + +static qboolean mlooking; + +// state struct passed in Init +static in_state_t *in_state; + +static cvar_t *sensitivity; +static cvar_t *lookstrafe; +static cvar_t *m_side; +static cvar_t *m_yaw; +static cvar_t *m_pitch; +static cvar_t *m_forward; +static cvar_t *freelook; + +static void Force_CenterView_f (void) +{ + in_state->viewangles[PITCH] = 0; +} + +static void RW_IN_MLookDown (void) +{ + mlooking = true; +} + +static void RW_IN_MLookUp (void) +{ + mlooking = false; + in_state->IN_CenterView_fp (); +} + +void RW_IN_Init(in_state_t *in_state_p) +{ + int mtype; + int i; + + in_state = in_state_p; + + // mouse variables + _windowed_mouse = ri.Cvar_Get ("_windowed_mouse", "0", CVAR_ARCHIVE); + m_filter = ri.Cvar_Get ("m_filter", "0", 0); + in_mouse = ri.Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE); + freelook = ri.Cvar_Get( "freelook", "0", 0 ); + lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0); + sensitivity = ri.Cvar_Get ("sensitivity", "3", 0); + m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0); + m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0); + m_forward = ri.Cvar_Get ("m_forward", "1", 0); + m_side = ri.Cvar_Get ("m_side", "0.8", 0); + + ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown); + ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp); + + ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f); + + mouse_x = mouse_y = 0.0; + mouse_avail = true; +} + +void RW_IN_Shutdown(void) +{ + mouse_avail = false; +} + +/* +=========== +IN_Commands +=========== +*/ +void RW_IN_Commands (void) +{ + int i; + + if (!mouse_avail) + return; + + for (i=0 ; i<3 ; i++) { + if ( (mouse_buttonstate & (1<Key_Event_fp (K_MOUSE1 + i, true); + + if ( !(mouse_buttonstate & (1<Key_Event_fp (K_MOUSE1 + i, false); + } + mouse_oldbuttonstate = mouse_buttonstate; +} + +/* +=========== +IN_Move +=========== +*/ +void RW_IN_Move (usercmd_t *cmd) +{ + if (!mouse_avail) + return; + + if (m_filter->value) + { + mouse_x = (mx + old_mouse_x) * 0.5; + mouse_y = (my + old_mouse_y) * 0.5; + } else { + mouse_x = mx; + mouse_y = my; + } + + old_mouse_x = mx; + old_mouse_y = my; + + if (!mouse_x && !mouse_y) + return; + + mouse_x *= sensitivity->value; + mouse_y *= sensitivity->value; + +// add mouse X/Y movement to cmd + if ( (*in_state->in_strafe_state & 1) || + (lookstrafe->value && mlooking )) + cmd->sidemove += m_side->value * mouse_x; + else + in_state->viewangles[YAW] -= m_yaw->value * mouse_x; + + if ( (mlooking || freelook->value) && + !(*in_state->in_strafe_state & 1)) + { + in_state->viewangles[PITCH] += m_pitch->value * mouse_y; + } + else + { + cmd->forwardmove -= m_forward->value * mouse_y; + } + mx = my = 0; +} + +void RW_IN_Frame (void) +{ +} + +void RW_IN_Activate(void) +{ +} + +/*****************************************************************************/ + +static PIXEL st2d_8to16table[256]; +static int shiftmask_fl=0; +static long r_shift,g_shift,b_shift; +static unsigned long r_mask,g_mask,b_mask; + +void shiftmask_init() +{ + unsigned int x; + r_mask=x_vis->red_mask; + g_mask=x_vis->green_mask; + b_mask=x_vis->blue_mask; + for(r_shift=-8,x=1;x0) { + p=(r<<(r_shift))&r_mask; + } else if(r_shift<0) { + p=(r>>(-r_shift))&r_mask; + } else p|=(r&r_mask); + + if(g_shift>0) { + p|=(g<<(g_shift))&g_mask; + } else if(g_shift<0) { + p|=(g>>(-g_shift))&g_mask; + } else p|=(g&g_mask); + + if(b_shift>0) { + p|=(b<<(b_shift))&b_mask; + } else if(b_shift<0) { + p|=(b>>(-b_shift))&b_mask; + } else p|=(b&b_mask); + + return p; +} + +void st2_fixup( XImage *framebuf, int x, int y, int width, int height) +{ + int xi,yi; + unsigned char *src; + PIXEL *dest; + + if( (x<0)||(y<0) )return; + + for (yi = y; yi < (y+height); yi++) { + src = &framebuf->data [yi * framebuf->bytes_per_line]; + dest = (PIXEL*)src; + for(xi = (x+width-1); xi >= x; xi -= 8) { + dest[xi ] = st2d_8to16table[src[xi ]]; + dest[xi-1] = st2d_8to16table[src[xi-1]]; + dest[xi-2] = st2d_8to16table[src[xi-2]]; + dest[xi-3] = st2d_8to16table[src[xi-3]]; + dest[xi-4] = st2d_8to16table[src[xi-4]]; + dest[xi-5] = st2d_8to16table[src[xi-5]]; + dest[xi-6] = st2d_8to16table[src[xi-6]]; + dest[xi-7] = st2d_8to16table[src[xi-7]]; + } + } +} + +// ======================================================================== +// makes a null cursor +// ======================================================================== + +static Cursor CreateNullCursor(Display *display, Window root) +{ + Pixmap cursormask; + XGCValues xgc; + GC gc; + XColor dummycolour; + Cursor cursor; + + cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/); + xgc.function = GXclear; + gc = XCreateGC(display, cursormask, GCFunction, &xgc); + XFillRectangle(display, cursormask, gc, 0, 0, 1, 1); + dummycolour.pixel = 0; + dummycolour.red = 0; + dummycolour.flags = 04; + cursor = XCreatePixmapCursor(display, cursormask, cursormask, + &dummycolour,&dummycolour, 0,0); + XFreePixmap(display,cursormask); + XFreeGC(display,gc); + return cursor; +} + +void ResetFrameBuffer(void) +{ + int mem; + int pwidth; + + if (x_framebuffer[0]) + { + free(x_framebuffer[0]->data); + free(x_framebuffer[0]); + } + +// alloc an extra line in case we want to wrap, and allocate the z-buffer + pwidth = x_visinfo->depth / 8; + if (pwidth == 3) pwidth = 4; + mem = ((vid.width*pwidth+7)&~7) * vid.height; + + x_framebuffer[0] = XCreateImage( x_disp, + x_vis, + x_visinfo->depth, + ZPixmap, + 0, + malloc(mem), + vid.width, vid.height, + 32, + 0); + + if (!x_framebuffer[0]) + Sys_Error("VID: XCreateImage failed\n"); + + vid.buffer = (byte*) (x_framebuffer[0]); +} + +void ResetSharedFrameBuffers(void) +{ + int size; + int key; + int minsize = getpagesize(); + int frm; + + for (frm=0 ; frm<2 ; frm++) + { + // free up old frame buffer memory + if (x_framebuffer[frm]) + { + XShmDetach(x_disp, &x_shminfo[frm]); + free(x_framebuffer[frm]); + shmdt(x_shminfo[frm].shmaddr); + } + + // create the image + x_framebuffer[frm] = XShmCreateImage( x_disp, + x_vis, + x_visinfo->depth, + ZPixmap, + 0, + &x_shminfo[frm], + vid.width, + vid.height ); + + // grab shared memory + + size = x_framebuffer[frm]->bytes_per_line + * x_framebuffer[frm]->height; + if (size < minsize) + Sys_Error("VID: Window must use at least %d bytes\n", minsize); + + key = random(); + x_shminfo[frm].shmid = shmget((key_t)key, size, IPC_CREAT|0777); + if (x_shminfo[frm].shmid==-1) + Sys_Error("VID: Could not get any shared memory\n"); + + // attach to the shared memory segment + x_shminfo[frm].shmaddr = + (void *) shmat(x_shminfo[frm].shmid, 0, 0); + + ri.Con_Printf(PRINT_ALL, + "MITSHM shared memory (id=%d, addr=0x%lx)\n", + x_shminfo[frm].shmid, + (long) x_shminfo[frm].shmaddr); + + x_framebuffer[frm]->data = x_shminfo[frm].shmaddr; + + // get the X server to attach to it + + if (!XShmAttach(x_disp, &x_shminfo[frm])) + Sys_Error("VID: XShmAttach() failed\n"); + XSync(x_disp, 0); + shmctl(x_shminfo[frm].shmid, IPC_RMID, 0); + } + +} + +// ======================================================================== +// Tragic death handler +// ======================================================================== + +void TragicDeath(int signal_num) +{ + XAutoRepeatOn(x_disp); + XCloseDisplay(x_disp); + Sys_Error("This death brought to you by the number %d\n", signal_num); +} + +int XLateKey(XKeyEvent *ev) +{ + + int key; + char buf[64]; + KeySym keysym; + + key = 0; + + XLookupString(ev, buf, sizeof buf, &keysym, 0); + + switch(keysym) + { + case XK_KP_Page_Up: key = K_KP_PGUP; break; + case XK_Page_Up: key = K_PGUP; break; + + case XK_KP_Page_Down: key = K_KP_PGDN; break; + case XK_Page_Down: key = K_PGDN; break; + + case XK_KP_Home: key = K_KP_HOME; break; + case XK_Home: key = K_HOME; break; + + case XK_KP_End: key = K_KP_END; break; + case XK_End: key = K_END; break; + + case XK_KP_Left: key = K_KP_LEFTARROW; break; + case XK_Left: key = K_LEFTARROW; break; + + case XK_KP_Right: key = K_KP_RIGHTARROW; break; + case XK_Right: key = K_RIGHTARROW; break; + + case XK_KP_Down: key = K_KP_DOWNARROW; break; + case XK_Down: key = K_DOWNARROW; break; + + case XK_KP_Up: key = K_KP_UPARROW; break; + case XK_Up: key = K_UPARROW; break; + + case XK_Escape: key = K_ESCAPE; break; + + case XK_KP_Enter: key = K_KP_ENTER; break; + case XK_Return: key = K_ENTER; break; + + case XK_Tab: key = K_TAB; break; + + case XK_F1: key = K_F1; break; + + case XK_F2: key = K_F2; break; + + case XK_F3: key = K_F3; break; + + case XK_F4: key = K_F4; break; + + case XK_F5: key = K_F5; break; + + case XK_F6: key = K_F6; break; + + case XK_F7: key = K_F7; break; + + case XK_F8: key = K_F8; break; + + case XK_F9: key = K_F9; break; + + case XK_F10: key = K_F10; break; + + case XK_F11: key = K_F11; break; + + case XK_F12: key = K_F12; break; + + case XK_BackSpace: key = K_BACKSPACE; break; + + case XK_KP_Delete: key = K_KP_DEL; break; + case XK_Delete: key = K_DEL; break; + + case XK_Pause: key = K_PAUSE; break; + + case XK_Shift_L: + case XK_Shift_R: key = K_SHIFT; break; + + case XK_Execute: + case XK_Control_L: + case XK_Control_R: key = K_CTRL; break; + + case XK_Alt_L: + case XK_Meta_L: + case XK_Alt_R: + case XK_Meta_R: key = K_ALT; break; + + case XK_KP_Begin: key = K_KP_5; break; + + case XK_Insert:key = K_INS; break; + case XK_KP_Insert: key = K_KP_INS; break; + + case XK_KP_Multiply: key = '*'; break; + case XK_KP_Add: key = K_KP_PLUS; break; + case XK_KP_Subtract: key = K_KP_MINUS; break; + case XK_KP_Divide: key = K_KP_SLASH; break; + +#if 0 + case 0x021: key = '1';break;/* [!] */ + case 0x040: key = '2';break;/* [@] */ + case 0x023: key = '3';break;/* [#] */ + case 0x024: key = '4';break;/* [$] */ + case 0x025: key = '5';break;/* [%] */ + case 0x05e: key = '6';break;/* [^] */ + case 0x026: key = '7';break;/* [&] */ + case 0x02a: key = '8';break;/* [*] */ + case 0x028: key = '9';;break;/* [(] */ + case 0x029: key = '0';break;/* [)] */ + case 0x05f: key = '-';break;/* [_] */ + case 0x02b: key = '=';break;/* [+] */ + case 0x07c: key = '\'';break;/* [|] */ + case 0x07d: key = '[';break;/* [}] */ + case 0x07b: key = ']';break;/* [{] */ + case 0x022: key = '\'';break;/* ["] */ + case 0x03a: key = ';';break;/* [:] */ + case 0x03f: key = '/';break;/* [?] */ + case 0x03e: key = '.';break;/* [>] */ + case 0x03c: key = ',';break;/* [<] */ +#endif + + default: + key = *(unsigned char*)buf; + if (key >= 'A' && key <= 'Z') + key = key - 'A' + 'a'; + break; + } + + return key; +} + +void GetEvent(void) +{ + XEvent x_event; + int b; + + XNextEvent(x_disp, &x_event); + switch(x_event.type) { + case KeyPress: + keyq[keyq_head].key = XLateKey(&x_event.xkey); + keyq[keyq_head].down = true; + keyq_head = (keyq_head + 1) & 63; + break; + case KeyRelease: + keyq[keyq_head].key = XLateKey(&x_event.xkey); + keyq[keyq_head].down = false; + keyq_head = (keyq_head + 1) & 63; + break; + + case MotionNotify: + if (_windowed_mouse->value) { + mx += ((int)x_event.xmotion.x - (int)(vid.width/2)); + my += ((int)x_event.xmotion.y - (int)(vid.height/2)); + + /* move the mouse to the window center again */ + XSelectInput(x_disp,x_win, STD_EVENT_MASK & ~PointerMotionMask); + XWarpPointer(x_disp,None,x_win,0,0,0,0, + (vid.width/2),(vid.height/2)); + XSelectInput(x_disp,x_win, STD_EVENT_MASK); + } else { + mx = ((int)x_event.xmotion.x - (int)p_mouse_x); + my = ((int)x_event.xmotion.y - (int)p_mouse_y); + p_mouse_x=x_event.xmotion.x; + p_mouse_y=x_event.xmotion.y; + } + break; + + case ButtonPress: + b=-1; + if (x_event.xbutton.button == 1) + b = 0; + else if (x_event.xbutton.button == 2) + b = 2; + else if (x_event.xbutton.button == 3) + b = 1; + if (b>=0) + mouse_buttonstate |= 1<=0) + mouse_buttonstate &= ~(1<value) { + old_windowed_mouse = _windowed_mouse->value; + + if (!_windowed_mouse->value) { + /* ungrab the pointer */ + XUngrabPointer(x_disp,CurrentTime); + } else { + /* grab the pointer */ + XGrabPointer(x_disp,x_win,True,0,GrabModeAsync, + GrabModeAsync,x_win,None,CurrentTime); + } + } +} + +/*****************************************************************************/ + +/* +** SWimp_Init +** +** This routine is responsible for initializing the implementation +** specific stuff in a software rendering subsystem. +*/ +int SWimp_Init( void *hInstance, void *wndProc ) +{ +// open the display + x_disp = XOpenDisplay(0); + if (!x_disp) + { + if (getenv("DISPLAY")) + Sys_Error("VID: Could not open display [%s]\n", + getenv("DISPLAY")); + else + Sys_Error("VID: Could not open local display\n"); + } + +// catch signals so i can turn on auto-repeat + + { + struct sigaction sa; + sigaction(SIGINT, 0, &sa); + sa.sa_handler = TragicDeath; + sigaction(SIGINT, &sa, 0); + sigaction(SIGTERM, &sa, 0); + } + + return true; +} + +/* +** SWimp_InitGraphics +** +** This initializes the software refresh's implementation specific +** graphics subsystem. In the case of Windows it creates DIB or +** DDRAW surfaces. +** +** The necessary width and height parameters are grabbed from +** vid.width and vid.height. +*/ +static qboolean SWimp_InitGraphics( qboolean fullscreen ) +{ + int pnum, i; + XVisualInfo template; + int num_visuals; + int template_mask; + + srandom(getpid()); + + // free resources in use + SWimp_Shutdown (); + + // let the sound and input subsystems know about the new window + ri.Vid_NewWindow (vid.width, vid.height); + + XAutoRepeatOff(x_disp); + +// for debugging only + XSynchronize(x_disp, True); + +// check for command-line window size + template_mask = 0; + +#if 0 +// specify a visual id + if ((pnum=COM_CheckParm("-visualid"))) + { + if (pnum >= com_argc-1) + Sys_Error("VID: -visualid \n"); + template.visualid = Q_atoi(com_argv[pnum+1]); + template_mask = VisualIDMask; + } + +// If not specified, use default visual + else +#endif + { + int screen; + screen = XDefaultScreen(x_disp); + template.visualid = + XVisualIDFromVisual(XDefaultVisual(x_disp, screen)); + template_mask = VisualIDMask; + } + +// pick a visual- warn if more than one was available + x_visinfo = XGetVisualInfo(x_disp, template_mask, &template, &num_visuals); + if (num_visuals > 1) + { + printf("Found more than one visual id at depth %d:\n", template.depth); + for (i=0 ; ivisualid)); + printf(" screen %d\n", x_visinfo->screen); + printf(" red_mask 0x%x\n", (int)(x_visinfo->red_mask)); + printf(" green_mask 0x%x\n", (int)(x_visinfo->green_mask)); + printf(" blue_mask 0x%x\n", (int)(x_visinfo->blue_mask)); + printf(" colormap_size %d\n", x_visinfo->colormap_size); + printf(" bits_per_rgb %d\n", x_visinfo->bits_per_rgb); + } +#endif + + x_vis = x_visinfo->visual; + +// setup attributes for main window + { + int attribmask = CWEventMask | CWColormap | CWBorderPixel; + XSetWindowAttributes attribs; + Colormap tmpcmap; + + tmpcmap = XCreateColormap(x_disp, XRootWindow(x_disp, + x_visinfo->screen), x_vis, AllocNone); + + attribs.event_mask = STD_EVENT_MASK; + attribs.border_pixel = 0; + attribs.colormap = tmpcmap; + +// create the main window + x_win = XCreateWindow( x_disp, + XRootWindow(x_disp, x_visinfo->screen), + 0, 0, // x, y + vid.width, vid.height, + 0, // borderwidth + x_visinfo->depth, + InputOutput, + x_vis, + attribmask, + &attribs ); + XStoreName(x_disp, x_win, "Quake II"); + + if (x_visinfo->class != TrueColor) + XFreeColormap(x_disp, tmpcmap); + } + + if (x_visinfo->depth == 8) + { + // create and upload the palette + if (x_visinfo->class == PseudoColor) + { + x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll); + XSetWindowColormap(x_disp, x_win, x_cmap); + } + + } + +// inviso cursor + XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win)); + +// create the GC + { + XGCValues xgcvalues; + int valuemask = GCGraphicsExposures; + xgcvalues.graphics_exposures = False; + x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues ); + } + +// map the window + XMapWindow(x_disp, x_win); + +// wait for first exposure event + { + XEvent event; + do + { + XNextEvent(x_disp, &event); + if (event.type == Expose && !event.xexpose.count) + oktodraw = true; + } while (!oktodraw); + } +// now safe to draw + +// even if MITSHM is available, make sure it's a local connection + if (XShmQueryExtension(x_disp)) + { + char *displayname; + doShm = true; + displayname = (char *) getenv("DISPLAY"); + if (displayname) + { + char *d = displayname; + while (*d && (*d != ':')) d++; + if (*d) *d = 0; + if (!(!strcasecmp(displayname, "unix") || !*displayname)) + doShm = false; + } + } + + if (doShm) + { + x_shmeventtype = XShmGetEventBase(x_disp) + ShmCompletion; + ResetSharedFrameBuffers(); + } + else + ResetFrameBuffer(); + + current_framebuffer = 0; + vid.rowbytes = x_framebuffer[0]->bytes_per_line; + vid.buffer = x_framebuffer[0]->data; + +// XSynchronize(x_disp, False); + + X11_active = true; + + return true; +} + +/* +** SWimp_EndFrame +** +** This does an implementation specific copy from the backbuffer to the +** front buffer. In the Win32 case it uses BitBlt or BltFast depending +** on whether we're using DIB sections/GDI or DDRAW. +*/ +void SWimp_EndFrame (void) +{ +// if the window changes dimension, skip this frame +#if 0 + if (config_notify) + { + fprintf(stderr, "config notify\n"); + config_notify = 0; + vid.width = config_notify_width & ~7; + vid.height = config_notify_height; + if (doShm) + ResetSharedFrameBuffers(); + else + ResetFrameBuffer(); + vid.rowbytes = x_framebuffer[0]->bytes_per_line; + vid.buffer = x_framebuffer[current_framebuffer]->data; + vid.recalc_refdef = 1; // force a surface cache flush + Con_CheckResize(); + Con_Clear_f(); + return; + } +#endif + + if (doShm) + { + + if (x_visinfo->depth != 8) + st2_fixup( x_framebuffer[current_framebuffer], + 0, 0, vid.width, vid.height); + if (!XShmPutImage(x_disp, x_win, x_gc, + x_framebuffer[current_framebuffer], 0, 0, + 0, 0, vid.width, vid.height, True)) + Sys_Error("VID_Update: XShmPutImage failed\n"); + oktodraw = false; + while (!oktodraw) + GetEvent(); + current_framebuffer = !current_framebuffer; + vid.buffer = x_framebuffer[current_framebuffer]->data; + XSync(x_disp, False); + } + else + { + if (x_visinfo->depth != 8) + st2_fixup( x_framebuffer[current_framebuffer], + 0, 0, vid.width, vid.height); + XPutImage(x_disp, x_win, x_gc, x_framebuffer[0], + 0, 0, 0, 0, vid.width, vid.height); + XSync(x_disp, False); + } +} + +/* +** SWimp_SetMode +*/ +rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen ) +{ + rserr_t retval = rserr_ok; + + ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode ); + + if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) ) + { + ri.Con_Printf( PRINT_ALL, " invalid mode\n" ); + return rserr_invalid_mode; + } + + ri.Con_Printf( PRINT_ALL, " %d %d\n", *pwidth, *pheight); + + if ( !SWimp_InitGraphics( false ) ) { + // failed to set a valid mode in windowed mode + return rserr_invalid_mode; + } + + R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table ); + + return retval; +} + +/* +** SWimp_SetPalette +** +** System specific palette setting routine. A NULL palette means +** to use the existing palette. The palette is expected to be in +** a padded 4-byte xRGB format. +*/ +void SWimp_SetPalette( const unsigned char *palette ) +{ + int i; + XColor colors[256]; + + if (!X11_active) + return; + + if ( !palette ) + palette = ( const unsigned char * ) sw_state.currentpalette; + + for(i=0;i<256;i++) + st2d_8to16table[i]= xlib_rgb(palette[i*4], + palette[i*4+1],palette[i*4+2]); + + if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8) + { + for (i=0 ; i<256 ; i++) + { + colors[i].pixel = i; + colors[i].flags = DoRed|DoGreen|DoBlue; + colors[i].red = palette[i*4] * 257; + colors[i].green = palette[i*4+1] * 257; + colors[i].blue = palette[i*4+2] * 257; + } + XStoreColors(x_disp, x_cmap, colors, 256); + } +} + +/* +** SWimp_Shutdown +** +** System specific graphics subsystem shutdown routine. Destroys +** DIBs or DDRAW surfaces as appropriate. +*/ +void SWimp_Shutdown( void ) +{ + int i; + + if (!X11_active) + return; + + if (doShm) { + for (i = 0; i < 2; i++) + if (x_framebuffer[i]) { + XShmDetach(x_disp, &x_shminfo[i]); + free(x_framebuffer[i]); + shmdt(x_shminfo[i].shmaddr); + x_framebuffer[i] = NULL; + } + } else if (x_framebuffer[0]) { + free(x_framebuffer[0]->data); + free(x_framebuffer[0]); + x_framebuffer[0] = NULL; + } + + XDestroyWindow( x_disp, x_win ); + + XAutoRepeatOn(x_disp); +// XCloseDisplay(x_disp); + + X11_active = false; +} + +/* +** SWimp_AppActivate +*/ +void SWimp_AppActivate( qboolean active ) +{ +} + +//=============================================================================== + +/* +================ +Sys_MakeCodeWriteable +================ +*/ +void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length) +{ + + int r; + unsigned long addr; + int psize = getpagesize(); + + addr = (startaddr & ~(psize-1)) - psize; + +// fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr, +// addr, startaddr+length, length); + + r = mprotect((char*)addr, length + startaddr - addr + psize, 7); + + if (r < 0) + Sys_Error("Protection change failed\n"); + +} + +/*****************************************************************************/ +/* KEYBOARD */ +/*****************************************************************************/ + +Key_Event_fp_t Key_Event_fp; + +void KBD_Init(Key_Event_fp_t fp) +{ + Key_Event_fp = fp; +} + +void KBD_Update(void) +{ +// get events from x server + if (x_disp) + { + while (XPending(x_disp)) + GetEvent(); + while (keyq_head != keyq_tail) + { + Key_Event_fp(keyq[keyq_tail].key, keyq[keyq_tail].down); + keyq_tail = (keyq_tail + 1) & 63; + } + } +} + +void KBD_Close(void) +{ +} + + diff --git a/linux/snd_linux.c b/linux/snd_linux.c new file mode 100644 index 000000000..9f46f6324 --- /dev/null +++ b/linux/snd_linux.c @@ -0,0 +1,266 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../client/client.h" +#include "../client/snd_loc.h" + +int audio_fd; +int snd_inited; + +cvar_t *sndbits; +cvar_t *sndspeed; +cvar_t *sndchannels; +cvar_t *snddevice; + +static int tryrates[] = { 11025, 22051, 44100, 8000 }; + +qboolean SNDDMA_Init(void) +{ + + int rc; + int fmt; + int tmp; + int i; + char *s; + struct audio_buf_info info; + int caps; + extern uid_t saved_euid; + + if (snd_inited) + return; + + if (!snddevice) { + sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE); + sndspeed = Cvar_Get("sndspeed", "0", CVAR_ARCHIVE); + sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE); + snddevice = Cvar_Get("snddevice", "/dev/dsp", CVAR_ARCHIVE); + } + +// open /dev/dsp, confirm capability to mmap, and get size of dma buffer + + if (!audio_fd) { + seteuid(saved_euid); + + audio_fd = open(snddevice->string, O_RDWR); + + seteuid(getuid()); + + if (audio_fd < 0) + { + perror(snddevice->string); + Com_Printf("Could not open %s\n", snddevice->string); + return 0; + } + } + + rc = ioctl(audio_fd, SNDCTL_DSP_RESET, 0); + if (rc < 0) + { + perror(snddevice->string); + Com_Printf("Could not reset %s\n", snddevice->string); + close(audio_fd); + return 0; + } + + if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps)==-1) + { + perror(snddevice->string); + Com_Printf("Sound driver too old\n"); + close(audio_fd); + return 0; + } + + if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP)) + { + Com_Printf("Sorry but your soundcard can't do this\n"); + close(audio_fd); + return 0; + } + + if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1) + { + perror("GETOSPACE"); + Com_Printf("Um, can't do GETOSPACE?\n"); + close(audio_fd); + return 0; + } + +// set sample bits & speed + + dma.samplebits = (int)sndbits->value; + if (dma.samplebits != 16 && dma.samplebits != 8) + { + ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt); + if (fmt & AFMT_S16_LE) dma.samplebits = 16; + else if (fmt & AFMT_U8) dma.samplebits = 8; + } + + dma.speed = (int)sndspeed->value; + if (!dma.speed) { + for (i=0 ; ivalue; + if (dma.channels < 1 || dma.channels > 2) + dma.channels = 2; + + dma.samples = info.fragstotal * info.fragsize / (dma.samplebits/8); + dma.submission_chunk = 1; + +// memory map the dma buffer + + if (!dma.buffer) + dma.buffer = (unsigned char *) mmap(NULL, info.fragstotal + * info.fragsize, PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0); + if (!dma.buffer) + { + perror(snddevice->string); + Com_Printf("Could not mmap %s\n", snddevice->string); + close(audio_fd); + return 0; + } + + tmp = 0; + if (dma.channels == 2) + tmp = 1; + rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp); + if (rc < 0) + { + perror(snddevice->string); + Com_Printf("Could not set %s to stereo=%d", snddevice->string, dma.channels); + close(audio_fd); + return 0; + } + if (tmp) + dma.channels = 2; + else + dma.channels = 1; + + rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &dma.speed); + if (rc < 0) + { + perror(snddevice->string); + Com_Printf("Could not set %s speed to %d", snddevice->string, dma.speed); + close(audio_fd); + return 0; + } + + if (dma.samplebits == 16) + { + rc = AFMT_S16_LE; + rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc); + if (rc < 0) + { + perror(snddevice->string); + Com_Printf("Could not support 16-bit data. Try 8-bit.\n"); + close(audio_fd); + return 0; + } + } + else if (dma.samplebits == 8) + { + rc = AFMT_U8; + rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc); + if (rc < 0) + { + perror(snddevice->string); + Com_Printf("Could not support 8-bit data.\n"); + close(audio_fd); + return 0; + } + } + else + { + perror(snddevice->string); + Com_Printf("%d-bit sound not supported.", dma.samplebits); + close(audio_fd); + return 0; + } + +// toggle the trigger & start her up + + tmp = 0; + rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp); + if (rc < 0) + { + perror(snddevice->string); + Com_Printf("Could not toggle.\n"); + close(audio_fd); + return 0; + } + tmp = PCM_ENABLE_OUTPUT; + rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp); + if (rc < 0) + { + perror(snddevice->string); + Com_Printf("Could not toggle.\n"); + close(audio_fd); + return 0; + } + + dma.samplepos = 0; + + snd_inited = 1; + return 1; + +} + +int SNDDMA_GetDMAPos(void) +{ + + struct count_info count; + + if (!snd_inited) return 0; + + if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count)==-1) + { + perror(snddevice->string); + Com_Printf("Uh, sound dead.\n"); + close(audio_fd); + snd_inited = 0; + return 0; + } +// dma.samplepos = (count.bytes / (dma.samplebits / 8)) & (dma.samples-1); +// fprintf(stderr, "%d \r", count.ptr); + dma.samplepos = count.ptr / (dma.samplebits / 8); + + return dma.samplepos; + +} + +void SNDDMA_Shutdown(void) +{ +#if 0 + if (snd_inited) + { + close(audio_fd); + snd_inited = 0; + } +#endif +} + +/* +============== +SNDDMA_Submit + +Send sound to device if buffer isn't really the dma buffer +=============== +*/ +void SNDDMA_Submit(void) +{ +} + +void SNDDMA_BeginPainting (void) +{ +} + diff --git a/linux/snd_mixa.s b/linux/snd_mixa.s new file mode 100644 index 000000000..7128e195a --- /dev/null +++ b/linux/snd_mixa.s @@ -0,0 +1,193 @@ +// +// snd_mixa.s +// x86 assembly-language sound code +// + +#include "qasm.h" + +#if id386 + + .text + +//---------------------------------------------------------------------- +// 8-bit sound-mixing code +//---------------------------------------------------------------------- + +#define ch 4+16 +#define sc 8+16 +#define count 12+16 + +.globl C(S_PaintChannelFrom8) +C(S_PaintChannelFrom8): + pushl %esi // preserve register variables + pushl %edi + pushl %ebx + pushl %ebp + +// int data; +// short *lscale, *rscale; +// unsigned char *sfx; +// int i; + + movl ch(%esp),%ebx + movl sc(%esp),%esi + +// if (ch->leftvol > 255) +// ch->leftvol = 255; +// if (ch->rightvol > 255) +// ch->rightvol = 255; + movl ch_leftvol(%ebx),%eax + movl ch_rightvol(%ebx),%edx + cmpl $255,%eax + jna LLeftSet + movl $255,%eax +LLeftSet: + cmpl $255,%edx + jna LRightSet + movl $255,%edx +LRightSet: + +// lscale = snd_scaletable[ch->leftvol >> 3]; +// rscale = snd_scaletable[ch->rightvol >> 3]; +// sfx = (signed char *)sc->data + ch->pos; +// ch->pos += count; + andl $0xF8,%eax + addl $(sfxc_data),%esi + andl $0xF8,%edx + movl ch_pos(%ebx),%edi + movl count(%esp),%ecx + addl %edi,%esi + shll $7,%eax + addl %ecx,%edi + shll $7,%edx + movl %edi,ch_pos(%ebx) + addl $(C(snd_scaletable)),%eax + addl $(C(snd_scaletable)),%edx + subl %ebx,%ebx + movb -1(%esi,%ecx,1),%bl + + testl $1,%ecx + jz LMix8Loop + + movl (%eax,%ebx,4),%edi + movl (%edx,%ebx,4),%ebp + addl C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size),%edi + addl C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size),%ebp + movl %edi,C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size) + movl %ebp,C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size) + movb -2(%esi,%ecx,1),%bl + + decl %ecx + jz LDone + +// for (i=0 ; i>8; +// if (val > 0x7fff) +// snd_out[i] = 0x7fff; +// else if (val < (short)0x8000) +// snd_out[i] = (short)0x8000; +// else +// snd_out[i] = val; + movl -8(%ebx,%ecx,4),%eax + sarl $8,%eax + cmpl $0x7FFF,%eax + jg LClampHigh + cmpl $0xFFFF8000,%eax + jnl LClampDone + movl $0xFFFF8000,%eax + jmp LClampDone +LClampHigh: + movl $0x7FFF,%eax +LClampDone: + +// val = (snd_p[i+1]*snd_vol)>>8; +// if (val > 0x7fff) +// snd_out[i+1] = 0x7fff; +// else if (val < (short)0x8000) +// snd_out[i+1] = (short)0x8000; +// else +// snd_out[i+1] = val; + movl -4(%ebx,%ecx,4),%edx + sarl $8,%edx + cmpl $0x7FFF,%edx + jg LClampHigh2 + cmpl $0xFFFF8000,%edx + jnl LClampDone2 + movl $0xFFFF8000,%edx + jmp LClampDone2 +LClampHigh2: + movl $0x7FFF,%edx +LClampDone2: + shll $16,%edx + andl $0xFFFF,%eax + orl %eax,%edx + movl %edx,-4(%edi,%ecx,2) + +// } + subl $2,%ecx + jnz LWLBLoopTop + +// snd_p += snd_linear_count; + + popl %ebx + popl %edi + + ret + + +#endif // id386 + diff --git a/linux/sys_dosa.s b/linux/sys_dosa.s new file mode 100644 index 000000000..276874e0a --- /dev/null +++ b/linux/sys_dosa.s @@ -0,0 +1,94 @@ +// +// sys_dosa.s +// x86 assembly-language DOS-dependent routines. + +#include "qasm.h" + + + .data + + .align 4 +fpenv: + .long 0, 0, 0, 0, 0, 0, 0, 0 + + .text + +.globl C(MaskExceptions) +C(MaskExceptions): + fnstenv fpenv + orl $0x3F,fpenv + fldenv fpenv + + ret + +#if 0 +.globl C(unmaskexceptions) +C(unmaskexceptions): + fnstenv fpenv + andl $0xFFFFFFE0,fpenv + fldenv fpenv + + ret +#endif + + .data + + .align 4 +.globl ceil_cw, single_cw, full_cw, cw, pushed_cw +ceil_cw: .long 0 +single_cw: .long 0 +full_cw: .long 0 +cw: .long 0 +pushed_cw: .long 0 + + .text + +.globl C(Sys_LowFPPrecision) +C(Sys_LowFPPrecision): + fldcw single_cw + + ret + +.globl C(Sys_HighFPPrecision) +C(Sys_HighFPPrecision): + fldcw full_cw + + ret + +.globl C(Sys_PushFPCW_SetHigh) +C(Sys_PushFPCW_SetHigh): + fnstcw pushed_cw + fldcw full_cw + + ret + +.globl C(Sys_PopFPCW) +C(Sys_PopFPCW): + fldcw pushed_cw + + ret + +.globl C(Sys_SetFPCW) +C(Sys_SetFPCW): + fnstcw cw + movl cw,%eax +#if id386 + andb $0xF0,%ah + orb $0x03,%ah // round mode, 64-bit precision +#endif + movl %eax,full_cw + +#if id386 + andb $0xF0,%ah + orb $0x0C,%ah // chop mode, single precision +#endif + movl %eax,single_cw + +#if id386 + andb $0xF0,%ah + orb $0x08,%ah // ceil mode, single precision +#endif + movl %eax,ceil_cw + + ret + diff --git a/linux/sys_linux.c b/linux/sys_linux.c new file mode 100644 index 000000000..c7077fc8b --- /dev/null +++ b/linux/sys_linux.c @@ -0,0 +1,379 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../qcommon/qcommon.h" + +#include "../linux/rw_linux.h" + +cvar_t *nostdout; + +unsigned sys_frame_time; + +uid_t saved_euid; +qboolean stdin_active = true; + +// ======================================================================= +// General routines +// ======================================================================= + +void Sys_ConsoleOutput (char *string) +{ + if (nostdout && nostdout->value) + return; + + fputs(string, stdout); +} + +void Sys_Printf (char *fmt, ...) +{ + va_list argptr; + char text[1024]; + unsigned char *p; + + va_start (argptr,fmt); + vsprintf (text,fmt,argptr); + va_end (argptr); + + if (strlen(text) > sizeof(text)) + Sys_Error("memory overwrite in Sys_Printf"); + + if (nostdout && nostdout->value) + return; + + for (p = (unsigned char *)text; *p; p++) { + *p &= 0x7f; + if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9) + printf("[%02x]", *p); + else + putc(*p, stdout); + } +} + +void Sys_Quit (void) +{ + CL_Shutdown (); + Qcommon_Shutdown (); + fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY); + _exit(0); +} + +void Sys_Init(void) +{ +#if id386 +// Sys_SetFPCW(); +#endif +} + +void Sys_Error (char *error, ...) +{ + va_list argptr; + char string[1024]; + +// change stdin to non blocking + fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY); + + CL_Shutdown (); + Qcommon_Shutdown (); + + va_start (argptr,error); + vsprintf (string,error,argptr); + va_end (argptr); + fprintf(stderr, "Error: %s\n", string); + + _exit (1); + +} + +void Sys_Warn (char *warning, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,warning); + vsprintf (string,warning,argptr); + va_end (argptr); + fprintf(stderr, "Warning: %s", string); +} + +/* +============ +Sys_FileTime + +returns -1 if not present +============ +*/ +int Sys_FileTime (char *path) +{ + struct stat buf; + + if (stat (path,&buf) == -1) + return -1; + + return buf.st_mtime; +} + +void floating_point_exception_handler(int whatever) +{ +// Sys_Warn("floating point exception\n"); + signal(SIGFPE, floating_point_exception_handler); +} + +char *Sys_ConsoleInput(void) +{ + static char text[256]; + int len; + fd_set fdset; + struct timeval timeout; + + if (!dedicated || !dedicated->value) + return NULL; + + if (!stdin_active) + return NULL; + + FD_ZERO(&fdset); + FD_SET(0, &fdset); // stdin + timeout.tv_sec = 0; + timeout.tv_usec = 0; + if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset)) + return NULL; + + len = read (0, text, sizeof(text)); + if (len == 0) { // eof! + stdin_active = false; + return NULL; + } + + if (len < 1) + return NULL; + text[len-1] = 0; // rip off the /n and terminate + + return text; +} + +/*****************************************************************************/ + +static void *game_library; + +/* +================= +Sys_UnloadGame +================= +*/ +void Sys_UnloadGame (void) +{ + if (game_library) + dlclose (game_library); + game_library = NULL; +} + +/* +================= +Sys_GetGameAPI + +Loads the game dll +================= +*/ +void *Sys_GetGameAPI (void *parms) +{ + void *(*GetGameAPI) (void *); + + char name[MAX_OSPATH]; + char curpath[MAX_OSPATH]; + char *path; +#ifdef __i386__ + const char *gamename = "gamei386.so"; +#elif defined __alpha__ + const char *gamename = "gameaxp.so"; +#else +#error Unknown arch +#endif + + setreuid(getuid(), getuid()); + setegid(getgid()); + + if (game_library) + Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame"); + + getcwd(curpath, sizeof(curpath)); + + Com_Printf("------- Loading %s -------", gamename); + + // now run through the search paths + path = NULL; + while (1) + { + path = FS_NextPath (path); + if (!path) + return NULL; // couldn't find one anywhere + sprintf (name, "%s/%s/%s", curpath, path, gamename); + game_library = dlopen (name, RTLD_NOW ); + if (game_library) + { + Com_DPrintf ("LoadLibrary (%s)\n",name); + break; + } + } + + GetGameAPI = (void *)dlsym (game_library, "GetGameAPI"); + if (!GetGameAPI) + { + Sys_UnloadGame (); + return NULL; + } + + return GetGameAPI (parms); +} + +/*****************************************************************************/ + +void Sys_AppActivate (void) +{ +} + +void Sys_SendKeyEvents (void) +{ +#ifndef DEDICATED_ONLY + if (KBD_Update_fp) + KBD_Update_fp(); +#endif + + // grab frame time + sys_frame_time = Sys_Milliseconds(); +} + +/*****************************************************************************/ + +char *Sys_GetClipboardData(void) +{ + return NULL; +} + +int main (int argc, char **argv) +{ + int time, oldtime, newtime; + + // go back to real user for config loads + saved_euid = geteuid(); + seteuid(getuid()); + + Qcommon_Init(argc, argv); + + fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY); + + nostdout = Cvar_Get("nostdout", "0", 0); + if (!nostdout->value) { + fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY); +// printf ("Linux Quake -- Version %0.3f\n", LINUX_VERSION); + } + + oldtime = Sys_Milliseconds (); + while (1) + { +// find time spent rendering last frame + do { + newtime = Sys_Milliseconds (); + time = newtime - oldtime; + } while (time < 1); + Qcommon_Frame (time); + oldtime = newtime; + } + +} + +void Sys_CopyProtect(void) +{ + FILE *mnt; + struct mntent *ent; + char path[MAX_OSPATH]; + struct stat st; + qboolean found_cd = false; + + static qboolean checked = false; + + if (checked) + return; + + if ((mnt = setmntent("/etc/mtab", "r")) == NULL) + Com_Error(ERR_FATAL, "Can't read mount table to determine mounted cd location."); + + while ((ent = getmntent(mnt)) != NULL) { + if (strcmp(ent->mnt_type, "iso9660") == 0) { + // found a cd file system + found_cd = true; + sprintf(path, "%s/%s", ent->mnt_dir, "install/data/quake2.exe"); + if (stat(path, &st) == 0) { + // found it + checked = true; + endmntent(mnt); + return; + } + sprintf(path, "%s/%s", ent->mnt_dir, "Install/Data/quake2.exe"); + if (stat(path, &st) == 0) { + // found it + checked = true; + endmntent(mnt); + return; + } + sprintf(path, "%s/%s", ent->mnt_dir, "quake2.exe"); + if (stat(path, &st) == 0) { + // found it + checked = true; + endmntent(mnt); + return; + } + } + } + endmntent(mnt); + + if (found_cd) + Com_Error (ERR_FATAL, "Could not find a Quake2 CD in your CD drive."); + Com_Error (ERR_FATAL, "Unable to find a mounted iso9660 file system.\n" + "You must mount the Quake2 CD in a cdrom drive in order to play."); +} + +#if 0 +/* +================ +Sys_MakeCodeWriteable +================ +*/ +void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length) +{ + + int r; + unsigned long addr; + int psize = getpagesize(); + + addr = (startaddr & ~(psize-1)) - psize; + +// fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr, +// addr, startaddr+length, length); + + r = mprotect((char*)addr, length + startaddr - addr + psize, 7); + + if (r < 0) + Sys_Error("Protection change failed\n"); + +} + +#endif diff --git a/linux/vid_menu.c b/linux/vid_menu.c new file mode 100644 index 000000000..c85a1314a --- /dev/null +++ b/linux/vid_menu.c @@ -0,0 +1,437 @@ +#include "../client/client.h" +#include "../client/qmenu.h" + +#define REF_SOFT 0 +#define REF_SOFTX11 1 +#define REF_OPENGL 2 + +extern cvar_t *vid_ref; +extern cvar_t *vid_fullscreen; +extern cvar_t *vid_gamma; +extern cvar_t *scr_viewsize; + +static cvar_t *gl_mode; +static cvar_t *gl_driver; +static cvar_t *gl_picmip; +static cvar_t *gl_ext_palettedtexture; + +static cvar_t *sw_mode; +static cvar_t *sw_stipplealpha; + +static cvar_t *_windowed_mouse; + +extern void M_ForceMenuOff( void ); + +/* +==================================================================== + +MENU INTERACTION + +==================================================================== +*/ +#define SOFTWARE_MENU 0 +#define OPENGL_MENU 1 + +static menuframework_s s_software_menu; +static menuframework_s s_opengl_menu; +static menuframework_s *s_current_menu; +static int s_current_menu_index; + +static menulist_s s_mode_list[2]; +static menulist_s s_ref_list[2]; +static menuslider_s s_tq_slider; +static menuslider_s s_screensize_slider[2]; +static menuslider_s s_brightness_slider[2]; +static menulist_s s_fs_box[2]; +static menulist_s s_stipple_box; +static menulist_s s_paletted_texture_box; +static menulist_s s_windowed_mouse; +static menuaction_s s_apply_action[2]; +static menuaction_s s_defaults_action[2]; + +static void DriverCallback( void *unused ) +{ + s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue; + + if ( s_ref_list[s_current_menu_index].curvalue < 2 ) + { + s_current_menu = &s_software_menu; + s_current_menu_index = 0; + } + else + { + s_current_menu = &s_opengl_menu; + s_current_menu_index = 1; + } + +} + +static void ScreenSizeCallback( void *s ) +{ + menuslider_s *slider = ( menuslider_s * ) s; + + Cvar_SetValue( "viewsize", slider->curvalue * 10 ); +} + +static void BrightnessCallback( void *s ) +{ + menuslider_s *slider = ( menuslider_s * ) s; + + if ( s_current_menu_index == 0) + s_brightness_slider[1].curvalue = s_brightness_slider[0].curvalue; + else + s_brightness_slider[0].curvalue = s_brightness_slider[1].curvalue; + + if ( stricmp( vid_ref->string, "soft" ) == 0 || + stricmp( vid_ref->string, "softx" ) == 0 ) + { + float gamma = ( 0.8 - ( slider->curvalue/10.0 - 0.5 ) ) + 0.5; + + Cvar_SetValue( "vid_gamma", gamma ); + } +} + +static void ResetDefaults( void *unused ) +{ + VID_MenuInit(); +} + +static void ApplyChanges( void *unused ) +{ + float gamma; + + /* + ** make values consistent + */ + s_fs_box[!s_current_menu_index].curvalue = s_fs_box[s_current_menu_index].curvalue; + s_brightness_slider[!s_current_menu_index].curvalue = s_brightness_slider[s_current_menu_index].curvalue; + s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue; + + /* + ** invert sense so greater = brighter, and scale to a range of 0.5 to 1.3 + */ + gamma = ( 0.8 - ( s_brightness_slider[s_current_menu_index].curvalue/10.0 - 0.5 ) ) + 0.5; + + Cvar_SetValue( "vid_gamma", gamma ); + Cvar_SetValue( "sw_stipplealpha", s_stipple_box.curvalue ); + Cvar_SetValue( "gl_picmip", 3 - s_tq_slider.curvalue ); + Cvar_SetValue( "vid_fullscreen", s_fs_box[s_current_menu_index].curvalue ); + Cvar_SetValue( "gl_ext_palettedtexture", s_paletted_texture_box.curvalue ); + Cvar_SetValue( "sw_mode", s_mode_list[SOFTWARE_MENU].curvalue ); + Cvar_SetValue( "gl_mode", s_mode_list[OPENGL_MENU].curvalue ); + Cvar_SetValue( "_windowed_mouse", s_windowed_mouse.curvalue); + + switch ( s_ref_list[s_current_menu_index].curvalue ) + { + case REF_SOFT: + Cvar_Set( "vid_ref", "soft" ); + break; + case REF_SOFTX11: + Cvar_Set( "vid_ref", "softx" ); + break; + case REF_OPENGL: + Cvar_Set( "vid_ref", "gl" ); + Cvar_Set( "gl_driver", "opengl32" ); + break; + } + +#if 0 + /* + ** update appropriate stuff if we're running OpenGL and gamma + ** has been modified + */ + if ( stricmp( vid_ref->string, "gl" ) == 0 ) + { + if ( vid_gamma->modified ) + { + vid_ref->modified = true; + if ( stricmp( gl_driver->string, "3dfxgl" ) == 0 ) + { + char envbuffer[1024]; + float g; + + vid_ref->modified = true; + + g = 2.00 * ( 0.8 - ( vid_gamma->value - 0.5 ) ) + 1.0F; + Com_sprintf( envbuffer, sizeof(envbuffer), "SST_GAMMA=%f", g ); + putenv( envbuffer ); + + vid_gamma->modified = false; + } + } + } +#endif + + M_ForceMenuOff(); +} + +/* +** VID_MenuInit +*/ +void VID_MenuInit( void ) +{ + static const char *resolutions[] = + { + "[320 240 ]", + "[400 300 ]", + "[512 384 ]", + "[640 480 ]", + "[800 600 ]", + "[960 720 ]", + "[1024 768 ]", + "[1152 864 ]", + "[1280 1024]", + "[1600 1200]", + 0 + }; + static const char *refs[] = + { + "[software ]", + "[software X11 ]", + "[default OpenGL]", + 0 + }; + static const char *yesno_names[] = + { + "no", + "yes", + 0 + }; + int i; + + if ( !gl_driver ) + gl_driver = Cvar_Get( "gl_driver", "opengl32", 0 ); + if ( !gl_picmip ) + gl_picmip = Cvar_Get( "gl_picmip", "0", 0 ); + if ( !gl_mode ) + gl_mode = Cvar_Get( "gl_mode", "3", 0 ); + if ( !sw_mode ) + sw_mode = Cvar_Get( "sw_mode", "0", 0 ); + if ( !gl_ext_palettedtexture ) + gl_ext_palettedtexture = Cvar_Get( "gl_ext_palettedtexture", "1", CVAR_ARCHIVE ); + + if ( !sw_stipplealpha ) + sw_stipplealpha = Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE ); + + if ( !_windowed_mouse) + _windowed_mouse = Cvar_Get( "_windowed_mouse", "0", CVAR_ARCHIVE ); + + s_mode_list[SOFTWARE_MENU].curvalue = sw_mode->value; + s_mode_list[OPENGL_MENU].curvalue = gl_mode->value; + + if ( !scr_viewsize ) + scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE); + + s_screensize_slider[SOFTWARE_MENU].curvalue = scr_viewsize->value/10; + s_screensize_slider[OPENGL_MENU].curvalue = scr_viewsize->value/10; + + if ( strcmp( vid_ref->string, "soft" ) == 0) + { + s_current_menu_index = SOFTWARE_MENU; + s_ref_list[0].curvalue = s_ref_list[1].curvalue = REF_SOFT; + } + else if (strcmp( vid_ref->string, "softx" ) == 0 ) + { + s_current_menu_index = SOFTWARE_MENU; + s_ref_list[0].curvalue = s_ref_list[1].curvalue = REF_SOFTX11; + } + else if ( strcmp( vid_ref->string, "gl" ) == 0 ) + { + s_current_menu_index = OPENGL_MENU; + s_ref_list[s_current_menu_index].curvalue = REF_OPENGL; +#if 0 + if ( strcmp( gl_driver->string, "3dfxgl" ) == 0 ) + s_ref_list[s_current_menu_index].curvalue = REF_3DFX; + else if ( strcmp( gl_driver->string, "pvrgl" ) == 0 ) + s_ref_list[s_current_menu_index].curvalue = REF_POWERVR; + else if ( strcmp( gl_driver->string, "opengl32" ) == 0 ) + s_ref_list[s_current_menu_index].curvalue = REF_OPENGL; + else + s_ref_list[s_current_menu_index].curvalue = REF_VERITE; +#endif + } + + s_software_menu.x = viddef.width * 0.50; + s_software_menu.nitems = 0; + s_opengl_menu.x = viddef.width * 0.50; + s_opengl_menu.nitems = 0; + + for ( i = 0; i < 2; i++ ) + { + s_ref_list[i].generic.type = MTYPE_SPINCONTROL; + s_ref_list[i].generic.name = "driver"; + s_ref_list[i].generic.x = 0; + s_ref_list[i].generic.y = 0; + s_ref_list[i].generic.callback = DriverCallback; + s_ref_list[i].itemnames = refs; + + s_mode_list[i].generic.type = MTYPE_SPINCONTROL; + s_mode_list[i].generic.name = "video mode"; + s_mode_list[i].generic.x = 0; + s_mode_list[i].generic.y = 10; + s_mode_list[i].itemnames = resolutions; + + s_screensize_slider[i].generic.type = MTYPE_SLIDER; + s_screensize_slider[i].generic.x = 0; + s_screensize_slider[i].generic.y = 20; + s_screensize_slider[i].generic.name = "screen size"; + s_screensize_slider[i].minvalue = 3; + s_screensize_slider[i].maxvalue = 12; + s_screensize_slider[i].generic.callback = ScreenSizeCallback; + + s_brightness_slider[i].generic.type = MTYPE_SLIDER; + s_brightness_slider[i].generic.x = 0; + s_brightness_slider[i].generic.y = 30; + s_brightness_slider[i].generic.name = "brightness"; + s_brightness_slider[i].generic.callback = BrightnessCallback; + s_brightness_slider[i].minvalue = 5; + s_brightness_slider[i].maxvalue = 13; + s_brightness_slider[i].curvalue = ( 1.3 - vid_gamma->value + 0.5 ) * 10; + + s_fs_box[i].generic.type = MTYPE_SPINCONTROL; + s_fs_box[i].generic.x = 0; + s_fs_box[i].generic.y = 40; + s_fs_box[i].generic.name = "fullscreen"; + s_fs_box[i].itemnames = yesno_names; + s_fs_box[i].curvalue = vid_fullscreen->value; + + s_defaults_action[i].generic.type = MTYPE_ACTION; + s_defaults_action[i].generic.name = "reset to default"; + s_defaults_action[i].generic.x = 0; + s_defaults_action[i].generic.y = 90; + s_defaults_action[i].generic.callback = ResetDefaults; + + s_apply_action[i].generic.type = MTYPE_ACTION; + s_apply_action[i].generic.name = "apply"; + s_apply_action[i].generic.x = 0; + s_apply_action[i].generic.y = 100; + s_apply_action[i].generic.callback = ApplyChanges; + } + + s_stipple_box.generic.type = MTYPE_SPINCONTROL; + s_stipple_box.generic.x = 0; + s_stipple_box.generic.y = 60; + s_stipple_box.generic.name = "stipple alpha"; + s_stipple_box.curvalue = sw_stipplealpha->value; + s_stipple_box.itemnames = yesno_names; + + s_windowed_mouse.generic.type = MTYPE_SPINCONTROL; + s_windowed_mouse.generic.x = 0; + s_windowed_mouse.generic.y = 72; + s_windowed_mouse.generic.name = "windowed mouse"; + s_windowed_mouse.curvalue = _windowed_mouse->value; + s_windowed_mouse.itemnames = yesno_names; + + s_tq_slider.generic.type = MTYPE_SLIDER; + s_tq_slider.generic.x = 0; + s_tq_slider.generic.y = 60; + s_tq_slider.generic.name = "texture quality"; + s_tq_slider.minvalue = 0; + s_tq_slider.maxvalue = 3; + s_tq_slider.curvalue = 3-gl_picmip->value; + + s_paletted_texture_box.generic.type = MTYPE_SPINCONTROL; + s_paletted_texture_box.generic.x = 0; + s_paletted_texture_box.generic.y = 70; + s_paletted_texture_box.generic.name = "8-bit textures"; + s_paletted_texture_box.itemnames = yesno_names; + s_paletted_texture_box.curvalue = gl_ext_palettedtexture->value; + + Menu_AddItem( &s_software_menu, ( void * ) &s_ref_list[SOFTWARE_MENU] ); + Menu_AddItem( &s_software_menu, ( void * ) &s_mode_list[SOFTWARE_MENU] ); + Menu_AddItem( &s_software_menu, ( void * ) &s_screensize_slider[SOFTWARE_MENU] ); + Menu_AddItem( &s_software_menu, ( void * ) &s_brightness_slider[SOFTWARE_MENU] ); + Menu_AddItem( &s_software_menu, ( void * ) &s_fs_box[SOFTWARE_MENU] ); + Menu_AddItem( &s_software_menu, ( void * ) &s_stipple_box ); + Menu_AddItem( &s_software_menu, ( void * ) &s_windowed_mouse ); + + Menu_AddItem( &s_opengl_menu, ( void * ) &s_ref_list[OPENGL_MENU] ); + Menu_AddItem( &s_opengl_menu, ( void * ) &s_mode_list[OPENGL_MENU] ); + Menu_AddItem( &s_opengl_menu, ( void * ) &s_screensize_slider[OPENGL_MENU] ); + Menu_AddItem( &s_opengl_menu, ( void * ) &s_brightness_slider[OPENGL_MENU] ); + Menu_AddItem( &s_opengl_menu, ( void * ) &s_fs_box[OPENGL_MENU] ); + Menu_AddItem( &s_opengl_menu, ( void * ) &s_tq_slider ); + Menu_AddItem( &s_opengl_menu, ( void * ) &s_paletted_texture_box ); + + Menu_AddItem( &s_software_menu, ( void * ) &s_defaults_action[SOFTWARE_MENU] ); + Menu_AddItem( &s_software_menu, ( void * ) &s_apply_action[SOFTWARE_MENU] ); + Menu_AddItem( &s_opengl_menu, ( void * ) &s_defaults_action[OPENGL_MENU] ); + Menu_AddItem( &s_opengl_menu, ( void * ) &s_apply_action[OPENGL_MENU] ); + + Menu_Center( &s_software_menu ); + Menu_Center( &s_opengl_menu ); + s_opengl_menu.x -= 8; + s_software_menu.x -= 8; +} + +/* +================ +VID_MenuDraw +================ +*/ +void VID_MenuDraw (void) +{ + int w, h; + + if ( s_current_menu_index == 0 ) + s_current_menu = &s_software_menu; + else + s_current_menu = &s_opengl_menu; + + /* + ** draw the banner + */ + re.DrawGetPicSize( &w, &h, "m_banner_video" ); + re.DrawPic( viddef.width / 2 - w / 2, viddef.height /2 - 110, "m_banner_video" ); + + /* + ** move cursor to a reasonable starting position + */ + Menu_AdjustCursor( s_current_menu, 1 ); + + /* + ** draw the menu + */ + Menu_Draw( s_current_menu ); +} + +/* +================ +VID_MenuKey +================ +*/ +const char *VID_MenuKey( int key ) +{ + extern void M_PopMenu( void ); + + menuframework_s *m = s_current_menu; + static const char *sound = "misc/menu1.wav"; + + switch ( key ) + { + case K_ESCAPE: + M_PopMenu(); + return NULL; + case K_UPARROW: + m->cursor--; + Menu_AdjustCursor( m, -1 ); + break; + case K_DOWNARROW: + m->cursor++; + Menu_AdjustCursor( m, 1 ); + break; + case K_LEFTARROW: + Menu_SlideItem( m, -1 ); + break; + case K_RIGHTARROW: + Menu_SlideItem( m, 1 ); + break; + case K_ENTER: + Menu_SelectItem( m ); + break; + } + + return sound; +} + + diff --git a/linux/vid_so.c b/linux/vid_so.c new file mode 100644 index 000000000..d079b78a7 --- /dev/null +++ b/linux/vid_so.c @@ -0,0 +1,489 @@ +// Main windowed and fullscreen graphics interface module. This module +// is used for both the software and OpenGL rendering versions of the +// Quake refresh engine. + +#define SO_FILE "/etc/quake2.conf" + +#include +#include // ELF dl loader +#include +#include +#include + +#include "../client/client.h" + +#include "../linux/rw_linux.h" + +// Structure containing functions exported from refresh DLL +refexport_t re; + +// Console variables that we need to access from this module +cvar_t *vid_gamma; +cvar_t *vid_ref; // Name of Refresh DLL loaded +cvar_t *vid_xpos; // X coordinate of window position +cvar_t *vid_ypos; // Y coordinate of window position +cvar_t *vid_fullscreen; + +// Global variables used internally by this module +viddef_t viddef; // global video state; used by other modules +void *reflib_library; // Handle to refresh DLL +qboolean reflib_active = 0; + +#define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) ) + +/** KEYBOARD **************************************************************/ + +void Do_Key_Event(int key, qboolean down); + +void (*KBD_Update_fp)(void); +void (*KBD_Init_fp)(Key_Event_fp_t fp); +void (*KBD_Close_fp)(void); + +/** MOUSE *****************************************************************/ + +in_state_t in_state; + +void (*RW_IN_Init_fp)(in_state_t *in_state_p); +void (*RW_IN_Shutdown_fp)(void); +void (*RW_IN_Activate_fp)(qboolean active); +void (*RW_IN_Commands_fp)(void); +void (*RW_IN_Move_fp)(usercmd_t *cmd); +void (*RW_IN_Frame_fp)(void); + +void Real_IN_Init (void); + +/* +========================================================================== + +DLL GLUE + +========================================================================== +*/ + +#define MAXPRINTMSG 4096 +void VID_Printf (int print_level, char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + static qboolean inupdate; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + if (print_level == PRINT_ALL) + Com_Printf ("%s", msg); + else + Com_DPrintf ("%s", msg); +} + +void VID_Error (int err_level, char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + static qboolean inupdate; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + Com_Error (err_level,"%s", msg); +} + +//========================================================================== + +/* +============ +VID_Restart_f + +Console command to re-start the video mode and refresh DLL. We do this +simply by setting the modified flag for the vid_ref variable, which will +cause the entire video mode and refresh DLL to be reset on the next frame. +============ +*/ +void VID_Restart_f (void) +{ + vid_ref->modified = true; +} + +/* +** VID_GetModeInfo +*/ +typedef struct vidmode_s +{ + const char *description; + int width, height; + int mode; +} vidmode_t; + +vidmode_t vid_modes[] = +{ + { "Mode 0: 320x240", 320, 240, 0 }, + { "Mode 1: 400x300", 400, 300, 1 }, + { "Mode 2: 512x384", 512, 384, 2 }, + { "Mode 3: 640x480", 640, 480, 3 }, + { "Mode 4: 800x600", 800, 600, 4 }, + { "Mode 5: 960x720", 960, 720, 5 }, + { "Mode 6: 1024x768", 1024, 768, 6 }, + { "Mode 7: 1152x864", 1152, 864, 7 }, + { "Mode 8: 1280x1024", 1280, 1024, 8 }, + { "Mode 9: 1600x1200", 1600, 1200, 9 } +}; + +qboolean VID_GetModeInfo( int *width, int *height, int mode ) +{ + if ( mode < 0 || mode >= VID_NUM_MODES ) + return false; + + *width = vid_modes[mode].width; + *height = vid_modes[mode].height; + + return true; +} + +/* +** VID_NewWindow +*/ +void VID_NewWindow ( int width, int height) +{ + viddef.width = width; + viddef.height = height; +} + +void VID_FreeReflib (void) +{ + if (reflib_library) { + if (KBD_Close_fp) + KBD_Close_fp(); + if (RW_IN_Shutdown_fp) + RW_IN_Shutdown_fp(); + dlclose(reflib_library); + } + + KBD_Init_fp = NULL; + KBD_Update_fp = NULL; + KBD_Close_fp = NULL; + RW_IN_Init_fp = NULL; + RW_IN_Shutdown_fp = NULL; + RW_IN_Activate_fp = NULL; + RW_IN_Commands_fp = NULL; + RW_IN_Move_fp = NULL; + RW_IN_Frame_fp = NULL; + + memset (&re, 0, sizeof(re)); + reflib_library = NULL; + reflib_active = false; +} + +/* +============== +VID_LoadRefresh +============== +*/ +qboolean VID_LoadRefresh( char *name ) +{ + refimport_t ri; + GetRefAPI_t GetRefAPI; + char fn[MAX_OSPATH]; + struct stat st; + extern uid_t saved_euid; + FILE *fp; + + if ( reflib_active ) + { + if (KBD_Close_fp) + KBD_Close_fp(); + if (RW_IN_Shutdown_fp) + RW_IN_Shutdown_fp(); + KBD_Close_fp = NULL; + RW_IN_Shutdown_fp = NULL; + re.Shutdown(); + VID_FreeReflib (); + } + + Com_Printf( "------- Loading %s -------\n", name ); + + //regain root + seteuid(saved_euid); + + if ((fp = fopen(SO_FILE, "r")) == NULL) { + Com_Printf( "LoadLibrary(\"%s\") failed: can't open " SO_FILE " (required for location of ref libraries)\n", name); + return false; + } + fgets(fn, sizeof(fn), fp); + fclose(fp); + if (*fn && fn[strlen(fn) - 1] == '\n') + fn[strlen(fn) - 1] = 0; + + strcat(fn, "/"); + strcat(fn, name); + + // permission checking + if (strstr(fn, "softx") == NULL) { // softx doesn't require root + if (stat(fn, &st) == -1) { + Com_Printf( "LoadLibrary(\"%s\") failed: %s\n", name, strerror(errno)); + return false; + } + if (st.st_uid != 0) { + Com_Printf( "LoadLibrary(\"%s\") failed: ref is not owned by root\n", name); + return false; + } +#if 0 + if ((st.st_mode & 0777) & ~0700) { + Com_Printf( "LoadLibrary(\"%s\") failed: invalid permissions, must be 700 for security considerations\n", name); + return false; + } +#endif + } else { + // softx requires we give up root now + setreuid(getuid(), getuid()); + setegid(getgid()); + } + + if ( ( reflib_library = dlopen( fn, RTLD_NOW ) ) == 0 ) + { + Com_Printf( "LoadLibrary(\"%s\") failed: %s\n", name , dlerror()); + return false; + } + + ri.Cmd_AddCommand = Cmd_AddCommand; + ri.Cmd_RemoveCommand = Cmd_RemoveCommand; + ri.Cmd_Argc = Cmd_Argc; + ri.Cmd_Argv = Cmd_Argv; + ri.Cmd_ExecuteText = Cbuf_ExecuteText; + ri.Con_Printf = VID_Printf; + ri.Sys_Error = VID_Error; + ri.FS_LoadFile = FS_LoadFile; + ri.FS_FreeFile = FS_FreeFile; + ri.FS_Gamedir = FS_Gamedir; + ri.Cvar_Get = Cvar_Get; + ri.Cvar_Set = Cvar_Set; + ri.Cvar_SetValue = Cvar_SetValue; + ri.Vid_GetModeInfo = VID_GetModeInfo; + ri.Vid_MenuInit = VID_MenuInit; + ri.Vid_NewWindow = VID_NewWindow; + + if ( ( GetRefAPI = (void *) dlsym( reflib_library, "GetRefAPI" ) ) == 0 ) + Com_Error( ERR_FATAL, "dlsym failed on %s", name ); + + re = GetRefAPI( ri ); + + if (re.api_version != API_VERSION) + { + VID_FreeReflib (); + Com_Error (ERR_FATAL, "%s has incompatible api_version", name); + } + + /* Init IN (Mouse) */ + in_state.IN_CenterView_fp = IN_CenterView; + in_state.Key_Event_fp = Do_Key_Event; + in_state.viewangles = cl.viewangles; + in_state.in_strafe_state = &in_strafe.state; + + if ((RW_IN_Init_fp = dlsym(reflib_library, "RW_IN_Init")) == NULL || + (RW_IN_Shutdown_fp = dlsym(reflib_library, "RW_IN_Shutdown")) == NULL || + (RW_IN_Activate_fp = dlsym(reflib_library, "RW_IN_Activate")) == NULL || + (RW_IN_Commands_fp = dlsym(reflib_library, "RW_IN_Commands")) == NULL || + (RW_IN_Move_fp = dlsym(reflib_library, "RW_IN_Move")) == NULL || + (RW_IN_Frame_fp = dlsym(reflib_library, "RW_IN_Frame")) == NULL) + Sys_Error("No RW_IN functions in REF.\n"); + + Real_IN_Init(); + + if ( re.Init( 0, 0 ) == -1 ) + { + re.Shutdown(); + VID_FreeReflib (); + return false; + } + + /* Init KBD */ +#if 1 + if ((KBD_Init_fp = dlsym(reflib_library, "KBD_Init")) == NULL || + (KBD_Update_fp = dlsym(reflib_library, "KBD_Update")) == NULL || + (KBD_Close_fp = dlsym(reflib_library, "KBD_Close")) == NULL) + Sys_Error("No KBD functions in REF.\n"); +#else + { + void KBD_Init(void); + void KBD_Update(void); + void KBD_Close(void); + + KBD_Init_fp = KBD_Init; + KBD_Update_fp = KBD_Update; + KBD_Close_fp = KBD_Close; + } +#endif + KBD_Init_fp(Do_Key_Event); + + // give up root now + setreuid(getuid(), getuid()); + setegid(getgid()); + + Com_Printf( "------------------------------------\n"); + reflib_active = true; + return true; +} + +/* +============ +VID_CheckChanges + +This function gets called once just before drawing each frame, and it's sole purpose in life +is to check to see if any of the video mode parameters have changed, and if they have to +update the rendering DLL and/or video mode to match. +============ +*/ +void VID_CheckChanges (void) +{ + char name[100]; + cvar_t *sw_mode; + + if ( vid_ref->modified ) + { + S_StopAllSounds(); + } + + while (vid_ref->modified) + { + /* + ** refresh has changed + */ + vid_ref->modified = false; + vid_fullscreen->modified = true; + cl.refresh_prepped = false; + cls.disable_screen = true; + + sprintf( name, "ref_%s.so", vid_ref->string ); + if ( !VID_LoadRefresh( name ) ) + { + if ( strcmp (vid_ref->string, "soft") == 0 || + strcmp (vid_ref->string, "softx") == 0 ) { +Com_Printf("Refresh failed\n"); + sw_mode = Cvar_Get( "sw_mode", "0", 0 ); + if (sw_mode->value != 0) { +Com_Printf("Trying mode 0\n"); + Cvar_SetValue("sw_mode", 0); + if ( !VID_LoadRefresh( name ) ) + Com_Error (ERR_FATAL, "Couldn't fall back to software refresh!"); + } else + Com_Error (ERR_FATAL, "Couldn't fall back to software refresh!"); + } + + Cvar_Set( "vid_ref", "soft" ); + + /* + ** drop the console if we fail to load a refresh + */ + if ( cls.key_dest != key_console ) + { + Con_ToggleConsole_f(); + } + } + cls.disable_screen = false; + } + +} + +/* +============ +VID_Init +============ +*/ +void VID_Init (void) +{ + /* Create the video variables so we know how to start the graphics drivers */ + // if DISPLAY is defined, try X + if (getenv("DISPLAY")) + vid_ref = Cvar_Get ("vid_ref", "softx", CVAR_ARCHIVE); + else + vid_ref = Cvar_Get ("vid_ref", "soft", CVAR_ARCHIVE); + vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE); + vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE); + vid_fullscreen = Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE); + vid_gamma = Cvar_Get( "vid_gamma", "1", CVAR_ARCHIVE ); + + /* Add some console commands that we want to handle */ + Cmd_AddCommand ("vid_restart", VID_Restart_f); + + /* Disable the 3Dfx splash screen */ + putenv("FX_GLIDE_NO_SPLASH=0"); + + /* Start the graphics mode and load refresh DLL */ + VID_CheckChanges(); +} + +/* +============ +VID_Shutdown +============ +*/ +void VID_Shutdown (void) +{ + if ( reflib_active ) + { + if (KBD_Close_fp) + KBD_Close_fp(); + if (RW_IN_Shutdown_fp) + RW_IN_Shutdown_fp(); + KBD_Close_fp = NULL; + RW_IN_Shutdown_fp = NULL; + re.Shutdown (); + VID_FreeReflib (); + } +} + + +/*****************************************************************************/ +/* INPUT */ +/*****************************************************************************/ + +cvar_t *in_joystick; + +// This if fake, it's acutally done by the Refresh load +void IN_Init (void) +{ + in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE); +} + +void Real_IN_Init (void) +{ + if (RW_IN_Init_fp) + RW_IN_Init_fp(&in_state); +} + +void IN_Shutdown (void) +{ + if (RW_IN_Shutdown_fp) + RW_IN_Shutdown_fp(); +} + +void IN_Commands (void) +{ + if (RW_IN_Commands_fp) + RW_IN_Commands_fp(); +} + +void IN_Move (usercmd_t *cmd) +{ + if (RW_IN_Move_fp) + RW_IN_Move_fp(cmd); +} + +void IN_Frame (void) +{ + if (RW_IN_Frame_fp) + RW_IN_Frame_fp(); +} + +void IN_Activate (qboolean active) +{ + if (RW_IN_Activate_fp) + RW_IN_Activate_fp(active); +} + +void Do_Key_Event(int key, qboolean down) +{ + Key_Event(key, down, Sys_Milliseconds()); +} + diff --git a/null/cd_null.c b/null/cd_null.c new file mode 100644 index 000000000..43a28148c --- /dev/null +++ b/null/cd_null.c @@ -0,0 +1,31 @@ +#include "../client/client.h" + +void CDAudio_Play(int track, qboolean looping) +{ +} + + +void CDAudio_Stop(void) +{ +} + + +void CDAudio_Resume(void) +{ +} + + +void CDAudio_Update(void) +{ +} + + +int CDAudio_Init(void) +{ + return 0; +} + + +void CDAudio_Shutdown(void) +{ +} diff --git a/null/cl_null.c b/null/cl_null.c new file mode 100644 index 000000000..7967680e7 --- /dev/null +++ b/null/cl_null.c @@ -0,0 +1,55 @@ + +// cl_null.c -- this file can stub out the entire client system +// for pure dedicated servers + +#include "../qcommon/qcommon.h" + +void Key_Bind_Null_f(void) +{ +} + +void CL_Init (void) +{ +} + +void CL_Drop (void) +{ +} + +void CL_Shutdown (void) +{ +} + +void CL_Frame (int msec) +{ +} + +void Con_Print (char *text) +{ +} + +void Cmd_ForwardToServer (void) +{ + char *cmd; + + cmd = Cmd_Argv(0); + Com_Printf ("Unknown command \"%s\"\n", cmd); +} + +void SCR_DebugGraph (float value, int color) +{ +} + +void SCR_BeginLoadingPlaque (void) +{ +} + +void SCR_EndLoadingPlaque (void) +{ +} + +void Key_Init (void) +{ + Cmd_AddCommand ("bind", Key_Bind_Null_f); +} + diff --git a/null/glimp_null.c b/null/glimp_null.c new file mode 100644 index 000000000..c52196b55 --- /dev/null +++ b/null/glimp_null.c @@ -0,0 +1,34 @@ +#include "../ref_gl/gl_local.h" + +void GLimp_BeginFrame( float camera_separation ) +{ +} + +void GLimp_EndFrame( void ) +{ +} + +int GLimp_Init( void *hinstance, void *hWnd ) +{ +} + +void GLimp_Shutdown( void ) +{ +} + +int GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen ) +{ +} + +void GLimp_AppActivate( qboolean active ) +{ +} + +void GLimp_EnableLogging( qboolean enable ) +{ +} + +void GLimp_LogNewFrame( void ) +{ +} + diff --git a/null/in_null.c b/null/in_null.c new file mode 100644 index 000000000..79a927588 --- /dev/null +++ b/null/in_null.c @@ -0,0 +1,36 @@ +// in_null.c -- for systems without a mouse + +#include "../client/client.h" + +void IN_Init (void) +{ +} + +void IN_Shutdown (void) +{ +} + +void IN_Commands (void) +{ +} + +void IN_Frame (void) +{ +} + +void IN_Move (usercmd_t *cmd) +{ +} + +void IN_Activate (qboolean active) +{ +} + +void IN_ActivateMouse (void) +{ +} + +void IN_DeactivateMouse (void) +{ +} + diff --git a/null/snddma_null.c b/null/snddma_null.c new file mode 100644 index 000000000..f9107f75f --- /dev/null +++ b/null/snddma_null.c @@ -0,0 +1,28 @@ + +// snddma_null.c +// all other sound mixing is portable + +#include "../client/client.h" +#include "../client/snd_loc.h" + +qboolean SNDDMA_Init(void) +{ + return false; +} + +int SNDDMA_GetDMAPos(void) +{ + return 0; +} + +void SNDDMA_Shutdown(void) +{ +} + +void SNDDMA_BeginPainting (void) +{ +} + +void SNDDMA_Submit(void) +{ +} diff --git a/null/swimp_null.c b/null/swimp_null.c new file mode 100644 index 000000000..648f0b389 --- /dev/null +++ b/null/swimp_null.c @@ -0,0 +1,30 @@ +#include "../ref_soft/r_local.h" + +void SWimp_BeginFrame( float camera_separation ) +{ +} + +void SWimp_EndFrame (void) +{ +} + +int SWimp_Init( void *hInstance, void *wndProc ) +{ +} + +void SWimp_SetPalette( const unsigned char *palette) +{ +} + +void SWimp_Shutdown( void ) +{ +} + +rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen ) +{ +} + +void SWimp_AppActivate( qboolean active ) +{ +} + diff --git a/null/sys_null.c b/null/sys_null.c new file mode 100644 index 000000000..bf616bc3c --- /dev/null +++ b/null/sys_null.c @@ -0,0 +1,127 @@ +// sys_null.h -- null system driver to aid porting efforts + +#include "../qcommon/qcommon.h" +#include "errno.h" + +int curtime; + +unsigned sys_frame_time; + + +void Sys_mkdir (char *path) +{ +} + +void Sys_Error (char *error, ...) +{ + va_list argptr; + + printf ("Sys_Error: "); + va_start (argptr,error); + vprintf (error,argptr); + va_end (argptr); + printf ("\n"); + + exit (1); +} + +void Sys_Quit (void) +{ + exit (0); +} + +void Sys_UnloadGame (void) +{ +} + +void *Sys_GetGameAPI (void *parms) +{ + return NULL; +} + +char *Sys_ConsoleInput (void) +{ + return NULL; +} + +void Sys_ConsoleOutput (char *string) +{ +} + +void Sys_SendKeyEvents (void) +{ +} + +void Sys_AppActivate (void) +{ +} + +void Sys_CopyProtect (void) +{ +} + +char *Sys_GetClipboardData( void ) +{ + return NULL; +} + +void *Hunk_Begin (int maxsize) +{ + return NULL; +} + +void *Hunk_Alloc (int size) +{ + return NULL; +} + +void Hunk_Free (void *buf) +{ +} + +int Hunk_End (void) +{ + return 0; +} + +int Sys_Milliseconds (void) +{ + return 0; +} + +void Sys_Mkdir (char *path) +{ +} + +char *Sys_FindFirst (char *path, unsigned musthave, unsigned canthave) +{ + return NULL; +} + +char *Sys_FindNext (unsigned musthave, unsigned canthave) +{ + return NULL; +} + +void Sys_FindClose (void) +{ +} + +void Sys_Init (void) +{ +} + + +//============================================================================= + +void main (int argc, char **argv) +{ + Qcommon_Init (argc, argv); + + while (1) + { + Qcommon_Frame (0.1); + } +} + + diff --git a/null/vid_null.c b/null/vid_null.c new file mode 100644 index 000000000..10bb7a8e2 --- /dev/null +++ b/null/vid_null.c @@ -0,0 +1,145 @@ +// vid_null.c -- null video driver to aid porting efforts +// this assumes that one of the refs is statically linked to the executable + +#include "../client/client.h" + +viddef_t viddef; // global video state + +refexport_t re; + +refexport_t GetRefAPI (refimport_t rimp); + +/* +========================================================================== + +DIRECT LINK GLUE + +========================================================================== +*/ + +#define MAXPRINTMSG 4096 +void VID_Printf (int print_level, char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + if (print_level == PRINT_ALL) + Com_Printf ("%s", msg); + else + Com_DPrintf ("%s", msg); +} + +void VID_Error (int err_level, char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + Com_Error (err_level, "%s", msg); +} + +void VID_NewWindow (int width, int height) +{ + viddef.width = width; + viddef.height = height; +} + +/* +** VID_GetModeInfo +*/ +typedef struct vidmode_s +{ + const char *description; + int width, height; + int mode; +} vidmode_t; + +vidmode_t vid_modes[] = +{ + { "Mode 0: 320x240", 320, 240, 0 }, + { "Mode 1: 400x300", 400, 300, 1 }, + { "Mode 2: 512x384", 512, 384, 2 }, + { "Mode 3: 640x480", 640, 480, 3 }, + { "Mode 4: 800x600", 800, 600, 4 }, + { "Mode 5: 960x720", 960, 720, 5 }, + { "Mode 6: 1024x768", 1024, 768, 6 }, + { "Mode 7: 1152x864", 1152, 864, 7 }, + { "Mode 8: 1280x960", 1280, 960, 8 }, + { "Mode 9: 1600x1200", 1600, 1200, 9 } +}; +#define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) ) + +qboolean VID_GetModeInfo( int *width, int *height, int mode ) +{ + if ( mode < 0 || mode >= VID_NUM_MODES ) + return false; + + *width = vid_modes[mode].width; + *height = vid_modes[mode].height; + + return true; +} + + +void VID_Init (void) +{ + refimport_t ri; + + viddef.width = 320; + viddef.height = 240; + + ri.Cmd_AddCommand = Cmd_AddCommand; + ri.Cmd_RemoveCommand = Cmd_RemoveCommand; + ri.Cmd_Argc = Cmd_Argc; + ri.Cmd_Argv = Cmd_Argv; + ri.Cmd_ExecuteText = Cbuf_ExecuteText; + ri.Con_Printf = VID_Printf; + ri.Sys_Error = VID_Error; + ri.FS_LoadFile = FS_LoadFile; + ri.FS_FreeFile = FS_FreeFile; + ri.FS_Gamedir = FS_Gamedir; + ri.Vid_NewWindow = VID_NewWindow; + ri.Cvar_Get = Cvar_Get; + ri.Cvar_Set = Cvar_Set; + ri.Cvar_SetValue = Cvar_SetValue; + ri.Vid_GetModeInfo = VID_GetModeInfo; + + re = GetRefAPI(ri); + + if (re.api_version != API_VERSION) + Com_Error (ERR_FATAL, "Re has incompatible api_version"); + + // call the init function + if (re.Init (NULL, NULL) == -1) + Com_Error (ERR_FATAL, "Couldn't start refresh"); +} + +void VID_Shutdown (void) +{ + if (re.Shutdown) + re.Shutdown (); +} + +void VID_CheckChanges (void) +{ +} + +void VID_MenuInit (void) +{ +} + +void VID_MenuDraw (void) +{ +} + +const char *VID_MenuKey( int k) +{ + return NULL; +} diff --git a/qcommon/cmd.c b/qcommon/cmd.c new file mode 100644 index 000000000..14e9a8d74 --- /dev/null +++ b/qcommon/cmd.c @@ -0,0 +1,892 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +// cmd.c -- Quake script command processing module + +#include "qcommon.h" + +void Cmd_ForwardToServer (void); + +#define MAX_ALIAS_NAME 32 + +typedef struct cmdalias_s +{ + struct cmdalias_s *next; + char name[MAX_ALIAS_NAME]; + char *value; +} cmdalias_t; + +cmdalias_t *cmd_alias; + +qboolean cmd_wait; + +#define ALIAS_LOOP_COUNT 16 +int alias_count; // for detecting runaway loops + + +//============================================================================= + +/* +============ +Cmd_Wait_f + +Causes execution of the remainder of the command buffer to be delayed until +next frame. This allows commands like: +bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2" +============ +*/ +void Cmd_Wait_f (void) +{ + cmd_wait = true; +} + + +/* +============================================================================= + + COMMAND BUFFER + +============================================================================= +*/ + +sizebuf_t cmd_text; +byte cmd_text_buf[8192]; + +byte defer_text_buf[8192]; + +/* +============ +Cbuf_Init +============ +*/ +void Cbuf_Init (void) +{ + SZ_Init (&cmd_text, cmd_text_buf, sizeof(cmd_text_buf)); +} + +/* +============ +Cbuf_AddText + +Adds command text at the end of the buffer +============ +*/ +void Cbuf_AddText (char *text) +{ + int l; + + l = strlen (text); + + if (cmd_text.cursize + l >= cmd_text.maxsize) + { + Com_Printf ("Cbuf_AddText: overflow\n"); + return; + } + SZ_Write (&cmd_text, text, strlen (text)); +} + + +/* +============ +Cbuf_InsertText + +Adds command text immediately after the current command +Adds a \n to the text +FIXME: actually change the command buffer to do less copying +============ +*/ +void Cbuf_InsertText (char *text) +{ + char *temp; + int templen; + +// copy off any commands still remaining in the exec buffer + templen = cmd_text.cursize; + if (templen) + { + temp = Z_Malloc (templen); + memcpy (temp, cmd_text.data, templen); + SZ_Clear (&cmd_text); + } + else + temp = NULL; // shut up compiler + +// add the entire text of the file + Cbuf_AddText (text); + +// add the copied off data + if (templen) + { + SZ_Write (&cmd_text, temp, templen); + Z_Free (temp); + } +} + + +/* +============ +Cbuf_CopyToDefer +============ +*/ +void Cbuf_CopyToDefer (void) +{ + memcpy(defer_text_buf, cmd_text_buf, cmd_text.cursize); + defer_text_buf[cmd_text.cursize] = 0; + cmd_text.cursize = 0; +} + +/* +============ +Cbuf_InsertFromDefer +============ +*/ +void Cbuf_InsertFromDefer (void) +{ + Cbuf_InsertText (defer_text_buf); + defer_text_buf[0] = 0; +} + + +/* +============ +Cbuf_ExecuteText +============ +*/ +void Cbuf_ExecuteText (int exec_when, char *text) +{ + switch (exec_when) + { + case EXEC_NOW: + Cmd_ExecuteString (text); + break; + case EXEC_INSERT: + Cbuf_InsertText (text); + break; + case EXEC_APPEND: + Cbuf_AddText (text); + break; + default: + Com_Error (ERR_FATAL, "Cbuf_ExecuteText: bad exec_when"); + } +} + +/* +============ +Cbuf_Execute +============ +*/ +void Cbuf_Execute (void) +{ + int i; + char *text; + char line[1024]; + int quotes; + + alias_count = 0; // don't allow infinite alias loops + + while (cmd_text.cursize) + { +// find a \n or ; line break + text = (char *)cmd_text.data; + + quotes = 0; + for (i=0 ; i< cmd_text.cursize ; i++) + { + if (text[i] == '"') + quotes++; + if ( !(quotes&1) && text[i] == ';') + break; // don't break if inside a quoted string + if (text[i] == '\n') + break; + } + + + memcpy (line, text, i); + line[i] = 0; + +// delete the text from the command buffer and move remaining commands down +// this is necessary because commands (exec, alias) can insert data at the +// beginning of the text buffer + + if (i == cmd_text.cursize) + cmd_text.cursize = 0; + else + { + i++; + cmd_text.cursize -= i; + memmove (text, text+i, cmd_text.cursize); + } + +// execute the command line + Cmd_ExecuteString (line); + + if (cmd_wait) + { + // skip out while text still remains in buffer, leaving it + // for next frame + cmd_wait = false; + break; + } + } +} + + +/* +=============== +Cbuf_AddEarlyCommands + +Adds command line parameters as script statements +Commands lead with a +, and continue until another + + +Set commands are added early, so they are guaranteed to be set before +the client and server initialize for the first time. + +Other commands are added late, after all initialization is complete. +=============== +*/ +void Cbuf_AddEarlyCommands (qboolean clear) +{ + int i; + char *s; + + for (i=0 ; i : execute a script file\n"); + return; + } + + len = FS_LoadFile (Cmd_Argv(1), (void **)&f); + if (!f) + { + Com_Printf ("couldn't exec %s\n",Cmd_Argv(1)); + return; + } + Com_Printf ("execing %s\n",Cmd_Argv(1)); + + // the file doesn't have a trailing 0, so we need to copy it off + f2 = Z_Malloc(len+1); + memcpy (f2, f, len); + f2[len] = 0; + + Cbuf_InsertText (f2); + + Z_Free (f2); + FS_FreeFile (f); +} + + +/* +=============== +Cmd_Echo_f + +Just prints the rest of the line to the console +=============== +*/ +void Cmd_Echo_f (void) +{ + int i; + + for (i=1 ; inext) + Com_Printf ("%s : %s\n", a->name, a->value); + return; + } + + s = Cmd_Argv(1); + if (strlen(s) >= MAX_ALIAS_NAME) + { + Com_Printf ("Alias name is too long\n"); + return; + } + + // if the alias already exists, reuse it + for (a = cmd_alias ; a ; a=a->next) + { + if (!strcmp(s, a->name)) + { + Z_Free (a->value); + break; + } + } + + if (!a) + { + a = Z_Malloc (sizeof(cmdalias_t)); + a->next = cmd_alias; + cmd_alias = a; + } + strcpy (a->name, s); + +// copy the rest of the command line + cmd[0] = 0; // start out with a null string + c = Cmd_Argc(); + for (i=2 ; i< c ; i++) + { + strcat (cmd, Cmd_Argv(i)); + if (i != (c - 1)) + strcat (cmd, " "); + } + strcat (cmd, "\n"); + + a->value = CopyString (cmd); +} + +/* +============================================================================= + + COMMAND EXECUTION + +============================================================================= +*/ + +typedef struct cmd_function_s +{ + struct cmd_function_s *next; + char *name; + xcommand_t function; +} cmd_function_t; + + +static int cmd_argc; +static char *cmd_argv[MAX_STRING_TOKENS]; +static char *cmd_null_string = ""; +static char cmd_args[MAX_STRING_CHARS]; + +static cmd_function_t *cmd_functions; // possible commands to execute + +/* +============ +Cmd_Argc +============ +*/ +int Cmd_Argc (void) +{ + return cmd_argc; +} + +/* +============ +Cmd_Argv +============ +*/ +char *Cmd_Argv (int arg) +{ + if ( (unsigned)arg >= cmd_argc ) + return cmd_null_string; + return cmd_argv[arg]; +} + +/* +============ +Cmd_Args + +Returns a single string containing argv(1) to argv(argc()-1) +============ +*/ +char *Cmd_Args (void) +{ + return cmd_args; +} + + +/* +====================== +Cmd_MacroExpandString +====================== +*/ +char *Cmd_MacroExpandString (char *text) +{ + int i, j, count, len; + qboolean inquote; + char *scan; + static char expanded[MAX_STRING_CHARS]; + char temporary[MAX_STRING_CHARS]; + char *token, *start; + + inquote = false; + scan = text; + + len = strlen (scan); + if (len >= MAX_STRING_CHARS) + { + Com_Printf ("Line exceeded %i chars, discarded.\n", MAX_STRING_CHARS); + return NULL; + } + + count = 0; + + for (i=0 ; i= MAX_STRING_CHARS) + { + Com_Printf ("Expanded line exceeded %i chars, discarded.\n", MAX_STRING_CHARS); + return NULL; + } + + strncpy (temporary, scan, i); + strcpy (temporary+i, token); + strcpy (temporary+i+j, start); + + strcpy (expanded, temporary); + scan = expanded; + i--; + + if (++count == 100) + { + Com_Printf ("Macro expansion loop, discarded.\n"); + return NULL; + } + } + + if (inquote) + { + Com_Printf ("Line has unmatched quote, discarded.\n"); + return NULL; + } + + return scan; +} + + +/* +============ +Cmd_TokenizeString + +Parses the given string into command line tokens. +$Cvars will be expanded unless they are in a quoted token +============ +*/ +void Cmd_TokenizeString (char *text, qboolean macroExpand) +{ + int i; + char *com_token; + +// clear the args from the last string + for (i=0 ; i= 0 ; l--) + if (cmd_args[l] <= ' ') + cmd_args[l] = 0; + else + break; + } + + com_token = COM_Parse (&text); + if (!text) + return; + + if (cmd_argc < MAX_STRING_TOKENS) + { + cmd_argv[cmd_argc] = Z_Malloc (strlen(com_token)+1); + strcpy (cmd_argv[cmd_argc], com_token); + cmd_argc++; + } + } + +} + + +/* +============ +Cmd_AddCommand +============ +*/ +void Cmd_AddCommand (char *cmd_name, xcommand_t function) +{ + cmd_function_t *cmd; + +// fail if the command is a variable name + if (Cvar_VariableString(cmd_name)[0]) + { + Com_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name); + return; + } + +// fail if the command already exists + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + { + if (!strcmp (cmd_name, cmd->name)) + { + Com_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name); + return; + } + } + + cmd = Z_Malloc (sizeof(cmd_function_t)); + cmd->name = cmd_name; + cmd->function = function; + cmd->next = cmd_functions; + cmd_functions = cmd; +} + +/* +============ +Cmd_RemoveCommand +============ +*/ +void Cmd_RemoveCommand (char *cmd_name) +{ + cmd_function_t *cmd, **back; + + back = &cmd_functions; + while (1) + { + cmd = *back; + if (!cmd) + { + Com_Printf ("Cmd_RemoveCommand: %s not added\n", cmd_name); + return; + } + if (!strcmp (cmd_name, cmd->name)) + { + *back = cmd->next; + Z_Free (cmd); + return; + } + back = &cmd->next; + } +} + +/* +============ +Cmd_Exists +============ +*/ +qboolean Cmd_Exists (char *cmd_name) +{ + cmd_function_t *cmd; + + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + { + if (!strcmp (cmd_name,cmd->name)) + return true; + } + + return false; +} + + + +/* +============ +Cmd_CompleteCommand +============ +*/ +char *Cmd_CompleteCommand (char *partial) +{ + cmd_function_t *cmd; + int len; + cmdalias_t *a; + + len = strlen(partial); + + if (!len) + return NULL; + +// check for exact match + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + if (!strcmp (partial,cmd->name)) + return cmd->name; + for (a=cmd_alias ; a ; a=a->next) + if (!strcmp (partial, a->name)) + return a->name; + +// check for partial match + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + if (!strncmp (partial,cmd->name, len)) + return cmd->name; + for (a=cmd_alias ; a ; a=a->next) + if (!strncmp (partial, a->name, len)) + return a->name; + + return NULL; +} + + +/* +============ +Cmd_ExecuteString + +A complete command line has been parsed, so try to execute it +FIXME: lookupnoadd the token to speed search? +============ +*/ +void Cmd_ExecuteString (char *text) +{ + cmd_function_t *cmd; + cmdalias_t *a; + + Cmd_TokenizeString (text, true); + + // execute the command line + if (!Cmd_Argc()) + return; // no tokens + + // check functions + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + { + if (!Q_strcasecmp (cmd_argv[0],cmd->name)) + { + if (!cmd->function) + { // forward to server command + Cmd_ExecuteString (va("cmd %s", text)); + } + else + cmd->function (); + return; + } + } + + // check alias + for (a=cmd_alias ; a ; a=a->next) + { + if (!Q_strcasecmp (cmd_argv[0], a->name)) + { + if (++alias_count == ALIAS_LOOP_COUNT) + { + Com_Printf ("ALIAS_LOOP_COUNT\n"); + return; + } + Cbuf_InsertText (a->value); + return; + } + } + + // check cvars + if (Cvar_Command ()) + return; + + // send it as a server command if we are connected + Cmd_ForwardToServer (); +} + +/* +============ +Cmd_List_f +============ +*/ +void Cmd_List_f (void) +{ + cmd_function_t *cmd; + int i; + + i = 0; + for (cmd=cmd_functions ; cmd ; cmd=cmd->next, i++) + Com_Printf ("%s\n", cmd->name); + Com_Printf ("%i commands\n", i); +} + +/* +============ +Cmd_Init +============ +*/ +void Cmd_Init (void) +{ +// +// register our commands +// + Cmd_AddCommand ("cmdlist",Cmd_List_f); + Cmd_AddCommand ("exec",Cmd_Exec_f); + Cmd_AddCommand ("echo",Cmd_Echo_f); + Cmd_AddCommand ("alias",Cmd_Alias_f); + Cmd_AddCommand ("wait", Cmd_Wait_f); +} + diff --git a/qcommon/cmodel.c b/qcommon/cmodel.c new file mode 100644 index 000000000..7fc687975 --- /dev/null +++ b/qcommon/cmodel.c @@ -0,0 +1,1770 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +// cmodel.c -- model loading + +#include "qcommon.h" + +typedef struct +{ + cplane_t *plane; + int children[2]; // negative numbers are leafs +} cnode_t; + +typedef struct +{ + cplane_t *plane; + mapsurface_t *surface; +} cbrushside_t; + +typedef struct +{ + int contents; + int cluster; + int area; + unsigned short firstleafbrush; + unsigned short numleafbrushes; +} cleaf_t; + +typedef struct +{ + int contents; + int numsides; + int firstbrushside; + int checkcount; // to avoid repeated testings +} cbrush_t; + +typedef struct +{ + int numareaportals; + int firstareaportal; + int floodnum; // if two areas have equal floodnums, they are connected + int floodvalid; +} carea_t; + +int checkcount; + +char map_name[MAX_QPATH]; + +int numbrushsides; +cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES]; + +int numtexinfo; +mapsurface_t map_surfaces[MAX_MAP_TEXINFO]; + +int numplanes; +cplane_t map_planes[MAX_MAP_PLANES+6]; // extra for box hull + +int numnodes; +cnode_t map_nodes[MAX_MAP_NODES+6]; // extra for box hull + +int numleafs = 1; // allow leaf funcs to be called without a map +cleaf_t map_leafs[MAX_MAP_LEAFS]; +int emptyleaf, solidleaf; + +int numleafbrushes; +unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES]; + +int numcmodels; +cmodel_t map_cmodels[MAX_MAP_MODELS]; + +int numbrushes; +cbrush_t map_brushes[MAX_MAP_BRUSHES]; + +int numvisibility; +byte map_visibility[MAX_MAP_VISIBILITY]; +dvis_t *map_vis = (dvis_t *)map_visibility; + +int numentitychars; +char map_entitystring[MAX_MAP_ENTSTRING]; + +int numareas = 1; +carea_t map_areas[MAX_MAP_AREAS]; + +int numareaportals; +dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS]; + +int numclusters = 1; + +mapsurface_t nullsurface; + +int floodvalid; + +qboolean portalopen[MAX_MAP_AREAPORTALS]; + + +cvar_t *map_noareas; + +void CM_InitBoxHull (void); +void FloodAreaConnections (void); + + +int c_pointcontents; +int c_traces, c_brush_traces; + + +/* +=============================================================================== + + MAP LOADING + +=============================================================================== +*/ + +byte *cmod_base; + +/* +================= +CMod_LoadSubmodels +================= +*/ +void CMod_LoadSubmodels (lump_t *l) +{ + dmodel_t *in; + cmodel_t *out; + int i, j, count; + + in = (void *)(cmod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); + + if (count < 1) + Com_Error (ERR_DROP, "Map with no models"); + if (count > MAX_MAP_MODELS) + Com_Error (ERR_DROP, "Map has too many models"); + + numcmodels = count; + + for ( i=0 ; imins[j] = LittleFloat (in->mins[j]) - 1; + out->maxs[j] = LittleFloat (in->maxs[j]) + 1; + out->origin[j] = LittleFloat (in->origin[j]); + } + out->headnode = LittleLong (in->headnode); + } +} + + +/* +================= +CMod_LoadSurfaces +================= +*/ +void CMod_LoadSurfaces (lump_t *l) +{ + texinfo_t *in; + mapsurface_t *out; + int i, count; + + in = (void *)(cmod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); + if (count < 1) + Com_Error (ERR_DROP, "Map with no surfaces"); + if (count > MAX_MAP_TEXINFO) + Com_Error (ERR_DROP, "Map has too many surfaces"); + + numtexinfo = count; + out = map_surfaces; + + for ( i=0 ; ic.name, in->texture, sizeof(out->c.name)-1); + strncpy (out->rname, in->texture, sizeof(out->rname)-1); + out->c.flags = LittleLong (in->flags); + out->c.value = LittleLong (in->value); + } +} + + +/* +================= +CMod_LoadNodes + +================= +*/ +void CMod_LoadNodes (lump_t *l) +{ + dnode_t *in; + int child; + cnode_t *out; + int i, j, count; + + in = (void *)(cmod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); + + if (count < 1) + Com_Error (ERR_DROP, "Map has no nodes"); + if (count > MAX_MAP_NODES) + Com_Error (ERR_DROP, "Map has too many nodes"); + + out = map_nodes; + + numnodes = count; + + for (i=0 ; iplane = map_planes + LittleLong(in->planenum); + for (j=0 ; j<2 ; j++) + { + child = LittleLong (in->children[j]); + out->children[j] = child; + } + } + +} + +/* +================= +CMod_LoadBrushes + +================= +*/ +void CMod_LoadBrushes (lump_t *l) +{ + dbrush_t *in; + cbrush_t *out; + int i, count; + + in = (void *)(cmod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); + + if (count > MAX_MAP_BRUSHES) + Com_Error (ERR_DROP, "Map has too many brushes"); + + out = map_brushes; + + numbrushes = count; + + for (i=0 ; ifirstbrushside = LittleLong(in->firstside); + out->numsides = LittleLong(in->numsides); + out->contents = LittleLong(in->contents); + } + +} + +/* +================= +CMod_LoadLeafs +================= +*/ +void CMod_LoadLeafs (lump_t *l) +{ + int i; + cleaf_t *out; + dleaf_t *in; + int count; + + in = (void *)(cmod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); + + if (count < 1) + Com_Error (ERR_DROP, "Map with no leafs"); + // need to save space for box planes + if (count > MAX_MAP_PLANES) + Com_Error (ERR_DROP, "Map has too many planes"); + + out = map_leafs; + numleafs = count; + numclusters = 0; + + for ( i=0 ; icontents = LittleLong (in->contents); + out->cluster = LittleShort (in->cluster); + out->area = LittleShort (in->area); + out->firstleafbrush = LittleShort (in->firstleafbrush); + out->numleafbrushes = LittleShort (in->numleafbrushes); + + if (out->cluster >= numclusters) + numclusters = out->cluster + 1; + } + + if (map_leafs[0].contents != CONTENTS_SOLID) + Com_Error (ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID"); + solidleaf = 0; + emptyleaf = -1; + for (i=1 ; ifileofs); + if (l->filelen % sizeof(*in)) + Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); + + if (count < 1) + Com_Error (ERR_DROP, "Map with no planes"); + // need to save space for box planes + if (count > MAX_MAP_PLANES) + Com_Error (ERR_DROP, "Map has too many planes"); + + out = map_planes; + numplanes = count; + + for ( i=0 ; inormal[j] = LittleFloat (in->normal[j]); + if (out->normal[j] < 0) + bits |= 1<dist = LittleFloat (in->dist); + out->type = LittleLong (in->type); + out->signbits = bits; + } +} + +/* +================= +CMod_LoadLeafBrushes +================= +*/ +void CMod_LoadLeafBrushes (lump_t *l) +{ + int i; + unsigned short *out; + unsigned short *in; + int count; + + in = (void *)(cmod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); + + if (count < 1) + Com_Error (ERR_DROP, "Map with no planes"); + // need to save space for box planes + if (count > MAX_MAP_LEAFBRUSHES) + Com_Error (ERR_DROP, "Map has too many leafbrushes"); + + out = map_leafbrushes; + numleafbrushes = count; + + for ( i=0 ; ifileofs); + if (l->filelen % sizeof(*in)) + Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); + + // need to save space for box planes + if (count > MAX_MAP_BRUSHSIDES) + Com_Error (ERR_DROP, "Map has too many planes"); + + out = map_brushsides; + numbrushsides = count; + + for ( i=0 ; iplanenum); + out->plane = &map_planes[num]; + j = LittleShort (in->texinfo); + if (j >= numtexinfo) + Com_Error (ERR_DROP, "Bad brushside texinfo"); + out->surface = &map_surfaces[j]; + } +} + +/* +================= +CMod_LoadAreas +================= +*/ +void CMod_LoadAreas (lump_t *l) +{ + int i; + carea_t *out; + darea_t *in; + int count; + + in = (void *)(cmod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); + + if (count > MAX_MAP_AREAS) + Com_Error (ERR_DROP, "Map has too many areas"); + + out = map_areas; + numareas = count; + + for ( i=0 ; inumareaportals = LittleLong (in->numareaportals); + out->firstareaportal = LittleLong (in->firstareaportal); + out->floodvalid = 0; + out->floodnum = 0; + } +} + +/* +================= +CMod_LoadAreaPortals +================= +*/ +void CMod_LoadAreaPortals (lump_t *l) +{ + int i; + dareaportal_t *out; + dareaportal_t *in; + int count; + + in = (void *)(cmod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); + + if (count > MAX_MAP_AREAS) + Com_Error (ERR_DROP, "Map has too many areas"); + + out = map_areaportals; + numareaportals = count; + + for ( i=0 ; iportalnum = LittleLong (in->portalnum); + out->otherarea = LittleLong (in->otherarea); + } +} + +/* +================= +CMod_LoadVisibility +================= +*/ +void CMod_LoadVisibility (lump_t *l) +{ + int i; + + numvisibility = l->filelen; + if (l->filelen > MAX_MAP_VISIBILITY) + Com_Error (ERR_DROP, "Map has too large visibility lump"); + + memcpy (map_visibility, cmod_base + l->fileofs, l->filelen); + + map_vis->numclusters = LittleLong (map_vis->numclusters); + for (i=0 ; inumclusters ; i++) + { + map_vis->bitofs[i][0] = LittleLong (map_vis->bitofs[i][0]); + map_vis->bitofs[i][1] = LittleLong (map_vis->bitofs[i][1]); + } +} + + +/* +================= +CMod_LoadEntityString +================= +*/ +void CMod_LoadEntityString (lump_t *l) +{ + numentitychars = l->filelen; + if (l->filelen > MAX_MAP_ENTSTRING) + Com_Error (ERR_DROP, "Map has too large entity lump"); + + memcpy (map_entitystring, cmod_base + l->fileofs, l->filelen); +} + + + +/* +================== +CM_LoadMap + +Loads in the map and all submodels +================== +*/ +cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum) +{ + unsigned *buf; + int i; + dheader_t header; + int length; + static unsigned last_checksum; + + map_noareas = Cvar_Get ("map_noareas", "0", 0); + + if ( !strcmp (map_name, name) && (clientload || !Cvar_VariableValue ("flushmap")) ) + { + *checksum = last_checksum; + if (!clientload) + { + memset (portalopen, 0, sizeof(portalopen)); + FloodAreaConnections (); + } + return &map_cmodels[0]; // still have the right version + } + + // free old stuff + numplanes = 0; + numnodes = 0; + numleafs = 0; + numcmodels = 0; + numvisibility = 0; + numentitychars = 0; + map_entitystring[0] = 0; + map_name[0] = 0; + + if (!name || !name[0]) + { + numleafs = 1; + numclusters = 1; + numareas = 1; + *checksum = 0; + return &map_cmodels[0]; // cinematic servers won't have anything at all + } + + // + // load the file + // + length = FS_LoadFile (name, (void **)&buf); + if (!buf) + Com_Error (ERR_DROP, "Couldn't load %s", name); + + last_checksum = LittleLong (Com_BlockChecksum (buf, length)); + *checksum = last_checksum; + + header = *(dheader_t *)buf; + for (i=0 ; i= numcmodels) + Com_Error (ERR_DROP, "CM_InlineModel: bad number"); + + return &map_cmodels[num]; +} + +int CM_NumClusters (void) +{ + return numclusters; +} + +int CM_NumInlineModels (void) +{ + return numcmodels; +} + +char *CM_EntityString (void) +{ + return map_entitystring; +} + +int CM_LeafContents (int leafnum) +{ + if (leafnum < 0 || leafnum >= numleafs) + Com_Error (ERR_DROP, "CM_LeafContents: bad number"); + return map_leafs[leafnum].contents; +} + +int CM_LeafCluster (int leafnum) +{ + if (leafnum < 0 || leafnum >= numleafs) + Com_Error (ERR_DROP, "CM_LeafCluster: bad number"); + return map_leafs[leafnum].cluster; +} + +int CM_LeafArea (int leafnum) +{ + if (leafnum < 0 || leafnum >= numleafs) + Com_Error (ERR_DROP, "CM_LeafArea: bad number"); + return map_leafs[leafnum].area; +} + +//======================================================================= + + +cplane_t *box_planes; +int box_headnode; +cbrush_t *box_brush; +cleaf_t *box_leaf; + +/* +=================== +CM_InitBoxHull + +Set up the planes and nodes so that the six floats of a bounding box +can just be stored out and get a proper clipping hull structure. +=================== +*/ +void CM_InitBoxHull (void) +{ + int i; + int side; + cnode_t *c; + cplane_t *p; + cbrushside_t *s; + + box_headnode = numnodes; + box_planes = &map_planes[numplanes]; + if (numnodes+6 > MAX_MAP_NODES + || numbrushes+1 > MAX_MAP_BRUSHES + || numleafbrushes+1 > MAX_MAP_LEAFBRUSHES + || numbrushsides+6 > MAX_MAP_BRUSHSIDES + || numplanes+12 > MAX_MAP_PLANES) + Com_Error (ERR_DROP, "Not enough room for box tree"); + + box_brush = &map_brushes[numbrushes]; + box_brush->numsides = 6; + box_brush->firstbrushside = numbrushsides; + box_brush->contents = CONTENTS_MONSTER; + + box_leaf = &map_leafs[numleafs]; + box_leaf->contents = CONTENTS_MONSTER; + box_leaf->firstleafbrush = numleafbrushes; + box_leaf->numleafbrushes = 1; + + map_leafbrushes[numleafbrushes] = numbrushes; + + for (i=0 ; i<6 ; i++) + { + side = i&1; + + // brush sides + s = &map_brushsides[numbrushsides+i]; + s->plane = map_planes + (numplanes+i*2+side); + s->surface = &nullsurface; + + // nodes + c = &map_nodes[box_headnode+i]; + c->plane = map_planes + (numplanes+i*2); + c->children[side] = -1 - emptyleaf; + if (i != 5) + c->children[side^1] = box_headnode+i + 1; + else + c->children[side^1] = -1 - numleafs; + + // planes + p = &box_planes[i*2]; + p->type = i>>1; + p->signbits = 0; + VectorClear (p->normal); + p->normal[i>>1] = 1; + + p = &box_planes[i*2+1]; + p->type = 3 + (i>>1); + p->signbits = 0; + VectorClear (p->normal); + p->normal[i>>1] = -1; + } +} + + +/* +=================== +CM_HeadnodeForBox + +To keep everything totally uniform, bounding boxes are turned into small +BSP trees instead of being compared directly. +=================== +*/ +int CM_HeadnodeForBox (vec3_t mins, vec3_t maxs) +{ + box_planes[0].dist = maxs[0]; + box_planes[1].dist = -maxs[0]; + box_planes[2].dist = mins[0]; + box_planes[3].dist = -mins[0]; + box_planes[4].dist = maxs[1]; + box_planes[5].dist = -maxs[1]; + box_planes[6].dist = mins[1]; + box_planes[7].dist = -mins[1]; + box_planes[8].dist = maxs[2]; + box_planes[9].dist = -maxs[2]; + box_planes[10].dist = mins[2]; + box_planes[11].dist = -mins[2]; + + return box_headnode; +} + + +/* +================== +CM_PointLeafnum_r + +================== +*/ +int CM_PointLeafnum_r (vec3_t p, int num) +{ + float d; + cnode_t *node; + cplane_t *plane; + + while (num >= 0) + { + node = map_nodes + num; + plane = node->plane; + + if (plane->type < 3) + d = p[plane->type] - plane->dist; + else + d = DotProduct (plane->normal, p) - plane->dist; + if (d < 0) + num = node->children[1]; + else + num = node->children[0]; + } + + c_pointcontents++; // optimize counter + + return -1 - num; +} + +int CM_PointLeafnum (vec3_t p) +{ + if (!numplanes) + return 0; // sound may call this without map loaded + return CM_PointLeafnum_r (p, 0); +} + + + +/* +============= +CM_BoxLeafnums + +Fills in a list of all the leafs touched +============= +*/ +int leaf_count, leaf_maxcount; +int *leaf_list; +float *leaf_mins, *leaf_maxs; +int leaf_topnode; + +void CM_BoxLeafnums_r (int nodenum) +{ + cplane_t *plane; + cnode_t *node; + int s; + + while (1) + { + if (nodenum < 0) + { + if (leaf_count >= leaf_maxcount) + { +// Com_Printf ("CM_BoxLeafnums_r: overflow\n"); + return; + } + leaf_list[leaf_count++] = -1 - nodenum; + return; + } + + node = &map_nodes[nodenum]; + plane = node->plane; +// s = BoxOnPlaneSide (leaf_mins, leaf_maxs, plane); + s = BOX_ON_PLANE_SIDE(leaf_mins, leaf_maxs, plane); + if (s == 1) + nodenum = node->children[0]; + else if (s == 2) + nodenum = node->children[1]; + else + { // go down both + if (leaf_topnode == -1) + leaf_topnode = nodenum; + CM_BoxLeafnums_r (node->children[0]); + nodenum = node->children[1]; + } + + } +} + +int CM_BoxLeafnums_headnode (vec3_t mins, vec3_t maxs, int *list, int listsize, int headnode, int *topnode) +{ + leaf_list = list; + leaf_count = 0; + leaf_maxcount = listsize; + leaf_mins = mins; + leaf_maxs = maxs; + + leaf_topnode = -1; + + CM_BoxLeafnums_r (headnode); + + if (topnode) + *topnode = leaf_topnode; + + return leaf_count; +} + +int CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode) +{ + return CM_BoxLeafnums_headnode (mins, maxs, list, + listsize, map_cmodels[0].headnode, topnode); +} + + + +/* +================== +CM_PointContents + +================== +*/ +int CM_PointContents (vec3_t p, int headnode) +{ + int l; + + if (!numnodes) // map not loaded + return 0; + + l = CM_PointLeafnum_r (p, headnode); + + return map_leafs[l].contents; +} + +/* +================== +CM_TransformedPointContents + +Handles offseting and rotation of the end points for moving and +rotating entities +================== +*/ +int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles) +{ + vec3_t p_l; + vec3_t temp; + vec3_t forward, right, up; + int l; + + // subtract origin offset + VectorSubtract (p, origin, p_l); + + // rotate start and end into the models frame of reference + if (headnode != box_headnode && + (angles[0] || angles[1] || angles[2]) ) + { + AngleVectors (angles, forward, right, up); + + VectorCopy (p_l, temp); + p_l[0] = DotProduct (temp, forward); + p_l[1] = -DotProduct (temp, right); + p_l[2] = DotProduct (temp, up); + } + + l = CM_PointLeafnum_r (p_l, headnode); + + return map_leafs[l].contents; +} + + +/* +=============================================================================== + +BOX TRACING + +=============================================================================== +*/ + +// 1/32 epsilon to keep floating point happy +#define DIST_EPSILON (0.03125) + +vec3_t trace_start, trace_end; +vec3_t trace_mins, trace_maxs; +vec3_t trace_extents; + +trace_t trace_trace; +int trace_contents; +qboolean trace_ispoint; // optimized case + +/* +================ +CM_ClipBoxToBrush +================ +*/ +void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, + trace_t *trace, cbrush_t *brush) +{ + int i, j; + cplane_t *plane, *clipplane; + float dist; + float enterfrac, leavefrac; + vec3_t ofs; + float d1, d2; + qboolean getout, startout; + float f; + cbrushside_t *side, *leadside; + + enterfrac = -1; + leavefrac = 1; + clipplane = NULL; + + if (!brush->numsides) + return; + + c_brush_traces++; + + getout = false; + startout = false; + leadside = NULL; + + for (i=0 ; inumsides ; i++) + { + side = &map_brushsides[brush->firstbrushside+i]; + plane = side->plane; + + // FIXME: special case for axial + + if (!trace_ispoint) + { // general box case + + // push the plane out apropriately for mins/maxs + + // FIXME: use signbits into 8 way lookup for each mins/maxs + for (j=0 ; j<3 ; j++) + { + if (plane->normal[j] < 0) + ofs[j] = maxs[j]; + else + ofs[j] = mins[j]; + } + dist = DotProduct (ofs, plane->normal); + dist = plane->dist - dist; + } + else + { // special point case + dist = plane->dist; + } + + d1 = DotProduct (p1, plane->normal) - dist; + d2 = DotProduct (p2, plane->normal) - dist; + + if (d2 > 0) + getout = true; // endpoint is not in solid + if (d1 > 0) + startout = true; + + // if completely in front of face, no intersection + if (d1 > 0 && d2 >= d1) + return; + + if (d1 <= 0 && d2 <= 0) + continue; + + // crosses face + if (d1 > d2) + { // enter + f = (d1-DIST_EPSILON) / (d1-d2); + if (f > enterfrac) + { + enterfrac = f; + clipplane = plane; + leadside = side; + } + } + else + { // leave + f = (d1+DIST_EPSILON) / (d1-d2); + if (f < leavefrac) + leavefrac = f; + } + } + + if (!startout) + { // original point was inside brush + trace->startsolid = true; + if (!getout) + trace->allsolid = true; + return; + } + if (enterfrac < leavefrac) + { + if (enterfrac > -1 && enterfrac < trace->fraction) + { + if (enterfrac < 0) + enterfrac = 0; + trace->fraction = enterfrac; + trace->plane = *clipplane; + trace->surface = &(leadside->surface->c); + trace->contents = brush->contents; + } + } +} + +/* +================ +CM_TestBoxInBrush +================ +*/ +void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1, + trace_t *trace, cbrush_t *brush) +{ + int i, j; + cplane_t *plane; + float dist; + vec3_t ofs; + float d1; + cbrushside_t *side; + + if (!brush->numsides) + return; + + for (i=0 ; inumsides ; i++) + { + side = &map_brushsides[brush->firstbrushside+i]; + plane = side->plane; + + // FIXME: special case for axial + + // general box case + + // push the plane out apropriately for mins/maxs + + // FIXME: use signbits into 8 way lookup for each mins/maxs + for (j=0 ; j<3 ; j++) + { + if (plane->normal[j] < 0) + ofs[j] = maxs[j]; + else + ofs[j] = mins[j]; + } + dist = DotProduct (ofs, plane->normal); + dist = plane->dist - dist; + + d1 = DotProduct (p1, plane->normal) - dist; + + // if completely in front of face, no intersection + if (d1 > 0) + return; + + } + + // inside this brush + trace->startsolid = trace->allsolid = true; + trace->fraction = 0; + trace->contents = brush->contents; +} + + +/* +================ +CM_TraceToLeaf +================ +*/ +void CM_TraceToLeaf (int leafnum) +{ + int k; + int brushnum; + cleaf_t *leaf; + cbrush_t *b; + + leaf = &map_leafs[leafnum]; + if ( !(leaf->contents & trace_contents)) + return; + // trace line against all brushes in the leaf + for (k=0 ; knumleafbrushes ; k++) + { + brushnum = map_leafbrushes[leaf->firstleafbrush+k]; + b = &map_brushes[brushnum]; + if (b->checkcount == checkcount) + continue; // already checked this brush in another leaf + b->checkcount = checkcount; + + if ( !(b->contents & trace_contents)) + continue; + CM_ClipBoxToBrush (trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, b); + if (!trace_trace.fraction) + return; + } + +} + + +/* +================ +CM_TestInLeaf +================ +*/ +void CM_TestInLeaf (int leafnum) +{ + int k; + int brushnum; + cleaf_t *leaf; + cbrush_t *b; + + leaf = &map_leafs[leafnum]; + if ( !(leaf->contents & trace_contents)) + return; + // trace line against all brushes in the leaf + for (k=0 ; knumleafbrushes ; k++) + { + brushnum = map_leafbrushes[leaf->firstleafbrush+k]; + b = &map_brushes[brushnum]; + if (b->checkcount == checkcount) + continue; // already checked this brush in another leaf + b->checkcount = checkcount; + + if ( !(b->contents & trace_contents)) + continue; + CM_TestBoxInBrush (trace_mins, trace_maxs, trace_start, &trace_trace, b); + if (!trace_trace.fraction) + return; + } + +} + + +/* +================== +CM_RecursiveHullCheck + +================== +*/ +void CM_RecursiveHullCheck (int num, float p1f, float p2f, vec3_t p1, vec3_t p2) +{ + cnode_t *node; + cplane_t *plane; + float t1, t2, offset; + float frac, frac2; + float idist; + int i; + vec3_t mid; + int side; + float midf; + + if (trace_trace.fraction <= p1f) + return; // already hit something nearer + + // if < 0, we are in a leaf node + if (num < 0) + { + CM_TraceToLeaf (-1-num); + return; + } + + // + // find the point distances to the seperating plane + // and the offset for the size of the box + // + node = map_nodes + num; + plane = node->plane; + + if (plane->type < 3) + { + t1 = p1[plane->type] - plane->dist; + t2 = p2[plane->type] - plane->dist; + offset = trace_extents[plane->type]; + } + else + { + t1 = DotProduct (plane->normal, p1) - plane->dist; + t2 = DotProduct (plane->normal, p2) - plane->dist; + if (trace_ispoint) + offset = 0; + else + offset = fabs(trace_extents[0]*plane->normal[0]) + + fabs(trace_extents[1]*plane->normal[1]) + + fabs(trace_extents[2]*plane->normal[2]); + } + + +#if 0 +CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2); +CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2); +return; +#endif + + // see which sides we need to consider + if (t1 >= offset && t2 >= offset) + { + CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2); + return; + } + if (t1 < -offset && t2 < -offset) + { + CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2); + return; + } + + // put the crosspoint DIST_EPSILON pixels on the near side + if (t1 < t2) + { + idist = 1.0/(t1-t2); + side = 1; + frac2 = (t1 + offset + DIST_EPSILON)*idist; + frac = (t1 - offset + DIST_EPSILON)*idist; + } + else if (t1 > t2) + { + idist = 1.0/(t1-t2); + side = 0; + frac2 = (t1 - offset - DIST_EPSILON)*idist; + frac = (t1 + offset + DIST_EPSILON)*idist; + } + else + { + side = 0; + frac = 1; + frac2 = 0; + } + + // move up to the node + if (frac < 0) + frac = 0; + if (frac > 1) + frac = 1; + + midf = p1f + (p2f - p1f)*frac; + for (i=0 ; i<3 ; i++) + mid[i] = p1[i] + frac*(p2[i] - p1[i]); + + CM_RecursiveHullCheck (node->children[side], p1f, midf, p1, mid); + + + // go past the node + if (frac2 < 0) + frac2 = 0; + if (frac2 > 1) + frac2 = 1; + + midf = p1f + (p2f - p1f)*frac2; + for (i=0 ; i<3 ; i++) + mid[i] = p1[i] + frac2*(p2[i] - p1[i]); + + CM_RecursiveHullCheck (node->children[side^1], midf, p2f, mid, p2); +} + + + +//====================================================================== + +/* +================== +CM_BoxTrace +================== +*/ +trace_t CM_BoxTrace (vec3_t start, vec3_t end, + vec3_t mins, vec3_t maxs, + int headnode, int brushmask) +{ + int i; + + checkcount++; // for multi-check avoidance + + c_traces++; // for statistics, may be zeroed + + // fill in a default trace + memset (&trace_trace, 0, sizeof(trace_trace)); + trace_trace.fraction = 1; + trace_trace.surface = &(nullsurface.c); + + if (!numnodes) // map not loaded + return trace_trace; + + trace_contents = brushmask; + VectorCopy (start, trace_start); + VectorCopy (end, trace_end); + VectorCopy (mins, trace_mins); + VectorCopy (maxs, trace_maxs); + + // + // check for position test special case + // + if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) + { + int leafs[1024]; + int i, numleafs; + vec3_t c1, c2; + int topnode; + + VectorAdd (start, mins, c1); + VectorAdd (start, maxs, c2); + for (i=0 ; i<3 ; i++) + { + c1[i] -= 1; + c2[i] += 1; + } + + numleafs = CM_BoxLeafnums_headnode (c1, c2, leafs, 1024, headnode, &topnode); + for (i=0 ; i maxs[0] ? -mins[0] : maxs[0]; + trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1]; + trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2]; + } + + // + // general sweeping through world + // + CM_RecursiveHullCheck (headnode, 0, 1, start, end); + + if (trace_trace.fraction == 1) + { + VectorCopy (end, trace_trace.endpos); + } + else + { + for (i=0 ; i<3 ; i++) + trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]); + } + return trace_trace; +} + + +/* +================== +CM_TransformedBoxTrace + +Handles offseting and rotation of the end points for moving and +rotating entities +================== +*/ +#ifdef _WIN32 +#pragma optimize( "", off ) +#endif + + +trace_t CM_TransformedBoxTrace (vec3_t start, vec3_t end, + vec3_t mins, vec3_t maxs, + int headnode, int brushmask, + vec3_t origin, vec3_t angles) +{ + trace_t trace; + vec3_t start_l, end_l; + vec3_t a; + vec3_t forward, right, up; + vec3_t temp; + qboolean rotated; + + // subtract origin offset + VectorSubtract (start, origin, start_l); + VectorSubtract (end, origin, end_l); + + // rotate start and end into the models frame of reference + if (headnode != box_headnode && + (angles[0] || angles[1] || angles[2]) ) + rotated = true; + else + rotated = false; + + if (rotated) + { + AngleVectors (angles, forward, right, up); + + VectorCopy (start_l, temp); + start_l[0] = DotProduct (temp, forward); + start_l[1] = -DotProduct (temp, right); + start_l[2] = DotProduct (temp, up); + + VectorCopy (end_l, temp); + end_l[0] = DotProduct (temp, forward); + end_l[1] = -DotProduct (temp, right); + end_l[2] = DotProduct (temp, up); + } + + // sweep the box through the model + trace = CM_BoxTrace (start_l, end_l, mins, maxs, headnode, brushmask); + + if (rotated && trace.fraction != 1.0) + { + // FIXME: figure out how to do this with existing angles + VectorNegate (angles, a); + AngleVectors (a, forward, right, up); + + VectorCopy (trace.plane.normal, temp); + trace.plane.normal[0] = DotProduct (temp, forward); + trace.plane.normal[1] = -DotProduct (temp, right); + trace.plane.normal[2] = DotProduct (temp, up); + } + + trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]); + trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]); + trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]); + + return trace; +} + +#ifdef _WIN32 +#pragma optimize( "", on ) +#endif + + + +/* +=============================================================================== + +PVS / PHS + +=============================================================================== +*/ + +/* +=================== +CM_DecompressVis +=================== +*/ +void CM_DecompressVis (byte *in, byte *out) +{ + int c; + byte *out_p; + int row; + + row = (numclusters+7)>>3; + out_p = out; + + if (!in || !numvisibility) + { // no vis info, so make all visible + while (row) + { + *out_p++ = 0xff; + row--; + } + return; + } + + do + { + if (*in) + { + *out_p++ = *in++; + continue; + } + + c = in[1]; + in += 2; + if ((out_p - out) + c > row) + { + c = row - (out_p - out); + Com_DPrintf ("warning: Vis decompression overrun\n"); + } + while (c) + { + *out_p++ = 0; + c--; + } + } while (out_p - out < row); +} + +byte pvsrow[MAX_MAP_LEAFS/8]; +byte phsrow[MAX_MAP_LEAFS/8]; + +byte *CM_ClusterPVS (int cluster) +{ + if (cluster == -1) + memset (pvsrow, 0, (numclusters+7)>>3); + else + CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PVS], pvsrow); + return pvsrow; +} + +byte *CM_ClusterPHS (int cluster) +{ + if (cluster == -1) + memset (phsrow, 0, (numclusters+7)>>3); + else + CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PHS], phsrow); + return phsrow; +} + + +/* +=============================================================================== + +AREAPORTALS + +=============================================================================== +*/ + +void FloodArea_r (carea_t *area, int floodnum) +{ + int i; + dareaportal_t *p; + + if (area->floodvalid == floodvalid) + { + if (area->floodnum == floodnum) + return; + Com_Error (ERR_DROP, "FloodArea_r: reflooded"); + } + + area->floodnum = floodnum; + area->floodvalid = floodvalid; + p = &map_areaportals[area->firstareaportal]; + for (i=0 ; inumareaportals ; i++, p++) + { + if (portalopen[p->portalnum]) + FloodArea_r (&map_areas[p->otherarea], floodnum); + } +} + +/* +==================== +FloodAreaConnections + + +==================== +*/ +void FloodAreaConnections (void) +{ + int i; + carea_t *area; + int floodnum; + + // all current floods are now invalid + floodvalid++; + floodnum = 0; + + // area 0 is not used + for (i=1 ; ifloodvalid == floodvalid) + continue; // already flooded into + floodnum++; + FloodArea_r (area, floodnum); + } + +} + +void CM_SetAreaPortalState (int portalnum, qboolean open) +{ + if (portalnum > numareaportals) + Com_Error (ERR_DROP, "areaportal > numareaportals"); + + portalopen[portalnum] = open; + FloodAreaConnections (); +} + +qboolean CM_AreasConnected (int area1, int area2) +{ + if (map_noareas->value) + return true; + + if (area1 > numareas || area2 > numareas) + Com_Error (ERR_DROP, "area > numareas"); + + if (map_areas[area1].floodnum == map_areas[area2].floodnum) + return true; + return false; +} + + +/* +================= +CM_WriteAreaBits + +Writes a length byte followed by a bit vector of all the areas +that area in the same flood as the area parameter + +This is used by the client refreshes to cull visibility +================= +*/ +int CM_WriteAreaBits (byte *buffer, int area) +{ + int i; + int floodnum; + int bytes; + + bytes = (numareas+7)>>3; + + if (map_noareas->value) + { // for debugging, send everything + memset (buffer, 255, bytes); + } + else + { + memset (buffer, 0, bytes); + + floodnum = map_areas[area].floodnum; + for (i=0 ; i>3] |= 1<<(i&7); + } + } + + return bytes; +} + + +/* +=================== +CM_WritePortalState + +Writes the portal state to a savegame file +=================== +*/ +void CM_WritePortalState (FILE *f) +{ + fwrite (portalopen, sizeof(portalopen), 1, f); +} + +/* +=================== +CM_ReadPortalState + +Reads the portal state from a savegame file +and recalculates the area connections +=================== +*/ +void CM_ReadPortalState (FILE *f) +{ + FS_Read (portalopen, sizeof(portalopen), f); + FloodAreaConnections (); +} + +/* +============= +CM_HeadnodeVisible + +Returns true if any leaf under headnode has a cluster that +is potentially visible +============= +*/ +qboolean CM_HeadnodeVisible (int nodenum, byte *visbits) +{ + int leafnum; + int cluster; + cnode_t *node; + + if (nodenum < 0) + { + leafnum = -1-nodenum; + cluster = map_leafs[leafnum].cluster; + if (cluster == -1) + return false; + if (visbits[cluster>>3] & (1<<(cluster&7))) + return true; + return false; + } + + node = &map_nodes[nodenum]; + if (CM_HeadnodeVisible(node->children[0], visbits)) + return true; + return CM_HeadnodeVisible(node->children[1], visbits); +} + diff --git a/qcommon/common.c b/qcommon/common.c new file mode 100644 index 000000000..e14764729 --- /dev/null +++ b/qcommon/common.c @@ -0,0 +1,1588 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +// common.c -- misc functions used in client and server +#include "qcommon.h" +#include + +#define MAXPRINTMSG 4096 + +#define MAX_NUM_ARGVS 50 + + +int com_argc; +char *com_argv[MAX_NUM_ARGVS+1]; + +int realtime; + +jmp_buf abortframe; // an ERR_DROP occured, exit the entire frame + + +FILE *log_stats_file; + +cvar_t *host_speeds; +cvar_t *log_stats; +cvar_t *developer; +cvar_t *timescale; +cvar_t *fixedtime; +cvar_t *logfile_active; // 1 = buffer log, 2 = flush after each print +cvar_t *showtrace; +cvar_t *dedicated; + +FILE *logfile; + +int server_state; + +// host_speeds times +int time_before_game; +int time_after_game; +int time_before_ref; +int time_after_ref; + +/* +============================================================================ + +CLIENT / SERVER interactions + +============================================================================ +*/ + +static int rd_target; +static char *rd_buffer; +static int rd_buffersize; +static void (*rd_flush)(int target, char *buffer); + +void Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush)) +{ + if (!target || !buffer || !buffersize || !flush) + return; + rd_target = target; + rd_buffer = buffer; + rd_buffersize = buffersize; + rd_flush = flush; + + *rd_buffer = 0; +} + +void Com_EndRedirect (void) +{ + rd_flush(rd_target, rd_buffer); + + rd_target = 0; + rd_buffer = NULL; + rd_buffersize = 0; + rd_flush = NULL; +} + +/* +============= +Com_Printf + +Both client and server can use this, and it will output +to the apropriate place. +============= +*/ +void Com_Printf (char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + if (rd_target) + { + if ((strlen (msg) + strlen(rd_buffer)) > (rd_buffersize - 1)) + { + rd_flush(rd_target, rd_buffer); + *rd_buffer = 0; + } + strcat (rd_buffer, msg); + return; + } + + Con_Print (msg); + + // also echo to debugging console + Sys_ConsoleOutput (msg); + + // logfile + if (logfile_active && logfile_active->value) + { + char name[MAX_QPATH]; + + if (!logfile) + { + Com_sprintf (name, sizeof(name), "%s/qconsole.log", FS_Gamedir ()); + logfile = fopen (name, "w"); + } + if (logfile) + fprintf (logfile, "%s", msg); + if (logfile_active->value > 1) + fflush (logfile); // force it to save every time + } +} + + +/* +================ +Com_DPrintf + +A Com_Printf that only shows up if the "developer" cvar is set +================ +*/ +void Com_DPrintf (char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + if (!developer || !developer->value) + return; // don't confuse non-developers with techie stuff... + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + Com_Printf ("%s", msg); +} + + +/* +============= +Com_Error + +Both client and server can use this, and it will +do the apropriate things. +============= +*/ +void Com_Error (int code, char *fmt, ...) +{ + va_list argptr; + static char msg[MAXPRINTMSG]; + static qboolean recursive; + + if (recursive) + Sys_Error ("recursive error after: %s", msg); + recursive = true; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + if (code == ERR_DISCONNECT) + { + CL_Drop (); + recursive = false; + longjmp (abortframe, -1); + } + else if (code == ERR_DROP) + { + Com_Printf ("********************\nERROR: %s\n********************\n", msg); + SV_Shutdown (va("Server crashed: %s\n", msg), false); + CL_Drop (); + recursive = false; + longjmp (abortframe, -1); + } + else + { + SV_Shutdown (va("Server fatal crashed: %s\n", msg), false); + CL_Shutdown (); + } + + if (logfile) + { + fclose (logfile); + logfile = NULL; + } + + Sys_Error ("%s", msg); +} + + +/* +============= +Com_Quit + +Both client and server can use this, and it will +do the apropriate things. +============= +*/ +void Com_Quit (void) +{ + SV_Shutdown ("Server quit\n", false); + CL_Shutdown (); + + if (logfile) + { + fclose (logfile); + logfile = NULL; + } + + Sys_Quit (); +} + + +/* +================== +Com_ServerState +================== +*/ +int Com_ServerState (void) +{ + return server_state; +} + +/* +================== +Com_SetServerState +================== +*/ +void Com_SetServerState (int state) +{ + server_state = state; +} + + +/* +============================================================================== + + MESSAGE IO FUNCTIONS + +Handles byte ordering and avoids alignment errors +============================================================================== +*/ + +vec3_t bytedirs[NUMVERTEXNORMALS] = +{ +#include "../client/anorms.h" +}; + +// +// writing functions +// + +void MSG_WriteChar (sizebuf_t *sb, int c) +{ + byte *buf; + +#ifdef PARANOID + if (c < -128 || c > 127) + Com_Error (ERR_FATAL, "MSG_WriteChar: range error"); +#endif + + buf = SZ_GetSpace (sb, 1); + buf[0] = c; +} + +void MSG_WriteByte (sizebuf_t *sb, int c) +{ + byte *buf; + +#ifdef PARANOID + if (c < 0 || c > 255) + Com_Error (ERR_FATAL, "MSG_WriteByte: range error"); +#endif + + buf = SZ_GetSpace (sb, 1); + buf[0] = c; +} + +void MSG_WriteShort (sizebuf_t *sb, int c) +{ + byte *buf; + +#ifdef PARANOID + if (c < ((short)0x8000) || c > (short)0x7fff) + Com_Error (ERR_FATAL, "MSG_WriteShort: range error"); +#endif + + buf = SZ_GetSpace (sb, 2); + buf[0] = c&0xff; + buf[1] = c>>8; +} + +void MSG_WriteLong (sizebuf_t *sb, int c) +{ + byte *buf; + + buf = SZ_GetSpace (sb, 4); + buf[0] = c&0xff; + buf[1] = (c>>8)&0xff; + buf[2] = (c>>16)&0xff; + buf[3] = c>>24; +} + +void MSG_WriteFloat (sizebuf_t *sb, float f) +{ + union + { + float f; + int l; + } dat; + + + dat.f = f; + dat.l = LittleLong (dat.l); + + SZ_Write (sb, &dat.l, 4); +} + +void MSG_WriteString (sizebuf_t *sb, char *s) +{ + if (!s) + SZ_Write (sb, "", 1); + else + SZ_Write (sb, s, strlen(s)+1); +} + +void MSG_WriteCoord (sizebuf_t *sb, float f) +{ + MSG_WriteShort (sb, (int)(f*8)); +} + +void MSG_WritePos (sizebuf_t *sb, vec3_t pos) +{ + MSG_WriteShort (sb, (int)(pos[0]*8)); + MSG_WriteShort (sb, (int)(pos[1]*8)); + MSG_WriteShort (sb, (int)(pos[2]*8)); +} + +void MSG_WriteAngle (sizebuf_t *sb, float f) +{ + MSG_WriteByte (sb, (int)(f*256/360) & 255); +} + +void MSG_WriteAngle16 (sizebuf_t *sb, float f) +{ + MSG_WriteShort (sb, ANGLE2SHORT(f)); +} + + +void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd) +{ + int bits; + +// +// send the movement message +// + bits = 0; + if (cmd->angles[0] != from->angles[0]) + bits |= CM_ANGLE1; + if (cmd->angles[1] != from->angles[1]) + bits |= CM_ANGLE2; + if (cmd->angles[2] != from->angles[2]) + bits |= CM_ANGLE3; + if (cmd->forwardmove != from->forwardmove) + bits |= CM_FORWARD; + if (cmd->sidemove != from->sidemove) + bits |= CM_SIDE; + if (cmd->upmove != from->upmove) + bits |= CM_UP; + if (cmd->buttons != from->buttons) + bits |= CM_BUTTONS; + if (cmd->impulse != from->impulse) + bits |= CM_IMPULSE; + + MSG_WriteByte (buf, bits); + + if (bits & CM_ANGLE1) + MSG_WriteShort (buf, cmd->angles[0]); + if (bits & CM_ANGLE2) + MSG_WriteShort (buf, cmd->angles[1]); + if (bits & CM_ANGLE3) + MSG_WriteShort (buf, cmd->angles[2]); + + if (bits & CM_FORWARD) + MSG_WriteShort (buf, cmd->forwardmove); + if (bits & CM_SIDE) + MSG_WriteShort (buf, cmd->sidemove); + if (bits & CM_UP) + MSG_WriteShort (buf, cmd->upmove); + + if (bits & CM_BUTTONS) + MSG_WriteByte (buf, cmd->buttons); + if (bits & CM_IMPULSE) + MSG_WriteByte (buf, cmd->impulse); + + MSG_WriteByte (buf, cmd->msec); + MSG_WriteByte (buf, cmd->lightlevel); +} + + +void MSG_WriteDir (sizebuf_t *sb, vec3_t dir) +{ + int i, best; + float d, bestd; + + if (!dir) + { + MSG_WriteByte (sb, 0); + return; + } + + bestd = 0; + best = 0; + for (i=0 ; i bestd) + { + bestd = d; + best = i; + } + } + MSG_WriteByte (sb, best); +} + + +void MSG_ReadDir (sizebuf_t *sb, vec3_t dir) +{ + int b; + + b = MSG_ReadByte (sb); + if (b >= NUMVERTEXNORMALS) + Com_Error (ERR_DROP, "MSF_ReadDir: out of range"); + VectorCopy (bytedirs[b], dir); +} + + +/* +================== +MSG_WriteDeltaEntity + +Writes part of a packetentities message. +Can delta from either a baseline or a previous packet_entity +================== +*/ +void MSG_WriteDeltaEntity (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, qboolean newentity) +{ + int bits; + + if (!to->number) + Com_Error (ERR_FATAL, "Unset entity number"); + if (to->number >= MAX_EDICTS) + Com_Error (ERR_FATAL, "Entity number >= MAX_EDICTS"); + +// send an update + bits = 0; + + if (to->number >= 256) + bits |= U_NUMBER16; // number8 is implicit otherwise + + if (to->origin[0] != from->origin[0]) + bits |= U_ORIGIN1; + if (to->origin[1] != from->origin[1]) + bits |= U_ORIGIN2; + if (to->origin[2] != from->origin[2]) + bits |= U_ORIGIN3; + + if ( to->angles[0] != from->angles[0] ) + bits |= U_ANGLE1; + if ( to->angles[1] != from->angles[1] ) + bits |= U_ANGLE2; + if ( to->angles[2] != from->angles[2] ) + bits |= U_ANGLE3; + + if ( to->skinnum != from->skinnum ) + { + if ((unsigned)to->skinnum < 256) + bits |= U_SKIN8; + else if ((unsigned)to->skinnum < 0x10000) + bits |= U_SKIN16; + else + bits |= (U_SKIN8|U_SKIN16); + } + + if ( to->frame != from->frame ) + { + if (to->frame < 256) + bits |= U_FRAME8; + else + bits |= U_FRAME16; + } + + if ( to->effects != from->effects ) + { + if (to->effects < 256) + bits |= U_EFFECTS8; + else if (to->effects < 0x8000) + bits |= U_EFFECTS16; + else + bits |= U_EFFECTS8|U_EFFECTS16; + } + + if ( to->renderfx != from->renderfx ) + { + if (to->renderfx < 256) + bits |= U_RENDERFX8; + else if (to->renderfx < 0x8000) + bits |= U_RENDERFX16; + else + bits |= U_RENDERFX8|U_RENDERFX16; + } + + if ( to->solid != from->solid ) + bits |= U_SOLID; + + // event is not delta compressed, just 0 compressed + if ( to->event ) + bits |= U_EVENT; + + if ( to->modelindex != from->modelindex ) + bits |= U_MODEL; + if ( to->modelindex2 != from->modelindex2 ) + bits |= U_MODEL2; + if ( to->modelindex3 != from->modelindex3 ) + bits |= U_MODEL3; + if ( to->modelindex4 != from->modelindex4 ) + bits |= U_MODEL4; + + if ( to->sound != from->sound ) + bits |= U_SOUND; + + if (newentity || (to->renderfx & RF_BEAM)) + bits |= U_OLDORIGIN; + + // + // write the message + // + if (!bits && !force) + return; // nothing to send! + + //---------- + + if (bits & 0xff000000) + bits |= U_MOREBITS3 | U_MOREBITS2 | U_MOREBITS1; + else if (bits & 0x00ff0000) + bits |= U_MOREBITS2 | U_MOREBITS1; + else if (bits & 0x0000ff00) + bits |= U_MOREBITS1; + + MSG_WriteByte (msg, bits&255 ); + + if (bits & 0xff000000) + { + MSG_WriteByte (msg, (bits>>8)&255 ); + MSG_WriteByte (msg, (bits>>16)&255 ); + MSG_WriteByte (msg, (bits>>24)&255 ); + } + else if (bits & 0x00ff0000) + { + MSG_WriteByte (msg, (bits>>8)&255 ); + MSG_WriteByte (msg, (bits>>16)&255 ); + } + else if (bits & 0x0000ff00) + { + MSG_WriteByte (msg, (bits>>8)&255 ); + } + + //---------- + + if (bits & U_NUMBER16) + MSG_WriteShort (msg, to->number); + else + MSG_WriteByte (msg, to->number); + + if (bits & U_MODEL) + MSG_WriteByte (msg, to->modelindex); + if (bits & U_MODEL2) + MSG_WriteByte (msg, to->modelindex2); + if (bits & U_MODEL3) + MSG_WriteByte (msg, to->modelindex3); + if (bits & U_MODEL4) + MSG_WriteByte (msg, to->modelindex4); + + if (bits & U_FRAME8) + MSG_WriteByte (msg, to->frame); + if (bits & U_FRAME16) + MSG_WriteShort (msg, to->frame); + + if ((bits & U_SKIN8) && (bits & U_SKIN16)) //used for laser colors + MSG_WriteLong (msg, to->skinnum); + else if (bits & U_SKIN8) + MSG_WriteByte (msg, to->skinnum); + else if (bits & U_SKIN16) + MSG_WriteShort (msg, to->skinnum); + + + if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) ) + MSG_WriteLong (msg, to->effects); + else if (bits & U_EFFECTS8) + MSG_WriteByte (msg, to->effects); + else if (bits & U_EFFECTS16) + MSG_WriteShort (msg, to->effects); + + if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) ) + MSG_WriteLong (msg, to->renderfx); + else if (bits & U_RENDERFX8) + MSG_WriteByte (msg, to->renderfx); + else if (bits & U_RENDERFX16) + MSG_WriteShort (msg, to->renderfx); + + if (bits & U_ORIGIN1) + MSG_WriteCoord (msg, to->origin[0]); + if (bits & U_ORIGIN2) + MSG_WriteCoord (msg, to->origin[1]); + if (bits & U_ORIGIN3) + MSG_WriteCoord (msg, to->origin[2]); + + if (bits & U_ANGLE1) + MSG_WriteAngle(msg, to->angles[0]); + if (bits & U_ANGLE2) + MSG_WriteAngle(msg, to->angles[1]); + if (bits & U_ANGLE3) + MSG_WriteAngle(msg, to->angles[2]); + + if (bits & U_OLDORIGIN) + { + MSG_WriteCoord (msg, to->old_origin[0]); + MSG_WriteCoord (msg, to->old_origin[1]); + MSG_WriteCoord (msg, to->old_origin[2]); + } + + if (bits & U_SOUND) + MSG_WriteByte (msg, to->sound); + if (bits & U_EVENT) + MSG_WriteByte (msg, to->event); + if (bits & U_SOLID) + MSG_WriteShort (msg, to->solid); +} + + +//============================================================ + +// +// reading functions +// + +void MSG_BeginReading (sizebuf_t *msg) +{ + msg->readcount = 0; +} + +// returns -1 if no more characters are available +int MSG_ReadChar (sizebuf_t *msg_read) +{ + int c; + + if (msg_read->readcount+1 > msg_read->cursize) + c = -1; + else + c = (signed char)msg_read->data[msg_read->readcount]; + msg_read->readcount++; + + return c; +} + +int MSG_ReadByte (sizebuf_t *msg_read) +{ + int c; + + if (msg_read->readcount+1 > msg_read->cursize) + c = -1; + else + c = (unsigned char)msg_read->data[msg_read->readcount]; + msg_read->readcount++; + + return c; +} + +int MSG_ReadShort (sizebuf_t *msg_read) +{ + int c; + + if (msg_read->readcount+2 > msg_read->cursize) + c = -1; + else + c = (short)(msg_read->data[msg_read->readcount] + + (msg_read->data[msg_read->readcount+1]<<8)); + + msg_read->readcount += 2; + + return c; +} + +int MSG_ReadLong (sizebuf_t *msg_read) +{ + int c; + + if (msg_read->readcount+4 > msg_read->cursize) + c = -1; + else + c = msg_read->data[msg_read->readcount] + + (msg_read->data[msg_read->readcount+1]<<8) + + (msg_read->data[msg_read->readcount+2]<<16) + + (msg_read->data[msg_read->readcount+3]<<24); + + msg_read->readcount += 4; + + return c; +} + +float MSG_ReadFloat (sizebuf_t *msg_read) +{ + union + { + byte b[4]; + float f; + int l; + } dat; + + if (msg_read->readcount+4 > msg_read->cursize) + dat.f = -1; + else + { + dat.b[0] = msg_read->data[msg_read->readcount]; + dat.b[1] = msg_read->data[msg_read->readcount+1]; + dat.b[2] = msg_read->data[msg_read->readcount+2]; + dat.b[3] = msg_read->data[msg_read->readcount+3]; + } + msg_read->readcount += 4; + + dat.l = LittleLong (dat.l); + + return dat.f; +} + +char *MSG_ReadString (sizebuf_t *msg_read) +{ + static char string[2048]; + int l,c; + + l = 0; + do + { + c = MSG_ReadChar (msg_read); + if (c == -1 || c == 0) + break; + string[l] = c; + l++; + } while (l < sizeof(string)-1); + + string[l] = 0; + + return string; +} + +char *MSG_ReadStringLine (sizebuf_t *msg_read) +{ + static char string[2048]; + int l,c; + + l = 0; + do + { + c = MSG_ReadChar (msg_read); + if (c == -1 || c == 0 || c == '\n') + break; + string[l] = c; + l++; + } while (l < sizeof(string)-1); + + string[l] = 0; + + return string; +} + +float MSG_ReadCoord (sizebuf_t *msg_read) +{ + return MSG_ReadShort(msg_read) * (1.0/8); +} + +void MSG_ReadPos (sizebuf_t *msg_read, vec3_t pos) +{ + pos[0] = MSG_ReadShort(msg_read) * (1.0/8); + pos[1] = MSG_ReadShort(msg_read) * (1.0/8); + pos[2] = MSG_ReadShort(msg_read) * (1.0/8); +} + +float MSG_ReadAngle (sizebuf_t *msg_read) +{ + return MSG_ReadChar(msg_read) * (360.0/256); +} + +float MSG_ReadAngle16 (sizebuf_t *msg_read) +{ + return SHORT2ANGLE(MSG_ReadShort(msg_read)); +} + +void MSG_ReadDeltaUsercmd (sizebuf_t *msg_read, usercmd_t *from, usercmd_t *move) +{ + int bits; + + memcpy (move, from, sizeof(*move)); + + bits = MSG_ReadByte (msg_read); + +// read current angles + if (bits & CM_ANGLE1) + move->angles[0] = MSG_ReadShort (msg_read); + if (bits & CM_ANGLE2) + move->angles[1] = MSG_ReadShort (msg_read); + if (bits & CM_ANGLE3) + move->angles[2] = MSG_ReadShort (msg_read); + +// read movement + if (bits & CM_FORWARD) + move->forwardmove = MSG_ReadShort (msg_read); + if (bits & CM_SIDE) + move->sidemove = MSG_ReadShort (msg_read); + if (bits & CM_UP) + move->upmove = MSG_ReadShort (msg_read); + +// read buttons + if (bits & CM_BUTTONS) + move->buttons = MSG_ReadByte (msg_read); + + if (bits & CM_IMPULSE) + move->impulse = MSG_ReadByte (msg_read); + +// read time to run command + move->msec = MSG_ReadByte (msg_read); + +// read the light level + move->lightlevel = MSG_ReadByte (msg_read); +} + + +void MSG_ReadData (sizebuf_t *msg_read, void *data, int len) +{ + int i; + + for (i=0 ; idata = data; + buf->maxsize = length; +} + +void SZ_Clear (sizebuf_t *buf) +{ + buf->cursize = 0; + buf->overflowed = false; +} + +void *SZ_GetSpace (sizebuf_t *buf, int length) +{ + void *data; + + if (buf->cursize + length > buf->maxsize) + { + if (!buf->allowoverflow) + Com_Error (ERR_FATAL, "SZ_GetSpace: overflow without allowoverflow set"); + + if (length > buf->maxsize) + Com_Error (ERR_FATAL, "SZ_GetSpace: %i is > full buffer size", length); + + Com_Printf ("SZ_GetSpace: overflow\n"); + SZ_Clear (buf); + buf->overflowed = true; + } + + data = buf->data + buf->cursize; + buf->cursize += length; + + return data; +} + +void SZ_Write (sizebuf_t *buf, void *data, int length) +{ + memcpy (SZ_GetSpace(buf,length),data,length); +} + +void SZ_Print (sizebuf_t *buf, char *data) +{ + int len; + + len = strlen(data)+1; + + if (buf->cursize) + { + if (buf->data[buf->cursize-1]) + memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0 + else + memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0 + } + else + memcpy ((byte *)SZ_GetSpace(buf, len),data,len); +} + + +//============================================================================ + + +/* +================ +COM_CheckParm + +Returns the position (1 to argc-1) in the program's argument list +where the given parameter apears, or 0 if not present +================ +*/ +int COM_CheckParm (char *parm) +{ + int i; + + for (i=1 ; i= com_argc || !com_argv[arg]) + return ""; + return com_argv[arg]; +} + +void COM_ClearArgv (int arg) +{ + if (arg < 0 || arg >= com_argc || !com_argv[arg]) + return; + com_argv[arg] = ""; +} + + +/* +================ +COM_InitArgv +================ +*/ +void COM_InitArgv (int argc, char **argv) +{ + int i; + + if (argc > MAX_NUM_ARGVS) + Com_Error (ERR_FATAL, "argc > MAX_NUM_ARGVS"); + com_argc = argc; + for (i=0 ; i= MAX_TOKEN_CHARS ) + com_argv[i] = ""; + else + com_argv[i] = argv[i]; + } +} + +/* +================ +COM_AddParm + +Adds the given string at the end of the current argument list +================ +*/ +void COM_AddParm (char *parm) +{ + if (com_argc == MAX_NUM_ARGVS) + Com_Error (ERR_FATAL, "COM_AddParm: MAX_NUM)ARGS"); + com_argv[com_argc++] = parm; +} + + + + +/// just for debugging +int memsearch (byte *start, int count, int search) +{ + int i; + + for (i=0 ; imagic != Z_MAGIC) + Com_Error (ERR_FATAL, "Z_Free: bad magic"); + + z->prev->next = z->next; + z->next->prev = z->prev; + + z_count--; + z_bytes -= z->size; + free (z); +} + + +/* +======================== +Z_Stats_f +======================== +*/ +void Z_Stats_f (void) +{ + Com_Printf ("%i bytes in %i blocks\n", z_bytes, z_count); +} + +/* +======================== +Z_FreeTags +======================== +*/ +void Z_FreeTags (int tag) +{ + zhead_t *z, *next; + + for (z=z_chain.next ; z != &z_chain ; z=next) + { + next = z->next; + if (z->tag == tag) + Z_Free ((void *)(z+1)); + } +} + +/* +======================== +Z_TagMalloc +======================== +*/ +void *Z_TagMalloc (int size, int tag) +{ + zhead_t *z; + + size = size + sizeof(zhead_t); + z = malloc(size); + if (!z) + Com_Error (ERR_FATAL, "Z_Malloc: failed on allocation of %i bytes",size); + memset (z, 0, size); + z_count++; + z_bytes += size; + z->magic = Z_MAGIC; + z->tag = tag; + z->size = size; + + z->next = z_chain.next; + z->prev = &z_chain; + z_chain.next->prev = z; + z_chain.next = z; + + return (void *)(z+1); +} + +/* +======================== +Z_Malloc +======================== +*/ +void *Z_Malloc (int size) +{ + return Z_TagMalloc (size, 0); +} + + +//============================================================================ + + +/* +==================== +COM_BlockSequenceCheckByte + +For proxy protecting + +// THIS IS MASSIVELY BROKEN! CHALLENGE MAY BE NEGATIVE +// DON'T USE THIS FUNCTION!!!!! + +==================== +*/ +byte COM_BlockSequenceCheckByte (byte *base, int length, int sequence, int challenge) +{ + Sys_Error("COM_BlockSequenceCheckByte called\n"); + +#if 0 + int checksum; + byte buf[68]; + byte *p; + float temp; + byte c; + + temp = bytedirs[(sequence/3) % NUMVERTEXNORMALS][sequence % 3]; + temp = LittleFloat(temp); + p = ((byte *)&temp); + + if (length > 60) + length = 60; + memcpy (buf, base, length); + + buf[length] = (sequence & 0xff) ^ p[0]; + buf[length+1] = p[1]; + buf[length+2] = ((sequence>>8) & 0xff) ^ p[2]; + buf[length+3] = p[3]; + + temp = bytedirs[((sequence+challenge)/3) % NUMVERTEXNORMALS][(sequence+challenge) % 3]; + temp = LittleFloat(temp); + p = ((byte *)&temp); + + buf[length+4] = (sequence & 0xff) ^ p[3]; + buf[length+5] = (challenge & 0xff) ^ p[2]; + buf[length+6] = ((sequence>>8) & 0xff) ^ p[1]; + buf[length+7] = ((challenge >> 7) & 0xff) ^ p[0]; + + length += 8; + + checksum = LittleLong(Com_BlockChecksum (buf, length)); + + checksum &= 0xff; + + return checksum; +#endif + return 0; +} + +static byte chktbl[1024] = { +0x84, 0x47, 0x51, 0xc1, 0x93, 0x22, 0x21, 0x24, 0x2f, 0x66, 0x60, 0x4d, 0xb0, 0x7c, 0xda, +0x88, 0x54, 0x15, 0x2b, 0xc6, 0x6c, 0x89, 0xc5, 0x9d, 0x48, 0xee, 0xe6, 0x8a, 0xb5, 0xf4, +0xcb, 0xfb, 0xf1, 0x0c, 0x2e, 0xa0, 0xd7, 0xc9, 0x1f, 0xd6, 0x06, 0x9a, 0x09, 0x41, 0x54, +0x67, 0x46, 0xc7, 0x74, 0xe3, 0xc8, 0xb6, 0x5d, 0xa6, 0x36, 0xc4, 0xab, 0x2c, 0x7e, 0x85, +0xa8, 0xa4, 0xa6, 0x4d, 0x96, 0x19, 0x19, 0x9a, 0xcc, 0xd8, 0xac, 0x39, 0x5e, 0x3c, 0xf2, +0xf5, 0x5a, 0x72, 0xe5, 0xa9, 0xd1, 0xb3, 0x23, 0x82, 0x6f, 0x29, 0xcb, 0xd1, 0xcc, 0x71, +0xfb, 0xea, 0x92, 0xeb, 0x1c, 0xca, 0x4c, 0x70, 0xfe, 0x4d, 0xc9, 0x67, 0x43, 0x47, 0x94, +0xb9, 0x47, 0xbc, 0x3f, 0x01, 0xab, 0x7b, 0xa6, 0xe2, 0x76, 0xef, 0x5a, 0x7a, 0x29, 0x0b, +0x51, 0x54, 0x67, 0xd8, 0x1c, 0x14, 0x3e, 0x29, 0xec, 0xe9, 0x2d, 0x48, 0x67, 0xff, 0xed, +0x54, 0x4f, 0x48, 0xc0, 0xaa, 0x61, 0xf7, 0x78, 0x12, 0x03, 0x7a, 0x9e, 0x8b, 0xcf, 0x83, +0x7b, 0xae, 0xca, 0x7b, 0xd9, 0xe9, 0x53, 0x2a, 0xeb, 0xd2, 0xd8, 0xcd, 0xa3, 0x10, 0x25, +0x78, 0x5a, 0xb5, 0x23, 0x06, 0x93, 0xb7, 0x84, 0xd2, 0xbd, 0x96, 0x75, 0xa5, 0x5e, 0xcf, +0x4e, 0xe9, 0x50, 0xa1, 0xe6, 0x9d, 0xb1, 0xe3, 0x85, 0x66, 0x28, 0x4e, 0x43, 0xdc, 0x6e, +0xbb, 0x33, 0x9e, 0xf3, 0x0d, 0x00, 0xc1, 0xcf, 0x67, 0x34, 0x06, 0x7c, 0x71, 0xe3, 0x63, +0xb7, 0xb7, 0xdf, 0x92, 0xc4, 0xc2, 0x25, 0x5c, 0xff, 0xc3, 0x6e, 0xfc, 0xaa, 0x1e, 0x2a, +0x48, 0x11, 0x1c, 0x36, 0x68, 0x78, 0x86, 0x79, 0x30, 0xc3, 0xd6, 0xde, 0xbc, 0x3a, 0x2a, +0x6d, 0x1e, 0x46, 0xdd, 0xe0, 0x80, 0x1e, 0x44, 0x3b, 0x6f, 0xaf, 0x31, 0xda, 0xa2, 0xbd, +0x77, 0x06, 0x56, 0xc0, 0xb7, 0x92, 0x4b, 0x37, 0xc0, 0xfc, 0xc2, 0xd5, 0xfb, 0xa8, 0xda, +0xf5, 0x57, 0xa8, 0x18, 0xc0, 0xdf, 0xe7, 0xaa, 0x2a, 0xe0, 0x7c, 0x6f, 0x77, 0xb1, 0x26, +0xba, 0xf9, 0x2e, 0x1d, 0x16, 0xcb, 0xb8, 0xa2, 0x44, 0xd5, 0x2f, 0x1a, 0x79, 0x74, 0x87, +0x4b, 0x00, 0xc9, 0x4a, 0x3a, 0x65, 0x8f, 0xe6, 0x5d, 0xe5, 0x0a, 0x77, 0xd8, 0x1a, 0x14, +0x41, 0x75, 0xb1, 0xe2, 0x50, 0x2c, 0x93, 0x38, 0x2b, 0x6d, 0xf3, 0xf6, 0xdb, 0x1f, 0xcd, +0xff, 0x14, 0x70, 0xe7, 0x16, 0xe8, 0x3d, 0xf0, 0xe3, 0xbc, 0x5e, 0xb6, 0x3f, 0xcc, 0x81, +0x24, 0x67, 0xf3, 0x97, 0x3b, 0xfe, 0x3a, 0x96, 0x85, 0xdf, 0xe4, 0x6e, 0x3c, 0x85, 0x05, +0x0e, 0xa3, 0x2b, 0x07, 0xc8, 0xbf, 0xe5, 0x13, 0x82, 0x62, 0x08, 0x61, 0x69, 0x4b, 0x47, +0x62, 0x73, 0x44, 0x64, 0x8e, 0xe2, 0x91, 0xa6, 0x9a, 0xb7, 0xe9, 0x04, 0xb6, 0x54, 0x0c, +0xc5, 0xa9, 0x47, 0xa6, 0xc9, 0x08, 0xfe, 0x4e, 0xa6, 0xcc, 0x8a, 0x5b, 0x90, 0x6f, 0x2b, +0x3f, 0xb6, 0x0a, 0x96, 0xc0, 0x78, 0x58, 0x3c, 0x76, 0x6d, 0x94, 0x1a, 0xe4, 0x4e, 0xb8, +0x38, 0xbb, 0xf5, 0xeb, 0x29, 0xd8, 0xb0, 0xf3, 0x15, 0x1e, 0x99, 0x96, 0x3c, 0x5d, 0x63, +0xd5, 0xb1, 0xad, 0x52, 0xb8, 0x55, 0x70, 0x75, 0x3e, 0x1a, 0xd5, 0xda, 0xf6, 0x7a, 0x48, +0x7d, 0x44, 0x41, 0xf9, 0x11, 0xce, 0xd7, 0xca, 0xa5, 0x3d, 0x7a, 0x79, 0x7e, 0x7d, 0x25, +0x1b, 0x77, 0xbc, 0xf7, 0xc7, 0x0f, 0x84, 0x95, 0x10, 0x92, 0x67, 0x15, 0x11, 0x5a, 0x5e, +0x41, 0x66, 0x0f, 0x38, 0x03, 0xb2, 0xf1, 0x5d, 0xf8, 0xab, 0xc0, 0x02, 0x76, 0x84, 0x28, +0xf4, 0x9d, 0x56, 0x46, 0x60, 0x20, 0xdb, 0x68, 0xa7, 0xbb, 0xee, 0xac, 0x15, 0x01, 0x2f, +0x20, 0x09, 0xdb, 0xc0, 0x16, 0xa1, 0x89, 0xf9, 0x94, 0x59, 0x00, 0xc1, 0x76, 0xbf, 0xc1, +0x4d, 0x5d, 0x2d, 0xa9, 0x85, 0x2c, 0xd6, 0xd3, 0x14, 0xcc, 0x02, 0xc3, 0xc2, 0xfa, 0x6b, +0xb7, 0xa6, 0xef, 0xdd, 0x12, 0x26, 0xa4, 0x63, 0xe3, 0x62, 0xbd, 0x56, 0x8a, 0x52, 0x2b, +0xb9, 0xdf, 0x09, 0xbc, 0x0e, 0x97, 0xa9, 0xb0, 0x82, 0x46, 0x08, 0xd5, 0x1a, 0x8e, 0x1b, +0xa7, 0x90, 0x98, 0xb9, 0xbb, 0x3c, 0x17, 0x9a, 0xf2, 0x82, 0xba, 0x64, 0x0a, 0x7f, 0xca, +0x5a, 0x8c, 0x7c, 0xd3, 0x79, 0x09, 0x5b, 0x26, 0xbb, 0xbd, 0x25, 0xdf, 0x3d, 0x6f, 0x9a, +0x8f, 0xee, 0x21, 0x66, 0xb0, 0x8d, 0x84, 0x4c, 0x91, 0x45, 0xd4, 0x77, 0x4f, 0xb3, 0x8c, +0xbc, 0xa8, 0x99, 0xaa, 0x19, 0x53, 0x7c, 0x02, 0x87, 0xbb, 0x0b, 0x7c, 0x1a, 0x2d, 0xdf, +0x48, 0x44, 0x06, 0xd6, 0x7d, 0x0c, 0x2d, 0x35, 0x76, 0xae, 0xc4, 0x5f, 0x71, 0x85, 0x97, +0xc4, 0x3d, 0xef, 0x52, 0xbe, 0x00, 0xe4, 0xcd, 0x49, 0xd1, 0xd1, 0x1c, 0x3c, 0xd0, 0x1c, +0x42, 0xaf, 0xd4, 0xbd, 0x58, 0x34, 0x07, 0x32, 0xee, 0xb9, 0xb5, 0xea, 0xff, 0xd7, 0x8c, +0x0d, 0x2e, 0x2f, 0xaf, 0x87, 0xbb, 0xe6, 0x52, 0x71, 0x22, 0xf5, 0x25, 0x17, 0xa1, 0x82, +0x04, 0xc2, 0x4a, 0xbd, 0x57, 0xc6, 0xab, 0xc8, 0x35, 0x0c, 0x3c, 0xd9, 0xc2, 0x43, 0xdb, +0x27, 0x92, 0xcf, 0xb8, 0x25, 0x60, 0xfa, 0x21, 0x3b, 0x04, 0x52, 0xc8, 0x96, 0xba, 0x74, +0xe3, 0x67, 0x3e, 0x8e, 0x8d, 0x61, 0x90, 0x92, 0x59, 0xb6, 0x1a, 0x1c, 0x5e, 0x21, 0xc1, +0x65, 0xe5, 0xa6, 0x34, 0x05, 0x6f, 0xc5, 0x60, 0xb1, 0x83, 0xc1, 0xd5, 0xd5, 0xed, 0xd9, +0xc7, 0x11, 0x7b, 0x49, 0x7a, 0xf9, 0xf9, 0x84, 0x47, 0x9b, 0xe2, 0xa5, 0x82, 0xe0, 0xc2, +0x88, 0xd0, 0xb2, 0x58, 0x88, 0x7f, 0x45, 0x09, 0x67, 0x74, 0x61, 0xbf, 0xe6, 0x40, 0xe2, +0x9d, 0xc2, 0x47, 0x05, 0x89, 0xed, 0xcb, 0xbb, 0xb7, 0x27, 0xe7, 0xdc, 0x7a, 0xfd, 0xbf, +0xa8, 0xd0, 0xaa, 0x10, 0x39, 0x3c, 0x20, 0xf0, 0xd3, 0x6e, 0xb1, 0x72, 0xf8, 0xe6, 0x0f, +0xef, 0x37, 0xe5, 0x09, 0x33, 0x5a, 0x83, 0x43, 0x80, 0x4f, 0x65, 0x2f, 0x7c, 0x8c, 0x6a, +0xa0, 0x82, 0x0c, 0xd4, 0xd4, 0xfa, 0x81, 0x60, 0x3d, 0xdf, 0x06, 0xf1, 0x5f, 0x08, 0x0d, +0x6d, 0x43, 0xf2, 0xe3, 0x11, 0x7d, 0x80, 0x32, 0xc5, 0xfb, 0xc5, 0xd9, 0x27, 0xec, 0xc6, +0x4e, 0x65, 0x27, 0x76, 0x87, 0xa6, 0xee, 0xee, 0xd7, 0x8b, 0xd1, 0xa0, 0x5c, 0xb0, 0x42, +0x13, 0x0e, 0x95, 0x4a, 0xf2, 0x06, 0xc6, 0x43, 0x33, 0xf4, 0xc7, 0xf8, 0xe7, 0x1f, 0xdd, +0xe4, 0x46, 0x4a, 0x70, 0x39, 0x6c, 0xd0, 0xed, 0xca, 0xbe, 0x60, 0x3b, 0xd1, 0x7b, 0x57, +0x48, 0xe5, 0x3a, 0x79, 0xc1, 0x69, 0x33, 0x53, 0x1b, 0x80, 0xb8, 0x91, 0x7d, 0xb4, 0xf6, +0x17, 0x1a, 0x1d, 0x5a, 0x32, 0xd6, 0xcc, 0x71, 0x29, 0x3f, 0x28, 0xbb, 0xf3, 0x5e, 0x71, +0xb8, 0x43, 0xaf, 0xf8, 0xb9, 0x64, 0xef, 0xc4, 0xa5, 0x6c, 0x08, 0x53, 0xc7, 0x00, 0x10, +0x39, 0x4f, 0xdd, 0xe4, 0xb6, 0x19, 0x27, 0xfb, 0xb8, 0xf5, 0x32, 0x73, 0xe5, 0xcb, 0x32 +}; + +/* +==================== +COM_BlockSequenceCRCByte + +For proxy protecting +==================== +*/ +byte COM_BlockSequenceCRCByte (byte *base, int length, int sequence) +{ + int n; + byte *p; + int x; + byte chkb[60 + 4]; + unsigned short crc; + + + if (sequence < 0) + Sys_Error("sequence < 0, this shouldn't happen\n"); + + p = chktbl + (sequence % (sizeof(chktbl) - 4)); + + if (length > 60) + length = 60; + memcpy (chkb, base, length); + + chkb[length] = p[0]; + chkb[length+1] = p[1]; + chkb[length+2] = p[2]; + chkb[length+3] = p[3]; + + length += 4; + + crc = CRC_Block(chkb, length); + + for (x=0, n=0; nvalue) + Cmd_AddCommand ("quit", Com_Quit); + + Sys_Init (); + + NET_Init (); + Netchan_Init (); + + SV_Init (); + CL_Init (); + + // add + commands from command line + if (!Cbuf_AddLateCommands ()) + { // if the user didn't give any commands, run default action + if (!dedicated->value) + Cbuf_AddText ("d1\n"); + else + Cbuf_AddText ("dedicated_start\n"); + Cbuf_Execute (); + } + else + { // the user asked for something explicit + // so drop the loading plaque + SCR_EndLoadingPlaque (); + } + + Com_Printf ("====== Quake2 Initialized ======\n\n"); +} + +/* +================= +Qcommon_Frame +================= +*/ +void Qcommon_Frame (int msec) +{ + char *s; + int time_before, time_between, time_after; + + if (setjmp (abortframe) ) + return; // an ERR_DROP was thrown + + if ( log_stats->modified ) + { + log_stats->modified = false; + if ( log_stats->value ) + { + if ( log_stats_file ) + { + fclose( log_stats_file ); + log_stats_file = 0; + } + log_stats_file = fopen( "stats.log", "w" ); + if ( log_stats_file ) + fprintf( log_stats_file, "entities,dlights,parts,frame time\n" ); + } + else + { + if ( log_stats_file ) + { + fclose( log_stats_file ); + log_stats_file = 0; + } + } + } + + if (fixedtime->value) + msec = fixedtime->value; + else if (timescale->value) + { + msec *= timescale->value; + if (msec < 1) + msec = 1; + } + + if (showtrace->value) + { + extern int c_traces, c_brush_traces; + extern int c_pointcontents; + + Com_Printf ("%4i traces %4i points\n", c_traces, c_pointcontents); + c_traces = 0; + c_brush_traces = 0; + c_pointcontents = 0; + } + + do + { + s = Sys_ConsoleInput (); + if (s) + Cbuf_AddText (va("%s\n",s)); + } while (s); + Cbuf_Execute (); + + if (host_speeds->value) + time_before = Sys_Milliseconds (); + + SV_Frame (msec); + + if (host_speeds->value) + time_between = Sys_Milliseconds (); + + CL_Frame (msec); + + if (host_speeds->value) + time_after = Sys_Milliseconds (); + + + if (host_speeds->value) + { + int all, sv, gm, cl, rf; + + all = time_after - time_before; + sv = time_between - time_before; + cl = time_after - time_between; + gm = time_after_game - time_before_game; + rf = time_after_ref - time_before_ref; + sv -= gm; + cl -= rf; + Com_Printf ("all:%3i sv:%3i gm:%3i cl:%3i rf:%3i\n", + all, sv, gm, cl, rf); + } +} + +/* +================= +Qcommon_Shutdown +================= +*/ +void Qcommon_Shutdown (void) +{ +} diff --git a/qcommon/crc.c b/qcommon/crc.c new file mode 100644 index 000000000..a74846434 --- /dev/null +++ b/qcommon/crc.c @@ -0,0 +1,92 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +/* crc.c */ + +#include "qcommon.h" + +// this is a 16 bit, non-reflected CRC using the polynomial 0x1021 +// and the initial and final xor values shown below... in other words, the +// CCITT standard CRC used by XMODEM + +#define CRC_INIT_VALUE 0xffff +#define CRC_XOR_VALUE 0x0000 + +static unsigned short crctable[256] = +{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +void CRC_Init(unsigned short *crcvalue) +{ + *crcvalue = CRC_INIT_VALUE; +} + +void CRC_ProcessByte(unsigned short *crcvalue, byte data) +{ + *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data]; +} + +unsigned short CRC_Value(unsigned short crcvalue) +{ + return crcvalue ^ CRC_XOR_VALUE; +} + +unsigned short CRC_Block (byte *start, int count) +{ + unsigned short crc; + + CRC_Init (&crc); + while (count--) + crc = (crc << 8) ^ crctable[(crc >> 8) ^ *start++]; + + return crc; +} + diff --git a/qcommon/crc.h b/qcommon/crc.h new file mode 100644 index 000000000..25c4dfe03 --- /dev/null +++ b/qcommon/crc.h @@ -0,0 +1,6 @@ +/* crc.h */ + +void CRC_Init(unsigned short *crcvalue); +void CRC_ProcessByte(unsigned short *crcvalue, byte data); +unsigned short CRC_Value(unsigned short crcvalue); +unsigned short CRC_Block (byte *start, int count); diff --git a/qcommon/cvar.c b/qcommon/cvar.c new file mode 100644 index 000000000..29a12dfed --- /dev/null +++ b/qcommon/cvar.c @@ -0,0 +1,527 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +// cvar.c -- dynamic variable tracking + +#include "qcommon.h" + +cvar_t *cvar_vars; + +/* +============ +Cvar_InfoValidate +============ +*/ +static qboolean Cvar_InfoValidate (char *s) +{ + if (strstr (s, "\\")) + return false; + if (strstr (s, "\"")) + return false; + if (strstr (s, ";")) + return false; + return true; +} + +/* +============ +Cvar_FindVar +============ +*/ +static cvar_t *Cvar_FindVar (char *var_name) +{ + cvar_t *var; + + for (var=cvar_vars ; var ; var=var->next) + if (!strcmp (var_name, var->name)) + return var; + + return NULL; +} + +/* +============ +Cvar_VariableValue +============ +*/ +float Cvar_VariableValue (char *var_name) +{ + cvar_t *var; + + var = Cvar_FindVar (var_name); + if (!var) + return 0; + return atof (var->string); +} + + +/* +============ +Cvar_VariableString +============ +*/ +char *Cvar_VariableString (char *var_name) +{ + cvar_t *var; + + var = Cvar_FindVar (var_name); + if (!var) + return ""; + return var->string; +} + + +/* +============ +Cvar_CompleteVariable +============ +*/ +char *Cvar_CompleteVariable (char *partial) +{ + cvar_t *cvar; + int len; + + len = strlen(partial); + + if (!len) + return NULL; + + // check exact match + for (cvar=cvar_vars ; cvar ; cvar=cvar->next) + if (!strcmp (partial,cvar->name)) + return cvar->name; + + // check partial match + for (cvar=cvar_vars ; cvar ; cvar=cvar->next) + if (!strncmp (partial,cvar->name, len)) + return cvar->name; + + return NULL; +} + + +/* +============ +Cvar_Get + +If the variable already exists, the value will not be set +The flags will be or'ed in if the variable exists. +============ +*/ +cvar_t *Cvar_Get (char *var_name, char *var_value, int flags) +{ + cvar_t *var; + + if (flags & (CVAR_USERINFO | CVAR_SERVERINFO)) + { + if (!Cvar_InfoValidate (var_name)) + { + Com_Printf("invalid info cvar name\n"); + return NULL; + } + } + + var = Cvar_FindVar (var_name); + if (var) + { + var->flags |= flags; + return var; + } + + if (!var_value) + return NULL; + + if (flags & (CVAR_USERINFO | CVAR_SERVERINFO)) + { + if (!Cvar_InfoValidate (var_value)) + { + Com_Printf("invalid info cvar value\n"); + return NULL; + } + } + + var = Z_Malloc (sizeof(*var)); + var->name = CopyString (var_name); + var->string = CopyString (var_value); + var->modified = true; + var->value = atof (var->string); + + // link the variable in + var->next = cvar_vars; + cvar_vars = var; + + var->flags = flags; + + return var; +} + +/* +============ +Cvar_Set2 +============ +*/ +cvar_t *Cvar_Set2 (char *var_name, char *value, qboolean force) +{ + cvar_t *var; + + var = Cvar_FindVar (var_name); + if (!var) + { // create it + return Cvar_Get (var_name, value, 0); + } + + if (var->flags & (CVAR_USERINFO | CVAR_SERVERINFO)) + { + if (!Cvar_InfoValidate (value)) + { + Com_Printf("invalid info cvar value\n"); + return var; + } + } + + if (!force) + { + if (var->flags & CVAR_NOSET) + { + Com_Printf ("%s is write protected.\n", var_name); + return var; + } + + if (var->flags & CVAR_LATCH) + { + if (var->latched_string) + { + if (strcmp(value, var->latched_string) == 0) + return var; + Z_Free (var->latched_string); + } + else + { + if (strcmp(value, var->string) == 0) + return var; + } + + if (Com_ServerState()) + { + Com_Printf ("%s will be changed for next game.\n", var_name); + var->latched_string = CopyString(value); + } + else + { + var->string = CopyString(value); + var->value = atof (var->string); + if (!strcmp(var->name, "game")) + { + FS_SetGamedir (var->string); + FS_ExecAutoexec (); + } + } + return var; + } + } + else + { + if (var->latched_string) + { + Z_Free (var->latched_string); + var->latched_string = NULL; + } + } + + if (!strcmp(value, var->string)) + return var; // not changed + + var->modified = true; + + if (var->flags & CVAR_USERINFO) + userinfo_modified = true; // transmit at next oportunity + + Z_Free (var->string); // free the old value string + + var->string = CopyString(value); + var->value = atof (var->string); + + return var; +} + +/* +============ +Cvar_ForceSet +============ +*/ +cvar_t *Cvar_ForceSet (char *var_name, char *value) +{ + return Cvar_Set2 (var_name, value, true); +} + +/* +============ +Cvar_Set +============ +*/ +cvar_t *Cvar_Set (char *var_name, char *value) +{ + return Cvar_Set2 (var_name, value, false); +} + +/* +============ +Cvar_FullSet +============ +*/ +cvar_t *Cvar_FullSet (char *var_name, char *value, int flags) +{ + cvar_t *var; + + var = Cvar_FindVar (var_name); + if (!var) + { // create it + return Cvar_Get (var_name, value, flags); + } + + var->modified = true; + + if (var->flags & CVAR_USERINFO) + userinfo_modified = true; // transmit at next oportunity + + Z_Free (var->string); // free the old value string + + var->string = CopyString(value); + var->value = atof (var->string); + var->flags = flags; + + return var; +} + +/* +============ +Cvar_SetValue +============ +*/ +void Cvar_SetValue (char *var_name, float value) +{ + char val[32]; + + if (value == (int)value) + Com_sprintf (val, sizeof(val), "%i",(int)value); + else + Com_sprintf (val, sizeof(val), "%f",value); + Cvar_Set (var_name, val); +} + + +/* +============ +Cvar_GetLatchedVars + +Any variables with latched values will now be updated +============ +*/ +void Cvar_GetLatchedVars (void) +{ + cvar_t *var; + + for (var = cvar_vars ; var ; var = var->next) + { + if (!var->latched_string) + continue; + Z_Free (var->string); + var->string = var->latched_string; + var->latched_string = NULL; + var->value = atof(var->string); + if (!strcmp(var->name, "game")) + { + FS_SetGamedir (var->string); + FS_ExecAutoexec (); + } + } +} + +/* +============ +Cvar_Command + +Handles variable inspection and changing from the console +============ +*/ +qboolean Cvar_Command (void) +{ + cvar_t *v; + +// check variables + v = Cvar_FindVar (Cmd_Argv(0)); + if (!v) + return false; + +// perform a variable print or set + if (Cmd_Argc() == 1) + { + Com_Printf ("\"%s\" is \"%s\"\n", v->name, v->string); + return true; + } + + Cvar_Set (v->name, Cmd_Argv(1)); + return true; +} + + +/* +============ +Cvar_Set_f + +Allows setting and defining of arbitrary cvars from console +============ +*/ +void Cvar_Set_f (void) +{ + int c; + int flags; + + c = Cmd_Argc(); + if (c != 3 && c != 4) + { + Com_Printf ("usage: set [u / s]\n"); + return; + } + + if (c == 4) + { + if (!strcmp(Cmd_Argv(3), "u")) + flags = CVAR_USERINFO; + else if (!strcmp(Cmd_Argv(3), "s")) + flags = CVAR_SERVERINFO; + else + { + Com_Printf ("flags can only be 'u' or 's'\n"); + return; + } + Cvar_FullSet (Cmd_Argv(1), Cmd_Argv(2), flags); + } + else + Cvar_Set (Cmd_Argv(1), Cmd_Argv(2)); +} + + +/* +============ +Cvar_WriteVariables + +Appends lines containing "set variable value" for all variables +with the archive flag set to true. +============ +*/ +void Cvar_WriteVariables (char *path) +{ + cvar_t *var; + char buffer[1024]; + FILE *f; + + f = fopen (path, "a"); + for (var = cvar_vars ; var ; var = var->next) + { + if (var->flags & CVAR_ARCHIVE) + { + Com_sprintf (buffer, sizeof(buffer), "set %s \"%s\"\n", var->name, var->string); + fprintf (f, "%s", buffer); + } + } + fclose (f); +} + +/* +============ +Cvar_List_f + +============ +*/ +void Cvar_List_f (void) +{ + cvar_t *var; + int i; + + i = 0; + for (var = cvar_vars ; var ; var = var->next, i++) + { + if (var->flags & CVAR_ARCHIVE) + Com_Printf ("*"); + else + Com_Printf (" "); + if (var->flags & CVAR_USERINFO) + Com_Printf ("U"); + else + Com_Printf (" "); + if (var->flags & CVAR_SERVERINFO) + Com_Printf ("S"); + else + Com_Printf (" "); + if (var->flags & CVAR_NOSET) + Com_Printf ("-"); + else if (var->flags & CVAR_LATCH) + Com_Printf ("L"); + else + Com_Printf (" "); + Com_Printf (" %s \"%s\"\n", var->name, var->string); + } + Com_Printf ("%i cvars\n", i); +} + + +qboolean userinfo_modified; + + +char *Cvar_BitInfo (int bit) +{ + static char info[MAX_INFO_STRING]; + cvar_t *var; + + info[0] = 0; + + for (var = cvar_vars ; var ; var = var->next) + { + if (var->flags & bit) + Info_SetValueForKey (info, var->name, var->string); + } + return info; +} + +// returns an info string containing all the CVAR_USERINFO cvars +char *Cvar_Userinfo (void) +{ + return Cvar_BitInfo (CVAR_USERINFO); +} + +// returns an info string containing all the CVAR_SERVERINFO cvars +char *Cvar_Serverinfo (void) +{ + return Cvar_BitInfo (CVAR_SERVERINFO); +} + +/* +============ +Cvar_Init + +Reads in all archived cvars +============ +*/ +void Cvar_Init (void) +{ + Cmd_AddCommand ("set", Cvar_Set_f); + Cmd_AddCommand ("cvarlist", Cvar_List_f); + +} diff --git a/qcommon/files.c b/qcommon/files.c new file mode 100644 index 000000000..4e2de9a2b --- /dev/null +++ b/qcommon/files.c @@ -0,0 +1,877 @@ +/* +Copyright (C) 1997-2001 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. + +*/ + +#include "qcommon.h" + +// define this to dissalow any data but the demo pak file +//#define NO_ADDONS + +// if a packfile directory differs from this, it is assumed to be hacked +// Full version +#define PAK0_CHECKSUM 0x40e614e0 +// Demo +//#define PAK0_CHECKSUM 0xb2c6d7ea +// OEM +//#define PAK0_CHECKSUM 0x78e135c + +/* +============================================================================= + +QUAKE FILESYSTEM + +============================================================================= +*/ + + +// +// in memory +// + +typedef struct +{ + char name[MAX_QPATH]; + int filepos, filelen; +} packfile_t; + +typedef struct pack_s +{ + char filename[MAX_OSPATH]; + FILE *handle; + int numfiles; + packfile_t *files; +} pack_t; + +char fs_gamedir[MAX_OSPATH]; +cvar_t *fs_basedir; +cvar_t *fs_cddir; +cvar_t *fs_gamedirvar; + +typedef struct filelink_s +{ + struct filelink_s *next; + char *from; + int fromlength; + char *to; +} filelink_t; + +filelink_t *fs_links; + +typedef struct searchpath_s +{ + char filename[MAX_OSPATH]; + pack_t *pack; // only one of filename / pack will be used + struct searchpath_s *next; +} searchpath_t; + +searchpath_t *fs_searchpaths; +searchpath_t *fs_base_searchpaths; // without gamedirs + + +/* + +All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources. + +The "base directory" is the path to the directory holding the quake.exe and all game directories. The sys_* files pass this to host_init in quakeparms_t->basedir. This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory. The base directory is +only used during filesystem initialization. + +The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to. This can be overridden with the "-game" command line parameter. The game directory can never be changed while quake is executing. This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't. + +*/ + + +/* +================ +FS_filelength +================ +*/ +int FS_filelength (FILE *f) +{ + int pos; + int end; + + pos = ftell (f); + fseek (f, 0, SEEK_END); + end = ftell (f); + fseek (f, pos, SEEK_SET); + + return end; +} + + +/* +============ +FS_CreatePath + +Creates any directories needed to store the given filename +============ +*/ +void FS_CreatePath (char *path) +{ + char *ofs; + + for (ofs = path+1 ; *ofs ; ofs++) + { + if (*ofs == '/') + { // create the directory + *ofs = 0; + Sys_Mkdir (path); + *ofs = '/'; + } + } +} + + +/* +============== +FS_FCloseFile + +For some reason, other dll's can't just cal fclose() +on files returned by FS_FOpenFile... +============== +*/ +void FS_FCloseFile (FILE *f) +{ + fclose (f); +} + + +// RAFAEL +/* + Developer_searchpath +*/ +int Developer_searchpath (int who) +{ + + int ch; + // PMM - warning removal +// char *start; + searchpath_t *search; + + if (who == 1) // xatrix + ch = 'x'; + else if (who == 2) + ch = 'r'; + + for (search = fs_searchpaths ; search ; search = search->next) + { + if (strstr (search->filename, "xatrix")) + return 1; + + if (strstr (search->filename, "rogue")) + return 2; +/* + start = strchr (search->filename, ch); + + if (start == NULL) + continue; + + if (strcmp (start ,"xatrix") == 0) + return (1); +*/ + } + return (0); + +} + + +/* +=========== +FS_FOpenFile + +Finds the file in the search path. +returns filesize and an open FILE * +Used for streaming data out of either a pak file or +a seperate file. +=========== +*/ +int file_from_pak = 0; +#ifndef NO_ADDONS +int FS_FOpenFile (char *filename, FILE **file) +{ + searchpath_t *search; + char netpath[MAX_OSPATH]; + pack_t *pak; + int i; + filelink_t *link; + + file_from_pak = 0; + + // check for links first + for (link = fs_links ; link ; link=link->next) + { + if (!strncmp (filename, link->from, link->fromlength)) + { + Com_sprintf (netpath, sizeof(netpath), "%s%s",link->to, filename+link->fromlength); + *file = fopen (netpath, "rb"); + if (*file) + { + Com_DPrintf ("link file: %s\n",netpath); + return FS_filelength (*file); + } + return -1; + } + } + +// +// search through the path, one element at a time +// + for (search = fs_searchpaths ; search ; search = search->next) + { + // is the element a pak file? + if (search->pack) + { + // look through all the pak file elements + pak = search->pack; + for (i=0 ; inumfiles ; i++) + if (!Q_strcasecmp (pak->files[i].name, filename)) + { // found it! + file_from_pak = 1; + Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename); + // open a new file on the pakfile + *file = fopen (pak->filename, "rb"); + if (!*file) + Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename); + fseek (*file, pak->files[i].filepos, SEEK_SET); + return pak->files[i].filelen; + } + } + else + { + // check a file in the directory tree + + Com_sprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename); + + *file = fopen (netpath, "rb"); + if (!*file) + continue; + + Com_DPrintf ("FindFile: %s\n",netpath); + + return FS_filelength (*file); + } + + } + + Com_DPrintf ("FindFile: can't find %s\n", filename); + + *file = NULL; + return -1; +} + +#else + +// this is just for demos to prevent add on hacking + +int FS_FOpenFile (char *filename, FILE **file) +{ + searchpath_t *search; + char netpath[MAX_OSPATH]; + pack_t *pak; + int i; + + file_from_pak = 0; + + // get config from directory, everything else from pak + if (!strcmp(filename, "config.cfg") || !strncmp(filename, "players/", 8)) + { + Com_sprintf (netpath, sizeof(netpath), "%s/%s",FS_Gamedir(), filename); + + *file = fopen (netpath, "rb"); + if (!*file) + return -1; + + Com_DPrintf ("FindFile: %s\n",netpath); + + return FS_filelength (*file); + } + + for (search = fs_searchpaths ; search ; search = search->next) + if (search->pack) + break; + if (!search) + { + *file = NULL; + return -1; + } + + pak = search->pack; + for (i=0 ; inumfiles ; i++) + if (!Q_strcasecmp (pak->files[i].name, filename)) + { // found it! + file_from_pak = 1; + Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename); + // open a new file on the pakfile + *file = fopen (pak->filename, "rb"); + if (!*file) + Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename); + fseek (*file, pak->files[i].filepos, SEEK_SET); + return pak->files[i].filelen; + } + + Com_DPrintf ("FindFile: can't find %s\n", filename); + + *file = NULL; + return -1; +} + +#endif + + +/* +================= +FS_ReadFile + +Properly handles partial reads +================= +*/ +void CDAudio_Stop(void); +#define MAX_READ 0x10000 // read in blocks of 64k +void FS_Read (void *buffer, int len, FILE *f) +{ + int block, remaining; + int read; + byte *buf; + int tries; + + buf = (byte *)buffer; + + // read in chunks for progress bar + remaining = len; + tries = 0; + while (remaining) + { + block = remaining; + if (block > MAX_READ) + block = MAX_READ; + read = fread (buf, 1, block, f); + if (read == 0) + { + // we might have been trying to read from a CD + if (!tries) + { + tries = 1; + CDAudio_Stop(); + } + else + Com_Error (ERR_FATAL, "FS_Read: 0 bytes read"); + } + + if (read == -1) + Com_Error (ERR_FATAL, "FS_Read: -1 bytes read"); + + // do some progress bar thing here... + + remaining -= read; + buf += read; + } +} + +/* +============ +FS_LoadFile + +Filename are reletive to the quake search path +a null buffer will just return the file length without loading +============ +*/ +int FS_LoadFile (char *path, void **buffer) +{ + FILE *h; + byte *buf; + int len; + + buf = NULL; // quiet compiler warning + +// look for it in the filesystem or pack files + len = FS_FOpenFile (path, &h); + if (!h) + { + if (buffer) + *buffer = NULL; + return -1; + } + + if (!buffer) + { + fclose (h); + return len; + } + + buf = Z_Malloc(len); + *buffer = buf; + + FS_Read (buf, len, h); + + fclose (h); + + return len; +} + + +/* +============= +FS_FreeFile +============= +*/ +void FS_FreeFile (void *buffer) +{ + Z_Free (buffer); +} + +/* +================= +FS_LoadPackFile + +Takes an explicit (not game tree related) path to a pak file. + +Loads the header and directory, adding the files at the beginning +of the list so they override previous pack files. +================= +*/ +pack_t *FS_LoadPackFile (char *packfile) +{ + dpackheader_t header; + int i; + packfile_t *newfiles; + int numpackfiles; + pack_t *pack; + FILE *packhandle; + dpackfile_t info[MAX_FILES_IN_PACK]; + unsigned checksum; + + packhandle = fopen(packfile, "rb"); + if (!packhandle) + return NULL; + + fread (&header, 1, sizeof(header), packhandle); + if (LittleLong(header.ident) != IDPAKHEADER) + Com_Error (ERR_FATAL, "%s is not a packfile", packfile); + header.dirofs = LittleLong (header.dirofs); + header.dirlen = LittleLong (header.dirlen); + + numpackfiles = header.dirlen / sizeof(dpackfile_t); + + if (numpackfiles > MAX_FILES_IN_PACK) + Com_Error (ERR_FATAL, "%s has %i files", packfile, numpackfiles); + + newfiles = Z_Malloc (numpackfiles * sizeof(packfile_t)); + + fseek (packhandle, header.dirofs, SEEK_SET); + fread (info, 1, header.dirlen, packhandle); + +// crc the directory to check for modifications + checksum = Com_BlockChecksum ((void *)info, header.dirlen); + +#ifdef NO_ADDONS + if (checksum != PAK0_CHECKSUM) + return NULL; +#endif +// parse the directory + for (i=0 ; ifilename, packfile); + pack->handle = packhandle; + pack->numfiles = numpackfiles; + pack->files = newfiles; + + Com_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles); + return pack; +} + + +/* +================ +FS_AddGameDirectory + +Sets fs_gamedir, adds the directory to the head of the path, +then loads and adds pak1.pak pak2.pak ... +================ +*/ +void FS_AddGameDirectory (char *dir) +{ + int i; + searchpath_t *search; + pack_t *pak; + char pakfile[MAX_OSPATH]; + + strcpy (fs_gamedir, dir); + + // + // add the directory to the search path + // + search = Z_Malloc (sizeof(searchpath_t)); + strcpy (search->filename, dir); + search->next = fs_searchpaths; + fs_searchpaths = search; + + // + // add any pak files in the format pak0.pak pak1.pak, ... + // + for (i=0; i<10; i++) + { + Com_sprintf (pakfile, sizeof(pakfile), "%s/pak%i.pak", dir, i); + pak = FS_LoadPackFile (pakfile); + if (!pak) + continue; + search = Z_Malloc (sizeof(searchpath_t)); + search->pack = pak; + search->next = fs_searchpaths; + fs_searchpaths = search; + } + + +} + +/* +============ +FS_Gamedir + +Called to find where to write a file (demos, savegames, etc) +============ +*/ +char *FS_Gamedir (void) +{ + return fs_gamedir; +} + +/* +============= +FS_ExecAutoexec +============= +*/ +void FS_ExecAutoexec (void) +{ + char *dir; + char name [MAX_QPATH]; + + dir = Cvar_VariableString("gamedir"); + if (*dir) + Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, dir); + else + Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, BASEDIRNAME); + if (Sys_FindFirst(name, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM)) + Cbuf_AddText ("exec autoexec.cfg\n"); + Sys_FindClose(); +} + + +/* +================ +FS_SetGamedir + +Sets the gamedir and path to a different directory. +================ +*/ +void FS_SetGamedir (char *dir) +{ + searchpath_t *next; + + if (strstr(dir, "..") || strstr(dir, "/") + || strstr(dir, "\\") || strstr(dir, ":") ) + { + Com_Printf ("Gamedir should be a single filename, not a path\n"); + return; + } + + // + // free up any current game dir info + // + while (fs_searchpaths != fs_base_searchpaths) + { + if (fs_searchpaths->pack) + { + fclose (fs_searchpaths->pack->handle); + Z_Free (fs_searchpaths->pack->files); + Z_Free (fs_searchpaths->pack); + } + next = fs_searchpaths->next; + Z_Free (fs_searchpaths); + fs_searchpaths = next; + } + + // + // flush all data, so it will be forced to reload + // + if (dedicated && !dedicated->value) + Cbuf_AddText ("vid_restart\nsnd_restart\n"); + + Com_sprintf (fs_gamedir, sizeof(fs_gamedir), "%s/%s", fs_basedir->string, dir); + + if (!strcmp(dir,BASEDIRNAME) || (*dir == 0)) + { + Cvar_FullSet ("gamedir", "", CVAR_SERVERINFO|CVAR_NOSET); + Cvar_FullSet ("game", "", CVAR_LATCH|CVAR_SERVERINFO); + } + else + { + Cvar_FullSet ("gamedir", dir, CVAR_SERVERINFO|CVAR_NOSET); + if (fs_cddir->string[0]) + FS_AddGameDirectory (va("%s/%s", fs_cddir->string, dir) ); + FS_AddGameDirectory (va("%s/%s", fs_basedir->string, dir) ); + } +} + + +/* +================ +FS_Link_f + +Creates a filelink_t +================ +*/ +void FS_Link_f (void) +{ + filelink_t *l, **prev; + + if (Cmd_Argc() != 3) + { + Com_Printf ("USAGE: link \n"); + return; + } + + // see if the link already exists + prev = &fs_links; + for (l=fs_links ; l ; l=l->next) + { + if (!strcmp (l->from, Cmd_Argv(1))) + { + Z_Free (l->to); + if (!strlen(Cmd_Argv(2))) + { // delete it + *prev = l->next; + Z_Free (l->from); + Z_Free (l); + return; + } + l->to = CopyString (Cmd_Argv(2)); + return; + } + prev = &l->next; + } + + // create a new link + l = Z_Malloc(sizeof(*l)); + l->next = fs_links; + fs_links = l; + l->from = CopyString(Cmd_Argv(1)); + l->fromlength = strlen(l->from); + l->to = CopyString(Cmd_Argv(2)); +} + +/* +** FS_ListFiles +*/ +char **FS_ListFiles( char *findname, int *numfiles, unsigned musthave, unsigned canthave ) +{ + char *s; + int nfiles = 0; + char **list = 0; + + s = Sys_FindFirst( findname, musthave, canthave ); + while ( s ) + { + if ( s[strlen(s)-1] != '.' ) + nfiles++; + s = Sys_FindNext( musthave, canthave ); + } + Sys_FindClose (); + + if ( !nfiles ) + return NULL; + + nfiles++; // add space for a guard + *numfiles = nfiles; + + list = malloc( sizeof( char * ) * nfiles ); + memset( list, 0, sizeof( char * ) * nfiles ); + + s = Sys_FindFirst( findname, musthave, canthave ); + nfiles = 0; + while ( s ) + { + if ( s[strlen(s)-1] != '.' ) + { + list[nfiles] = strdup( s ); +#ifdef _WIN32 + strlwr( list[nfiles] ); +#endif + nfiles++; + } + s = Sys_FindNext( musthave, canthave ); + } + Sys_FindClose (); + + return list; +} + +/* +** FS_Dir_f +*/ +void FS_Dir_f( void ) +{ + char *path = NULL; + char findname[1024]; + char wildcard[1024] = "*.*"; + char **dirnames; + int ndirs; + + if ( Cmd_Argc() != 1 ) + { + strcpy( wildcard, Cmd_Argv( 1 ) ); + } + + while ( ( path = FS_NextPath( path ) ) != NULL ) + { + char *tmp = findname; + + Com_sprintf( findname, sizeof(findname), "%s/%s", path, wildcard ); + + while ( *tmp != 0 ) + { + if ( *tmp == '\\' ) + *tmp = '/'; + tmp++; + } + Com_Printf( "Directory of %s\n", findname ); + Com_Printf( "----\n" ); + + if ( ( dirnames = FS_ListFiles( findname, &ndirs, 0, 0 ) ) != 0 ) + { + int i; + + for ( i = 0; i < ndirs-1; i++ ) + { + if ( strrchr( dirnames[i], '/' ) ) + Com_Printf( "%s\n", strrchr( dirnames[i], '/' ) + 1 ); + else + Com_Printf( "%s\n", dirnames[i] ); + + free( dirnames[i] ); + } + free( dirnames ); + } + Com_Printf( "\n" ); + }; +} + +/* +============ +FS_Path_f + +============ +*/ +void FS_Path_f (void) +{ + searchpath_t *s; + filelink_t *l; + + Com_Printf ("Current search path:\n"); + for (s=fs_searchpaths ; s ; s=s->next) + { + if (s == fs_base_searchpaths) + Com_Printf ("----------\n"); + if (s->pack) + Com_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles); + else + Com_Printf ("%s\n", s->filename); + } + + Com_Printf ("\nLinks:\n"); + for (l=fs_links ; l ; l=l->next) + Com_Printf ("%s : %s\n", l->from, l->to); +} + +/* +================ +FS_NextPath + +Allows enumerating all of the directories in the search path +================ +*/ +char *FS_NextPath (char *prevpath) +{ + searchpath_t *s; + char *prev; + + if (!prevpath) + return fs_gamedir; + + prev = fs_gamedir; + for (s=fs_searchpaths ; s ; s=s->next) + { + if (s->pack) + continue; + if (prevpath == prev) + return s->filename; + prev = s->filename; + } + + return NULL; +} + + +/* +================ +FS_InitFilesystem +================ +*/ +void FS_InitFilesystem (void) +{ + Cmd_AddCommand ("path", FS_Path_f); + Cmd_AddCommand ("link", FS_Link_f); + Cmd_AddCommand ("dir", FS_Dir_f ); + + // + // basedir + // allows the game to run from outside the data tree + // + fs_basedir = Cvar_Get ("basedir", ".", CVAR_NOSET); + + // + // cddir + // Logically concatenates the cddir after the basedir for + // allows the game to run from outside the data tree + // + fs_cddir = Cvar_Get ("cddir", "", CVAR_NOSET); + if (fs_cddir->string[0]) + FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_cddir->string) ); + + // + // start up with baseq2 by default + // + FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_basedir->string) ); + + // any set gamedirs will be freed up to here + fs_base_searchpaths = fs_searchpaths; + + // check for game override + fs_gamedirvar = Cvar_Get ("game", "", CVAR_LATCH|CVAR_SERVERINFO); + if (fs_gamedirvar->string[0]) + FS_SetGamedir (fs_gamedirvar->string); +} + + + diff --git a/qcommon/md4.c b/qcommon/md4.c new file mode 100644 index 000000000..0ceca0c59 --- /dev/null +++ b/qcommon/md4.c @@ -0,0 +1,278 @@ +/* GLOBAL.H - RSAREF types and constants */ + +#include + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/* UINT2 defines a two byte word */ +typedef unsigned short int UINT2; + +/* UINT4 defines a four byte word */ +#ifdef __alpha__ +typedef unsigned int UINT4; +#else +typedef unsigned long int UINT4; +#endif + + +/* MD4.H - header file for MD4C.C */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. + +All rights reserved. + +License to copy and use this software is granted provided that it is identified as the “RSA Data Security, Inc. MD4 Message-Digest Algorithm” in all material mentioning or referencing this software or this function. +License is also granted to make and use derivative works provided that such works are identified as “derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm” in all material mentioning or referencing the derived work. +RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided “as is” without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this documentation and/or software. */ + +/* MD4 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD4_CTX; + +void MD4Init (MD4_CTX *); +void MD4Update (MD4_CTX *, unsigned char *, unsigned int); +void MD4Final (unsigned char [16], MD4_CTX *); + + + +/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm */ +/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved. + +License to copy and use this software is granted provided that it is identified as the +RSA Data Security, Inc. MD4 Message-Digest Algorithm + in all material mentioning or referencing this software or this function. +License is also granted to make and use derivative works provided that such works are identified as +derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm +in all material mentioning or referencing the derived work. +RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided +as is without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this documentation and/or software. */ + +/* Constants for MD4Transform routine. */ +#define S11 3 +#define S12 7 +#define S13 11 +#define S14 19 +#define S21 3 +#define S22 5 +#define S23 9 +#define S24 13 +#define S31 3 +#define S32 9 +#define S33 11 +#define S34 15 + +static void MD4Transform (UINT4 [4], unsigned char [64]); +static void Encode (unsigned char *, UINT4 *, unsigned int); +static void Decode (UINT4 *, unsigned char *, unsigned int); + +static unsigned char PADDING[64] = { +0x80, 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 +}; + +/* F, G and H are basic MD4 functions. */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +/* ROTATE_LEFT rotates x left n bits. */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG and HH are transformations for rounds 1, 2 and 3 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s) {(a) += F ((b), (c), (d)) + (x); (a) = ROTATE_LEFT ((a), (s));} + +#define GG(a, b, c, d, x, s) {(a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; (a) = ROTATE_LEFT ((a), (s));} + +#define HH(a, b, c, d, x, s) {(a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; (a) = ROTATE_LEFT ((a), (s));} + + +/* MD4 initialization. Begins an MD4 operation, writing a new context. */ +void MD4Init (MD4_CTX *context) +{ + context->count[0] = context->count[1] = 0; + +/* Load magic initialization constants.*/ +context->state[0] = 0x67452301; +context->state[1] = 0xefcdab89; +context->state[2] = 0x98badcfe; +context->state[3] = 0x10325476; +} + +/* MD4 block update operation. Continues an MD4 message-digest operation, processing another message block, and updating the context. */ +void MD4Update (MD4_CTX *context, unsigned char *input, unsigned int inputLen) +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3))< ((UINT4)inputLen << 3)) + context->count[1]++; + + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible.*/ + if (inputLen >= partLen) + { + memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD4Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD4Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i); +} + + +/* MD4 finalization. Ends an MD4 message-digest operation, writing the the message digest and zeroizing the context. */ +void MD4Final (unsigned char digest[16], MD4_CTX *context) +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64.*/ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD4Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD4Update (context, bits, 8); + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information.*/ + memset ((POINTER)context, 0, sizeof (*context)); +} + + +/* MD4 basic transformation. Transforms state based on block. */ +static void MD4Transform (UINT4 state[4], unsigned char block[64]) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + +/* Round 1 */ +FF (a, b, c, d, x[ 0], S11); /* 1 */ +FF (d, a, b, c, x[ 1], S12); /* 2 */ +FF (c, d, a, b, x[ 2], S13); /* 3 */ +FF (b, c, d, a, x[ 3], S14); /* 4 */ +FF (a, b, c, d, x[ 4], S11); /* 5 */ +FF (d, a, b, c, x[ 5], S12); /* 6 */ +FF (c, d, a, b, x[ 6], S13); /* 7 */ +FF (b, c, d, a, x[ 7], S14); /* 8 */ +FF (a, b, c, d, x[ 8], S11); /* 9 */ +FF (d, a, b, c, x[ 9], S12); /* 10 */ +FF (c, d, a, b, x[10], S13); /* 11 */ +FF (b, c, d, a, x[11], S14); /* 12 */ +FF (a, b, c, d, x[12], S11); /* 13 */ +FF (d, a, b, c, x[13], S12); /* 14 */ +FF (c, d, a, b, x[14], S13); /* 15 */ +FF (b, c, d, a, x[15], S14); /* 16 */ + +/* Round 2 */ +GG (a, b, c, d, x[ 0], S21); /* 17 */ +GG (d, a, b, c, x[ 4], S22); /* 18 */ +GG (c, d, a, b, x[ 8], S23); /* 19 */ +GG (b, c, d, a, x[12], S24); /* 20 */ +GG (a, b, c, d, x[ 1], S21); /* 21 */ +GG (d, a, b, c, x[ 5], S22); /* 22 */ +GG (c, d, a, b, x[ 9], S23); /* 23 */ +GG (b, c, d, a, x[13], S24); /* 24 */ +GG (a, b, c, d, x[ 2], S21); /* 25 */ +GG (d, a, b, c, x[ 6], S22); /* 26 */ +GG (c, d, a, b, x[10], S23); /* 27 */ +GG (b, c, d, a, x[14], S24); /* 28 */ +GG (a, b, c, d, x[ 3], S21); /* 29 */ +GG (d, a, b, c, x[ 7], S22); /* 30 */ +GG (c, d, a, b, x[11], S23); /* 31 */ +GG (b, c, d, a, x[15], S24); /* 32 */ + +/* Round 3 */ +HH (a, b, c, d, x[ 0], S31); /* 33 */ +HH (d, a, b, c, x[ 8], S32); /* 34 */ +HH (c, d, a, b, x[ 4], S33); /* 35 */ +HH (b, c, d, a, x[12], S34); /* 36 */ +HH (a, b, c, d, x[ 2], S31); /* 37 */ +HH (d, a, b, c, x[10], S32); /* 38 */ +HH (c, d, a, b, x[ 6], S33); /* 39 */ +HH (b, c, d, a, x[14], S34); /* 40 */ +HH (a, b, c, d, x[ 1], S31); /* 41 */ +HH (d, a, b, c, x[ 9], S32); /* 42 */ +HH (c, d, a, b, x[ 5], S33); /* 43 */ +HH (b, c, d, a, x[13], S34); /* 44 */ +HH (a, b, c, d, x[ 3], S31); /* 45 */ +HH (d, a, b, c, x[11], S32); /* 46 */ +HH (c, d, a, b, x[ 7], S33); /* 47 */ +HH (b, c, d, a, x[15], S34); /* 48 */ + +state[0] += a; +state[1] += b; +state[2] += c; +state[3] += d; + + /* Zeroize sensitive information.*/ + memset ((POINTER)x, 0, sizeof (x)); +} + + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */ +static void Encode (unsigned char *output, UINT4 *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */ +static void Decode (UINT4 *output, unsigned char *input, unsigned int len) +{ +unsigned int i, j; + +for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +//=================================================================== + +unsigned Com_BlockChecksum (void *buffer, int length) +{ + int digest[4]; + unsigned val; + MD4_CTX ctx; + + MD4Init (&ctx); + MD4Update (&ctx, (unsigned char *)buffer, length); + MD4Final ( (unsigned char *)digest, &ctx); + + val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3]; + + return val; +} diff --git a/qcommon/net_chan.c b/qcommon/net_chan.c new file mode 100644 index 000000000..acb6eb901 --- /dev/null +++ b/qcommon/net_chan.c @@ -0,0 +1,387 @@ +/* +Copyright (C) 1997-2001 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. + +*/ + +#include "qcommon.h" + +/* + +packet header +------------- +31 sequence +1 does this message contain a reliable payload +31 acknowledge sequence +1 acknowledge receipt of even/odd message +16 qport + +The remote connection never knows if it missed a reliable message, the +local side detects that it has been dropped by seeing a sequence acknowledge +higher thatn the last reliable sequence, but without the correct evon/odd +bit for the reliable set. + +If the sender notices that a reliable message has been dropped, it will be +retransmitted. It will not be retransmitted again until a message after +the retransmit has been acknowledged and the reliable still failed to get there. + +if the sequence number is -1, the packet should be handled without a netcon + +The reliable message can be added to at any time by doing +MSG_Write* (&netchan->message, ). + +If the message buffer is overflowed, either by a single message, or by +multiple frames worth piling up while the last reliable transmit goes +unacknowledged, the netchan signals a fatal error. + +Reliable messages are always placed first in a packet, then the unreliable +message is included if there is sufficient room. + +To the receiver, there is no distinction between the reliable and unreliable +parts of the message, they are just processed out as a single larger message. + +Illogical packet sequence numbers cause the packet to be dropped, but do +not kill the connection. This, combined with the tight window of valid +reliable acknowledgement numbers provides protection against malicious +address spoofing. + + +The qport field is a workaround for bad address translating routers that +sometimes remap the client's source port on a packet during gameplay. + +If the base part of the net address matches and the qport matches, then the +channel matches even if the IP port differs. The IP port should be updated +to the new value before sending out any replies. + + +If there is no information that needs to be transfered on a given frame, +such as during the connection stage while waiting for the client to load, +then a packet only needs to be delivered if there is something in the +unacknowledged reliable +*/ + +cvar_t *showpackets; +cvar_t *showdrop; +cvar_t *qport; + +netadr_t net_from; +sizebuf_t net_message; +byte net_message_buffer[MAX_MSGLEN]; + +/* +=============== +Netchan_Init + +=============== +*/ +void Netchan_Init (void) +{ + int port; + + // pick a port value that should be nice and random + port = Sys_Milliseconds() & 0xffff; + + showpackets = Cvar_Get ("showpackets", "0", 0); + showdrop = Cvar_Get ("showdrop", "0", 0); + qport = Cvar_Get ("qport", va("%i", port), CVAR_NOSET); +} + +/* +=============== +Netchan_OutOfBand + +Sends an out-of-band datagram +================ +*/ +void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data) +{ + sizebuf_t send; + byte send_buf[MAX_MSGLEN]; + +// write the packet header + SZ_Init (&send, send_buf, sizeof(send_buf)); + + MSG_WriteLong (&send, -1); // -1 sequence means out of band + SZ_Write (&send, data, length); + +// send the datagram + NET_SendPacket (net_socket, send.cursize, send.data, adr); +} + +/* +=============== +Netchan_OutOfBandPrint + +Sends a text message in an out-of-band datagram +================ +*/ +void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...) +{ + va_list argptr; + static char string[MAX_MSGLEN - 4]; + + va_start (argptr, format); + vsprintf (string, format,argptr); + va_end (argptr); + + Netchan_OutOfBand (net_socket, adr, strlen(string), (byte *)string); +} + + +/* +============== +Netchan_Setup + +called to open a channel to a remote system +============== +*/ +void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport) +{ + memset (chan, 0, sizeof(*chan)); + + chan->sock = sock; + chan->remote_address = adr; + chan->qport = qport; + chan->last_received = curtime; + chan->incoming_sequence = 0; + chan->outgoing_sequence = 1; + + SZ_Init (&chan->message, chan->message_buf, sizeof(chan->message_buf)); + chan->message.allowoverflow = true; +} + + +/* +=============== +Netchan_CanReliable + +Returns true if the last reliable message has acked +================ +*/ +qboolean Netchan_CanReliable (netchan_t *chan) +{ + if (chan->reliable_length) + return false; // waiting for ack + return true; +} + + +qboolean Netchan_NeedReliable (netchan_t *chan) +{ + qboolean send_reliable; + +// if the remote side dropped the last reliable message, resend it + send_reliable = false; + + if (chan->incoming_acknowledged > chan->last_reliable_sequence + && chan->incoming_reliable_acknowledged != chan->reliable_sequence) + send_reliable = true; + +// if the reliable transmit buffer is empty, copy the current message out + if (!chan->reliable_length && chan->message.cursize) + { + send_reliable = true; + } + + return send_reliable; +} + +/* +=============== +Netchan_Transmit + +tries to send an unreliable message to a connection, and handles the +transmition / retransmition of the reliable messages. + +A 0 length will still generate a packet and deal with the reliable messages. +================ +*/ +void Netchan_Transmit (netchan_t *chan, int length, byte *data) +{ + sizebuf_t send; + byte send_buf[MAX_MSGLEN]; + qboolean send_reliable; + unsigned w1, w2; + +// check for message overflow + if (chan->message.overflowed) + { + chan->fatal_error = true; + Com_Printf ("%s:Outgoing message overflow\n" + , NET_AdrToString (chan->remote_address)); + return; + } + + send_reliable = Netchan_NeedReliable (chan); + + if (!chan->reliable_length && chan->message.cursize) + { + memcpy (chan->reliable_buf, chan->message_buf, chan->message.cursize); + chan->reliable_length = chan->message.cursize; + chan->message.cursize = 0; + chan->reliable_sequence ^= 1; + } + + +// write the packet header + SZ_Init (&send, send_buf, sizeof(send_buf)); + + w1 = ( chan->outgoing_sequence & ~(1<<31) ) | (send_reliable<<31); + w2 = ( chan->incoming_sequence & ~(1<<31) ) | (chan->incoming_reliable_sequence<<31); + + chan->outgoing_sequence++; + chan->last_sent = curtime; + + MSG_WriteLong (&send, w1); + MSG_WriteLong (&send, w2); + + // send the qport if we are a client + if (chan->sock == NS_CLIENT) + MSG_WriteShort (&send, qport->value); + +// copy the reliable message to the packet first + if (send_reliable) + { + SZ_Write (&send, chan->reliable_buf, chan->reliable_length); + chan->last_reliable_sequence = chan->outgoing_sequence; + } + +// add the unreliable part if space is available + if (send.maxsize - send.cursize >= length) + SZ_Write (&send, data, length); + else + Com_Printf ("Netchan_Transmit: dumped unreliable\n"); + +// send the datagram + NET_SendPacket (chan->sock, send.cursize, send.data, chan->remote_address); + + if (showpackets->value) + { + if (send_reliable) + Com_Printf ("send %4i : s=%i reliable=%i ack=%i rack=%i\n" + , send.cursize + , chan->outgoing_sequence - 1 + , chan->reliable_sequence + , chan->incoming_sequence + , chan->incoming_reliable_sequence); + else + Com_Printf ("send %4i : s=%i ack=%i rack=%i\n" + , send.cursize + , chan->outgoing_sequence - 1 + , chan->incoming_sequence + , chan->incoming_reliable_sequence); + } +} + +/* +================= +Netchan_Process + +called when the current net_message is from remote_address +modifies net_message so that it points to the packet payload +================= +*/ +qboolean Netchan_Process (netchan_t *chan, sizebuf_t *msg) +{ + unsigned sequence, sequence_ack; + unsigned reliable_ack, reliable_message; + int qport; + +// get sequence numbers + MSG_BeginReading (msg); + sequence = MSG_ReadLong (msg); + sequence_ack = MSG_ReadLong (msg); + + // read the qport if we are a server + if (chan->sock == NS_SERVER) + qport = MSG_ReadShort (msg); + + reliable_message = sequence >> 31; + reliable_ack = sequence_ack >> 31; + + sequence &= ~(1<<31); + sequence_ack &= ~(1<<31); + + if (showpackets->value) + { + if (reliable_message) + Com_Printf ("recv %4i : s=%i reliable=%i ack=%i rack=%i\n" + , msg->cursize + , sequence + , chan->incoming_reliable_sequence ^ 1 + , sequence_ack + , reliable_ack); + else + Com_Printf ("recv %4i : s=%i ack=%i rack=%i\n" + , msg->cursize + , sequence + , sequence_ack + , reliable_ack); + } + +// +// discard stale or duplicated packets +// + if (sequence <= chan->incoming_sequence) + { + if (showdrop->value) + Com_Printf ("%s:Out of order packet %i at %i\n" + , NET_AdrToString (chan->remote_address) + , sequence + , chan->incoming_sequence); + return false; + } + +// +// dropped packets don't keep the message from being used +// + chan->dropped = sequence - (chan->incoming_sequence+1); + if (chan->dropped > 0) + { + if (showdrop->value) + Com_Printf ("%s:Dropped %i packets at %i\n" + , NET_AdrToString (chan->remote_address) + , chan->dropped + , sequence); + } + +// +// if the current outgoing reliable message has been acknowledged +// clear the buffer to make way for the next +// + if (reliable_ack == chan->reliable_sequence) + chan->reliable_length = 0; // it has been received + +// +// if this message contains a reliable message, bump incoming_reliable_sequence +// + chan->incoming_sequence = sequence; + chan->incoming_acknowledged = sequence_ack; + chan->incoming_reliable_acknowledged = reliable_ack; + if (reliable_message) + { + chan->incoming_reliable_sequence ^= 1; + } + +// +// the message can now be read from the current message pointer +// + chan->last_received = curtime; + + return true; +} + diff --git a/qcommon/pmove.c b/qcommon/pmove.c new file mode 100644 index 000000000..d597e27e7 --- /dev/null +++ b/qcommon/pmove.c @@ -0,0 +1,1360 @@ +/* +Copyright (C) 1997-2001 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. + +*/ + +#include "qcommon.h" + + + +#define STEPSIZE 18 + +// all of the locals will be zeroed before each +// pmove, just to make damn sure we don't have +// any differences when running on client or server + +typedef struct +{ + vec3_t origin; // full float precision + vec3_t velocity; // full float precision + + vec3_t forward, right, up; + float frametime; + + + csurface_t *groundsurface; + cplane_t groundplane; + int groundcontents; + + vec3_t previous_origin; + qboolean ladder; +} pml_t; + +pmove_t *pm; +pml_t pml; + + +// movement parameters +float pm_stopspeed = 100; +float pm_maxspeed = 300; +float pm_duckspeed = 100; +float pm_accelerate = 10; +float pm_airaccelerate = 0; +float pm_wateraccelerate = 10; +float pm_friction = 6; +float pm_waterfriction = 1; +float pm_waterspeed = 400; + +/* + + walking up a step should kill some velocity + +*/ + + +/* +================== +PM_ClipVelocity + +Slide off of the impacting object +returns the blocked flags (1 = floor, 2 = step / wall) +================== +*/ +#define STOP_EPSILON 0.1 + +void PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) +{ + float backoff; + float change; + int i; + + backoff = DotProduct (in, normal) * overbounce; + + for (i=0 ; i<3 ; i++) + { + change = normal[i]*backoff; + out[i] = in[i] - change; + if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) + out[i] = 0; + } +} + + + + +/* +================== +PM_StepSlideMove + +Each intersection will try to step over the obstruction instead of +sliding along it. + +Returns a new origin, velocity, and contact entity +Does not modify any world state? +================== +*/ +#define MIN_STEP_NORMAL 0.7 // can't step up onto very steep slopes +#define MAX_CLIP_PLANES 5 +void PM_StepSlideMove_ (void) +{ + int bumpcount, numbumps; + vec3_t dir; + float d; + int numplanes; + vec3_t planes[MAX_CLIP_PLANES]; + vec3_t primal_velocity; + int i, j; + trace_t trace; + vec3_t end; + float time_left; + + numbumps = 4; + + VectorCopy (pml.velocity, primal_velocity); + numplanes = 0; + + time_left = pml.frametime; + + for (bumpcount=0 ; bumpcounttrace (pml.origin, pm->mins, pm->maxs, end); + + if (trace.allsolid) + { // entity is trapped in another solid + pml.velocity[2] = 0; // don't build up falling damage + return; + } + + if (trace.fraction > 0) + { // actually covered some distance + VectorCopy (trace.endpos, pml.origin); + numplanes = 0; + } + + if (trace.fraction == 1) + break; // moved the entire distance + + // save entity for contact + if (pm->numtouch < MAXTOUCH && trace.ent) + { + pm->touchents[pm->numtouch] = trace.ent; + pm->numtouch++; + } + + time_left -= time_left * trace.fraction; + + // slide along this plane + if (numplanes >= MAX_CLIP_PLANES) + { // this shouldn't really happen + VectorCopy (vec3_origin, pml.velocity); + break; + } + + VectorCopy (trace.plane.normal, planes[numplanes]); + numplanes++; + +#if 0 + float rub; + + // + // modify velocity so it parallels all of the clip planes + // + if (numplanes == 1) + { // go along this plane + VectorCopy (pml.velocity, dir); + VectorNormalize (dir); + rub = 1.0 + 0.5 * DotProduct (dir, planes[0]); + + // slide along the plane + PM_ClipVelocity (pml.velocity, planes[0], pml.velocity, 1.01); + // rub some extra speed off on xy axis + // not on Z, or you can scrub down walls + pml.velocity[0] *= rub; + pml.velocity[1] *= rub; + pml.velocity[2] *= rub; + } + else if (numplanes == 2) + { // go along the crease + VectorCopy (pml.velocity, dir); + VectorNormalize (dir); + rub = 1.0 + 0.5 * DotProduct (dir, planes[0]); + + // slide along the plane + CrossProduct (planes[0], planes[1], dir); + d = DotProduct (dir, pml.velocity); + VectorScale (dir, d, pml.velocity); + + // rub some extra speed off + VectorScale (pml.velocity, rub, pml.velocity); + } + else + { +// Con_Printf ("clip velocity, numplanes == %i\n",numplanes); + VectorCopy (vec3_origin, pml.velocity); + break; + } + +#else +// +// modify original_velocity so it parallels all of the clip planes +// + for (i=0 ; is.pm_time) + { + VectorCopy (primal_velocity, pml.velocity); + } +} + +/* +================== +PM_StepSlideMove + +================== +*/ +void PM_StepSlideMove (void) +{ + vec3_t start_o, start_v; + vec3_t down_o, down_v; + trace_t trace; + float down_dist, up_dist; +// vec3_t delta; + vec3_t up, down; + + VectorCopy (pml.origin, start_o); + VectorCopy (pml.velocity, start_v); + + PM_StepSlideMove_ (); + + VectorCopy (pml.origin, down_o); + VectorCopy (pml.velocity, down_v); + + VectorCopy (start_o, up); + up[2] += STEPSIZE; + + trace = pm->trace (up, pm->mins, pm->maxs, up); + if (trace.allsolid) + return; // can't step up + + // try sliding above + VectorCopy (up, pml.origin); + VectorCopy (start_v, pml.velocity); + + PM_StepSlideMove_ (); + + // push down the final amount + VectorCopy (pml.origin, down); + down[2] -= STEPSIZE; + trace = pm->trace (pml.origin, pm->mins, pm->maxs, down); + if (!trace.allsolid) + { + VectorCopy (trace.endpos, pml.origin); + } + +#if 0 + VectorSubtract (pml.origin, up, delta); + up_dist = DotProduct (delta, start_v); + + VectorSubtract (down_o, start_o, delta); + down_dist = DotProduct (delta, start_v); +#else + VectorCopy(pml.origin, up); + + // decide which one went farther + down_dist = (down_o[0] - start_o[0])*(down_o[0] - start_o[0]) + + (down_o[1] - start_o[1])*(down_o[1] - start_o[1]); + up_dist = (up[0] - start_o[0])*(up[0] - start_o[0]) + + (up[1] - start_o[1])*(up[1] - start_o[1]); +#endif + + if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL) + { + VectorCopy (down_o, pml.origin); + VectorCopy (down_v, pml.velocity); + return; + } + //!! Special case + // if we were walking along a plane, then we need to copy the Z over + pml.velocity[2] = down_v[2]; +} + + +/* +================== +PM_Friction + +Handles both ground friction and water friction +================== +*/ +void PM_Friction (void) +{ + float *vel; + float speed, newspeed, control; + float friction; + float drop; + + vel = pml.velocity; + + speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]); + if (speed < 1) + { + vel[0] = 0; + vel[1] = 0; + return; + } + + drop = 0; + +// apply ground friction + if ((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK) ) || (pml.ladder) ) + { + friction = pm_friction; + control = speed < pm_stopspeed ? pm_stopspeed : speed; + drop += control*friction*pml.frametime; + } + +// apply water friction + if (pm->waterlevel && !pml.ladder) + drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime; + +// scale the velocity + newspeed = speed - drop; + if (newspeed < 0) + { + newspeed = 0; + } + newspeed /= speed; + + vel[0] = vel[0] * newspeed; + vel[1] = vel[1] * newspeed; + vel[2] = vel[2] * newspeed; +} + + +/* +============== +PM_Accelerate + +Handles user intended acceleration +============== +*/ +void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel) +{ + int i; + float addspeed, accelspeed, currentspeed; + + currentspeed = DotProduct (pml.velocity, wishdir); + addspeed = wishspeed - currentspeed; + if (addspeed <= 0) + return; + accelspeed = accel*pml.frametime*wishspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + pml.velocity[i] += accelspeed*wishdir[i]; +} + +void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel) +{ + int i; + float addspeed, accelspeed, currentspeed, wishspd = wishspeed; + + if (wishspd > 30) + wishspd = 30; + currentspeed = DotProduct (pml.velocity, wishdir); + addspeed = wishspd - currentspeed; + if (addspeed <= 0) + return; + accelspeed = accel * wishspeed * pml.frametime; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + pml.velocity[i] += accelspeed*wishdir[i]; +} + +/* +============= +PM_AddCurrents +============= +*/ +void PM_AddCurrents (vec3_t wishvel) +{ + vec3_t v; + float s; + + // + // account for ladders + // + + if (pml.ladder && fabs(pml.velocity[2]) <= 200) + { + if ((pm->viewangles[PITCH] <= -15) && (pm->cmd.forwardmove > 0)) + wishvel[2] = 200; + else if ((pm->viewangles[PITCH] >= 15) && (pm->cmd.forwardmove > 0)) + wishvel[2] = -200; + else if (pm->cmd.upmove > 0) + wishvel[2] = 200; + else if (pm->cmd.upmove < 0) + wishvel[2] = -200; + else + wishvel[2] = 0; + + // limit horizontal speed when on a ladder + if (wishvel[0] < -25) + wishvel[0] = -25; + else if (wishvel[0] > 25) + wishvel[0] = 25; + + if (wishvel[1] < -25) + wishvel[1] = -25; + else if (wishvel[1] > 25) + wishvel[1] = 25; + } + + + // + // add water currents + // + + if (pm->watertype & MASK_CURRENT) + { + VectorClear (v); + + if (pm->watertype & CONTENTS_CURRENT_0) + v[0] += 1; + if (pm->watertype & CONTENTS_CURRENT_90) + v[1] += 1; + if (pm->watertype & CONTENTS_CURRENT_180) + v[0] -= 1; + if (pm->watertype & CONTENTS_CURRENT_270) + v[1] -= 1; + if (pm->watertype & CONTENTS_CURRENT_UP) + v[2] += 1; + if (pm->watertype & CONTENTS_CURRENT_DOWN) + v[2] -= 1; + + s = pm_waterspeed; + if ((pm->waterlevel == 1) && (pm->groundentity)) + s /= 2; + + VectorMA (wishvel, s, v, wishvel); + } + + // + // add conveyor belt velocities + // + + if (pm->groundentity) + { + VectorClear (v); + + if (pml.groundcontents & CONTENTS_CURRENT_0) + v[0] += 1; + if (pml.groundcontents & CONTENTS_CURRENT_90) + v[1] += 1; + if (pml.groundcontents & CONTENTS_CURRENT_180) + v[0] -= 1; + if (pml.groundcontents & CONTENTS_CURRENT_270) + v[1] -= 1; + if (pml.groundcontents & CONTENTS_CURRENT_UP) + v[2] += 1; + if (pml.groundcontents & CONTENTS_CURRENT_DOWN) + v[2] -= 1; + + VectorMA (wishvel, 100 /* pm->groundentity->speed */, v, wishvel); + } +} + + +/* +=================== +PM_WaterMove + +=================== +*/ +void PM_WaterMove (void) +{ + int i; + vec3_t wishvel; + float wishspeed; + vec3_t wishdir; + +// +// user intentions +// + for (i=0 ; i<3 ; i++) + wishvel[i] = pml.forward[i]*pm->cmd.forwardmove + pml.right[i]*pm->cmd.sidemove; + + if (!pm->cmd.forwardmove && !pm->cmd.sidemove && !pm->cmd.upmove) + wishvel[2] -= 60; // drift towards bottom + else + wishvel[2] += pm->cmd.upmove; + + PM_AddCurrents (wishvel); + + VectorCopy (wishvel, wishdir); + wishspeed = VectorNormalize(wishdir); + + if (wishspeed > pm_maxspeed) + { + VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel); + wishspeed = pm_maxspeed; + } + wishspeed *= 0.5; + + PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate); + + PM_StepSlideMove (); +} + + +/* +=================== +PM_AirMove + +=================== +*/ +void PM_AirMove (void) +{ + int i; + vec3_t wishvel; + float fmove, smove; + vec3_t wishdir; + float wishspeed; + float maxspeed; + + fmove = pm->cmd.forwardmove; + smove = pm->cmd.sidemove; + +//!!!!! pitch should be 1/3 so this isn't needed??! +#if 0 + pml.forward[2] = 0; + pml.right[2] = 0; + VectorNormalize (pml.forward); + VectorNormalize (pml.right); +#endif + + for (i=0 ; i<2 ; i++) + wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; + wishvel[2] = 0; + + PM_AddCurrents (wishvel); + + VectorCopy (wishvel, wishdir); + wishspeed = VectorNormalize(wishdir); + +// +// clamp to server defined max speed +// + maxspeed = (pm->s.pm_flags & PMF_DUCKED) ? pm_duckspeed : pm_maxspeed; + + if (wishspeed > maxspeed) + { + VectorScale (wishvel, maxspeed/wishspeed, wishvel); + wishspeed = maxspeed; + } + + if ( pml.ladder ) + { + PM_Accelerate (wishdir, wishspeed, pm_accelerate); + if (!wishvel[2]) + { + if (pml.velocity[2] > 0) + { + pml.velocity[2] -= pm->s.gravity * pml.frametime; + if (pml.velocity[2] < 0) + pml.velocity[2] = 0; + } + else + { + pml.velocity[2] += pm->s.gravity * pml.frametime; + if (pml.velocity[2] > 0) + pml.velocity[2] = 0; + } + } + PM_StepSlideMove (); + } + else if ( pm->groundentity ) + { // walking on ground + pml.velocity[2] = 0; //!!! this is before the accel + PM_Accelerate (wishdir, wishspeed, pm_accelerate); + +// PGM -- fix for negative trigger_gravity fields +// pml.velocity[2] = 0; + if(pm->s.gravity > 0) + pml.velocity[2] = 0; + else + pml.velocity[2] -= pm->s.gravity * pml.frametime; +// PGM + + if (!pml.velocity[0] && !pml.velocity[1]) + return; + PM_StepSlideMove (); + } + else + { // not on ground, so little effect on velocity + if (pm_airaccelerate) + PM_AirAccelerate (wishdir, wishspeed, pm_accelerate); + else + PM_Accelerate (wishdir, wishspeed, 1); + // add gravity + pml.velocity[2] -= pm->s.gravity * pml.frametime; + PM_StepSlideMove (); + } +} + + + +/* +============= +PM_CatagorizePosition +============= +*/ +void PM_CatagorizePosition (void) +{ + vec3_t point; + int cont; + trace_t trace; + int sample1; + int sample2; + +// if the player hull point one unit down is solid, the player +// is on ground + +// see if standing on something solid + point[0] = pml.origin[0]; + point[1] = pml.origin[1]; + point[2] = pml.origin[2] - 0.25; + if (pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp accel) + { + pm->s.pm_flags &= ~PMF_ON_GROUND; + pm->groundentity = NULL; + } + else + { + trace = pm->trace (pml.origin, pm->mins, pm->maxs, point); + pml.groundplane = trace.plane; + pml.groundsurface = trace.surface; + pml.groundcontents = trace.contents; + + if (!trace.ent || (trace.plane.normal[2] < 0.7 && !trace.startsolid) ) + { + pm->groundentity = NULL; + pm->s.pm_flags &= ~PMF_ON_GROUND; + } + else + { + pm->groundentity = trace.ent; + + // hitting solid ground will end a waterjump + if (pm->s.pm_flags & PMF_TIME_WATERJUMP) + { + pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT); + pm->s.pm_time = 0; + } + + if (! (pm->s.pm_flags & PMF_ON_GROUND) ) + { // just hit the ground + pm->s.pm_flags |= PMF_ON_GROUND; + // don't do landing time if we were just going down a slope + if (pml.velocity[2] < -200) + { + pm->s.pm_flags |= PMF_TIME_LAND; + // don't allow another jump for a little while + if (pml.velocity[2] < -400) + pm->s.pm_time = 25; + else + pm->s.pm_time = 18; + } + } + } + +#if 0 + if (trace.fraction < 1.0 && trace.ent && pml.velocity[2] < 0) + pml.velocity[2] = 0; +#endif + + if (pm->numtouch < MAXTOUCH && trace.ent) + { + pm->touchents[pm->numtouch] = trace.ent; + pm->numtouch++; + } + } + +// +// get waterlevel, accounting for ducking +// + pm->waterlevel = 0; + pm->watertype = 0; + + sample2 = pm->viewheight - pm->mins[2]; + sample1 = sample2 / 2; + + point[2] = pml.origin[2] + pm->mins[2] + 1; + cont = pm->pointcontents (point); + + if (cont & MASK_WATER) + { + pm->watertype = cont; + pm->waterlevel = 1; + point[2] = pml.origin[2] + pm->mins[2] + sample1; + cont = pm->pointcontents (point); + if (cont & MASK_WATER) + { + pm->waterlevel = 2; + point[2] = pml.origin[2] + pm->mins[2] + sample2; + cont = pm->pointcontents (point); + if (cont & MASK_WATER) + pm->waterlevel = 3; + } + } + +} + + +/* +============= +PM_CheckJump +============= +*/ +void PM_CheckJump (void) +{ + if (pm->s.pm_flags & PMF_TIME_LAND) + { // hasn't been long enough since landing to jump again + return; + } + + if (pm->cmd.upmove < 10) + { // not holding jump + pm->s.pm_flags &= ~PMF_JUMP_HELD; + return; + } + + // must wait for jump to be released + if (pm->s.pm_flags & PMF_JUMP_HELD) + return; + + if (pm->s.pm_type == PM_DEAD) + return; + + if (pm->waterlevel >= 2) + { // swimming, not jumping + pm->groundentity = NULL; + + if (pml.velocity[2] <= -300) + return; + + if (pm->watertype == CONTENTS_WATER) + pml.velocity[2] = 100; + else if (pm->watertype == CONTENTS_SLIME) + pml.velocity[2] = 80; + else + pml.velocity[2] = 50; + return; + } + + if (pm->groundentity == NULL) + return; // in air, so no effect + + pm->s.pm_flags |= PMF_JUMP_HELD; + + pm->groundentity = NULL; + pml.velocity[2] += 270; + if (pml.velocity[2] < 270) + pml.velocity[2] = 270; +} + + +/* +============= +PM_CheckSpecialMovement +============= +*/ +void PM_CheckSpecialMovement (void) +{ + vec3_t spot; + int cont; + vec3_t flatforward; + trace_t trace; + + if (pm->s.pm_time) + return; + + pml.ladder = false; + + // check for ladder + flatforward[0] = pml.forward[0]; + flatforward[1] = pml.forward[1]; + flatforward[2] = 0; + VectorNormalize (flatforward); + + VectorMA (pml.origin, 1, flatforward, spot); + trace = pm->trace (pml.origin, pm->mins, pm->maxs, spot); + if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER)) + pml.ladder = true; + + // check for water jump + if (pm->waterlevel != 2) + return; + + VectorMA (pml.origin, 30, flatforward, spot); + spot[2] += 4; + cont = pm->pointcontents (spot); + if (!(cont & CONTENTS_SOLID)) + return; + + spot[2] += 16; + cont = pm->pointcontents (spot); + if (cont) + return; + // jump out of water + VectorScale (flatforward, 50, pml.velocity); + pml.velocity[2] = 350; + + pm->s.pm_flags |= PMF_TIME_WATERJUMP; + pm->s.pm_time = 255; +} + + +/* +=============== +PM_FlyMove +=============== +*/ +void PM_FlyMove (qboolean doclip) +{ + float speed, drop, friction, control, newspeed; + float currentspeed, addspeed, accelspeed; + int i; + vec3_t wishvel; + float fmove, smove; + vec3_t wishdir; + float wishspeed; + vec3_t end; + trace_t trace; + + pm->viewheight = 22; + + // friction + + speed = VectorLength (pml.velocity); + if (speed < 1) + { + VectorCopy (vec3_origin, pml.velocity); + } + else + { + drop = 0; + + friction = pm_friction*1.5; // extra friction + control = speed < pm_stopspeed ? pm_stopspeed : speed; + drop += control*friction*pml.frametime; + + // scale the velocity + newspeed = speed - drop; + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + + VectorScale (pml.velocity, newspeed, pml.velocity); + } + + // accelerate + fmove = pm->cmd.forwardmove; + smove = pm->cmd.sidemove; + + VectorNormalize (pml.forward); + VectorNormalize (pml.right); + + for (i=0 ; i<3 ; i++) + wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; + wishvel[2] += pm->cmd.upmove; + + VectorCopy (wishvel, wishdir); + wishspeed = VectorNormalize(wishdir); + + // + // clamp to server defined max speed + // + if (wishspeed > pm_maxspeed) + { + VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel); + wishspeed = pm_maxspeed; + } + + + currentspeed = DotProduct(pml.velocity, wishdir); + addspeed = wishspeed - currentspeed; + if (addspeed <= 0) + return; + accelspeed = pm_accelerate*pml.frametime*wishspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + pml.velocity[i] += accelspeed*wishdir[i]; + + if (doclip) { + for (i=0 ; i<3 ; i++) + end[i] = pml.origin[i] + pml.frametime * pml.velocity[i]; + + trace = pm->trace (pml.origin, pm->mins, pm->maxs, end); + + VectorCopy (trace.endpos, pml.origin); + } else { + // move + VectorMA (pml.origin, pml.frametime, pml.velocity, pml.origin); + } +} + + +/* +============== +PM_CheckDuck + +Sets mins, maxs, and pm->viewheight +============== +*/ +void PM_CheckDuck (void) +{ + trace_t trace; + + pm->mins[0] = -16; + pm->mins[1] = -16; + + pm->maxs[0] = 16; + pm->maxs[1] = 16; + + if (pm->s.pm_type == PM_GIB) + { + pm->mins[2] = 0; + pm->maxs[2] = 16; + pm->viewheight = 8; + return; + } + + pm->mins[2] = -24; + + if (pm->s.pm_type == PM_DEAD) + { + pm->s.pm_flags |= PMF_DUCKED; + } + else if (pm->cmd.upmove < 0 && (pm->s.pm_flags & PMF_ON_GROUND) ) + { // duck + pm->s.pm_flags |= PMF_DUCKED; + } + else + { // stand up if possible + if (pm->s.pm_flags & PMF_DUCKED) + { + // try to stand up + pm->maxs[2] = 32; + trace = pm->trace (pml.origin, pm->mins, pm->maxs, pml.origin); + if (!trace.allsolid) + pm->s.pm_flags &= ~PMF_DUCKED; + } + } + + if (pm->s.pm_flags & PMF_DUCKED) + { + pm->maxs[2] = 4; + pm->viewheight = -2; + } + else + { + pm->maxs[2] = 32; + pm->viewheight = 22; + } +} + + +/* +============== +PM_DeadMove +============== +*/ +void PM_DeadMove (void) +{ + float forward; + + if (!pm->groundentity) + return; + + // extra friction + + forward = VectorLength (pml.velocity); + forward -= 20; + if (forward <= 0) + { + VectorClear (pml.velocity); + } + else + { + VectorNormalize (pml.velocity); + VectorScale (pml.velocity, forward, pml.velocity); + } +} + + +qboolean PM_GoodPosition (void) +{ + trace_t trace; + vec3_t origin, end; + int i; + + if (pm->s.pm_type == PM_SPECTATOR) + return true; + + for (i=0 ; i<3 ; i++) + origin[i] = end[i] = pm->s.origin[i]*0.125; + trace = pm->trace (origin, pm->mins, pm->maxs, end); + + return !trace.allsolid; +} + +/* +================ +PM_SnapPosition + +On exit, the origin will have a value that is pre-quantized to the 0.125 +precision of the network channel and in a valid position. +================ +*/ +void PM_SnapPosition (void) +{ + int sign[3]; + int i, j, bits; + short base[3]; + // try all single bits first + static int jitterbits[8] = {0,4,1,2,3,5,6,7}; + + // snap velocity to eigths + for (i=0 ; i<3 ; i++) + pm->s.velocity[i] = (int)(pml.velocity[i]*8); + + for (i=0 ; i<3 ; i++) + { + if (pml.origin[i] >= 0) + sign[i] = 1; + else + sign[i] = -1; + pm->s.origin[i] = (int)(pml.origin[i]*8); + if (pm->s.origin[i]*0.125 == pml.origin[i]) + sign[i] = 0; + } + VectorCopy (pm->s.origin, base); + + // try all combinations + for (j=0 ; j<8 ; j++) + { + bits = jitterbits[j]; + VectorCopy (base, pm->s.origin); + for (i=0 ; i<3 ; i++) + if (bits & (1<s.origin[i] += sign[i]; + + if (PM_GoodPosition ()) + return; + } + + // go back to the last position + VectorCopy (pml.previous_origin, pm->s.origin); +// Com_DPrintf ("using previous_origin\n"); +} + +#if 0 +//NO LONGER USED +/* +================ +PM_InitialSnapPosition + +================ +*/ +void PM_InitialSnapPosition (void) +{ + int x, y, z; + short base[3]; + + VectorCopy (pm->s.origin, base); + + for (z=1 ; z>=-1 ; z--) + { + pm->s.origin[2] = base[2] + z; + for (y=1 ; y>=-1 ; y--) + { + pm->s.origin[1] = base[1] + y; + for (x=1 ; x>=-1 ; x--) + { + pm->s.origin[0] = base[0] + x; + if (PM_GoodPosition ()) + { + pml.origin[0] = pm->s.origin[0]*0.125; + pml.origin[1] = pm->s.origin[1]*0.125; + pml.origin[2] = pm->s.origin[2]*0.125; + VectorCopy (pm->s.origin, pml.previous_origin); + return; + } + } + } + } + + Com_DPrintf ("Bad InitialSnapPosition\n"); +} +#else +/* +================ +PM_InitialSnapPosition + +================ +*/ +void PM_InitialSnapPosition(void) +{ + int x, y, z; + short base[3]; + static int offset[3] = { 0, -1, 1 }; + + VectorCopy (pm->s.origin, base); + + for ( z = 0; z < 3; z++ ) { + pm->s.origin[2] = base[2] + offset[ z ]; + for ( y = 0; y < 3; y++ ) { + pm->s.origin[1] = base[1] + offset[ y ]; + for ( x = 0; x < 3; x++ ) { + pm->s.origin[0] = base[0] + offset[ x ]; + if (PM_GoodPosition ()) { + pml.origin[0] = pm->s.origin[0]*0.125; + pml.origin[1] = pm->s.origin[1]*0.125; + pml.origin[2] = pm->s.origin[2]*0.125; + VectorCopy (pm->s.origin, pml.previous_origin); + return; + } + } + } + } + + Com_DPrintf ("Bad InitialSnapPosition\n"); +} + +#endif + +/* +================ +PM_ClampAngles + +================ +*/ +void PM_ClampAngles (void) +{ + short temp; + int i; + + if (pm->s.pm_flags & PMF_TIME_TELEPORT) + { + pm->viewangles[YAW] = SHORT2ANGLE(pm->cmd.angles[YAW] + pm->s.delta_angles[YAW]); + pm->viewangles[PITCH] = 0; + pm->viewangles[ROLL] = 0; + } + else + { + // circularly clamp the angles with deltas + for (i=0 ; i<3 ; i++) + { + temp = pm->cmd.angles[i] + pm->s.delta_angles[i]; + pm->viewangles[i] = SHORT2ANGLE(temp); + } + + // don't let the player look up or down more than 90 degrees + if (pm->viewangles[PITCH] > 89 && pm->viewangles[PITCH] < 180) + pm->viewangles[PITCH] = 89; + else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180) + pm->viewangles[PITCH] = 271; + } + AngleVectors (pm->viewangles, pml.forward, pml.right, pml.up); +} + +/* +================ +Pmove + +Can be called by either the server or the client +================ +*/ +void Pmove (pmove_t *pmove) +{ + pm = pmove; + + // clear results + pm->numtouch = 0; + VectorClear (pm->viewangles); + pm->viewheight = 0; + pm->groundentity = 0; + pm->watertype = 0; + pm->waterlevel = 0; + + // clear all pmove local vars + memset (&pml, 0, sizeof(pml)); + + // convert origin and velocity to float values + pml.origin[0] = pm->s.origin[0]*0.125; + pml.origin[1] = pm->s.origin[1]*0.125; + pml.origin[2] = pm->s.origin[2]*0.125; + + pml.velocity[0] = pm->s.velocity[0]*0.125; + pml.velocity[1] = pm->s.velocity[1]*0.125; + pml.velocity[2] = pm->s.velocity[2]*0.125; + + // save old org in case we get stuck + VectorCopy (pm->s.origin, pml.previous_origin); + + pml.frametime = pm->cmd.msec * 0.001; + + PM_ClampAngles (); + + if (pm->s.pm_type == PM_SPECTATOR) + { + PM_FlyMove (false); + PM_SnapPosition (); + return; + } + + if (pm->s.pm_type >= PM_DEAD) + { + pm->cmd.forwardmove = 0; + pm->cmd.sidemove = 0; + pm->cmd.upmove = 0; + } + + if (pm->s.pm_type == PM_FREEZE) + return; // no movement at all + + // set mins, maxs, and viewheight + PM_CheckDuck (); + + if (pm->snapinitial) + PM_InitialSnapPosition (); + + // set groundentity, watertype, and waterlevel + PM_CatagorizePosition (); + + if (pm->s.pm_type == PM_DEAD) + PM_DeadMove (); + + PM_CheckSpecialMovement (); + + // drop timing counter + if (pm->s.pm_time) + { + int msec; + + msec = pm->cmd.msec >> 3; + if (!msec) + msec = 1; + if ( msec >= pm->s.pm_time) + { + pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT); + pm->s.pm_time = 0; + } + else + pm->s.pm_time -= msec; + } + + if (pm->s.pm_flags & PMF_TIME_TELEPORT) + { // teleport pause stays exactly in place + } + else if (pm->s.pm_flags & PMF_TIME_WATERJUMP) + { // waterjump has no control, but falls + pml.velocity[2] -= pm->s.gravity * pml.frametime; + if (pml.velocity[2] < 0) + { // cancel as soon as we are falling down again + pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT); + pm->s.pm_time = 0; + } + + PM_StepSlideMove (); + } + else + { + PM_CheckJump (); + + PM_Friction (); + + if (pm->waterlevel >= 2) + PM_WaterMove (); + else { + vec3_t angles; + + VectorCopy(pm->viewangles, angles); + if (angles[PITCH] > 180) + angles[PITCH] = angles[PITCH] - 360; + angles[PITCH] /= 3; + + AngleVectors (angles, pml.forward, pml.right, pml.up); + + PM_AirMove (); + } + } + + // set groundentity, watertype, and waterlevel for final spot + PM_CatagorizePosition (); + + PM_SnapPosition (); +} + diff --git a/qcommon/qcommon.h b/qcommon/qcommon.h new file mode 100644 index 000000000..9481b4c46 --- /dev/null +++ b/qcommon/qcommon.h @@ -0,0 +1,826 @@ +/* +Copyright (C) 1997-2001 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. + +*/ + +// qcommon.h -- definitions common between client and server, but not game.dll + +#include "../game/q_shared.h" + + +#define VERSION 3.19 + +#define BASEDIRNAME "baseq2" + +#ifdef WIN32 + +#ifdef NDEBUG +#define BUILDSTRING "Win32 RELEASE" +#else +#define BUILDSTRING "Win32 DEBUG" +#endif + +#ifdef _M_IX86 +#define CPUSTRING "x86" +#elif defined _M_ALPHA +#define CPUSTRING "AXP" +#endif + +#elif defined __linux__ + +#define BUILDSTRING "Linux" + +#ifdef __i386__ +#define CPUSTRING "i386" +#elif defined __alpha__ +#define CPUSTRING "axp" +#else +#define CPUSTRING "Unknown" +#endif + +#elif defined __sun__ + +#define BUILDSTRING "Solaris" + +#ifdef __i386__ +#define CPUSTRING "i386" +#else +#define CPUSTRING "sparc" +#endif + +#else // !WIN32 + +#define BUILDSTRING "NON-WIN32" +#define CPUSTRING "NON-WIN32" + +#endif + +//============================================================================ + +typedef struct sizebuf_s +{ + qboolean allowoverflow; // if false, do a Com_Error + qboolean overflowed; // set to true if the buffer size failed + byte *data; + int maxsize; + int cursize; + int readcount; +} sizebuf_t; + +void SZ_Init (sizebuf_t *buf, byte *data, int length); +void SZ_Clear (sizebuf_t *buf); +void *SZ_GetSpace (sizebuf_t *buf, int length); +void SZ_Write (sizebuf_t *buf, void *data, int length); +void SZ_Print (sizebuf_t *buf, char *data); // strcats onto the sizebuf + +//============================================================================ + +struct usercmd_s; +struct entity_state_s; + +void MSG_WriteChar (sizebuf_t *sb, int c); +void MSG_WriteByte (sizebuf_t *sb, int c); +void MSG_WriteShort (sizebuf_t *sb, int c); +void MSG_WriteLong (sizebuf_t *sb, int c); +void MSG_WriteFloat (sizebuf_t *sb, float f); +void MSG_WriteString (sizebuf_t *sb, char *s); +void MSG_WriteCoord (sizebuf_t *sb, float f); +void MSG_WritePos (sizebuf_t *sb, vec3_t pos); +void MSG_WriteAngle (sizebuf_t *sb, float f); +void MSG_WriteAngle16 (sizebuf_t *sb, float f); +void MSG_WriteDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct usercmd_s *cmd); +void MSG_WriteDeltaEntity (struct entity_state_s *from, struct entity_state_s *to, sizebuf_t *msg, qboolean force, qboolean newentity); +void MSG_WriteDir (sizebuf_t *sb, vec3_t vector); + + +void MSG_BeginReading (sizebuf_t *sb); + +int MSG_ReadChar (sizebuf_t *sb); +int MSG_ReadByte (sizebuf_t *sb); +int MSG_ReadShort (sizebuf_t *sb); +int MSG_ReadLong (sizebuf_t *sb); +float MSG_ReadFloat (sizebuf_t *sb); +char *MSG_ReadString (sizebuf_t *sb); +char *MSG_ReadStringLine (sizebuf_t *sb); + +float MSG_ReadCoord (sizebuf_t *sb); +void MSG_ReadPos (sizebuf_t *sb, vec3_t pos); +float MSG_ReadAngle (sizebuf_t *sb); +float MSG_ReadAngle16 (sizebuf_t *sb); +void MSG_ReadDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct usercmd_s *cmd); + +void MSG_ReadDir (sizebuf_t *sb, vec3_t vector); + +void MSG_ReadData (sizebuf_t *sb, void *buffer, int size); + +//============================================================================ + +extern qboolean bigendien; + +extern short BigShort (short l); +extern short LittleShort (short l); +extern int BigLong (int l); +extern int LittleLong (int l); +extern float BigFloat (float l); +extern float LittleFloat (float l); + +//============================================================================ + + +int COM_Argc (void); +char *COM_Argv (int arg); // range and null checked +void COM_ClearArgv (int arg); +int COM_CheckParm (char *parm); +void COM_AddParm (char *parm); + +void COM_Init (void); +void COM_InitArgv (int argc, char **argv); + +char *CopyString (char *in); + +//============================================================================ + +void Info_Print (char *s); + + +/* crc.h */ + +void CRC_Init(unsigned short *crcvalue); +void CRC_ProcessByte(unsigned short *crcvalue, byte data); +unsigned short CRC_Value(unsigned short crcvalue); +unsigned short CRC_Block (byte *start, int count); + + + +/* +============================================================== + +PROTOCOL + +============================================================== +*/ + +// protocol.h -- communications protocols + +#define PROTOCOL_VERSION 34 + +//========================================= + +#define PORT_MASTER 27900 +#define PORT_CLIENT 27901 +#define PORT_SERVER 27910 + +//========================================= + +#define UPDATE_BACKUP 16 // copies of entity_state_t to keep buffered + // must be power of two +#define UPDATE_MASK (UPDATE_BACKUP-1) + + + +//================== +// the svc_strings[] array in cl_parse.c should mirror this +//================== + +// +// server to client +// +enum svc_ops_e +{ + svc_bad, + + // these ops are known to the game dll + svc_muzzleflash, + svc_muzzleflash2, + svc_temp_entity, + svc_layout, + svc_inventory, + + // the rest are private to the client and server + svc_nop, + svc_disconnect, + svc_reconnect, + svc_sound, // + svc_print, // [byte] id [string] null terminated string + svc_stufftext, // [string] stuffed into client's console buffer, should be \n terminated + svc_serverdata, // [long] protocol ... + svc_configstring, // [short] [string] + svc_spawnbaseline, + svc_centerprint, // [string] to put in center of the screen + svc_download, // [short] size [size bytes] + svc_playerinfo, // variable + svc_packetentities, // [...] + svc_deltapacketentities, // [...] + svc_frame +}; + +//============================================== + +// +// client to server +// +enum clc_ops_e +{ + clc_bad, + clc_nop, + clc_move, // [[usercmd_t] + clc_userinfo, // [[userinfo string] + clc_stringcmd // [string] message +}; + +//============================================== + +// plyer_state_t communication + +#define PS_M_TYPE (1<<0) +#define PS_M_ORIGIN (1<<1) +#define PS_M_VELOCITY (1<<2) +#define PS_M_TIME (1<<3) +#define PS_M_FLAGS (1<<4) +#define PS_M_GRAVITY (1<<5) +#define PS_M_DELTA_ANGLES (1<<6) + +#define PS_VIEWOFFSET (1<<7) +#define PS_VIEWANGLES (1<<8) +#define PS_KICKANGLES (1<<9) +#define PS_BLEND (1<<10) +#define PS_FOV (1<<11) +#define PS_WEAPONINDEX (1<<12) +#define PS_WEAPONFRAME (1<<13) +#define PS_RDFLAGS (1<<14) + +//============================================== + +// user_cmd_t communication + +// ms and light always sent, the others are optional +#define CM_ANGLE1 (1<<0) +#define CM_ANGLE2 (1<<1) +#define CM_ANGLE3 (1<<2) +#define CM_FORWARD (1<<3) +#define CM_SIDE (1<<4) +#define CM_UP (1<<5) +#define CM_BUTTONS (1<<6) +#define CM_IMPULSE (1<<7) + +//============================================== + +// a sound without an ent or pos will be a local only sound +#define SND_VOLUME (1<<0) // a byte +#define SND_ATTENUATION (1<<1) // a byte +#define SND_POS (1<<2) // three coordinates +#define SND_ENT (1<<3) // a short 0-2: channel, 3-12: entity +#define SND_OFFSET (1<<4) // a byte, msec offset from frame start + +#define DEFAULT_SOUND_PACKET_VOLUME 1.0 +#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0 + +//============================================== + +// entity_state_t communication + +// try to pack the common update flags into the first byte +#define U_ORIGIN1 (1<<0) +#define U_ORIGIN2 (1<<1) +#define U_ANGLE2 (1<<2) +#define U_ANGLE3 (1<<3) +#define U_FRAME8 (1<<4) // frame is a byte +#define U_EVENT (1<<5) +#define U_REMOVE (1<<6) // REMOVE this entity, don't add it +#define U_MOREBITS1 (1<<7) // read one additional byte + +// second byte +#define U_NUMBER16 (1<<8) // NUMBER8 is implicit if not set +#define U_ORIGIN3 (1<<9) +#define U_ANGLE1 (1<<10) +#define U_MODEL (1<<11) +#define U_RENDERFX8 (1<<12) // fullbright, etc +#define U_EFFECTS8 (1<<14) // autorotate, trails, etc +#define U_MOREBITS2 (1<<15) // read one additional byte + +// third byte +#define U_SKIN8 (1<<16) +#define U_FRAME16 (1<<17) // frame is a short +#define U_RENDERFX16 (1<<18) // 8 + 16 = 32 +#define U_EFFECTS16 (1<<19) // 8 + 16 = 32 +#define U_MODEL2 (1<<20) // weapons, flags, etc +#define U_MODEL3 (1<<21) +#define U_MODEL4 (1<<22) +#define U_MOREBITS3 (1<<23) // read one additional byte + +// fourth byte +#define U_OLDORIGIN (1<<24) // FIXME: get rid of this +#define U_SKIN16 (1<<25) +#define U_SOUND (1<<26) +#define U_SOLID (1<<27) + + +/* +============================================================== + +CMD + +Command text buffering and command execution + +============================================================== +*/ + +/* + +Any number of commands can be added in a frame, from several different sources. +Most commands come from either keybindings or console line input, but remote +servers can also send across commands and entire text files can be execed. + +The + command line options are also added to the command buffer. + +The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute (); + +*/ + +#define EXEC_NOW 0 // don't return until completed +#define EXEC_INSERT 1 // insert at current position, but don't run yet +#define EXEC_APPEND 2 // add to end of the command buffer + +void Cbuf_Init (void); +// allocates an initial text buffer that will grow as needed + +void Cbuf_AddText (char *text); +// as new commands are generated from the console or keybindings, +// the text is added to the end of the command buffer. + +void Cbuf_InsertText (char *text); +// when a command wants to issue other commands immediately, the text is +// inserted at the beginning of the buffer, before any remaining unexecuted +// commands. + +void Cbuf_ExecuteText (int exec_when, char *text); +// this can be used in place of either Cbuf_AddText or Cbuf_InsertText + +void Cbuf_AddEarlyCommands (qboolean clear); +// adds all the +set commands from the command line + +qboolean Cbuf_AddLateCommands (void); +// adds all the remaining + commands from the command line +// Returns true if any late commands were added, which +// will keep the demoloop from immediately starting + +void Cbuf_Execute (void); +// Pulls off \n terminated lines of text from the command buffer and sends +// them through Cmd_ExecuteString. Stops when the buffer is empty. +// Normally called once per frame, but may be explicitly invoked. +// Do not call inside a command function! + +void Cbuf_CopyToDefer (void); +void Cbuf_InsertFromDefer (void); +// These two functions are used to defer any pending commands while a map +// is being loaded + +//=========================================================================== + +/* + +Command execution takes a null terminated string, breaks it into tokens, +then searches for a command or variable that matches the first token. + +*/ + +typedef void (*xcommand_t) (void); + +void Cmd_Init (void); + +void Cmd_AddCommand (char *cmd_name, xcommand_t function); +// called by the init functions of other parts of the program to +// register commands and functions to call for them. +// The cmd_name is referenced later, so it should not be in temp memory +// if function is NULL, the command will be forwarded to the server +// as a clc_stringcmd instead of executed locally +void Cmd_RemoveCommand (char *cmd_name); + +qboolean Cmd_Exists (char *cmd_name); +// used by the cvar code to check for cvar / command name overlap + +char *Cmd_CompleteCommand (char *partial); +// attempts to match a partial command for automatic command line completion +// returns NULL if nothing fits + +int Cmd_Argc (void); +char *Cmd_Argv (int arg); +char *Cmd_Args (void); +// The functions that execute commands get their parameters with these +// functions. Cmd_Argv () will return an empty string, not a NULL +// if arg > argc, so string operations are always safe. + +void Cmd_TokenizeString (char *text, qboolean macroExpand); +// Takes a null terminated string. Does not need to be /n terminated. +// breaks the string up into arg tokens. + +void Cmd_ExecuteString (char *text); +// Parses a single line of text into arguments and tries to execute it +// as if it was typed at the console + +void Cmd_ForwardToServer (void); +// adds the current command line as a clc_stringcmd to the client message. +// things like godmode, noclip, etc, are commands directed to the server, +// so when they are typed in at the console, they will need to be forwarded. + + +/* +============================================================== + +CVAR + +============================================================== +*/ + +/* + +cvar_t variables are used to hold scalar or string variables that can be changed or displayed at the console or prog code as well as accessed directly +in C code. + +The user can access cvars from the console in three ways: +r_draworder prints the current value +r_draworder 0 sets the current value to 0 +set r_draworder 0 as above, but creates the cvar if not present +Cvars are restricted from having the same names as commands to keep this +interface from being ambiguous. +*/ + +extern cvar_t *cvar_vars; + +cvar_t *Cvar_Get (char *var_name, char *value, int flags); +// creates the variable if it doesn't exist, or returns the existing one +// if it exists, the value will not be changed, but flags will be ORed in +// that allows variables to be unarchived without needing bitflags + +cvar_t *Cvar_Set (char *var_name, char *value); +// will create the variable if it doesn't exist + +cvar_t *Cvar_ForceSet (char *var_name, char *value); +// will set the variable even if NOSET or LATCH + +cvar_t *Cvar_FullSet (char *var_name, char *value, int flags); + +void Cvar_SetValue (char *var_name, float value); +// expands value to a string and calls Cvar_Set + +float Cvar_VariableValue (char *var_name); +// returns 0 if not defined or non numeric + +char *Cvar_VariableString (char *var_name); +// returns an empty string if not defined + +char *Cvar_CompleteVariable (char *partial); +// attempts to match a partial variable name for command line completion +// returns NULL if nothing fits + +void Cvar_GetLatchedVars (void); +// any CVAR_LATCHED variables that have been set will now take effect + +qboolean Cvar_Command (void); +// called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known +// command. Returns true if the command was a variable reference that +// was handled. (print or change) + +void Cvar_WriteVariables (char *path); +// appends lines containing "set variable value" for all variables +// with the archive flag set to true. + +void Cvar_Init (void); + +char *Cvar_Userinfo (void); +// returns an info string containing all the CVAR_USERINFO cvars + +char *Cvar_Serverinfo (void); +// returns an info string containing all the CVAR_SERVERINFO cvars + +extern qboolean userinfo_modified; +// this is set each time a CVAR_USERINFO variable is changed +// so that the client knows to send it to the server + +/* +============================================================== + +NET + +============================================================== +*/ + +// net.h -- quake's interface to the networking layer + +#define PORT_ANY -1 + +#define MAX_MSGLEN 1400 // max length of a message +#define PACKET_HEADER 10 // two ints and a short + +typedef enum {NA_LOOPBACK, NA_BROADCAST, NA_IP, NA_IPX, NA_BROADCAST_IPX} netadrtype_t; + +typedef enum {NS_CLIENT, NS_SERVER} netsrc_t; + +typedef struct +{ + netadrtype_t type; + + byte ip[4]; + byte ipx[10]; + + unsigned short port; +} netadr_t; + +void NET_Init (void); +void NET_Shutdown (void); + +void NET_Config (qboolean multiplayer); + +qboolean NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message); +void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to); + +qboolean NET_CompareAdr (netadr_t a, netadr_t b); +qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b); +qboolean NET_IsLocalAddress (netadr_t adr); +char *NET_AdrToString (netadr_t a); +qboolean NET_StringToAdr (char *s, netadr_t *a); +void NET_Sleep(int msec); + +//============================================================================ + +#define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG) + +#define MAX_LATENT 32 + +typedef struct +{ + qboolean fatal_error; + + netsrc_t sock; + + int dropped; // between last packet and previous + + int last_received; // for timeouts + int last_sent; // for retransmits + + netadr_t remote_address; + int qport; // qport value to write when transmitting + +// sequencing variables + int incoming_sequence; + int incoming_acknowledged; + int incoming_reliable_acknowledged; // single bit + + int incoming_reliable_sequence; // single bit, maintained local + + int outgoing_sequence; + int reliable_sequence; // single bit + int last_reliable_sequence; // sequence number of last send + +// reliable staging and holding areas + sizebuf_t message; // writing buffer to send to server + byte message_buf[MAX_MSGLEN-16]; // leave space for header + +// message is copied to this buffer when it is first transfered + int reliable_length; + byte reliable_buf[MAX_MSGLEN-16]; // unacked reliable message +} netchan_t; + +extern netadr_t net_from; +extern sizebuf_t net_message; +extern byte net_message_buffer[MAX_MSGLEN]; + + +void Netchan_Init (void); +void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport); + +qboolean Netchan_NeedReliable (netchan_t *chan); +void Netchan_Transmit (netchan_t *chan, int length, byte *data); +void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data); +void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...); +qboolean Netchan_Process (netchan_t *chan, sizebuf_t *msg); + +qboolean Netchan_CanReliable (netchan_t *chan); + + +/* +============================================================== + +CMODEL + +============================================================== +*/ + + +#include "../qcommon/qfiles.h" + +cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum); +cmodel_t *CM_InlineModel (char *name); // *1, *2, etc + +int CM_NumClusters (void); +int CM_NumInlineModels (void); +char *CM_EntityString (void); + +// creates a clipping hull for an arbitrary box +int CM_HeadnodeForBox (vec3_t mins, vec3_t maxs); + + +// returns an ORed contents mask +int CM_PointContents (vec3_t p, int headnode); +int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles); + +trace_t CM_BoxTrace (vec3_t start, vec3_t end, + vec3_t mins, vec3_t maxs, + int headnode, int brushmask); +trace_t CM_TransformedBoxTrace (vec3_t start, vec3_t end, + vec3_t mins, vec3_t maxs, + int headnode, int brushmask, + vec3_t origin, vec3_t angles); + +byte *CM_ClusterPVS (int cluster); +byte *CM_ClusterPHS (int cluster); + +int CM_PointLeafnum (vec3_t p); + +// call with topnode set to the headnode, returns with topnode +// set to the first node that splits the box +int CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list, + int listsize, int *topnode); + +int CM_LeafContents (int leafnum); +int CM_LeafCluster (int leafnum); +int CM_LeafArea (int leafnum); + +void CM_SetAreaPortalState (int portalnum, qboolean open); +qboolean CM_AreasConnected (int area1, int area2); + +int CM_WriteAreaBits (byte *buffer, int area); +qboolean CM_HeadnodeVisible (int headnode, byte *visbits); + +void CM_WritePortalState (FILE *f); +void CM_ReadPortalState (FILE *f); + +/* +============================================================== + +PLAYER MOVEMENT CODE + +Common between server and client so prediction matches + +============================================================== +*/ + +extern float pm_airaccelerate; + +void Pmove (pmove_t *pmove); + +/* +============================================================== + +FILESYSTEM + +============================================================== +*/ + +void FS_InitFilesystem (void); +void FS_SetGamedir (char *dir); +char *FS_Gamedir (void); +char *FS_NextPath (char *prevpath); +void FS_ExecAutoexec (void); + +int FS_FOpenFile (char *filename, FILE **file); +void FS_FCloseFile (FILE *f); +// note: this can't be called from another DLL, due to MS libc issues + +int FS_LoadFile (char *path, void **buffer); +// a null buffer will just return the file length without loading +// a -1 length is not present + +void FS_Read (void *buffer, int len, FILE *f); +// properly handles partial reads + +void FS_FreeFile (void *buffer); + +void FS_CreatePath (char *path); + + +/* +============================================================== + +MISC + +============================================================== +*/ + + +#define ERR_FATAL 0 // exit the entire game with a popup window +#define ERR_DROP 1 // print to console and disconnect from game +#define ERR_QUIT 2 // not an error, just a normal exit + +#define EXEC_NOW 0 // don't return until completed +#define EXEC_INSERT 1 // insert at current position, but don't run yet +#define EXEC_APPEND 2 // add to end of the command buffer + +#define PRINT_ALL 0 +#define PRINT_DEVELOPER 1 // only print when "developer 1" + +void Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush)); +void Com_EndRedirect (void); +void Com_Printf (char *fmt, ...); +void Com_DPrintf (char *fmt, ...); +void Com_Error (int code, char *fmt, ...); +void Com_Quit (void); + +int Com_ServerState (void); // this should have just been a cvar... +void Com_SetServerState (int state); + +unsigned Com_BlockChecksum (void *buffer, int length); +byte COM_BlockSequenceCRCByte (byte *base, int length, int sequence); + +float frand(void); // 0 ti 1 +float crand(void); // -1 to 1 + +extern cvar_t *developer; +extern cvar_t *dedicated; +extern cvar_t *host_speeds; +extern cvar_t *log_stats; + +extern FILE *log_stats_file; + +// host_speeds times +extern int time_before_game; +extern int time_after_game; +extern int time_before_ref; +extern int time_after_ref; + +void Z_Free (void *ptr); +void *Z_Malloc (int size); // returns 0 filled memory +void *Z_TagMalloc (int size, int tag); +void Z_FreeTags (int tag); + +void Qcommon_Init (int argc, char **argv); +void Qcommon_Frame (int msec); +void Qcommon_Shutdown (void); + +#define NUMVERTEXNORMALS 162 +extern vec3_t bytedirs[NUMVERTEXNORMALS]; + +// this is in the client code, but can be used for debugging from server +void SCR_DebugGraph (float value, int color); + + +/* +============================================================== + +NON-PORTABLE SYSTEM SERVICES + +============================================================== +*/ + +void Sys_Init (void); + +void Sys_AppActivate (void); + +void Sys_UnloadGame (void); +void *Sys_GetGameAPI (void *parms); +// loads the game dll and calls the api init function + +char *Sys_ConsoleInput (void); +void Sys_ConsoleOutput (char *string); +void Sys_SendKeyEvents (void); +void Sys_Error (char *error, ...); +void Sys_Quit (void); +char *Sys_GetClipboardData( void ); +void Sys_CopyProtect (void); + +/* +============================================================== + +CLIENT / SERVER SYSTEMS + +============================================================== +*/ + +void CL_Init (void); +void CL_Drop (void); +void CL_Shutdown (void); +void CL_Frame (int msec); +void Con_Print (char *text); +void SCR_BeginLoadingPlaque (void); + +void SV_Init (void); +void SV_Shutdown (char *finalmsg, qboolean reconnect); +void SV_Frame (int msec); + + + diff --git a/qcommon/qfiles.h b/qcommon/qfiles.h new file mode 100644 index 000000000..a7bc440f8 --- /dev/null +++ b/qcommon/qfiles.h @@ -0,0 +1,482 @@ +/* +Copyright (C) 1997-2001 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. + +*/ + +// +// qfiles.h: quake file formats +// This file must be identical in the quake and utils directories +// + +/* +======================================================================== + +The .pak files are just a linear collapse of a directory tree + +======================================================================== +*/ + +#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P') + +typedef struct +{ + char name[56]; + int filepos, filelen; +} dpackfile_t; + +typedef struct +{ + int ident; // == IDPAKHEADER + int dirofs; + int dirlen; +} dpackheader_t; + +#define MAX_FILES_IN_PACK 4096 + + +/* +======================================================================== + +PCX files are used for as many images as possible + +======================================================================== +*/ + +typedef struct +{ + char manufacturer; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin,ymin,xmax,ymax; + unsigned short hres,vres; + unsigned char palette[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; + unsigned char data; // unbounded +} pcx_t; + + +/* +======================================================================== + +.MD2 triangle model file format + +======================================================================== +*/ + +#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I') +#define ALIAS_VERSION 8 + +#define MAX_TRIANGLES 4096 +#define MAX_VERTS 2048 +#define MAX_FRAMES 512 +#define MAX_MD2SKINS 32 +#define MAX_SKINNAME 64 + +typedef struct +{ + short s; + short t; +} dstvert_t; + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} dtriangle_t; + +typedef struct +{ + byte v[3]; // scaled byte to fit in frame mins/maxs + byte lightnormalindex; +} dtrivertx_t; + +#define DTRIVERTX_V0 0 +#define DTRIVERTX_V1 1 +#define DTRIVERTX_V2 2 +#define DTRIVERTX_LNI 3 +#define DTRIVERTX_SIZE 4 + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + dtrivertx_t verts[1]; // variable sized +} daliasframe_t; + + +// the glcmd format: +// a positive integer starts a tristrip command, followed by that many +// vertex structures. +// a negative integer starts a trifan command, followed by -x vertexes +// a zero indicates the end of the command list. +// a vertex consists of a floating point s, a floating point t, +// and an integer vertex index. + + +typedef struct +{ + int ident; + int version; + + int skinwidth; + int skinheight; + int framesize; // byte size of each frame + + int num_skins; + int num_xyz; + int num_st; // greater than num_xyz for seams + int num_tris; + int num_glcmds; // dwords in strip/fan command list + int num_frames; + + int ofs_skins; // each skin is a MAX_SKINNAME string + int ofs_st; // byte offset from start for stverts + int ofs_tris; // offset for dtriangles + int ofs_frames; // offset for first frame + int ofs_glcmds; + int ofs_end; // end of file + +} dmdl_t; + +/* +======================================================================== + +.SP2 sprite file format + +======================================================================== +*/ + +#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I') + // little-endian "IDS2" +#define SPRITE_VERSION 2 + +typedef struct +{ + int width, height; + int origin_x, origin_y; // raster coordinates inside pic + char name[MAX_SKINNAME]; // name of pcx file +} dsprframe_t; + +typedef struct { + int ident; + int version; + int numframes; + dsprframe_t frames[1]; // variable sized +} dsprite_t; + +/* +============================================================================== + + .WAL texture file format + +============================================================================== +*/ + + +#define MIPLEVELS 4 +typedef struct miptex_s +{ + char name[32]; + unsigned width, height; + unsigned offsets[MIPLEVELS]; // four mip maps stored + char animname[32]; // next frame in animation chain + int flags; + int contents; + int value; +} miptex_t; + + + +/* +============================================================================== + + .BSP file format + +============================================================================== +*/ + +#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') + // little-endian "IBSP" + +#define BSPVERSION 38 + + +// upper design bounds +// leaffaces, leafbrushes, planes, and verts are still bounded by +// 16 bit short limits +#define MAX_MAP_MODELS 1024 +#define MAX_MAP_BRUSHES 8192 +#define MAX_MAP_ENTITIES 2048 +#define MAX_MAP_ENTSTRING 0x40000 +#define MAX_MAP_TEXINFO 8192 + +#define MAX_MAP_AREAS 256 +#define MAX_MAP_AREAPORTALS 1024 +#define MAX_MAP_PLANES 65536 +#define MAX_MAP_NODES 65536 +#define MAX_MAP_BRUSHSIDES 65536 +#define MAX_MAP_LEAFS 65536 +#define MAX_MAP_VERTS 65536 +#define MAX_MAP_FACES 65536 +#define MAX_MAP_LEAFFACES 65536 +#define MAX_MAP_LEAFBRUSHES 65536 +#define MAX_MAP_PORTALS 65536 +#define MAX_MAP_EDGES 128000 +#define MAX_MAP_SURFEDGES 256000 +#define MAX_MAP_LIGHTING 0x200000 +#define MAX_MAP_VISIBILITY 0x100000 + +// key / value pair sizes + +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +//============================================================================= + +typedef struct +{ + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_VERTEXES 2 +#define LUMP_VISIBILITY 3 +#define LUMP_NODES 4 +#define LUMP_TEXINFO 5 +#define LUMP_FACES 6 +#define LUMP_LIGHTING 7 +#define LUMP_LEAFS 8 +#define LUMP_LEAFFACES 9 +#define LUMP_LEAFBRUSHES 10 +#define LUMP_EDGES 11 +#define LUMP_SURFEDGES 12 +#define LUMP_MODELS 13 +#define LUMP_BRUSHES 14 +#define LUMP_BRUSHSIDES 15 +#define LUMP_POP 16 +#define LUMP_AREAS 17 +#define LUMP_AREAPORTALS 18 +#define HEADER_LUMPS 19 + +typedef struct +{ + int ident; + int version; + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + float mins[3], maxs[3]; + float origin[3]; // for sounds or lights + int headnode; + int firstface, numfaces; // submodels just draw faces + // without walking the bsp tree +} dmodel_t; + + +typedef struct +{ + float point[3]; +} dvertex_t; + + +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +// 3-5 are non-axial planes snapped to the nearest +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +// planes (x&~1) and (x&~1)+1 are always opposites + +typedef struct +{ + float normal[3]; + float dist; + int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate +} dplane_t; + + +// contents flags are seperate bits +// a given brush can contribute multiple content bits +// multiple brushes can be in a single leaf + +// these definitions also need to be in q_shared.h! + +// lower bits are stronger, and will eat weaker brushes completely +#define CONTENTS_SOLID 1 // an eye is never valid in a solid +#define CONTENTS_WINDOW 2 // translucent, but not watery +#define CONTENTS_AUX 4 +#define CONTENTS_LAVA 8 +#define CONTENTS_SLIME 16 +#define CONTENTS_WATER 32 +#define CONTENTS_MIST 64 +#define LAST_VISIBLE_CONTENTS 64 + +// remaining contents are non-visible, and don't eat brushes + +#define CONTENTS_AREAPORTAL 0x8000 + +#define CONTENTS_PLAYERCLIP 0x10000 +#define CONTENTS_MONSTERCLIP 0x20000 + +// currents can be added to any other contents, and may be mixed +#define CONTENTS_CURRENT_0 0x40000 +#define CONTENTS_CURRENT_90 0x80000 +#define CONTENTS_CURRENT_180 0x100000 +#define CONTENTS_CURRENT_270 0x200000 +#define CONTENTS_CURRENT_UP 0x400000 +#define CONTENTS_CURRENT_DOWN 0x800000 + +#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity + +#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game +#define CONTENTS_DEADMONSTER 0x4000000 +#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs +#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans +#define CONTENTS_LADDER 0x20000000 + + + +#define SURF_LIGHT 0x1 // value will hold the light strength + +#define SURF_SLICK 0x2 // effects game physics + +#define SURF_SKY 0x4 // don't draw, but add to skybox +#define SURF_WARP 0x8 // turbulent water warp +#define SURF_TRANS33 0x10 +#define SURF_TRANS66 0x20 +#define SURF_FLOWING 0x40 // scroll towards angle +#define SURF_NODRAW 0x80 // don't bother referencing the texture + + + + +typedef struct +{ + int planenum; + int children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for frustom culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides +} dnode_t; + + +typedef struct texinfo_s +{ + float vecs[2][4]; // [s/t][xyz offset] + int flags; // miptex flags + overrides + int value; // light emission, etc + char texture[32]; // texture name (textures/*.wal) + int nexttexinfo; // for animations, -1 = end of chain +} texinfo_t; + + +// note that edge 0 is never used, because negative edge nums are used for +// counterclockwise use of the edge in a face +typedef struct +{ + unsigned short v[2]; // vertex numbers +} dedge_t; + +#define MAXLIGHTMAPS 4 +typedef struct +{ + unsigned short planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + +typedef struct +{ + int contents; // OR of all brushes (not needed?) + + short cluster; + short area; + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstleafface; + unsigned short numleaffaces; + + unsigned short firstleafbrush; + unsigned short numleafbrushes; +} dleaf_t; + +typedef struct +{ + unsigned short planenum; // facing out of the leaf + short texinfo; +} dbrushside_t; + +typedef struct +{ + int firstside; + int numsides; + int contents; +} dbrush_t; + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + + +// the visibility lump consists of a header with a count, then +// byte offsets for the PVS and PHS of each cluster, then the raw +// compressed bit vectors +#define DVIS_PVS 0 +#define DVIS_PHS 1 +typedef struct +{ + int numclusters; + int bitofs[8][2]; // bitofs[numclusters][2] +} dvis_t; + +// each area has a list of portals that lead into other areas +// when portals are closed, other areas may not be visible or +// hearable even if the vis info says that it should be +typedef struct +{ + int portalnum; + int otherarea; +} dareaportal_t; + +typedef struct +{ + int numareaportals; + int firstareaportal; +} darea_t; diff --git a/ref_gl/anorms.h b/ref_gl/anorms.h new file mode 100644 index 000000000..011582eb4 --- /dev/null +++ b/ref_gl/anorms.h @@ -0,0 +1,181 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +{-0.525731, 0.000000, 0.850651}, +{-0.442863, 0.238856, 0.864188}, +{-0.295242, 0.000000, 0.955423}, +{-0.309017, 0.500000, 0.809017}, +{-0.162460, 0.262866, 0.951056}, +{0.000000, 0.000000, 1.000000}, +{0.000000, 0.850651, 0.525731}, +{-0.147621, 0.716567, 0.681718}, +{0.147621, 0.716567, 0.681718}, +{0.000000, 0.525731, 0.850651}, +{0.309017, 0.500000, 0.809017}, +{0.525731, 0.000000, 0.850651}, +{0.295242, 0.000000, 0.955423}, +{0.442863, 0.238856, 0.864188}, +{0.162460, 0.262866, 0.951056}, +{-0.681718, 0.147621, 0.716567}, +{-0.809017, 0.309017, 0.500000}, +{-0.587785, 0.425325, 0.688191}, +{-0.850651, 0.525731, 0.000000}, +{-0.864188, 0.442863, 0.238856}, +{-0.716567, 0.681718, 0.147621}, +{-0.688191, 0.587785, 0.425325}, +{-0.500000, 0.809017, 0.309017}, +{-0.238856, 0.864188, 0.442863}, +{-0.425325, 0.688191, 0.587785}, +{-0.716567, 0.681718, -0.147621}, +{-0.500000, 0.809017, -0.309017}, +{-0.525731, 0.850651, 0.000000}, +{0.000000, 0.850651, -0.525731}, +{-0.238856, 0.864188, -0.442863}, +{0.000000, 0.955423, -0.295242}, +{-0.262866, 0.951056, -0.162460}, +{0.000000, 1.000000, 0.000000}, +{0.000000, 0.955423, 0.295242}, +{-0.262866, 0.951056, 0.162460}, +{0.238856, 0.864188, 0.442863}, +{0.262866, 0.951056, 0.162460}, +{0.500000, 0.809017, 0.309017}, +{0.238856, 0.864188, -0.442863}, +{0.262866, 0.951056, -0.162460}, +{0.500000, 0.809017, -0.309017}, +{0.850651, 0.525731, 0.000000}, +{0.716567, 0.681718, 0.147621}, +{0.716567, 0.681718, -0.147621}, +{0.525731, 0.850651, 0.000000}, +{0.425325, 0.688191, 0.587785}, +{0.864188, 0.442863, 0.238856}, +{0.688191, 0.587785, 0.425325}, +{0.809017, 0.309017, 0.500000}, +{0.681718, 0.147621, 0.716567}, +{0.587785, 0.425325, 0.688191}, +{0.955423, 0.295242, 0.000000}, +{1.000000, 0.000000, 0.000000}, +{0.951056, 0.162460, 0.262866}, +{0.850651, -0.525731, 0.000000}, +{0.955423, -0.295242, 0.000000}, +{0.864188, -0.442863, 0.238856}, +{0.951056, -0.162460, 0.262866}, +{0.809017, -0.309017, 0.500000}, +{0.681718, -0.147621, 0.716567}, +{0.850651, 0.000000, 0.525731}, +{0.864188, 0.442863, -0.238856}, +{0.809017, 0.309017, -0.500000}, +{0.951056, 0.162460, -0.262866}, +{0.525731, 0.000000, -0.850651}, +{0.681718, 0.147621, -0.716567}, +{0.681718, -0.147621, -0.716567}, +{0.850651, 0.000000, -0.525731}, +{0.809017, -0.309017, -0.500000}, +{0.864188, -0.442863, -0.238856}, +{0.951056, -0.162460, -0.262866}, +{0.147621, 0.716567, -0.681718}, +{0.309017, 0.500000, -0.809017}, +{0.425325, 0.688191, -0.587785}, +{0.442863, 0.238856, -0.864188}, +{0.587785, 0.425325, -0.688191}, +{0.688191, 0.587785, -0.425325}, +{-0.147621, 0.716567, -0.681718}, +{-0.309017, 0.500000, -0.809017}, +{0.000000, 0.525731, -0.850651}, +{-0.525731, 0.000000, -0.850651}, +{-0.442863, 0.238856, -0.864188}, +{-0.295242, 0.000000, -0.955423}, +{-0.162460, 0.262866, -0.951056}, +{0.000000, 0.000000, -1.000000}, +{0.295242, 0.000000, -0.955423}, +{0.162460, 0.262866, -0.951056}, +{-0.442863, -0.238856, -0.864188}, +{-0.309017, -0.500000, -0.809017}, +{-0.162460, -0.262866, -0.951056}, +{0.000000, -0.850651, -0.525731}, +{-0.147621, -0.716567, -0.681718}, +{0.147621, -0.716567, -0.681718}, +{0.000000, -0.525731, -0.850651}, +{0.309017, -0.500000, -0.809017}, +{0.442863, -0.238856, -0.864188}, +{0.162460, -0.262866, -0.951056}, +{0.238856, -0.864188, -0.442863}, +{0.500000, -0.809017, -0.309017}, +{0.425325, -0.688191, -0.587785}, +{0.716567, -0.681718, -0.147621}, +{0.688191, -0.587785, -0.425325}, +{0.587785, -0.425325, -0.688191}, +{0.000000, -0.955423, -0.295242}, +{0.000000, -1.000000, 0.000000}, +{0.262866, -0.951056, -0.162460}, +{0.000000, -0.850651, 0.525731}, +{0.000000, -0.955423, 0.295242}, +{0.238856, -0.864188, 0.442863}, +{0.262866, -0.951056, 0.162460}, +{0.500000, -0.809017, 0.309017}, +{0.716567, -0.681718, 0.147621}, +{0.525731, -0.850651, 0.000000}, +{-0.238856, -0.864188, -0.442863}, +{-0.500000, -0.809017, -0.309017}, +{-0.262866, -0.951056, -0.162460}, +{-0.850651, -0.525731, 0.000000}, +{-0.716567, -0.681718, -0.147621}, +{-0.716567, -0.681718, 0.147621}, +{-0.525731, -0.850651, 0.000000}, +{-0.500000, -0.809017, 0.309017}, +{-0.238856, -0.864188, 0.442863}, +{-0.262866, -0.951056, 0.162460}, +{-0.864188, -0.442863, 0.238856}, +{-0.809017, -0.309017, 0.500000}, +{-0.688191, -0.587785, 0.425325}, +{-0.681718, -0.147621, 0.716567}, +{-0.442863, -0.238856, 0.864188}, +{-0.587785, -0.425325, 0.688191}, +{-0.309017, -0.500000, 0.809017}, +{-0.147621, -0.716567, 0.681718}, +{-0.425325, -0.688191, 0.587785}, +{-0.162460, -0.262866, 0.951056}, +{0.442863, -0.238856, 0.864188}, +{0.162460, -0.262866, 0.951056}, +{0.309017, -0.500000, 0.809017}, +{0.147621, -0.716567, 0.681718}, +{0.000000, -0.525731, 0.850651}, +{0.425325, -0.688191, 0.587785}, +{0.587785, -0.425325, 0.688191}, +{0.688191, -0.587785, 0.425325}, +{-0.955423, 0.295242, 0.000000}, +{-0.951056, 0.162460, 0.262866}, +{-1.000000, 0.000000, 0.000000}, +{-0.850651, 0.000000, 0.525731}, +{-0.955423, -0.295242, 0.000000}, +{-0.951056, -0.162460, 0.262866}, +{-0.864188, 0.442863, -0.238856}, +{-0.951056, 0.162460, -0.262866}, +{-0.809017, 0.309017, -0.500000}, +{-0.864188, -0.442863, -0.238856}, +{-0.951056, -0.162460, -0.262866}, +{-0.809017, -0.309017, -0.500000}, +{-0.681718, 0.147621, -0.716567}, +{-0.681718, -0.147621, -0.716567}, +{-0.850651, 0.000000, -0.525731}, +{-0.688191, 0.587785, -0.425325}, +{-0.587785, 0.425325, -0.688191}, +{-0.425325, 0.688191, -0.587785}, +{-0.425325, -0.688191, -0.587785}, +{-0.587785, -0.425325, -0.688191}, +{-0.688191, -0.587785, -0.425325}, diff --git a/ref_gl/anormtab.h b/ref_gl/anormtab.h new file mode 100644 index 000000000..fc08f5581 --- /dev/null +++ b/ref_gl/anormtab.h @@ -0,0 +1,37 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +{ +{1.23,1.30,1.47,1.35,1.56,1.71,1.37,1.38,1.59,1.60,1.79,1.97,1.88,1.92,1.79,1.02,0.93,1.07,0.82,0.87,0.88,0.94,0.96,1.14,1.11,0.82,0.83,0.89,0.89,0.86,0.94,0.91,1.00,1.21,0.98,1.48,1.30,1.57,0.96,1.07,1.14,1.60,1.61,1.40,1.37,1.72,1.78,1.79,1.93,1.99,1.90,1.68,1.71,1.86,1.60,1.68,1.78,1.86,1.93,1.99,1.97,1.44,1.22,1.49,0.93,0.99,0.99,1.23,1.22,1.44,1.49,0.89,0.89,0.97,0.91,0.98,1.19,0.82,0.76,0.82,0.71,0.72,0.73,0.76,0.79,0.86,0.83,0.72,0.76,0.76,0.89,0.82,0.89,0.82,0.89,0.91,0.83,0.96,1.14,0.97,1.40,1.19,0.98,0.94,1.00,1.07,1.37,1.21,1.48,1.30,1.57,1.61,1.37,0.86,0.83,0.91,0.82,0.82,0.88,0.89,0.96,1.14,0.98,0.87,0.93,0.94,1.02,1.30,1.07,1.35,1.38,1.11,1.56,1.92,1.79,1.79,1.59,1.60,1.72,1.90,1.79,0.80,0.85,0.79,0.93,0.80,0.85,0.77,0.74,0.72,0.77,0.74,0.72,0.70,0.70,0.71,0.76,0.73,0.79,0.79,0.73,0.76,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.26,1.26,1.48,1.23,1.50,1.71,1.14,1.19,1.38,1.46,1.64,1.94,1.87,1.84,1.71,1.02,0.92,1.00,0.79,0.85,0.84,0.91,0.90,0.98,0.99,0.77,0.77,0.83,0.82,0.79,0.86,0.84,0.92,0.99,0.91,1.24,1.03,1.33,0.88,0.94,0.97,1.41,1.39,1.18,1.11,1.51,1.61,1.59,1.80,1.91,1.76,1.54,1.65,1.76,1.70,1.70,1.85,1.85,1.97,1.99,1.93,1.28,1.09,1.39,0.92,0.97,0.99,1.18,1.26,1.52,1.48,0.83,0.85,0.90,0.88,0.93,1.00,0.77,0.73,0.78,0.72,0.71,0.74,0.75,0.79,0.86,0.81,0.75,0.81,0.79,0.96,0.88,0.94,0.86,0.93,0.92,0.85,1.08,1.33,1.05,1.55,1.31,1.01,1.05,1.27,1.31,1.60,1.47,1.70,1.54,1.76,1.76,1.57,0.93,0.90,0.99,0.88,0.88,0.95,0.97,1.11,1.39,1.20,0.92,0.97,1.01,1.10,1.39,1.22,1.51,1.58,1.32,1.64,1.97,1.85,1.91,1.77,1.74,1.88,1.99,1.91,0.79,0.86,0.80,0.94,0.84,0.88,0.74,0.74,0.71,0.82,0.77,0.76,0.70,0.73,0.72,0.73,0.70,0.74,0.85,0.77,0.82,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.34,1.27,1.53,1.17,1.46,1.71,0.98,1.05,1.20,1.34,1.48,1.86,1.82,1.71,1.62,1.09,0.94,0.99,0.79,0.85,0.82,0.90,0.87,0.93,0.96,0.76,0.74,0.79,0.76,0.74,0.79,0.78,0.85,0.92,0.85,1.00,0.93,1.06,0.81,0.86,0.89,1.16,1.12,0.97,0.95,1.28,1.38,1.35,1.60,1.77,1.57,1.33,1.50,1.58,1.69,1.63,1.82,1.74,1.91,1.92,1.80,1.04,0.97,1.21,0.90,0.93,0.97,1.05,1.21,1.48,1.37,0.77,0.80,0.84,0.85,0.88,0.92,0.73,0.71,0.74,0.74,0.71,0.75,0.73,0.79,0.84,0.78,0.79,0.86,0.81,1.05,0.94,0.99,0.90,0.95,0.92,0.86,1.24,1.44,1.14,1.59,1.34,1.02,1.27,1.50,1.49,1.80,1.69,1.86,1.72,1.87,1.80,1.69,1.00,0.98,1.23,0.95,0.96,1.09,1.16,1.37,1.63,1.46,0.99,1.10,1.25,1.24,1.51,1.41,1.67,1.77,1.55,1.72,1.95,1.89,1.98,1.91,1.86,1.97,1.99,1.94,0.81,0.89,0.85,0.98,0.90,0.94,0.75,0.78,0.73,0.89,0.83,0.82,0.72,0.77,0.76,0.72,0.70,0.71,0.91,0.83,0.89,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.46,1.34,1.60,1.16,1.46,1.71,0.94,0.99,1.05,1.26,1.33,1.74,1.76,1.57,1.54,1.23,0.98,1.05,0.83,0.89,0.84,0.92,0.87,0.91,0.96,0.78,0.74,0.79,0.72,0.72,0.75,0.76,0.80,0.88,0.83,0.94,0.87,0.95,0.76,0.80,0.82,0.97,0.96,0.89,0.88,1.08,1.11,1.10,1.37,1.59,1.37,1.07,1.27,1.34,1.57,1.45,1.69,1.55,1.77,1.79,1.60,0.93,0.90,0.99,0.86,0.87,0.93,0.96,1.07,1.35,1.18,0.73,0.76,0.77,0.81,0.82,0.85,0.70,0.71,0.72,0.78,0.73,0.77,0.73,0.79,0.82,0.76,0.83,0.90,0.84,1.18,0.98,1.03,0.92,0.95,0.90,0.86,1.32,1.45,1.15,1.53,1.27,0.99,1.42,1.65,1.58,1.93,1.83,1.94,1.81,1.88,1.74,1.70,1.19,1.17,1.44,1.11,1.15,1.36,1.41,1.61,1.81,1.67,1.22,1.34,1.50,1.42,1.65,1.61,1.82,1.91,1.75,1.80,1.89,1.89,1.98,1.99,1.94,1.98,1.92,1.87,0.86,0.95,0.92,1.14,0.98,1.03,0.79,0.84,0.77,0.97,0.90,0.89,0.76,0.82,0.82,0.74,0.72,0.71,0.98,0.89,0.97,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.60,1.44,1.68,1.22,1.49,1.71,0.93,0.99,0.99,1.23,1.22,1.60,1.68,1.44,1.49,1.40,1.14,1.19,0.89,0.96,0.89,0.97,0.89,0.91,0.98,0.82,0.76,0.82,0.71,0.72,0.73,0.76,0.79,0.86,0.83,0.91,0.83,0.89,0.72,0.76,0.76,0.89,0.89,0.82,0.82,0.98,0.96,0.97,1.14,1.40,1.19,0.94,1.00,1.07,1.37,1.21,1.48,1.30,1.57,1.61,1.37,0.86,0.83,0.91,0.82,0.82,0.88,0.89,0.96,1.14,0.98,0.70,0.72,0.73,0.77,0.76,0.79,0.70,0.72,0.71,0.82,0.77,0.80,0.74,0.79,0.80,0.74,0.87,0.93,0.85,1.23,1.02,1.02,0.93,0.93,0.87,0.85,1.30,1.35,1.07,1.38,1.11,0.94,1.47,1.71,1.56,1.97,1.88,1.92,1.79,1.79,1.59,1.60,1.30,1.35,1.56,1.37,1.38,1.59,1.60,1.79,1.92,1.79,1.48,1.57,1.72,1.61,1.78,1.79,1.93,1.99,1.90,1.86,1.78,1.86,1.93,1.99,1.97,1.90,1.79,1.72,0.94,1.07,1.00,1.37,1.21,1.30,0.86,0.91,0.83,1.14,0.98,0.96,0.82,0.88,0.89,0.79,0.76,0.73,1.07,0.94,1.11,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.74,1.57,1.76,1.33,1.54,1.71,0.94,1.05,0.99,1.26,1.16,1.46,1.60,1.34,1.46,1.59,1.37,1.37,0.97,1.11,0.96,1.10,0.95,0.94,1.08,0.89,0.82,0.88,0.72,0.76,0.75,0.80,0.80,0.88,0.87,0.91,0.83,0.87,0.72,0.76,0.74,0.83,0.84,0.78,0.79,0.96,0.89,0.92,0.98,1.23,1.05,0.86,0.92,0.95,1.11,0.98,1.22,1.03,1.34,1.42,1.14,0.79,0.77,0.84,0.78,0.76,0.82,0.82,0.89,0.97,0.90,0.70,0.71,0.71,0.73,0.72,0.74,0.73,0.76,0.72,0.86,0.81,0.82,0.76,0.79,0.77,0.73,0.90,0.95,0.86,1.18,1.03,0.98,0.92,0.90,0.83,0.84,1.19,1.17,0.98,1.15,0.97,0.89,1.42,1.65,1.44,1.93,1.83,1.81,1.67,1.61,1.36,1.41,1.32,1.45,1.58,1.57,1.53,1.74,1.70,1.88,1.94,1.81,1.69,1.77,1.87,1.79,1.89,1.92,1.98,1.99,1.98,1.89,1.65,1.80,1.82,1.91,1.94,1.75,1.61,1.50,1.07,1.34,1.27,1.60,1.45,1.55,0.93,0.99,0.90,1.35,1.18,1.07,0.87,0.93,0.96,0.85,0.82,0.77,1.15,0.99,1.27,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.86,1.71,1.82,1.48,1.62,1.71,0.98,1.20,1.05,1.34,1.17,1.34,1.53,1.27,1.46,1.77,1.60,1.57,1.16,1.38,1.12,1.35,1.06,1.00,1.28,0.97,0.89,0.95,0.76,0.81,0.79,0.86,0.85,0.92,0.93,0.93,0.85,0.87,0.74,0.78,0.74,0.79,0.82,0.76,0.79,0.96,0.85,0.90,0.94,1.09,0.99,0.81,0.85,0.89,0.95,0.90,0.99,0.94,1.10,1.24,0.98,0.75,0.73,0.78,0.74,0.72,0.77,0.76,0.82,0.89,0.83,0.73,0.71,0.71,0.71,0.70,0.72,0.77,0.80,0.74,0.90,0.85,0.84,0.78,0.79,0.75,0.73,0.92,0.95,0.86,1.05,0.99,0.94,0.90,0.86,0.79,0.81,1.00,0.98,0.91,0.96,0.89,0.83,1.27,1.50,1.23,1.80,1.69,1.63,1.46,1.37,1.09,1.16,1.24,1.44,1.49,1.69,1.59,1.80,1.69,1.87,1.86,1.72,1.82,1.91,1.94,1.92,1.95,1.99,1.98,1.91,1.97,1.89,1.51,1.72,1.67,1.77,1.86,1.55,1.41,1.25,1.33,1.58,1.50,1.80,1.63,1.74,1.04,1.21,0.97,1.48,1.37,1.21,0.93,0.97,1.05,0.92,0.88,0.84,1.14,1.02,1.34,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.94,1.84,1.87,1.64,1.71,1.71,1.14,1.38,1.19,1.46,1.23,1.26,1.48,1.26,1.50,1.91,1.80,1.76,1.41,1.61,1.39,1.59,1.33,1.24,1.51,1.18,0.97,1.11,0.82,0.88,0.86,0.94,0.92,0.99,1.03,0.98,0.91,0.90,0.79,0.84,0.77,0.79,0.84,0.77,0.83,0.99,0.85,0.91,0.92,1.02,1.00,0.79,0.80,0.86,0.88,0.84,0.92,0.88,0.97,1.10,0.94,0.74,0.71,0.74,0.72,0.70,0.73,0.72,0.76,0.82,0.77,0.77,0.73,0.74,0.71,0.70,0.73,0.83,0.85,0.78,0.92,0.88,0.86,0.81,0.79,0.74,0.75,0.92,0.93,0.85,0.96,0.94,0.88,0.86,0.81,0.75,0.79,0.93,0.90,0.85,0.88,0.82,0.77,1.05,1.27,0.99,1.60,1.47,1.39,1.20,1.11,0.95,0.97,1.08,1.33,1.31,1.70,1.55,1.76,1.57,1.76,1.70,1.54,1.85,1.97,1.91,1.99,1.97,1.99,1.91,1.77,1.88,1.85,1.39,1.64,1.51,1.58,1.74,1.32,1.22,1.01,1.54,1.76,1.65,1.93,1.70,1.85,1.28,1.39,1.09,1.52,1.48,1.26,0.97,0.99,1.18,1.00,0.93,0.90,1.05,1.01,1.31,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.97,1.92,1.88,1.79,1.79,1.71,1.37,1.59,1.38,1.60,1.35,1.23,1.47,1.30,1.56,1.99,1.93,1.90,1.60,1.78,1.61,1.79,1.57,1.48,1.72,1.40,1.14,1.37,0.89,0.96,0.94,1.07,1.00,1.21,1.30,1.14,0.98,0.96,0.86,0.91,0.83,0.82,0.88,0.82,0.89,1.11,0.87,0.94,0.93,1.02,1.07,0.80,0.79,0.85,0.82,0.80,0.87,0.85,0.93,1.02,0.93,0.77,0.72,0.74,0.71,0.70,0.70,0.71,0.72,0.77,0.74,0.82,0.76,0.79,0.72,0.73,0.76,0.89,0.89,0.82,0.93,0.91,0.86,0.83,0.79,0.73,0.76,0.91,0.89,0.83,0.89,0.89,0.82,0.82,0.76,0.72,0.76,0.86,0.83,0.79,0.82,0.76,0.73,0.94,1.00,0.91,1.37,1.21,1.14,0.98,0.96,0.88,0.89,0.96,1.14,1.07,1.60,1.40,1.61,1.37,1.57,1.48,1.30,1.78,1.93,1.79,1.99,1.92,1.90,1.79,1.59,1.72,1.79,1.30,1.56,1.35,1.38,1.60,1.11,1.07,0.94,1.68,1.86,1.71,1.97,1.68,1.86,1.44,1.49,1.22,1.44,1.49,1.22,0.99,0.99,1.23,1.19,0.98,0.97,0.97,0.98,1.19,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.94,1.97,1.87,1.91,1.85,1.71,1.60,1.77,1.58,1.74,1.51,1.26,1.48,1.39,1.64,1.99,1.97,1.99,1.70,1.85,1.76,1.91,1.76,1.70,1.88,1.55,1.33,1.57,0.96,1.08,1.05,1.31,1.27,1.47,1.54,1.39,1.20,1.11,0.93,0.99,0.90,0.88,0.95,0.88,0.97,1.32,0.92,1.01,0.97,1.10,1.22,0.84,0.80,0.88,0.79,0.79,0.85,0.86,0.92,1.02,0.94,0.82,0.76,0.77,0.72,0.73,0.70,0.72,0.71,0.74,0.74,0.88,0.81,0.85,0.75,0.77,0.82,0.94,0.93,0.86,0.92,0.92,0.86,0.85,0.79,0.74,0.79,0.88,0.85,0.81,0.82,0.83,0.77,0.78,0.73,0.71,0.75,0.79,0.77,0.74,0.77,0.73,0.70,0.86,0.92,0.84,1.14,0.99,0.98,0.91,0.90,0.84,0.83,0.88,0.97,0.94,1.41,1.18,1.39,1.11,1.33,1.24,1.03,1.61,1.80,1.59,1.91,1.84,1.76,1.64,1.38,1.51,1.71,1.26,1.50,1.23,1.19,1.46,0.99,1.00,0.91,1.70,1.85,1.65,1.93,1.54,1.76,1.52,1.48,1.26,1.28,1.39,1.09,0.99,0.97,1.18,1.31,1.01,1.05,0.90,0.93,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.86,1.95,1.82,1.98,1.89,1.71,1.80,1.91,1.77,1.86,1.67,1.34,1.53,1.51,1.72,1.92,1.91,1.99,1.69,1.82,1.80,1.94,1.87,1.86,1.97,1.59,1.44,1.69,1.05,1.24,1.27,1.49,1.50,1.69,1.72,1.63,1.46,1.37,1.00,1.23,0.98,0.95,1.09,0.96,1.16,1.55,0.99,1.25,1.10,1.24,1.41,0.90,0.85,0.94,0.79,0.81,0.85,0.89,0.94,1.09,0.98,0.89,0.82,0.83,0.74,0.77,0.72,0.76,0.73,0.75,0.78,0.94,0.86,0.91,0.79,0.83,0.89,0.99,0.95,0.90,0.90,0.92,0.84,0.86,0.79,0.75,0.81,0.85,0.80,0.78,0.76,0.77,0.73,0.74,0.71,0.71,0.73,0.74,0.74,0.71,0.76,0.72,0.70,0.79,0.85,0.78,0.98,0.92,0.93,0.85,0.87,0.82,0.79,0.81,0.89,0.86,1.16,0.97,1.12,0.95,1.06,1.00,0.93,1.38,1.60,1.35,1.77,1.71,1.57,1.48,1.20,1.28,1.62,1.27,1.46,1.17,1.05,1.34,0.96,0.99,0.90,1.63,1.74,1.50,1.80,1.33,1.58,1.48,1.37,1.21,1.04,1.21,0.97,0.97,0.93,1.05,1.34,1.02,1.14,0.84,0.88,0.92,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.74,1.89,1.76,1.98,1.89,1.71,1.93,1.99,1.91,1.94,1.82,1.46,1.60,1.65,1.80,1.79,1.77,1.92,1.57,1.69,1.74,1.87,1.88,1.94,1.98,1.53,1.45,1.70,1.18,1.32,1.42,1.58,1.65,1.83,1.81,1.81,1.67,1.61,1.19,1.44,1.17,1.11,1.36,1.15,1.41,1.75,1.22,1.50,1.34,1.42,1.61,0.98,0.92,1.03,0.83,0.86,0.89,0.95,0.98,1.23,1.14,0.97,0.89,0.90,0.78,0.82,0.76,0.82,0.77,0.79,0.84,0.98,0.90,0.98,0.83,0.89,0.97,1.03,0.95,0.92,0.86,0.90,0.82,0.86,0.79,0.77,0.84,0.81,0.76,0.76,0.72,0.73,0.70,0.72,0.71,0.73,0.73,0.72,0.74,0.71,0.78,0.74,0.72,0.75,0.80,0.76,0.94,0.88,0.91,0.83,0.87,0.84,0.79,0.76,0.82,0.80,0.97,0.89,0.96,0.88,0.95,0.94,0.87,1.11,1.37,1.10,1.59,1.57,1.37,1.33,1.05,1.08,1.54,1.34,1.46,1.16,0.99,1.26,0.96,1.05,0.92,1.45,1.55,1.27,1.60,1.07,1.34,1.35,1.18,1.07,0.93,0.99,0.90,0.93,0.87,0.96,1.27,0.99,1.15,0.77,0.82,0.85,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.60,1.78,1.68,1.93,1.86,1.71,1.97,1.99,1.99,1.97,1.93,1.60,1.68,1.78,1.86,1.61,1.57,1.79,1.37,1.48,1.59,1.72,1.79,1.92,1.90,1.38,1.35,1.60,1.23,1.30,1.47,1.56,1.71,1.88,1.79,1.92,1.79,1.79,1.30,1.56,1.35,1.37,1.59,1.38,1.60,1.90,1.48,1.72,1.57,1.61,1.79,1.21,1.00,1.30,0.89,0.94,0.96,1.07,1.14,1.40,1.37,1.14,0.96,0.98,0.82,0.88,0.82,0.89,0.83,0.86,0.91,1.02,0.93,1.07,0.87,0.94,1.11,1.02,0.93,0.93,0.82,0.87,0.80,0.85,0.79,0.80,0.85,0.77,0.72,0.74,0.71,0.70,0.70,0.71,0.72,0.77,0.74,0.72,0.76,0.73,0.82,0.79,0.76,0.73,0.79,0.76,0.93,0.86,0.91,0.83,0.89,0.89,0.82,0.72,0.76,0.76,0.89,0.82,0.89,0.82,0.89,0.91,0.83,0.96,1.14,0.97,1.40,1.44,1.19,1.22,0.99,0.98,1.49,1.44,1.49,1.22,0.99,1.23,0.98,1.19,0.97,1.21,1.30,1.00,1.37,0.94,1.07,1.14,0.98,0.96,0.86,0.91,0.83,0.88,0.82,0.89,1.11,0.94,1.07,0.73,0.76,0.79,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.46,1.65,1.60,1.82,1.80,1.71,1.93,1.91,1.99,1.94,1.98,1.74,1.76,1.89,1.89,1.42,1.34,1.61,1.11,1.22,1.36,1.50,1.61,1.81,1.75,1.15,1.17,1.41,1.18,1.19,1.42,1.44,1.65,1.83,1.67,1.94,1.81,1.88,1.32,1.58,1.45,1.57,1.74,1.53,1.70,1.98,1.69,1.87,1.77,1.79,1.92,1.45,1.27,1.55,0.97,1.07,1.11,1.34,1.37,1.59,1.60,1.35,1.07,1.18,0.86,0.93,0.87,0.96,0.90,0.93,0.99,1.03,0.95,1.15,0.90,0.99,1.27,0.98,0.90,0.92,0.78,0.83,0.77,0.84,0.79,0.82,0.86,0.73,0.71,0.73,0.72,0.70,0.73,0.72,0.76,0.81,0.76,0.76,0.82,0.77,0.89,0.85,0.82,0.75,0.80,0.80,0.94,0.88,0.94,0.87,0.95,0.96,0.88,0.72,0.74,0.76,0.83,0.78,0.84,0.79,0.87,0.91,0.83,0.89,0.98,0.92,1.23,1.34,1.05,1.16,0.99,0.96,1.46,1.57,1.54,1.33,1.05,1.26,1.08,1.37,1.10,0.98,1.03,0.92,1.14,0.86,0.95,0.97,0.90,0.89,0.79,0.84,0.77,0.82,0.76,0.82,0.97,0.89,0.98,0.71,0.72,0.74,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.34,1.51,1.53,1.67,1.72,1.71,1.80,1.77,1.91,1.86,1.98,1.86,1.82,1.95,1.89,1.24,1.10,1.41,0.95,0.99,1.09,1.25,1.37,1.63,1.55,0.96,0.98,1.16,1.05,1.00,1.27,1.23,1.50,1.69,1.46,1.86,1.72,1.87,1.24,1.49,1.44,1.69,1.80,1.59,1.69,1.97,1.82,1.94,1.91,1.92,1.99,1.63,1.50,1.74,1.16,1.33,1.38,1.58,1.60,1.77,1.80,1.48,1.21,1.37,0.90,0.97,0.93,1.05,0.97,1.04,1.21,0.99,0.95,1.14,0.92,1.02,1.34,0.94,0.86,0.90,0.74,0.79,0.75,0.81,0.79,0.84,0.86,0.71,0.71,0.73,0.76,0.73,0.77,0.74,0.80,0.85,0.78,0.81,0.89,0.84,0.97,0.92,0.88,0.79,0.85,0.86,0.98,0.92,1.00,0.93,1.06,1.12,0.95,0.74,0.74,0.78,0.79,0.76,0.82,0.79,0.87,0.93,0.85,0.85,0.94,0.90,1.09,1.27,0.99,1.17,1.05,0.96,1.46,1.71,1.62,1.48,1.20,1.34,1.28,1.57,1.35,0.90,0.94,0.85,0.98,0.81,0.89,0.89,0.83,0.82,0.75,0.78,0.73,0.77,0.72,0.76,0.89,0.83,0.91,0.71,0.70,0.72,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}, +{1.26,1.39,1.48,1.51,1.64,1.71,1.60,1.58,1.77,1.74,1.91,1.94,1.87,1.97,1.85,1.10,0.97,1.22,0.88,0.92,0.95,1.01,1.11,1.39,1.32,0.88,0.90,0.97,0.96,0.93,1.05,0.99,1.27,1.47,1.20,1.70,1.54,1.76,1.08,1.31,1.33,1.70,1.76,1.55,1.57,1.88,1.85,1.91,1.97,1.99,1.99,1.70,1.65,1.85,1.41,1.54,1.61,1.76,1.80,1.91,1.93,1.52,1.26,1.48,0.92,0.99,0.97,1.18,1.09,1.28,1.39,0.94,0.93,1.05,0.92,1.01,1.31,0.88,0.81,0.86,0.72,0.75,0.74,0.79,0.79,0.86,0.85,0.71,0.73,0.75,0.82,0.77,0.83,0.78,0.85,0.88,0.81,0.88,0.97,0.90,1.18,1.00,0.93,0.86,0.92,0.94,1.14,0.99,1.24,1.03,1.33,1.39,1.11,0.79,0.77,0.84,0.79,0.77,0.84,0.83,0.90,0.98,0.91,0.85,0.92,0.91,1.02,1.26,1.00,1.23,1.19,0.99,1.50,1.84,1.71,1.64,1.38,1.46,1.51,1.76,1.59,0.84,0.88,0.80,0.94,0.79,0.86,0.82,0.77,0.76,0.74,0.74,0.71,0.73,0.70,0.72,0.82,0.77,0.85,0.74,0.70,0.73,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00} +} diff --git a/ref_gl/gl_draw.c b/ref_gl/gl_draw.c new file mode 100644 index 000000000..159eaacb6 --- /dev/null +++ b/ref_gl/gl_draw.c @@ -0,0 +1,415 @@ +/* +Copyright (C) 1997-2001 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. + +*/ + +// draw.c + +#include "gl_local.h" + +image_t *draw_chars; + +extern qboolean scrap_dirty; +void Scrap_Upload (void); + + +/* +=============== +Draw_InitLocal +=============== +*/ +void Draw_InitLocal (void) +{ + // load console characters (don't bilerp characters) + draw_chars = GL_FindImage ("pics/conchars.pcx", it_pic); + GL_Bind( draw_chars->texnum ); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +} + + + +/* +================ +Draw_Char + +Draws one 8*8 graphics character with 0 being transparent. +It can be clipped to the top of the screen to allow the console to be +smoothly scrolled off. +================ +*/ +void Draw_Char (int x, int y, int num) +{ + int row, col; + float frow, fcol, size; + + num &= 255; + + if ( (num&127) == 32 ) + return; // space + + if (y <= -8) + return; // totally off screen + + row = num>>4; + col = num&15; + + frow = row*0.0625; + fcol = col*0.0625; + size = 0.0625; + + GL_Bind (draw_chars->texnum); + + qglBegin (GL_QUADS); + qglTexCoord2f (fcol, frow); + qglVertex2f (x, y); + qglTexCoord2f (fcol + size, frow); + qglVertex2f (x+8, y); + qglTexCoord2f (fcol + size, frow + size); + qglVertex2f (x+8, y+8); + qglTexCoord2f (fcol, frow + size); + qglVertex2f (x, y+8); + qglEnd (); +} + +/* +============= +Draw_FindPic +============= +*/ +image_t *Draw_FindPic (char *name) +{ + image_t *gl; + char fullname[MAX_QPATH]; + + if (name[0] != '/' && name[0] != '\\') + { + Com_sprintf (fullname, sizeof(fullname), "pics/%s.pcx", name); + gl = GL_FindImage (fullname, it_pic); + } + else + gl = GL_FindImage (name+1, it_pic); + + return gl; +} + +/* +============= +Draw_GetPicSize +============= +*/ +void Draw_GetPicSize (int *w, int *h, char *pic) +{ + image_t *gl; + + gl = Draw_FindPic (pic); + if (!gl) + { + *w = *h = -1; + return; + } + *w = gl->width; + *h = gl->height; +} + +/* +============= +Draw_StretchPic +============= +*/ +void Draw_StretchPic (int x, int y, int w, int h, char *pic) +{ + image_t *gl; + + gl = Draw_FindPic (pic); + if (!gl) + { + ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic); + return; + } + + if (scrap_dirty) + Scrap_Upload (); + + if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha) + qglDisable (GL_ALPHA_TEST); + + GL_Bind (gl->texnum); + qglBegin (GL_QUADS); + qglTexCoord2f (gl->sl, gl->tl); + qglVertex2f (x, y); + qglTexCoord2f (gl->sh, gl->tl); + qglVertex2f (x+w, y); + qglTexCoord2f (gl->sh, gl->th); + qglVertex2f (x+w, y+h); + qglTexCoord2f (gl->sl, gl->th); + qglVertex2f (x, y+h); + qglEnd (); + + if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha) + qglEnable (GL_ALPHA_TEST); +} + + +/* +============= +Draw_Pic +============= +*/ +void Draw_Pic (int x, int y, char *pic) +{ + image_t *gl; + + gl = Draw_FindPic (pic); + if (!gl) + { + ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic); + return; + } + if (scrap_dirty) + Scrap_Upload (); + + if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha) + qglDisable (GL_ALPHA_TEST); + + GL_Bind (gl->texnum); + qglBegin (GL_QUADS); + qglTexCoord2f (gl->sl, gl->tl); + qglVertex2f (x, y); + qglTexCoord2f (gl->sh, gl->tl); + qglVertex2f (x+gl->width, y); + qglTexCoord2f (gl->sh, gl->th); + qglVertex2f (x+gl->width, y+gl->height); + qglTexCoord2f (gl->sl, gl->th); + qglVertex2f (x, y+gl->height); + qglEnd (); + + if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha) + qglEnable (GL_ALPHA_TEST); +} + +/* +============= +Draw_TileClear + +This repeats a 64*64 tile graphic to fill the screen around a sized down +refresh window. +============= +*/ +void Draw_TileClear (int x, int y, int w, int h, char *pic) +{ + image_t *image; + + image = Draw_FindPic (pic); + if (!image) + { + ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic); + return; + } + + if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !image->has_alpha) + qglDisable (GL_ALPHA_TEST); + + GL_Bind (image->texnum); + qglBegin (GL_QUADS); + qglTexCoord2f (x/64.0, y/64.0); + qglVertex2f (x, y); + qglTexCoord2f ( (x+w)/64.0, y/64.0); + qglVertex2f (x+w, y); + qglTexCoord2f ( (x+w)/64.0, (y+h)/64.0); + qglVertex2f (x+w, y+h); + qglTexCoord2f ( x/64.0, (y+h)/64.0 ); + qglVertex2f (x, y+h); + qglEnd (); + + if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !image->has_alpha) + qglEnable (GL_ALPHA_TEST); +} + + +/* +============= +Draw_Fill + +Fills a box of pixels with a single color +============= +*/ +void Draw_Fill (int x, int y, int w, int h, int c) +{ + union + { + unsigned c; + byte v[4]; + } color; + + if ( (unsigned)c > 255) + ri.Sys_Error (ERR_FATAL, "Draw_Fill: bad color"); + + qglDisable (GL_TEXTURE_2D); + + color.c = d_8to24table[c]; + qglColor3f (color.v[0]/255.0, + color.v[1]/255.0, + color.v[2]/255.0); + + qglBegin (GL_QUADS); + + qglVertex2f (x,y); + qglVertex2f (x+w, y); + qglVertex2f (x+w, y+h); + qglVertex2f (x, y+h); + + qglEnd (); + qglColor3f (1,1,1); + qglEnable (GL_TEXTURE_2D); +} + +//============================================================================= + +/* +================ +Draw_FadeScreen + +================ +*/ +void Draw_FadeScreen (void) +{ + qglEnable (GL_BLEND); + qglDisable (GL_TEXTURE_2D); + qglColor4f (0, 0, 0, 0.8); + qglBegin (GL_QUADS); + + qglVertex2f (0,0); + qglVertex2f (vid.width, 0); + qglVertex2f (vid.width, vid.height); + qglVertex2f (0, vid.height); + + qglEnd (); + qglColor4f (1,1,1,1); + qglEnable (GL_TEXTURE_2D); + qglDisable (GL_BLEND); +} + + +//==================================================================== + + +/* +============= +Draw_StretchRaw +============= +*/ +extern unsigned r_rawpalette[256]; + +void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data) +{ + unsigned image32[256*256]; + unsigned char image8[256*256]; + int i, j, trows; + byte *source; + int frac, fracstep; + float hscale; + int row; + float t; + + GL_Bind (0); + + if (rows<=256) + { + hscale = 1; + trows = rows; + } + else + { + hscale = rows/256.0; + trows = 256; + } + t = rows*hscale / 256; + + if ( !qglColorTableEXT ) + { + unsigned *dest; + + for (i=0 ; i rows) + break; + source = data + cols*row; + dest = &image32[i*256]; + fracstep = cols*0x10000/256; + frac = fracstep >> 1; + for (j=0 ; j<256 ; j++) + { + dest[j] = r_rawpalette[source[frac>>16]]; + frac += fracstep; + } + } + + qglTexImage2D (GL_TEXTURE_2D, 0, gl_tex_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, image32); + } + else + { + unsigned char *dest; + + for (i=0 ; i rows) + break; + source = data + cols*row; + dest = &image8[i*256]; + fracstep = cols*0x10000/256; + frac = fracstep >> 1; + for (j=0 ; j<256 ; j++) + { + dest[j] = source[frac>>16]; + frac += fracstep; + } + } + + qglTexImage2D( GL_TEXTURE_2D, + 0, + GL_COLOR_INDEX8_EXT, + 256, 256, + 0, + GL_COLOR_INDEX, + GL_UNSIGNED_BYTE, + image8 ); + } + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + if ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) + qglDisable (GL_ALPHA_TEST); + + qglBegin (GL_QUADS); + qglTexCoord2f (0, 0); + qglVertex2f (x, y); + qglTexCoord2f (1, 0); + qglVertex2f (x+w, y); + qglTexCoord2f (1, t); + qglVertex2f (x+w, y+h); + qglTexCoord2f (0, t); + qglVertex2f (x, y+h); + qglEnd (); + + if ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) + qglEnable (GL_ALPHA_TEST); +} + diff --git a/ref_gl/gl_image.c b/ref_gl/gl_image.c new file mode 100644 index 000000000..fcf25c612 --- /dev/null +++ b/ref_gl/gl_image.c @@ -0,0 +1,1571 @@ +/* +Copyright (C) 1997-2001 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. + +*/ + +#include "gl_local.h" + +image_t gltextures[MAX_GLTEXTURES]; +int numgltextures; +int base_textureid; // gltextures[i] = base_textureid+i + +static byte intensitytable[256]; +static unsigned char gammatable[256]; + +cvar_t *intensity; + +unsigned d_8to24table[256]; + +qboolean GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean is_sky ); +qboolean GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap); + + +int gl_solid_format = 3; +int gl_alpha_format = 4; + +int gl_tex_solid_format = 3; +int gl_tex_alpha_format = 4; + +int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; +int gl_filter_max = GL_LINEAR; + +void GL_SetTexturePalette( unsigned palette[256] ) +{ + int i; + unsigned char temptable[768]; + + for ( i = 0; i < 256; i++ ) + { + temptable[i*3+0] = ( palette[i] >> 0 ) & 0xff; + temptable[i*3+1] = ( palette[i] >> 8 ) & 0xff; + temptable[i*3+2] = ( palette[i] >> 16 ) & 0xff; + } + + if ( qglColorTableEXT && gl_ext_palettedtexture->value ) + { + qglColorTableEXT( GL_SHARED_TEXTURE_PALETTE_EXT, + GL_RGB, + 256, + GL_RGB, + GL_UNSIGNED_BYTE, + temptable ); + } +} + +void GL_EnableMultitexture( qboolean enable ) +{ + if ( !qglSelectTextureSGIS ) + return; + + if ( enable ) + { + GL_SelectTexture( GL_TEXTURE1_SGIS ); + qglEnable( GL_TEXTURE_2D ); + GL_TexEnv( GL_REPLACE ); + } + else + { + GL_SelectTexture( GL_TEXTURE1_SGIS ); + qglDisable( GL_TEXTURE_2D ); + GL_TexEnv( GL_REPLACE ); + } + GL_SelectTexture( GL_TEXTURE0_SGIS ); + GL_TexEnv( GL_REPLACE ); +} + +void GL_SelectTexture( GLenum texture ) +{ + int tmu; + + if ( !qglSelectTextureSGIS ) + return; + + if ( texture == GL_TEXTURE0_SGIS ) + tmu = 0; + else + tmu = 1; + + if ( tmu == gl_state.currenttmu ) + return; + + gl_state.currenttmu = tmu; + + if ( tmu == 0 ) + qglSelectTextureSGIS( GL_TEXTURE0_SGIS ); + else + qglSelectTextureSGIS( GL_TEXTURE1_SGIS ); +} + +void GL_TexEnv( GLenum mode ) +{ + static int lastmodes[2] = { -1, -1 }; + + if ( mode != lastmodes[gl_state.currenttmu] ) + { + qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode ); + lastmodes[gl_state.currenttmu] = mode; + } +} + +void GL_Bind (int texnum) +{ + extern image_t *draw_chars; + + if (gl_nobind->value && draw_chars) // performance evaluation option + texnum = draw_chars->texnum; + if ( gl_state.currenttextures[gl_state.currenttmu] == texnum) + return; + gl_state.currenttextures[gl_state.currenttmu] = texnum; + qglBindTexture (GL_TEXTURE_2D, texnum); +} + +void GL_MBind( GLenum target, int texnum ) +{ + GL_SelectTexture( target ); + if ( target == GL_TEXTURE0_SGIS ) + { + if ( gl_state.currenttextures[0] == texnum ) + return; + } + else + { + if ( gl_state.currenttextures[1] == texnum ) + return; + } + GL_Bind( texnum ); +} + +typedef struct +{ + char *name; + int minimize, maximize; +} glmode_t; + +glmode_t modes[] = { + {"GL_NEAREST", GL_NEAREST, GL_NEAREST}, + {"GL_LINEAR", GL_LINEAR, GL_LINEAR}, + {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, + {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, + {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, + {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} +}; + +#define NUM_GL_MODES (sizeof(modes) / sizeof (glmode_t)) + +typedef struct +{ + char *name; + int mode; +} gltmode_t; + +gltmode_t gl_alpha_modes[] = { + {"default", 4}, + {"GL_RGBA", GL_RGBA}, + {"GL_RGBA8", GL_RGBA8}, + {"GL_RGB5_A1", GL_RGB5_A1}, + {"GL_RGBA4", GL_RGBA4}, + {"GL_RGBA2", GL_RGBA2}, +}; + +#define NUM_GL_ALPHA_MODES (sizeof(gl_alpha_modes) / sizeof (gltmode_t)) + +gltmode_t gl_solid_modes[] = { + {"default", 3}, + {"GL_RGB", GL_RGB}, + {"GL_RGB8", GL_RGB8}, + {"GL_RGB5", GL_RGB5}, + {"GL_RGB4", GL_RGB4}, + {"GL_R3_G3_B2", GL_R3_G3_B2}, +#ifdef GL_RGB2_EXT + {"GL_RGB2", GL_RGB2_EXT}, +#endif +}; + +#define NUM_GL_SOLID_MODES (sizeof(gl_solid_modes) / sizeof (gltmode_t)) + +/* +=============== +GL_TextureMode +=============== +*/ +void GL_TextureMode( char *string ) +{ + int i; + image_t *glt; + + for (i=0 ; i< NUM_GL_MODES ; i++) + { + if ( !Q_stricmp( modes[i].name, string ) ) + break; + } + + if (i == NUM_GL_MODES) + { + ri.Con_Printf (PRINT_ALL, "bad filter name\n"); + return; + } + + gl_filter_min = modes[i].minimize; + gl_filter_max = modes[i].maximize; + + // change all the existing mipmap texture objects + for (i=0, glt=gltextures ; itype != it_pic && glt->type != it_sky ) + { + GL_Bind (glt->texnum); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + } + } +} + +/* +=============== +GL_TextureAlphaMode +=============== +*/ +void GL_TextureAlphaMode( char *string ) +{ + int i; + + for (i=0 ; i< NUM_GL_ALPHA_MODES ; i++) + { + if ( !Q_stricmp( gl_alpha_modes[i].name, string ) ) + break; + } + + if (i == NUM_GL_ALPHA_MODES) + { + ri.Con_Printf (PRINT_ALL, "bad alpha texture mode name\n"); + return; + } + + gl_tex_alpha_format = gl_alpha_modes[i].mode; +} + +/* +=============== +GL_TextureSolidMode +=============== +*/ +void GL_TextureSolidMode( char *string ) +{ + int i; + + for (i=0 ; i< NUM_GL_SOLID_MODES ; i++) + { + if ( !Q_stricmp( gl_solid_modes[i].name, string ) ) + break; + } + + if (i == NUM_GL_SOLID_MODES) + { + ri.Con_Printf (PRINT_ALL, "bad solid texture mode name\n"); + return; + } + + gl_tex_solid_format = gl_solid_modes[i].mode; +} + +/* +=============== +GL_ImageList_f +=============== +*/ +void GL_ImageList_f (void) +{ + int i; + image_t *image; + int texels; + const char *palstrings[2] = + { + "RGB", + "PAL" + }; + + ri.Con_Printf (PRINT_ALL, "------------------\n"); + texels = 0; + + for (i=0, image=gltextures ; itexnum <= 0) + continue; + texels += image->upload_width*image->upload_height; + switch (image->type) + { + case it_skin: + ri.Con_Printf (PRINT_ALL, "M"); + break; + case it_sprite: + ri.Con_Printf (PRINT_ALL, "S"); + break; + case it_wall: + ri.Con_Printf (PRINT_ALL, "W"); + break; + case it_pic: + ri.Con_Printf (PRINT_ALL, "P"); + break; + default: + ri.Con_Printf (PRINT_ALL, " "); + break; + } + + ri.Con_Printf (PRINT_ALL, " %3i %3i %s: %s\n", + image->upload_width, image->upload_height, palstrings[image->paletted], image->name); + } + ri.Con_Printf (PRINT_ALL, "Total texel count (not counting mipmaps): %i\n", texels); +} + + +/* +============================================================================= + + scrap allocation + + Allocate all the little status bar obejcts into a single texture + to crutch up inefficient hardware / drivers + +============================================================================= +*/ + +#define MAX_SCRAPS 1 +#define BLOCK_WIDTH 256 +#define BLOCK_HEIGHT 256 + +int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH]; +byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT]; +qboolean scrap_dirty; + +// returns a texture number and the position inside it +int Scrap_AllocBlock (int w, int h, int *x, int *y) +{ + int i, j; + int best, best2; + int texnum; + + for (texnum=0 ; texnum= best) + break; + if (scrap_allocated[texnum][i+j] > best2) + best2 = scrap_allocated[texnum][i+j]; + } + if (j == w) + { // this is a valid spot + *x = i; + *y = best = best2; + } + } + + if (best + h > BLOCK_HEIGHT) + continue; + + for (i=0 ; ixmin = LittleShort(pcx->xmin); + pcx->ymin = LittleShort(pcx->ymin); + pcx->xmax = LittleShort(pcx->xmax); + pcx->ymax = LittleShort(pcx->ymax); + pcx->hres = LittleShort(pcx->hres); + pcx->vres = LittleShort(pcx->vres); + pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); + pcx->palette_type = LittleShort(pcx->palette_type); + + raw = &pcx->data; + + if (pcx->manufacturer != 0x0a + || pcx->version != 5 + || pcx->encoding != 1 + || pcx->bits_per_pixel != 8 + || pcx->xmax >= 640 + || pcx->ymax >= 480) + { + ri.Con_Printf (PRINT_ALL, "Bad pcx file %s\n", filename); + return; + } + + out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); + + *pic = out; + + pix = out; + + if (palette) + { + *palette = malloc(768); + memcpy (*palette, (byte *)pcx + len - 768, 768); + } + + if (width) + *width = pcx->xmax+1; + if (height) + *height = pcx->ymax+1; + + for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1) + { + for (x=0 ; x<=pcx->xmax ; ) + { + dataByte = *raw++; + + if((dataByte & 0xC0) == 0xC0) + { + runLength = dataByte & 0x3F; + dataByte = *raw++; + } + else + runLength = 1; + + while(runLength-- > 0) + pix[x++] = dataByte; + } + + } + + if ( raw - (byte *)pcx > len) + { + ri.Con_Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename); + free (*pic); + *pic = NULL; + } + + ri.FS_FreeFile (pcx); +} + +/* +========================================================= + +TARGA LOADING + +========================================================= +*/ + +typedef struct _TargaHeader { + unsigned char id_length, colormap_type, image_type; + unsigned short colormap_index, colormap_length; + unsigned char colormap_size; + unsigned short x_origin, y_origin, width, height; + unsigned char pixel_size, attributes; +} TargaHeader; + + +/* +============= +LoadTGA +============= +*/ +void LoadTGA (char *name, byte **pic, int *width, int *height) +{ + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + byte *buf_p; + byte *buffer; + int length; + TargaHeader targa_header; + byte *targa_rgba; + byte tmp[2]; + + *pic = NULL; + + // + // load the file + // + length = ri.FS_LoadFile (name, (void **)&buffer); + if (!buffer) + { + ri.Con_Printf (PRINT_DEVELOPER, "Bad tga file %s\n", name); + return; + } + + buf_p = buffer; + + targa_header.id_length = *buf_p++; + targa_header.colormap_type = *buf_p++; + targa_header.image_type = *buf_p++; + + tmp[0] = buf_p[0]; + tmp[1] = buf_p[1]; + targa_header.colormap_index = LittleShort ( *((short *)tmp) ); + buf_p+=2; + tmp[0] = buf_p[0]; + tmp[1] = buf_p[1]; + targa_header.colormap_length = LittleShort ( *((short *)tmp) ); + buf_p+=2; + targa_header.colormap_size = *buf_p++; + targa_header.x_origin = LittleShort ( *((short *)buf_p) ); + buf_p+=2; + targa_header.y_origin = LittleShort ( *((short *)buf_p) ); + buf_p+=2; + targa_header.width = LittleShort ( *((short *)buf_p) ); + buf_p+=2; + targa_header.height = LittleShort ( *((short *)buf_p) ); + buf_p+=2; + targa_header.pixel_size = *buf_p++; + targa_header.attributes = *buf_p++; + + if (targa_header.image_type!=2 + && targa_header.image_type!=10) + ri.Sys_Error (ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n"); + + if (targa_header.colormap_type !=0 + || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24)) + ri.Sys_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + if (width) + *width = columns; + if (height) + *height = rows; + + targa_rgba = malloc (numPixels*4); + *pic = targa_rgba; + + if (targa_header.id_length != 0) + buf_p += targa_header.id_length; // skip TARGA image comment + + if (targa_header.image_type==2) { // Uncompressed, RGB images + for(row=rows-1; row>=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + else { // non run-length packet + for(j=0;j0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + } + breakOut:; + } + } + + ri.FS_FreeFile (buffer); +} + + +/* +==================================================================== + +IMAGE FLOOD FILLING + +==================================================================== +*/ + + +/* +================= +Mod_FloodFillSkin + +Fill background pixels so mipmapping doesn't have haloes +================= +*/ + +typedef struct +{ + short x, y; +} floodfill_t; + +// must be a power of 2 +#define FLOODFILL_FIFO_SIZE 0x1000 +#define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1) + +#define FLOODFILL_STEP( off, dx, dy ) \ +{ \ + if (pos[off] == fillcolor) \ + { \ + pos[off] = 255; \ + fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \ + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \ + } \ + else if (pos[off] != 255) fdc = pos[off]; \ +} + +void R_FloodFillSkin( byte *skin, int skinwidth, int skinheight ) +{ + byte fillcolor = *skin; // assume this is the pixel to fill + floodfill_t fifo[FLOODFILL_FIFO_SIZE]; + int inpt = 0, outpt = 0; + int filledcolor = -1; + int i; + + if (filledcolor == -1) + { + filledcolor = 0; + // attempt to find opaque black + for (i = 0; i < 256; ++i) + if (d_8to24table[i] == (255 << 0)) // alpha 1.0 + { + filledcolor = i; + break; + } + } + + // can't fill to filled color or to transparent color (used as visited marker) + if ((fillcolor == filledcolor) || (fillcolor == 255)) + { + //printf( "not filling skin from %d to %d\n", fillcolor, filledcolor ); + return; + } + + fifo[inpt].x = 0, fifo[inpt].y = 0; + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + + while (outpt != inpt) + { + int x = fifo[outpt].x, y = fifo[outpt].y; + int fdc = filledcolor; + byte *pos = &skin[x + skinwidth * y]; + + outpt = (outpt + 1) & FLOODFILL_FIFO_MASK; + + if (x > 0) FLOODFILL_STEP( -1, -1, 0 ); + if (x < skinwidth - 1) FLOODFILL_STEP( 1, 1, 0 ); + if (y > 0) FLOODFILL_STEP( -skinwidth, 0, -1 ); + if (y < skinheight - 1) FLOODFILL_STEP( skinwidth, 0, 1 ); + skin[x + skinwidth * y] = fdc; + } +} + +//======================================================= + + +/* +================ +GL_ResampleTexture +================ +*/ +void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight) +{ + int i, j; + unsigned *inrow, *inrow2; + unsigned frac, fracstep; + unsigned p1[1024], p2[1024]; + byte *pix1, *pix2, *pix3, *pix4; + + fracstep = inwidth*0x10000/outwidth; + + frac = fracstep>>2; + for (i=0 ; i>16); + frac += fracstep; + } + frac = 3*(fracstep>>2); + for (i=0 ; i>16); + frac += fracstep; + } + + for (i=0 ; i> 1; + for (j=0 ; j>2; + ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2; + ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2; + ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2; + } + } +} + +/* +================ +GL_LightScaleTexture + +Scale up the pixel values in a texture to increase the +lighting range +================ +*/ +void GL_LightScaleTexture (unsigned *in, int inwidth, int inheight, qboolean only_gamma ) +{ + if ( only_gamma ) + { + int i, c; + byte *p; + + p = (byte *)in; + + c = inwidth*inheight; + for (i=0 ; i>= 1; + out = in; + for (i=0 ; i>2; + out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2; + out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2; + out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2; + } + } +} + +/* +=============== +GL_Upload32 + +Returns has_alpha +=============== +*/ +void GL_BuildPalettedTexture( unsigned char *paletted_texture, unsigned char *scaled, int scaled_width, int scaled_height ) +{ + int i; + + for ( i = 0; i < scaled_width * scaled_height; i++ ) + { + unsigned int r, g, b, c; + + r = ( scaled[0] >> 3 ) & 31; + g = ( scaled[1] >> 2 ) & 63; + b = ( scaled[2] >> 3 ) & 31; + + c = r | ( g << 5 ) | ( b << 11 ); + + paletted_texture[i] = gl_state.d_16to8table[c]; + + scaled += 4; + } +} + +int upload_width, upload_height; +qboolean uploaded_paletted; + +qboolean GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap) +{ + int samples; + unsigned scaled[256*256]; + unsigned char paletted_texture[256*256]; + int scaled_width, scaled_height; + int i, c; + byte *scan; + int comp; + + uploaded_paletted = false; + + for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) + ; + if (gl_round_down->value && scaled_width > width && mipmap) + scaled_width >>= 1; + for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) + ; + if (gl_round_down->value && scaled_height > height && mipmap) + scaled_height >>= 1; + + // let people sample down the world textures for speed + if (mipmap) + { + scaled_width >>= (int)gl_picmip->value; + scaled_height >>= (int)gl_picmip->value; + } + + // don't ever bother with >256 textures + if (scaled_width > 256) + scaled_width = 256; + if (scaled_height > 256) + scaled_height = 256; + + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + + upload_width = scaled_width; + upload_height = scaled_height; + + if (scaled_width * scaled_height > sizeof(scaled)/4) + ri.Sys_Error (ERR_DROP, "GL_Upload32: too big"); + + // scan the texture for any non-255 alpha + c = width*height; + scan = ((byte *)data) + 3; + samples = gl_solid_format; + for (i=0 ; ivalue && samples == gl_solid_format ) + { + uploaded_paletted = true; + GL_BuildPalettedTexture( paletted_texture, ( unsigned char * ) data, scaled_width, scaled_height ); + qglTexImage2D( GL_TEXTURE_2D, + 0, + GL_COLOR_INDEX8_EXT, + scaled_width, + scaled_height, + 0, + GL_COLOR_INDEX, + GL_UNSIGNED_BYTE, + paletted_texture ); + } + else + { + qglTexImage2D (GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + } + goto done; + } + memcpy (scaled, data, width*height*4); + } + else + GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height); + + GL_LightScaleTexture (scaled, scaled_width, scaled_height, !mipmap ); + + if ( qglColorTableEXT && gl_ext_palettedtexture->value && ( samples == gl_solid_format ) ) + { + uploaded_paletted = true; + GL_BuildPalettedTexture( paletted_texture, ( unsigned char * ) scaled, scaled_width, scaled_height ); + qglTexImage2D( GL_TEXTURE_2D, + 0, + GL_COLOR_INDEX8_EXT, + scaled_width, + scaled_height, + 0, + GL_COLOR_INDEX, + GL_UNSIGNED_BYTE, + paletted_texture ); + } + else + { + qglTexImage2D( GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled ); + } + + if (mipmap) + { + int miplevel; + + miplevel = 0; + while (scaled_width > 1 || scaled_height > 1) + { + GL_MipMap ((byte *)scaled, scaled_width, scaled_height); + scaled_width >>= 1; + scaled_height >>= 1; + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + miplevel++; + if ( qglColorTableEXT && gl_ext_palettedtexture->value && samples == gl_solid_format ) + { + uploaded_paletted = true; + GL_BuildPalettedTexture( paletted_texture, ( unsigned char * ) scaled, scaled_width, scaled_height ); + qglTexImage2D( GL_TEXTURE_2D, + miplevel, + GL_COLOR_INDEX8_EXT, + scaled_width, + scaled_height, + 0, + GL_COLOR_INDEX, + GL_UNSIGNED_BYTE, + paletted_texture ); + } + else + { + qglTexImage2D (GL_TEXTURE_2D, miplevel, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); + } + } + } +done: ; +#endif + + + if (mipmap) + { + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + } + else + { + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + } + + return (samples == gl_alpha_format); +} + +/* +=============== +GL_Upload8 + +Returns has_alpha +=============== +*/ +/* +static qboolean IsPowerOf2( int value ) +{ + int i = 1; + + + while ( 1 ) + { + if ( value == i ) + return true; + if ( i > value ) + return false; + i <<= 1; + } +} +*/ + +qboolean GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean is_sky ) +{ + unsigned trans[512*256]; + int i, s; + int p; + + s = width*height; + + if (s > sizeof(trans)/4) + ri.Sys_Error (ERR_DROP, "GL_Upload8: too large"); + + if ( qglColorTableEXT && + gl_ext_palettedtexture->value && + is_sky ) + { + qglTexImage2D( GL_TEXTURE_2D, + 0, + GL_COLOR_INDEX8_EXT, + width, + height, + 0, + GL_COLOR_INDEX, + GL_UNSIGNED_BYTE, + data ); + + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + } + else + { + for (i=0 ; i width && data[i-width] != 255) + p = data[i-width]; + else if (i < s-width && data[i+width] != 255) + p = data[i+width]; + else if (i > 0 && data[i-1] != 255) + p = data[i-1]; + else if (i < s-1 && data[i+1] != 255) + p = data[i+1]; + else + p = 0; + // copy rgb components + ((byte *)&trans[i])[0] = ((byte *)&d_8to24table[p])[0]; + ((byte *)&trans[i])[1] = ((byte *)&d_8to24table[p])[1]; + ((byte *)&trans[i])[2] = ((byte *)&d_8to24table[p])[2]; + } + } + + return GL_Upload32 (trans, width, height, mipmap); + } +} + + +/* +================ +GL_LoadPic + +This is also used as an entry point for the generated r_notexture +================ +*/ +image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type, int bits) +{ + image_t *image; + int i; + + // find a free image_t + for (i=0, image=gltextures ; itexnum) + break; + } + if (i == numgltextures) + { + if (numgltextures == MAX_GLTEXTURES) + ri.Sys_Error (ERR_DROP, "MAX_GLTEXTURES"); + numgltextures++; + } + image = &gltextures[i]; + + if (strlen(name) >= sizeof(image->name)) + ri.Sys_Error (ERR_DROP, "Draw_LoadPic: \"%s\" is too long", name); + strcpy (image->name, name); + image->registration_sequence = registration_sequence; + + image->width = width; + image->height = height; + image->type = type; + + if (type == it_skin && bits == 8) + R_FloodFillSkin(pic, width, height); + + // load little pics into the scrap + if (image->type == it_pic && bits == 8 + && image->width < 64 && image->height < 64) + { + int x, y; + int i, j, k; + int texnum; + + texnum = Scrap_AllocBlock (image->width, image->height, &x, &y); + if (texnum == -1) + goto nonscrap; + scrap_dirty = true; + + // copy the texels into the scrap block + k = 0; + for (i=0 ; iheight ; i++) + for (j=0 ; jwidth ; j++, k++) + scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = pic[k]; + image->texnum = TEXNUM_SCRAPS + texnum; + image->scrap = true; + image->has_alpha = true; + image->sl = (x+0.01)/(float)BLOCK_WIDTH; + image->sh = (x+image->width-0.01)/(float)BLOCK_WIDTH; + image->tl = (y+0.01)/(float)BLOCK_WIDTH; + image->th = (y+image->height-0.01)/(float)BLOCK_WIDTH; + } + else + { +nonscrap: + image->scrap = false; + image->texnum = TEXNUM_IMAGES + (image - gltextures); + GL_Bind(image->texnum); + if (bits == 8) + image->has_alpha = GL_Upload8 (pic, width, height, (image->type != it_pic && image->type != it_sky), image->type == it_sky ); + else + image->has_alpha = GL_Upload32 ((unsigned *)pic, width, height, (image->type != it_pic && image->type != it_sky) ); + image->upload_width = upload_width; // after power of 2 and scales + image->upload_height = upload_height; + image->paletted = uploaded_paletted; + image->sl = 0; + image->sh = 1; + image->tl = 0; + image->th = 1; + } + + return image; +} + + +/* +================ +GL_LoadWal +================ +*/ +image_t *GL_LoadWal (char *name) +{ + miptex_t *mt; + int width, height, ofs; + image_t *image; + + ri.FS_LoadFile (name, (void **)&mt); + if (!mt) + { + ri.Con_Printf (PRINT_ALL, "GL_FindImage: can't load %s\n", name); + return r_notexture; + } + + width = LittleLong (mt->width); + height = LittleLong (mt->height); + ofs = LittleLong (mt->offsets[0]); + + image = GL_LoadPic (name, (byte *)mt + ofs, width, height, it_wall, 8); + + ri.FS_FreeFile ((void *)mt); + + return image; +} + +/* +=============== +GL_FindImage + +Finds or loads the given image +=============== +*/ +image_t *GL_FindImage (char *name, imagetype_t type) +{ + image_t *image; + int i, len; + byte *pic, *palette; + int width, height; + + if (!name) + return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: NULL name"); + len = strlen(name); + if (len<5) + return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: bad name: %s", name); + + // look for it + for (i=0, image=gltextures ; iname)) + { + image->registration_sequence = registration_sequence; + return image; + } + } + + // + // load the pic from disk + // + pic = NULL; + palette = NULL; + if (!strcmp(name+len-4, ".pcx")) + { + LoadPCX (name, &pic, &palette, &width, &height); + if (!pic) + return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: can't load %s", name); + image = GL_LoadPic (name, pic, width, height, type, 8); + } + else if (!strcmp(name+len-4, ".wal")) + { + image = GL_LoadWal (name); + } + else if (!strcmp(name+len-4, ".tga")) + { + LoadTGA (name, &pic, &width, &height); + if (!pic) + return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: can't load %s", name); + image = GL_LoadPic (name, pic, width, height, type, 32); + } + else + return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: bad extension on: %s", name); + + + if (pic) + free(pic); + if (palette) + free(palette); + + return image; +} + + + +/* +=============== +R_RegisterSkin +=============== +*/ +struct image_s *R_RegisterSkin (char *name) +{ + return GL_FindImage (name, it_skin); +} + + +/* +================ +GL_FreeUnusedImages + +Any image that was not touched on this registration sequence +will be freed. +================ +*/ +void GL_FreeUnusedImages (void) +{ + int i; + image_t *image; + + // never free r_notexture or particle texture + r_notexture->registration_sequence = registration_sequence; + r_particletexture->registration_sequence = registration_sequence; + + for (i=0, image=gltextures ; iregistration_sequence == registration_sequence) + continue; // used this sequence + if (!image->registration_sequence) + continue; // free image_t slot + if (image->type == it_pic) + continue; // don't free pics + // free it + qglDeleteTextures (1, &image->texnum); + memset (image, 0, sizeof(*image)); + } +} + + +/* +=============== +Draw_GetPalette +=============== +*/ +int Draw_GetPalette (void) +{ + int i; + int r, g, b; + unsigned v; + byte *pic, *pal; + int width, height; + + // get the palette + + LoadPCX ("pics/colormap.pcx", &pic, &pal, &width, &height); + if (!pal) + ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx"); + + for (i=0 ; i<256 ; i++) + { + r = pal[i*3+0]; + g = pal[i*3+1]; + b = pal[i*3+2]; + + v = (255<<24) + (r<<0) + (g<<8) + (b<<16); + d_8to24table[i] = LittleLong(v); + } + + d_8to24table[255] &= LittleLong(0xffffff); // 255 is transparent + + free (pic); + free (pal); + + return 0; +} + + +/* +=============== +GL_InitImages +=============== +*/ +void GL_InitImages (void) +{ + int i, j; + float g = vid_gamma->value; + + registration_sequence = 1; + + // init intensity conversions + intensity = ri.Cvar_Get ("intensity", "2", 0); + + if ( intensity->value <= 1 ) + ri.Cvar_Set( "intensity", "1" ); + + gl_state.inverse_intensity = 1 / intensity->value; + + Draw_GetPalette (); + + if ( qglColorTableEXT ) + { + ri.FS_LoadFile( "pics/16to8.dat", &gl_state.d_16to8table ); + if ( !gl_state.d_16to8table ) + ri.Sys_Error( ERR_FATAL, "Couldn't load pics/16to8.pcx"); + } + + if ( gl_config.renderer & ( GL_RENDERER_VOODOO | GL_RENDERER_VOODOO2 ) ) + { + g = 1.0F; + } + + for ( i = 0; i < 256; i++ ) + { + if ( g == 1 ) + { + gammatable[i] = i; + } + else + { + float inf; + + inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5; + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + gammatable[i] = inf; + } + } + + for (i=0 ; i<256 ; i++) + { + j = i*intensity->value; + if (j > 255) + j = 255; + intensitytable[i] = j; + } +} + +/* +=============== +GL_ShutdownImages +=============== +*/ +void GL_ShutdownImages (void) +{ + int i; + image_t *image; + + for (i=0, image=gltextures ; iregistration_sequence) + continue; // free image_t slot + // free it + qglDeleteTextures (1, &image->texnum); + memset (image, 0, sizeof(*image)); + } +} + diff --git a/ref_gl/gl_light.c b/ref_gl/gl_light.c new file mode 100644 index 000000000..041d80775 --- /dev/null +++ b/ref_gl/gl_light.c @@ -0,0 +1,729 @@ +/* +Copyright (C) 1997-2001 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_light.c + +#include "gl_local.h" + +int r_dlightframecount; + +#define DLIGHT_CUTOFF 64 + +/* +============================================================================= + +DYNAMIC LIGHTS BLEND RENDERING + +============================================================================= +*/ + +void R_RenderDlight (dlight_t *light) +{ + int i, j; + float a; + vec3_t v; + float rad; + + rad = light->intensity * 0.35; + + VectorSubtract (light->origin, r_origin, v); +#if 0 + // FIXME? + if (VectorLength (v) < rad) + { // view is inside the dlight + V_AddBlend (light->color[0], light->color[1], light->color[2], light->intensity * 0.0003, v_blend); + return; + } +#endif + + qglBegin (GL_TRIANGLE_FAN); + qglColor3f (light->color[0]*0.2, light->color[1]*0.2, light->color[2]*0.2); + for (i=0 ; i<3 ; i++) + v[i] = light->origin[i] - vpn[i]*rad; + qglVertex3fv (v); + qglColor3f (0,0,0); + for (i=16 ; i>=0 ; i--) + { + a = i/16.0 * M_PI*2; + for (j=0 ; j<3 ; j++) + v[j] = light->origin[j] + vright[j]*cos(a)*rad + + vup[j]*sin(a)*rad; + qglVertex3fv (v); + } + qglEnd (); +} + +/* +============= +R_RenderDlights +============= +*/ +void R_RenderDlights (void) +{ + int i; + dlight_t *l; + + if (!gl_flashblend->value) + return; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + qglDepthMask (0); + qglDisable (GL_TEXTURE_2D); + qglShadeModel (GL_SMOOTH); + qglEnable (GL_BLEND); + qglBlendFunc (GL_ONE, GL_ONE); + + l = r_newrefdef.dlights; + for (i=0 ; icontents != -1) + return; + + splitplane = node->plane; + dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; + + if (dist > light->intensity-DLIGHT_CUTOFF) + { + R_MarkLights (light, bit, node->children[0]); + return; + } + if (dist < -light->intensity+DLIGHT_CUTOFF) + { + R_MarkLights (light, bit, node->children[1]); + return; + } + +// mark the polygons + surf = r_worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->dlightframe != r_dlightframecount) + { + surf->dlightbits = 0; + surf->dlightframe = r_dlightframecount; + } + surf->dlightbits |= bit; + } + + R_MarkLights (light, bit, node->children[0]); + R_MarkLights (light, bit, node->children[1]); +} + + +/* +============= +R_PushDlights +============= +*/ +void R_PushDlights (void) +{ + int i; + dlight_t *l; + + if (gl_flashblend->value) + return; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + l = r_newrefdef.dlights; + for (i=0 ; inodes ); +} + + +/* +============================================================================= + +LIGHT SAMPLING + +============================================================================= +*/ + +vec3_t pointcolor; +cplane_t *lightplane; // used as shadow plane +vec3_t lightspot; + +int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) +{ + float front, back, frac; + int side; + cplane_t *plane; + vec3_t mid; + msurface_t *surf; + int s, t, ds, dt; + int i; + mtexinfo_t *tex; + byte *lightmap; + int maps; + int r; + + if (node->contents != -1) + return -1; // didn't hit anything + +// calculate mid point + +// FIXME: optimize for axial + plane = node->plane; + front = DotProduct (start, plane->normal) - plane->dist; + back = DotProduct (end, plane->normal) - plane->dist; + side = front < 0; + + if ( (back < 0) == side) + return RecursiveLightPoint (node->children[side], start, end); + + frac = front / (front-back); + mid[0] = start[0] + (end[0] - start[0])*frac; + mid[1] = start[1] + (end[1] - start[1])*frac; + mid[2] = start[2] + (end[2] - start[2])*frac; + +// go down front side + r = RecursiveLightPoint (node->children[side], start, mid); + if (r >= 0) + return r; // hit something + + if ( (back < 0) == side ) + return -1; // didn't hit anuthing + +// check for impact on this node + VectorCopy (mid, lightspot); + lightplane = plane; + + surf = r_worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->flags&(SURF_DRAWTURB|SURF_DRAWSKY)) + continue; // no lightmaps + + tex = surf->texinfo; + + s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3]; + t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];; + + if (s < surf->texturemins[0] || + t < surf->texturemins[1]) + continue; + + ds = s - surf->texturemins[0]; + dt = t - surf->texturemins[1]; + + if ( ds > surf->extents[0] || dt > surf->extents[1] ) + continue; + + if (!surf->samples) + return 0; + + ds >>= 4; + dt >>= 4; + + lightmap = surf->samples; + VectorCopy (vec3_origin, pointcolor); + if (lightmap) + { + vec3_t scale; + + lightmap += 3*(dt * ((surf->extents[0]>>4)+1) + ds); + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + for (i=0 ; i<3 ; i++) + scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i]; + + pointcolor[0] += lightmap[0] * scale[0] * (1.0/255); + pointcolor[1] += lightmap[1] * scale[1] * (1.0/255); + pointcolor[2] += lightmap[2] * scale[2] * (1.0/255); + lightmap += 3*((surf->extents[0]>>4)+1) * + ((surf->extents[1]>>4)+1); + } + } + + return 1; + } + +// go down back side + return RecursiveLightPoint (node->children[!side], mid, end); +} + +/* +=============== +R_LightPoint +=============== +*/ +void R_LightPoint (vec3_t p, vec3_t color) +{ + vec3_t end; + float r; + int lnum; + dlight_t *dl; + float light; + vec3_t dist; + float add; + + if (!r_worldmodel->lightdata) + { + color[0] = color[1] = color[2] = 1.0; + return; + } + + end[0] = p[0]; + end[1] = p[1]; + end[2] = p[2] - 2048; + + r = RecursiveLightPoint (r_worldmodel->nodes, p, end); + + if (r == -1) + { + VectorCopy (vec3_origin, color); + } + else + { + VectorCopy (pointcolor, color); + } + + // + // add dynamic lights + // + light = 0; + dl = r_newrefdef.dlights; + for (lnum=0 ; lnumorigin, + dl->origin, + dist); + add = dl->intensity - VectorLength(dist); + add *= (1.0/256); + if (add > 0) + { + VectorMA (color, add, dl->color, color); + } + } + + VectorScale (color, gl_modulate->value, color); +} + + +//=================================================================== + +static float s_blocklights[34*34*3]; +/* +=============== +R_AddDynamicLights +=============== +*/ +void R_AddDynamicLights (msurface_t *surf) +{ + int lnum; + int sd, td; + float fdist, frad, fminlight; + vec3_t impact, local; + int s, t; + int i; + int smax, tmax; + mtexinfo_t *tex; + dlight_t *dl; + float *pfBL; + float fsacc, ftacc; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + for (lnum=0 ; lnumdlightbits & (1<intensity; + fdist = DotProduct (dl->origin, surf->plane->normal) - + surf->plane->dist; + frad -= fabs(fdist); + // rad is now the highest intensity on the plane + + fminlight = DLIGHT_CUTOFF; // FIXME: make configurable? + if (frad < fminlight) + continue; + fminlight = frad - fminlight; + + for (i=0 ; i<3 ; i++) + { + impact[i] = dl->origin[i] - + surf->plane->normal[i]*fdist; + } + + local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3] - surf->texturemins[0]; + local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3] - surf->texturemins[1]; + + pfBL = s_blocklights; + for (t = 0, ftacc = 0 ; t td) + fdist = sd + (td>>1); + else + fdist = td + (sd>>1); + + if ( fdist < fminlight ) + { + pfBL[0] += ( frad - fdist ) * dl->color[0]; + pfBL[1] += ( frad - fdist ) * dl->color[1]; + pfBL[2] += ( frad - fdist ) * dl->color[2]; + } + } + } + } +} + + +/* +** R_SetCacheState +*/ +void R_SetCacheState( msurface_t *surf ) +{ + int maps; + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + surf->cached_light[maps] = r_newrefdef.lightstyles[surf->styles[maps]].white; + } +} + +/* +=============== +R_BuildLightMap + +Combine and scale multiple lightmaps into the floating format in blocklights +=============== +*/ +void R_BuildLightMap (msurface_t *surf, byte *dest, int stride) +{ + int smax, tmax; + int r, g, b, a, max; + int i, j, size; + byte *lightmap; + float scale[4]; + int nummaps; + float *bl; + lightstyle_t *style; + int monolightmap; + + if ( surf->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP) ) + ri.Sys_Error (ERR_DROP, "R_BuildLightMap called for non-lit surface"); + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + size = smax*tmax; + if (size > (sizeof(s_blocklights)>>4) ) + ri.Sys_Error (ERR_DROP, "Bad s_blocklights size"); + +// set to full bright if no light data + if (!surf->samples) + { + int maps; + + for (i=0 ; istyles[maps] != 255 ; + maps++) + { + style = &r_newrefdef.lightstyles[surf->styles[maps]]; + } + goto store; + } + + // count the # of maps + for ( nummaps = 0 ; nummaps < MAXLIGHTMAPS && surf->styles[nummaps] != 255 ; + nummaps++) + ; + + lightmap = surf->samples; + + // add all the lightmaps + if ( nummaps == 1 ) + { + int maps; + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + bl = s_blocklights; + + for (i=0 ; i<3 ; i++) + scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i]; + + if ( scale[0] == 1.0F && + scale[1] == 1.0F && + scale[2] == 1.0F ) + { + for (i=0 ; istyles[maps] != 255 ; + maps++) + { + bl = s_blocklights; + + for (i=0 ; i<3 ; i++) + scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i]; + + if ( scale[0] == 1.0F && + scale[1] == 1.0F && + scale[2] == 1.0F ) + { + for (i=0 ; idlightframe == r_framecount) + R_AddDynamicLights (surf); + +// put into texture format +store: + stride -= (smax<<2); + bl = s_blocklights; + + monolightmap = gl_monolightmap->string[0]; + + if ( monolightmap == '0' ) + { + for (i=0 ; i g) + max = r; + else + max = g; + if (b > max) + max = b; + + /* + ** alpha is ONLY used for the mono lightmap case. For this reason + ** we set it to the brightest of the color components so that + ** things don't get too dim. + */ + a = max; + + /* + ** rescale all the color components if the intensity of the greatest + ** channel exceeds 1.0 + */ + if (max > 255) + { + float t = 255.0F / max; + + r = r*t; + g = g*t; + b = b*t; + a = a*t; + } + + dest[0] = r; + dest[1] = g; + dest[2] = b; + dest[3] = a; + + bl += 3; + dest += 4; + } + } + } + else + { + for (i=0 ; i g) + max = r; + else + max = g; + if (b > max) + max = b; + + /* + ** alpha is ONLY used for the mono lightmap case. For this reason + ** we set it to the brightest of the color components so that + ** things don't get too dim. + */ + a = max; + + /* + ** rescale all the color components if the intensity of the greatest + ** channel exceeds 1.0 + */ + if (max > 255) + { + float t = 255.0F / max; + + r = r*t; + g = g*t; + b = b*t; + a = a*t; + } + + /* + ** So if we are doing alpha lightmaps we need to set the R, G, and B + ** components to 0 and we need to set alpha to 1-alpha. + */ + switch ( monolightmap ) + { + case 'L': + case 'I': + r = a; + g = b = 0; + break; + case 'C': + // try faking colored lighting + a = 255 - ((r+g+b)/3); + r *= a/255.0; + g *= a/255.0; + b *= a/255.0; + break; + case 'A': + default: + r = g = b = 0; + a = 255 - a; + break; + } + + dest[0] = r; + dest[1] = g; + dest[2] = b; + dest[3] = a; + + bl += 3; + dest += 4; + } + } + } +} + diff --git a/ref_gl/gl_local.h b/ref_gl/gl_local.h new file mode 100644 index 000000000..c090d2d7c --- /dev/null +++ b/ref_gl/gl_local.h @@ -0,0 +1,460 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +// disable data conversion warnings + +#if 0 +#pragma warning(disable : 4244) // MIPS +#pragma warning(disable : 4136) // X86 +#pragma warning(disable : 4051) // ALPHA +#endif + +#ifdef _WIN32 +# include +#endif + +#include + +#include +#include +#include + +#ifndef GL_COLOR_INDEX8_EXT +#define GL_COLOR_INDEX8_EXT GL_COLOR_INDEX +#endif + +#include "../client/ref.h" + +#include "qgl.h" + +#define REF_VERSION "GL 0.01" + +// up / down +#define PITCH 0 + +// left / right +#define YAW 1 + +// fall over +#define ROLL 2 + + +typedef struct +{ + unsigned width, height; // coordinates from main game +} viddef_t; + +extern viddef_t vid; + + +/* + + skins will be outline flood filled and mip mapped + pics and sprites with alpha will be outline flood filled + pic won't be mip mapped + + model skin + sprite frame + wall texture + pic + +*/ + +typedef enum +{ + it_skin, + it_sprite, + it_wall, + it_pic, + it_sky +} imagetype_t; + +typedef struct image_s +{ + char name[MAX_QPATH]; // game path, including extension + imagetype_t type; + int width, height; // source image + int upload_width, upload_height; // after power of two and picmip + int registration_sequence; // 0 = free + struct msurface_s *texturechain; // for sort-by-texture world drawing + int texnum; // gl texture binding + float sl, tl, sh, th; // 0,0 - 1,1 unless part of the scrap + qboolean scrap; + qboolean has_alpha; + + qboolean paletted; +} image_t; + +#define TEXNUM_LIGHTMAPS 1024 +#define TEXNUM_SCRAPS 1152 +#define TEXNUM_IMAGES 1153 + +#define MAX_GLTEXTURES 1024 + +//=================================================================== + +typedef enum +{ + rserr_ok, + + rserr_invalid_fullscreen, + rserr_invalid_mode, + + rserr_unknown +} rserr_t; + +#include "gl_model.h" + +void GL_BeginRendering (int *x, int *y, int *width, int *height); +void GL_EndRendering (void); + +void GL_SetDefaultState( void ); +void GL_UpdateSwapInterval( void ); + +extern float gldepthmin, gldepthmax; + +typedef struct +{ + float x, y, z; + float s, t; + float r, g, b; +} glvert_t; + + +#define MAX_LBM_HEIGHT 480 + +#define BACKFACE_EPSILON 0.01 + + +//==================================================== + +extern image_t gltextures[MAX_GLTEXTURES]; +extern int numgltextures; + + +extern image_t *r_notexture; +extern image_t *r_particletexture; +extern entity_t *currententity; +extern model_t *currentmodel; +extern int r_visframecount; +extern int r_framecount; +extern cplane_t frustum[4]; +extern int c_brush_polys, c_alias_polys; + + +extern int gl_filter_min, gl_filter_max; + +// +// view origin +// +extern vec3_t vup; +extern vec3_t vpn; +extern vec3_t vright; +extern vec3_t r_origin; + +// +// screen size info +// +extern refdef_t r_newrefdef; +extern int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2; + +extern cvar_t *r_norefresh; +extern cvar_t *r_lefthand; +extern cvar_t *r_drawentities; +extern cvar_t *r_drawworld; +extern cvar_t *r_speeds; +extern cvar_t *r_fullbright; +extern cvar_t *r_novis; +extern cvar_t *r_nocull; +extern cvar_t *r_lerpmodels; + +extern cvar_t *r_lightlevel; // FIXME: This is a HACK to get the client's light level + +extern cvar_t *gl_vertex_arrays; + +extern cvar_t *gl_ext_swapinterval; +extern cvar_t *gl_ext_palettedtexture; +extern cvar_t *gl_ext_multitexture; +extern cvar_t *gl_ext_pointparameters; +extern cvar_t *gl_ext_compiled_vertex_array; + +extern cvar_t *gl_particle_min_size; +extern cvar_t *gl_particle_max_size; +extern cvar_t *gl_particle_size; +extern cvar_t *gl_particle_att_a; +extern cvar_t *gl_particle_att_b; +extern cvar_t *gl_particle_att_c; + +extern cvar_t *gl_nosubimage; +extern cvar_t *gl_bitdepth; +extern cvar_t *gl_mode; +extern cvar_t *gl_log; +extern cvar_t *gl_lightmap; +extern cvar_t *gl_shadows; +extern cvar_t *gl_dynamic; +extern cvar_t *gl_monolightmap; +extern cvar_t *gl_nobind; +extern cvar_t *gl_round_down; +extern cvar_t *gl_picmip; +extern cvar_t *gl_skymip; +extern cvar_t *gl_showtris; +extern cvar_t *gl_finish; +extern cvar_t *gl_ztrick; +extern cvar_t *gl_clear; +extern cvar_t *gl_cull; +extern cvar_t *gl_poly; +extern cvar_t *gl_texsort; +extern cvar_t *gl_polyblend; +extern cvar_t *gl_flashblend; +extern cvar_t *gl_lightmaptype; +extern cvar_t *gl_modulate; +extern cvar_t *gl_playermip; +extern cvar_t *gl_drawbuffer; +extern cvar_t *gl_3dlabs_broken; +extern cvar_t *gl_driver; +extern cvar_t *gl_swapinterval; +extern cvar_t *gl_texturemode; +extern cvar_t *gl_texturealphamode; +extern cvar_t *gl_texturesolidmode; +extern cvar_t *gl_saturatelighting; +extern cvar_t *gl_lockpvs; + +extern cvar_t *vid_fullscreen; +extern cvar_t *vid_gamma; + +extern cvar_t *intensity; + +extern int gl_lightmap_format; +extern int gl_solid_format; +extern int gl_alpha_format; +extern int gl_tex_solid_format; +extern int gl_tex_alpha_format; + +extern int c_visible_lightmaps; +extern int c_visible_textures; + +extern float r_world_matrix[16]; + +void R_TranslatePlayerSkin (int playernum); +void GL_Bind (int texnum); +void GL_MBind( GLenum target, int texnum ); +void GL_TexEnv( GLenum value ); +void GL_EnableMultitexture( qboolean enable ); +void GL_SelectTexture( GLenum ); + +void R_LightPoint (vec3_t p, vec3_t color); +void R_PushDlights (void); + +//==================================================================== + +extern model_t *r_worldmodel; + +extern unsigned d_8to24table[256]; + +extern int registration_sequence; + + +void V_AddBlend (float r, float g, float b, float a, float *v_blend); + +int R_Init( void *hinstance, void *hWnd ); +void R_Shutdown( void ); + +void R_RenderView (refdef_t *fd); +void GL_ScreenShot_f (void); +void R_DrawAliasModel (entity_t *e); +void R_DrawBrushModel (entity_t *e); +void R_DrawSpriteModel (entity_t *e); +void R_DrawBeam( entity_t *e ); +void R_DrawWorld (void); +void R_RenderDlights (void); +void R_DrawAlphaSurfaces (void); +void R_RenderBrushPoly (msurface_t *fa); +void R_InitParticleTexture (void); +void Draw_InitLocal (void); +void GL_SubdivideSurface (msurface_t *fa); +qboolean R_CullBox (vec3_t mins, vec3_t maxs); +void R_RotateForEntity (entity_t *e); +void R_MarkLeaves (void); + +glpoly_t *WaterWarpPolyVerts (glpoly_t *p); +void EmitWaterPolys (msurface_t *fa); +void R_AddSkySurface (msurface_t *fa); +void R_ClearSkyBox (void); +void R_DrawSkyBox (void); +void R_MarkLights (dlight_t *light, int bit, mnode_t *node); + +#if 0 +short LittleShort (short l); +short BigShort (short l); +int LittleLong (int l); +float LittleFloat (float f); + +char *va(char *format, ...); +// does a varargs printf into a temp buffer +#endif + +void COM_StripExtension (char *in, char *out); + +void Draw_GetPicSize (int *w, int *h, char *name); +void Draw_Pic (int x, int y, char *name); +void Draw_StretchPic (int x, int y, int w, int h, char *name); +void Draw_Char (int x, int y, int c); +void Draw_TileClear (int x, int y, int w, int h, char *name); +void Draw_Fill (int x, int y, int w, int h, int c); +void Draw_FadeScreen (void); +void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data); + +void R_BeginFrame( float camera_separation ); +void R_SwapBuffers( int ); +void R_SetPalette ( const unsigned char *palette); + +int Draw_GetPalette (void); + +void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight); + +struct image_s *R_RegisterSkin (char *name); + +void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height); +image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type, int bits); +image_t *GL_FindImage (char *name, imagetype_t type); +void GL_TextureMode( char *string ); +void GL_ImageList_f (void); + +void GL_SetTexturePalette( unsigned palette[256] ); + +void GL_InitImages (void); +void GL_ShutdownImages (void); + +void GL_FreeUnusedImages (void); + +void GL_TextureAlphaMode( char *string ); +void GL_TextureSolidMode( char *string ); + +/* +** GL extension emulation functions +*/ +void GL_DrawParticles( int n, const particle_t particles[], const unsigned colortable[768] ); + +/* +** GL config stuff +*/ +#define GL_RENDERER_VOODOO 0x00000001 +#define GL_RENDERER_VOODOO2 0x00000002 +#define GL_RENDERER_VOODOO_RUSH 0x00000004 +#define GL_RENDERER_BANSHEE 0x00000008 +#define GL_RENDERER_3DFX 0x0000000F + +#define GL_RENDERER_PCX1 0x00000010 +#define GL_RENDERER_PCX2 0x00000020 +#define GL_RENDERER_PMX 0x00000040 +#define GL_RENDERER_POWERVR 0x00000070 + +#define GL_RENDERER_PERMEDIA2 0x00000100 +#define GL_RENDERER_GLINT_MX 0x00000200 +#define GL_RENDERER_GLINT_TX 0x00000400 +#define GL_RENDERER_3DLABS_MISC 0x00000800 +#define GL_RENDERER_3DLABS 0x00000F00 + +#define GL_RENDERER_REALIZM 0x00001000 +#define GL_RENDERER_REALIZM2 0x00002000 +#define GL_RENDERER_INTERGRAPH 0x00003000 + +#define GL_RENDERER_3DPRO 0x00004000 +#define GL_RENDERER_REAL3D 0x00008000 +#define GL_RENDERER_RIVA128 0x00010000 +#define GL_RENDERER_DYPIC 0x00020000 + +#define GL_RENDERER_V1000 0x00040000 +#define GL_RENDERER_V2100 0x00080000 +#define GL_RENDERER_V2200 0x00100000 +#define GL_RENDERER_RENDITION 0x001C0000 + +#define GL_RENDERER_O2 0x00100000 +#define GL_RENDERER_IMPACT 0x00200000 +#define GL_RENDERER_RE 0x00400000 +#define GL_RENDERER_IR 0x00800000 +#define GL_RENDERER_SGI 0x00F00000 + +#define GL_RENDERER_MCD 0x01000000 +#define GL_RENDERER_OTHER 0x80000000 + +typedef struct +{ + int renderer; + const char *renderer_string; + const char *vendor_string; + const char *version_string; + const char *extensions_string; + + qboolean allow_cds; +} glconfig_t; + +typedef struct +{ + float inverse_intensity; + qboolean fullscreen; + + int prev_mode; + + unsigned char *d_16to8table; + + int lightmap_textures; + + int currenttextures[2]; + int currenttmu; + + float camera_separation; + qboolean stereo_enabled; + + unsigned char originalRedGammaTable[256]; + unsigned char originalGreenGammaTable[256]; + unsigned char originalBlueGammaTable[256]; +} glstate_t; + +extern glconfig_t gl_config; +extern glstate_t gl_state; + +/* +==================================================================== + +IMPORTED FUNCTIONS + +==================================================================== +*/ + +extern refimport_t ri; + + +/* +==================================================================== + +IMPLEMENTATION SPECIFIC FUNCTIONS + +==================================================================== +*/ + +void GLimp_BeginFrame( float camera_separation ); +void GLimp_EndFrame( void ); +int GLimp_Init( void *hinstance, void *hWnd ); +void GLimp_Shutdown( void ); +int GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen ); +void GLimp_AppActivate( qboolean active ); +void GLimp_EnableLogging( qboolean enable ); +void GLimp_LogNewFrame( void ); + diff --git a/ref_gl/gl_mesh.c b/ref_gl/gl_mesh.c new file mode 100644 index 000000000..d6d1726db --- /dev/null +++ b/ref_gl/gl_mesh.c @@ -0,0 +1,839 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +// gl_mesh.c: triangle model functions + +#include "gl_local.h" + +/* +============================================================= + + ALIAS MODELS + +============================================================= +*/ + +#define NUMVERTEXNORMALS 162 + +float r_avertexnormals[NUMVERTEXNORMALS][3] = { +#include "anorms.h" +}; + +typedef float vec4_t[4]; + +static vec4_t s_lerped[MAX_VERTS]; +//static vec3_t lerped[MAX_VERTS]; + +vec3_t shadevector; +float shadelight[3]; + +// precalculated dot products for quantized angles +#define SHADEDOT_QUANT 16 +float r_avertexnormal_dots[SHADEDOT_QUANT][256] = +#include "anormtab.h" +; + +float *shadedots = r_avertexnormal_dots[0]; + +void GL_LerpVerts( int nverts, dtrivertx_t *v, dtrivertx_t *ov, dtrivertx_t *verts, float *lerp, float move[3], float frontv[3], float backv[3] ) +{ + int i; + + //PMM -- added RF_SHELL_DOUBLE, RF_SHELL_HALF_DAM + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) + { + for (i=0 ; i < nverts; i++, v++, ov++, lerp+=4 ) + { + float *normal = r_avertexnormals[verts[i].lightnormalindex]; + + lerp[0] = move[0] + ov->v[0]*backv[0] + v->v[0]*frontv[0] + normal[0] * POWERSUIT_SCALE; + lerp[1] = move[1] + ov->v[1]*backv[1] + v->v[1]*frontv[1] + normal[1] * POWERSUIT_SCALE; + lerp[2] = move[2] + ov->v[2]*backv[2] + v->v[2]*frontv[2] + normal[2] * POWERSUIT_SCALE; + } + } + else + { + for (i=0 ; i < nverts; i++, v++, ov++, lerp+=4) + { + lerp[0] = move[0] + ov->v[0]*backv[0] + v->v[0]*frontv[0]; + lerp[1] = move[1] + ov->v[1]*backv[1] + v->v[1]*frontv[1]; + lerp[2] = move[2] + ov->v[2]*backv[2] + v->v[2]*frontv[2]; + } + } + +} + +/* +============= +GL_DrawAliasFrameLerp + +interpolates between two frames and origins +FIXME: batch lerp all vertexes +============= +*/ +void GL_DrawAliasFrameLerp (dmdl_t *paliashdr, float backlerp) +{ + float l; + daliasframe_t *frame, *oldframe; + dtrivertx_t *v, *ov, *verts; + int *order; + int count; + float frontlerp; + float alpha; + vec3_t move, delta, vectors[3]; + vec3_t frontv, backv; + int i; + int index_xyz; + float *lerp; + + frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + + currententity->frame * paliashdr->framesize); + verts = v = frame->verts; + + oldframe = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + + currententity->oldframe * paliashdr->framesize); + ov = oldframe->verts; + + order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds); + +// glTranslatef (frame->translate[0], frame->translate[1], frame->translate[2]); +// glScalef (frame->scale[0], frame->scale[1], frame->scale[2]); + + if (currententity->flags & RF_TRANSLUCENT) + alpha = currententity->alpha; + else + alpha = 1.0; + + // PMM - added double shell + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) + qglDisable( GL_TEXTURE_2D ); + + frontlerp = 1.0 - backlerp; + + // move should be the delta back to the previous frame * backlerp + VectorSubtract (currententity->oldorigin, currententity->origin, delta); + AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]); + + move[0] = DotProduct (delta, vectors[0]); // forward + move[1] = -DotProduct (delta, vectors[1]); // left + move[2] = DotProduct (delta, vectors[2]); // up + + VectorAdd (move, oldframe->translate, move); + + for (i=0 ; i<3 ; i++) + { + move[i] = backlerp*move[i] + frontlerp*frame->translate[i]; + } + + for (i=0 ; i<3 ; i++) + { + frontv[i] = frontlerp*frame->scale[i]; + backv[i] = backlerp*oldframe->scale[i]; + } + + lerp = s_lerped[0]; + + GL_LerpVerts( paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv ); + + if ( gl_vertex_arrays->value ) + { + float colorArray[MAX_VERTS*4]; + + qglEnableClientState( GL_VERTEX_ARRAY ); + qglVertexPointer( 3, GL_FLOAT, 16, s_lerped ); // padded for SIMD + +// if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) + // PMM - added double damage shell + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) + { + qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha ); + } + else + { + qglEnableClientState( GL_COLOR_ARRAY ); + qglColorPointer( 3, GL_FLOAT, 0, colorArray ); + + // + // pre light everything + // + for ( i = 0; i < paliashdr->num_xyz; i++ ) + { + float l = shadedots[verts[i].lightnormalindex]; + + colorArray[i*3+0] = l * shadelight[0]; + colorArray[i*3+1] = l * shadelight[1]; + colorArray[i*3+2] = l * shadelight[2]; + } + } + + if ( qglLockArraysEXT != 0 ) + qglLockArraysEXT( 0, paliashdr->num_xyz ); + + while (1) + { + // get the vertex count and primitive type + count = *order++; + if (!count) + break; // done + if (count < 0) + { + count = -count; + qglBegin (GL_TRIANGLE_FAN); + } + else + { + qglBegin (GL_TRIANGLE_STRIP); + } + + // PMM - added double damage shell + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) + { + do + { + index_xyz = order[2]; + order += 3; + + qglVertex3fv( s_lerped[index_xyz] ); + + } while (--count); + } + else + { + do + { + // texture coordinates come from the draw list + qglTexCoord2f (((float *)order)[0], ((float *)order)[1]); + index_xyz = order[2]; + + order += 3; + + // normals and vertexes come from the frame list +// l = shadedots[verts[index_xyz].lightnormalindex]; + +// qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha); + qglArrayElement( index_xyz ); + + } while (--count); + } + qglEnd (); + } + + if ( qglUnlockArraysEXT != 0 ) + qglUnlockArraysEXT(); + } + else + { + while (1) + { + // get the vertex count and primitive type + count = *order++; + if (!count) + break; // done + if (count < 0) + { + count = -count; + qglBegin (GL_TRIANGLE_FAN); + } + else + { + qglBegin (GL_TRIANGLE_STRIP); + } + + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) + { + do + { + index_xyz = order[2]; + order += 3; + + qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha); + qglVertex3fv (s_lerped[index_xyz]); + + } while (--count); + } + else + { + do + { + // texture coordinates come from the draw list + qglTexCoord2f (((float *)order)[0], ((float *)order)[1]); + index_xyz = order[2]; + order += 3; + + // normals and vertexes come from the frame list + l = shadedots[verts[index_xyz].lightnormalindex]; + + qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha); + qglVertex3fv (s_lerped[index_xyz]); + } while (--count); + } + + qglEnd (); + } + } + +// if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) + // PMM - added double damage shell + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) + qglEnable( GL_TEXTURE_2D ); +} + + +#if 1 +/* +============= +GL_DrawAliasShadow +============= +*/ +extern vec3_t lightspot; + +void GL_DrawAliasShadow (dmdl_t *paliashdr, int posenum) +{ + dtrivertx_t *verts; + int *order; + vec3_t point; + float height, lheight; + int count; + daliasframe_t *frame; + + lheight = currententity->origin[2] - lightspot[2]; + + frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + + currententity->frame * paliashdr->framesize); + verts = frame->verts; + + height = 0; + + order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds); + + height = -lheight + 1.0; + + while (1) + { + // get the vertex count and primitive type + count = *order++; + if (!count) + break; // done + if (count < 0) + { + count = -count; + qglBegin (GL_TRIANGLE_FAN); + } + else + qglBegin (GL_TRIANGLE_STRIP); + + do + { + // normals and vertexes come from the frame list +/* + point[0] = verts[order[2]].v[0] * frame->scale[0] + frame->translate[0]; + point[1] = verts[order[2]].v[1] * frame->scale[1] + frame->translate[1]; + point[2] = verts[order[2]].v[2] * frame->scale[2] + frame->translate[2]; +*/ + + memcpy( point, s_lerped[order[2]], sizeof( point ) ); + + point[0] -= shadevector[0]*(point[2]+lheight); + point[1] -= shadevector[1]*(point[2]+lheight); + point[2] = height; +// height -= 0.001; + qglVertex3fv (point); + + order += 3; + +// verts++; + + } while (--count); + + qglEnd (); + } +} + +#endif + +/* +** R_CullAliasModel +*/ +static qboolean R_CullAliasModel( vec3_t bbox[8], entity_t *e ) +{ + int i; + vec3_t mins, maxs; + dmdl_t *paliashdr; + vec3_t vectors[3]; + vec3_t thismins, oldmins, thismaxs, oldmaxs; + daliasframe_t *pframe, *poldframe; + vec3_t angles; + + paliashdr = (dmdl_t *)currentmodel->extradata; + + if ( ( e->frame >= paliashdr->num_frames ) || ( e->frame < 0 ) ) + { + ri.Con_Printf (PRINT_ALL, "R_CullAliasModel %s: no such frame %d\n", + currentmodel->name, e->frame); + e->frame = 0; + } + if ( ( e->oldframe >= paliashdr->num_frames ) || ( e->oldframe < 0 ) ) + { + ri.Con_Printf (PRINT_ALL, "R_CullAliasModel %s: no such oldframe %d\n", + currentmodel->name, e->oldframe); + e->oldframe = 0; + } + + pframe = ( daliasframe_t * ) ( ( byte * ) paliashdr + + paliashdr->ofs_frames + + e->frame * paliashdr->framesize); + + poldframe = ( daliasframe_t * ) ( ( byte * ) paliashdr + + paliashdr->ofs_frames + + e->oldframe * paliashdr->framesize); + + /* + ** compute axially aligned mins and maxs + */ + if ( pframe == poldframe ) + { + for ( i = 0; i < 3; i++ ) + { + mins[i] = pframe->translate[i]; + maxs[i] = mins[i] + pframe->scale[i]*255; + } + } + else + { + for ( i = 0; i < 3; i++ ) + { + thismins[i] = pframe->translate[i]; + thismaxs[i] = thismins[i] + pframe->scale[i]*255; + + oldmins[i] = poldframe->translate[i]; + oldmaxs[i] = oldmins[i] + poldframe->scale[i]*255; + + if ( thismins[i] < oldmins[i] ) + mins[i] = thismins[i]; + else + mins[i] = oldmins[i]; + + if ( thismaxs[i] > oldmaxs[i] ) + maxs[i] = thismaxs[i]; + else + maxs[i] = oldmaxs[i]; + } + } + + /* + ** compute a full bounding box + */ + for ( i = 0; i < 8; i++ ) + { + vec3_t tmp; + + if ( i & 1 ) + tmp[0] = mins[0]; + else + tmp[0] = maxs[0]; + + if ( i & 2 ) + tmp[1] = mins[1]; + else + tmp[1] = maxs[1]; + + if ( i & 4 ) + tmp[2] = mins[2]; + else + tmp[2] = maxs[2]; + + VectorCopy( tmp, bbox[i] ); + } + + /* + ** rotate the bounding box + */ + VectorCopy( e->angles, angles ); + angles[YAW] = -angles[YAW]; + AngleVectors( angles, vectors[0], vectors[1], vectors[2] ); + + for ( i = 0; i < 8; i++ ) + { + vec3_t tmp; + + VectorCopy( bbox[i], tmp ); + + bbox[i][0] = DotProduct( vectors[0], tmp ); + bbox[i][1] = -DotProduct( vectors[1], tmp ); + bbox[i][2] = DotProduct( vectors[2], tmp ); + + VectorAdd( e->origin, bbox[i], bbox[i] ); + } + + { + int p, f, aggregatemask = ~0; + + for ( p = 0; p < 8; p++ ) + { + int mask = 0; + + for ( f = 0; f < 4; f++ ) + { + float dp = DotProduct( frustum[f].normal, bbox[p] ); + + if ( ( dp - frustum[f].dist ) < 0 ) + { + mask |= ( 1 << f ); + } + } + + aggregatemask &= mask; + } + + if ( aggregatemask ) + { + return true; + } + + return false; + } +} + +/* +================= +R_DrawAliasModel + +================= +*/ +void R_DrawAliasModel (entity_t *e) +{ + int i; + dmdl_t *paliashdr; + float an; + vec3_t bbox[8]; + image_t *skin; + + if ( !( e->flags & RF_WEAPONMODEL ) ) + { + if ( R_CullAliasModel( bbox, e ) ) + return; + } + + if ( e->flags & RF_WEAPONMODEL ) + { + if ( r_lefthand->value == 2 ) + return; + } + + paliashdr = (dmdl_t *)currentmodel->extradata; + + // + // get lighting information + // + // PMM - rewrote, reordered to handle new shells & mixing + // + if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) + { + // PMM -special case for godmode + if ( (currententity->flags & RF_SHELL_RED) && + (currententity->flags & RF_SHELL_BLUE) && + (currententity->flags & RF_SHELL_GREEN) ) + { + for (i=0 ; i<3 ; i++) + shadelight[i] = 1.0; + } + else if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) + { + VectorClear (shadelight); + + if ( currententity->flags & RF_SHELL_RED ) + { + shadelight[0] = 1.0; + if (currententity->flags & (RF_SHELL_BLUE|RF_SHELL_DOUBLE) ) + shadelight[2] = 1.0; + } + else if ( currententity->flags & RF_SHELL_BLUE ) + { + if ( currententity->flags & RF_SHELL_DOUBLE ) + { + shadelight[1] = 1.0; + shadelight[2] = 1.0; + } + else + { + shadelight[2] = 1.0; + } + } + else if ( currententity->flags & RF_SHELL_DOUBLE ) + { + shadelight[0] = 0.9; + shadelight[1] = 0.7; + } + } + else if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN ) ) + { + VectorClear (shadelight); + // PMM - new colors + if ( currententity->flags & RF_SHELL_HALF_DAM ) + { + shadelight[0] = 0.56; + shadelight[1] = 0.59; + shadelight[2] = 0.45; + } + if ( currententity->flags & RF_SHELL_GREEN ) + { + shadelight[1] = 1.0; + } + } + } + //PMM - ok, now flatten these down to range from 0 to 1.0. + // max_shell_val = max(shadelight[0], max(shadelight[1], shadelight[2])); + // if (max_shell_val > 0) + // { + // for (i=0; i<3; i++) + // { + // shadelight[i] = shadelight[i] / max_shell_val; + // } + // } + // pmm + else if ( currententity->flags & RF_FULLBRIGHT ) + { + for (i=0 ; i<3 ; i++) + shadelight[i] = 1.0; + } + else + { + R_LightPoint (currententity->origin, shadelight); + + // player lighting hack for communication back to server + // big hack! + if ( currententity->flags & RF_WEAPONMODEL ) + { + // pick the greatest component, which should be the same + // as the mono value returned by software + if (shadelight[0] > shadelight[1]) + { + if (shadelight[0] > shadelight[2]) + r_lightlevel->value = 150*shadelight[0]; + else + r_lightlevel->value = 150*shadelight[2]; + } + else + { + if (shadelight[1] > shadelight[2]) + r_lightlevel->value = 150*shadelight[1]; + else + r_lightlevel->value = 150*shadelight[2]; + } + + } + + if ( gl_monolightmap->string[0] != '0' ) + { + float s = shadelight[0]; + + if ( s < shadelight[1] ) + s = shadelight[1]; + if ( s < shadelight[2] ) + s = shadelight[2]; + + shadelight[0] = s; + shadelight[1] = s; + shadelight[2] = s; + } + } + + if ( currententity->flags & RF_MINLIGHT ) + { + for (i=0 ; i<3 ; i++) + if (shadelight[i] > 0.1) + break; + if (i == 3) + { + shadelight[0] = 0.1; + shadelight[1] = 0.1; + shadelight[2] = 0.1; + } + } + + if ( currententity->flags & RF_GLOW ) + { // bonus items will pulse with time + float scale; + float min; + + scale = 0.1 * sin(r_newrefdef.time*7); + for (i=0 ; i<3 ; i++) + { + min = shadelight[i] * 0.8; + shadelight[i] += scale; + if (shadelight[i] < min) + shadelight[i] = min; + } + } + +// ================= +// PGM ir goggles color override + if ( r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE) + { + shadelight[0] = 1.0; + shadelight[1] = 0.0; + shadelight[2] = 0.0; + } +// PGM +// ================= + + shadedots = r_avertexnormal_dots[((int)(currententity->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; + + an = currententity->angles[1]/180*M_PI; + shadevector[0] = cos(-an); + shadevector[1] = sin(-an); + shadevector[2] = 1; + VectorNormalize (shadevector); + + // + // locate the proper data + // + + c_alias_polys += paliashdr->num_tris; + + // + // draw all the triangles + // + if (currententity->flags & RF_DEPTHHACK) // hack the depth range to prevent view model from poking into walls + qglDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); + + if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) + { + extern void MYgluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar ); + + qglMatrixMode( GL_PROJECTION ); + qglPushMatrix(); + qglLoadIdentity(); + qglScalef( -1, 1, 1 ); + MYgluPerspective( r_newrefdef.fov_y, ( float ) r_newrefdef.width / r_newrefdef.height, 4, 4096); + qglMatrixMode( GL_MODELVIEW ); + + qglCullFace( GL_BACK ); + } + + qglPushMatrix (); + e->angles[PITCH] = -e->angles[PITCH]; // sigh. + R_RotateForEntity (e); + e->angles[PITCH] = -e->angles[PITCH]; // sigh. + + // select skin + if (currententity->skin) + skin = currententity->skin; // custom player skin + else + { + if (currententity->skinnum >= MAX_MD2SKINS) + skin = currentmodel->skins[0]; + else + { + skin = currentmodel->skins[currententity->skinnum]; + if (!skin) + skin = currentmodel->skins[0]; + } + } + if (!skin) + skin = r_notexture; // fallback... + GL_Bind(skin->texnum); + + // draw it + + qglShadeModel (GL_SMOOTH); + + GL_TexEnv( GL_MODULATE ); + if ( currententity->flags & RF_TRANSLUCENT ) + { + qglEnable (GL_BLEND); + } + + + if ( (currententity->frame >= paliashdr->num_frames) + || (currententity->frame < 0) ) + { + ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such frame %d\n", + currentmodel->name, currententity->frame); + currententity->frame = 0; + currententity->oldframe = 0; + } + + if ( (currententity->oldframe >= paliashdr->num_frames) + || (currententity->oldframe < 0)) + { + ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such oldframe %d\n", + currentmodel->name, currententity->oldframe); + currententity->frame = 0; + currententity->oldframe = 0; + } + + if ( !r_lerpmodels->value ) + currententity->backlerp = 0; + GL_DrawAliasFrameLerp (paliashdr, currententity->backlerp); + + GL_TexEnv( GL_REPLACE ); + qglShadeModel (GL_FLAT); + + qglPopMatrix (); + +#if 0 + qglDisable( GL_CULL_FACE ); + qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + qglDisable( GL_TEXTURE_2D ); + qglBegin( GL_TRIANGLE_STRIP ); + for ( i = 0; i < 8; i++ ) + { + qglVertex3fv( bbox[i] ); + } + qglEnd(); + qglEnable( GL_TEXTURE_2D ); + qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + qglEnable( GL_CULL_FACE ); +#endif + + if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) + { + qglMatrixMode( GL_PROJECTION ); + qglPopMatrix(); + qglMatrixMode( GL_MODELVIEW ); + qglCullFace( GL_FRONT ); + } + + if ( currententity->flags & RF_TRANSLUCENT ) + { + qglDisable (GL_BLEND); + } + + if (currententity->flags & RF_DEPTHHACK) + qglDepthRange (gldepthmin, gldepthmax); + +#if 1 + if (gl_shadows->value && !(currententity->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL))) + { + qglPushMatrix (); + R_RotateForEntity (e); + qglDisable (GL_TEXTURE_2D); + qglEnable (GL_BLEND); + qglColor4f (0,0,0,0.5); + GL_DrawAliasShadow (paliashdr, currententity->frame ); + qglEnable (GL_TEXTURE_2D); + qglDisable (GL_BLEND); + qglPopMatrix (); + } +#endif + qglColor4f (1,1,1,1); +} + + diff --git a/ref_gl/gl_model.c b/ref_gl/gl_model.c new file mode 100644 index 000000000..05307a3a5 --- /dev/null +++ b/ref_gl/gl_model.c @@ -0,0 +1,1223 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +// models.c -- model loading and caching + +#include "gl_local.h" + +model_t *loadmodel; +int modfilelen; + +void Mod_LoadSpriteModel (model_t *mod, void *buffer); +void Mod_LoadBrushModel (model_t *mod, void *buffer); +void Mod_LoadAliasModel (model_t *mod, void *buffer); +model_t *Mod_LoadModel (model_t *mod, qboolean crash); + +byte mod_novis[MAX_MAP_LEAFS/8]; + +#define MAX_MOD_KNOWN 512 +model_t mod_known[MAX_MOD_KNOWN]; +int mod_numknown; + +// the inline * models from the current map are kept seperate +model_t mod_inline[MAX_MOD_KNOWN]; + +int registration_sequence; + +/* +=============== +Mod_PointInLeaf +=============== +*/ +mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model) +{ + mnode_t *node; + float d; + cplane_t *plane; + + if (!model || !model->nodes) + ri.Sys_Error (ERR_DROP, "Mod_PointInLeaf: bad model"); + + node = model->nodes; + while (1) + { + if (node->contents != -1) + return (mleaf_t *)node; + plane = node->plane; + d = DotProduct (p,plane->normal) - plane->dist; + if (d > 0) + node = node->children[0]; + else + node = node->children[1]; + } + + return NULL; // never reached +} + + +/* +=================== +Mod_DecompressVis +=================== +*/ +byte *Mod_DecompressVis (byte *in, model_t *model) +{ + static byte decompressed[MAX_MAP_LEAFS/8]; + int c; + byte *out; + int row; + + row = (model->vis->numclusters+7)>>3; + out = decompressed; + + if (!in) + { // no vis info, so make all visible + while (row) + { + *out++ = 0xff; + row--; + } + return decompressed; + } + + do + { + if (*in) + { + *out++ = *in++; + continue; + } + + c = in[1]; + in += 2; + while (c) + { + *out++ = 0; + c--; + } + } while (out - decompressed < row); + + return decompressed; +} + +/* +============== +Mod_ClusterPVS +============== +*/ +byte *Mod_ClusterPVS (int cluster, model_t *model) +{ + if (cluster == -1 || !model->vis) + return mod_novis; + return Mod_DecompressVis ( (byte *)model->vis + model->vis->bitofs[cluster][DVIS_PVS], + model); +} + + +//=============================================================================== + +/* +================ +Mod_Modellist_f +================ +*/ +void Mod_Modellist_f (void) +{ + int i; + model_t *mod; + int total; + + total = 0; + ri.Con_Printf (PRINT_ALL,"Loaded models:\n"); + for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++) + { + if (!mod->name[0]) + continue; + ri.Con_Printf (PRINT_ALL, "%8i : %s\n",mod->extradatasize, mod->name); + total += mod->extradatasize; + } + ri.Con_Printf (PRINT_ALL, "Total resident: %i\n", total); +} + +/* +=============== +Mod_Init +=============== +*/ +void Mod_Init (void) +{ + memset (mod_novis, 0xff, sizeof(mod_novis)); +} + + + +/* +================== +Mod_ForName + +Loads in a model for the given name +================== +*/ +model_t *Mod_ForName (char *name, qboolean crash) +{ + model_t *mod; + unsigned *buf; + int i; + + if (!name[0]) + ri.Sys_Error (ERR_DROP, "Mod_ForName: NULL name"); + + // + // inline models are grabbed only from worldmodel + // + if (name[0] == '*') + { + i = atoi(name+1); + if (i < 1 || !r_worldmodel || i >= r_worldmodel->numsubmodels) + ri.Sys_Error (ERR_DROP, "bad inline model number"); + return &mod_inline[i]; + } + + // + // search the currently loaded models + // + for (i=0 , mod=mod_known ; iname[0]) + continue; + if (!strcmp (mod->name, name) ) + return mod; + } + + // + // find a free model slot spot + // + for (i=0 , mod=mod_known ; iname[0]) + break; // free spot + } + if (i == mod_numknown) + { + if (mod_numknown == MAX_MOD_KNOWN) + ri.Sys_Error (ERR_DROP, "mod_numknown == MAX_MOD_KNOWN"); + mod_numknown++; + } + strcpy (mod->name, name); + + // + // load the file + // + modfilelen = ri.FS_LoadFile (mod->name, &buf); + if (!buf) + { + if (crash) + ri.Sys_Error (ERR_DROP, "Mod_NumForName: %s not found", mod->name); + memset (mod->name, 0, sizeof(mod->name)); + return NULL; + } + + loadmodel = mod; + + // + // fill it in + // + + + // call the apropriate loader + + switch (LittleLong(*(unsigned *)buf)) + { + case IDALIASHEADER: + loadmodel->extradata = Hunk_Begin (0x200000); + Mod_LoadAliasModel (mod, buf); + break; + + case IDSPRITEHEADER: + loadmodel->extradata = Hunk_Begin (0x10000); + Mod_LoadSpriteModel (mod, buf); + break; + + case IDBSPHEADER: + loadmodel->extradata = Hunk_Begin (0x1000000); + Mod_LoadBrushModel (mod, buf); + break; + + default: + ri.Sys_Error (ERR_DROP,"Mod_NumForName: unknown fileid for %s", mod->name); + break; + } + + loadmodel->extradatasize = Hunk_End (); + + ri.FS_FreeFile (buf); + + return mod; +} + +/* +=============================================================================== + + BRUSHMODEL LOADING + +=============================================================================== +*/ + +byte *mod_base; + + +/* +================= +Mod_LoadLighting +================= +*/ +void Mod_LoadLighting (lump_t *l) +{ + if (!l->filelen) + { + loadmodel->lightdata = NULL; + return; + } + loadmodel->lightdata = Hunk_Alloc ( l->filelen); + memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); +} + + +/* +================= +Mod_LoadVisibility +================= +*/ +void Mod_LoadVisibility (lump_t *l) +{ + int i; + + if (!l->filelen) + { + loadmodel->vis = NULL; + return; + } + loadmodel->vis = Hunk_Alloc ( l->filelen); + memcpy (loadmodel->vis, mod_base + l->fileofs, l->filelen); + + loadmodel->vis->numclusters = LittleLong (loadmodel->vis->numclusters); + for (i=0 ; ivis->numclusters ; i++) + { + loadmodel->vis->bitofs[i][0] = LittleLong (loadmodel->vis->bitofs[i][0]); + loadmodel->vis->bitofs[i][1] = LittleLong (loadmodel->vis->bitofs[i][1]); + } +} + + +/* +================= +Mod_LoadVertexes +================= +*/ +void Mod_LoadVertexes (lump_t *l) +{ + dvertex_t *in; + mvertex_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->vertexes = out; + loadmodel->numvertexes = count; + + for ( i=0 ; iposition[0] = LittleFloat (in->point[0]); + out->position[1] = LittleFloat (in->point[1]); + out->position[2] = LittleFloat (in->point[2]); + } +} + +/* +================= +RadiusFromBounds +================= +*/ +float RadiusFromBounds (vec3_t mins, vec3_t maxs) +{ + int i; + vec3_t corner; + + for (i=0 ; i<3 ; i++) + { + corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]); + } + + return VectorLength (corner); +} + + +/* +================= +Mod_LoadSubmodels +================= +*/ +void Mod_LoadSubmodels (lump_t *l) +{ + dmodel_t *in; + mmodel_t *out; + int i, j, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->submodels = out; + loadmodel->numsubmodels = count; + + for ( i=0 ; imins[j] = LittleFloat (in->mins[j]) - 1; + out->maxs[j] = LittleFloat (in->maxs[j]) + 1; + out->origin[j] = LittleFloat (in->origin[j]); + } + out->radius = RadiusFromBounds (out->mins, out->maxs); + out->headnode = LittleLong (in->headnode); + out->firstface = LittleLong (in->firstface); + out->numfaces = LittleLong (in->numfaces); + } +} + +/* +================= +Mod_LoadEdges +================= +*/ +void Mod_LoadEdges (lump_t *l) +{ + dedge_t *in; + medge_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( (count + 1) * sizeof(*out)); + + loadmodel->edges = out; + loadmodel->numedges = count; + + for ( i=0 ; iv[0] = (unsigned short)LittleShort(in->v[0]); + out->v[1] = (unsigned short)LittleShort(in->v[1]); + } +} + +/* +================= +Mod_LoadTexinfo +================= +*/ +void Mod_LoadTexinfo (lump_t *l) +{ + texinfo_t *in; + mtexinfo_t *out, *step; + int i, j, count; + char name[MAX_QPATH]; + int next; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->texinfo = out; + loadmodel->numtexinfo = count; + + for ( i=0 ; ivecs[0][j] = LittleFloat (in->vecs[0][j]); + + out->flags = LittleLong (in->flags); + next = LittleLong (in->nexttexinfo); + if (next > 0) + out->next = loadmodel->texinfo + next; + else + out->next = NULL; + Com_sprintf (name, sizeof(name), "textures/%s.wal", in->texture); + + out->image = GL_FindImage (name, it_wall); + if (!out->image) + { + ri.Con_Printf (PRINT_ALL, "Couldn't load %s\n", name); + out->image = r_notexture; + } + } + + // count animation frames + for (i=0 ; itexinfo[i]; + out->numframes = 1; + for (step = out->next ; step && step != out ; step=step->next) + out->numframes++; + } +} + +/* +================ +CalcSurfaceExtents + +Fills in s->texturemins[] and s->extents[] +================ +*/ +void CalcSurfaceExtents (msurface_t *s) +{ + float mins[2], maxs[2], val; + int i,j, e; + mvertex_t *v; + mtexinfo_t *tex; + int bmins[2], bmaxs[2]; + + mins[0] = mins[1] = 999999; + maxs[0] = maxs[1] = -99999; + + tex = s->texinfo; + + for (i=0 ; inumedges ; i++) + { + e = loadmodel->surfedges[s->firstedge+i]; + if (e >= 0) + v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; + else + v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; + + for (j=0 ; j<2 ; j++) + { + val = v->position[0] * tex->vecs[j][0] + + v->position[1] * tex->vecs[j][1] + + v->position[2] * tex->vecs[j][2] + + tex->vecs[j][3]; + if (val < mins[j]) + mins[j] = val; + if (val > maxs[j]) + maxs[j] = val; + } + } + + for (i=0 ; i<2 ; i++) + { + bmins[i] = floor(mins[i]/16); + bmaxs[i] = ceil(maxs[i]/16); + + s->texturemins[i] = bmins[i] * 16; + s->extents[i] = (bmaxs[i] - bmins[i]) * 16; + +// if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 512 /* 256 */ ) +// ri.Sys_Error (ERR_DROP, "Bad surface extents"); + } +} + + +void GL_BuildPolygonFromSurface(msurface_t *fa); +void GL_CreateSurfaceLightmap (msurface_t *surf); +void GL_EndBuildingLightmaps (void); +void GL_BeginBuildingLightmaps (model_t *m); + +/* +================= +Mod_LoadFaces +================= +*/ +void Mod_LoadFaces (lump_t *l) +{ + dface_t *in; + msurface_t *out; + int i, count, surfnum; + int planenum, side; + int ti; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->surfaces = out; + loadmodel->numsurfaces = count; + + currentmodel = loadmodel; + + GL_BeginBuildingLightmaps (loadmodel); + + for ( surfnum=0 ; surfnumfirstedge = LittleLong(in->firstedge); + out->numedges = LittleShort(in->numedges); + out->flags = 0; + out->polys = NULL; + + planenum = LittleShort(in->planenum); + side = LittleShort(in->side); + if (side) + out->flags |= SURF_PLANEBACK; + + out->plane = loadmodel->planes + planenum; + + ti = LittleShort (in->texinfo); + if (ti < 0 || ti >= loadmodel->numtexinfo) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: bad texinfo number"); + out->texinfo = loadmodel->texinfo + ti; + + CalcSurfaceExtents (out); + + // lighting info + + for (i=0 ; istyles[i] = in->styles[i]; + i = LittleLong(in->lightofs); + if (i == -1) + out->samples = NULL; + else + out->samples = loadmodel->lightdata + i; + + // set the drawing flags + + if (out->texinfo->flags & SURF_WARP) + { + out->flags |= SURF_DRAWTURB; + for (i=0 ; i<2 ; i++) + { + out->extents[i] = 16384; + out->texturemins[i] = -8192; + } + GL_SubdivideSurface (out); // cut up polygon for warps + } + + // create lightmaps and polygons + if ( !(out->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP) ) ) + GL_CreateSurfaceLightmap (out); + + if (! (out->texinfo->flags & SURF_WARP) ) + GL_BuildPolygonFromSurface(out); + + } + + GL_EndBuildingLightmaps (); +} + + +/* +================= +Mod_SetParent +================= +*/ +void Mod_SetParent (mnode_t *node, mnode_t *parent) +{ + node->parent = parent; + if (node->contents != -1) + return; + Mod_SetParent (node->children[0], node); + Mod_SetParent (node->children[1], node); +} + +/* +================= +Mod_LoadNodes +================= +*/ +void Mod_LoadNodes (lump_t *l) +{ + int i, j, count, p; + dnode_t *in; + mnode_t *out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->nodes = out; + loadmodel->numnodes = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + p = LittleLong(in->planenum); + out->plane = loadmodel->planes + p; + + out->firstsurface = LittleShort (in->firstface); + out->numsurfaces = LittleShort (in->numfaces); + out->contents = -1; // differentiate from leafs + + for (j=0 ; j<2 ; j++) + { + p = LittleLong (in->children[j]); + if (p >= 0) + out->children[j] = loadmodel->nodes + p; + else + out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p)); + } + } + + Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs +} + +/* +================= +Mod_LoadLeafs +================= +*/ +void Mod_LoadLeafs (lump_t *l) +{ + dleaf_t *in; + mleaf_t *out; + int i, j, count, p; +// glpoly_t *poly; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->leafs = out; + loadmodel->numleafs = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + p = LittleLong(in->contents); + out->contents = p; + + out->cluster = LittleShort(in->cluster); + out->area = LittleShort(in->area); + + out->firstmarksurface = loadmodel->marksurfaces + + LittleShort(in->firstleafface); + out->nummarksurfaces = LittleShort(in->numleaffaces); + + // gl underwater warp +#if 0 + if (out->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA|CONTENTS_THINWATER) ) + { + for (j=0 ; jnummarksurfaces ; j++) + { + out->firstmarksurface[j]->flags |= SURF_UNDERWATER; + for (poly = out->firstmarksurface[j]->polys ; poly ; poly=poly->next) + poly->flags |= SURF_UNDERWATER; + } + } +#endif + } +} + +/* +================= +Mod_LoadMarksurfaces +================= +*/ +void Mod_LoadMarksurfaces (lump_t *l) +{ + int i, j, count; + short *in; + msurface_t **out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->marksurfaces = out; + loadmodel->nummarksurfaces = count; + + for ( i=0 ; i= loadmodel->numsurfaces) + ri.Sys_Error (ERR_DROP, "Mod_ParseMarksurfaces: bad surface number"); + out[i] = loadmodel->surfaces + j; + } +} + +/* +================= +Mod_LoadSurfedges +================= +*/ +void Mod_LoadSurfedges (lump_t *l) +{ + int i, count; + int *in, *out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + if (count < 1 || count >= MAX_MAP_SURFEDGES) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: bad surfedges count in %s: %i", + loadmodel->name, count); + + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->surfedges = out; + loadmodel->numsurfedges = count; + + for ( i=0 ; ifileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*2*sizeof(*out)); + + loadmodel->planes = out; + loadmodel->numplanes = count; + + for ( i=0 ; inormal[j] = LittleFloat (in->normal[j]); + if (out->normal[j] < 0) + bits |= 1<dist = LittleFloat (in->dist); + out->type = LittleLong (in->type); + out->signbits = bits; + } +} + +/* +================= +Mod_LoadBrushModel +================= +*/ +void Mod_LoadBrushModel (model_t *mod, void *buffer) +{ + int i; + dheader_t *header; + mmodel_t *bm; + + loadmodel->type = mod_brush; + if (loadmodel != mod_known) + ri.Sys_Error (ERR_DROP, "Loaded a brush model after the world"); + + header = (dheader_t *)buffer; + + i = LittleLong (header->version); + if (i != BSPVERSION) + ri.Sys_Error (ERR_DROP, "Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION); + +// swap all the lumps + mod_base = (byte *)header; + + for (i=0 ; ilumps[LUMP_VERTEXES]); + Mod_LoadEdges (&header->lumps[LUMP_EDGES]); + Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]); + Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]); + Mod_LoadPlanes (&header->lumps[LUMP_PLANES]); + Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]); + Mod_LoadFaces (&header->lumps[LUMP_FACES]); + Mod_LoadMarksurfaces (&header->lumps[LUMP_LEAFFACES]); + Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]); + Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]); + Mod_LoadNodes (&header->lumps[LUMP_NODES]); + Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]); + mod->numframes = 2; // regular and alternate animation + +// +// set up the submodels +// + for (i=0 ; inumsubmodels ; i++) + { + model_t *starmod; + + bm = &mod->submodels[i]; + starmod = &mod_inline[i]; + + *starmod = *loadmodel; + + starmod->firstmodelsurface = bm->firstface; + starmod->nummodelsurfaces = bm->numfaces; + starmod->firstnode = bm->headnode; + if (starmod->firstnode >= loadmodel->numnodes) + ri.Sys_Error (ERR_DROP, "Inline model %i has bad firstnode", i); + + VectorCopy (bm->maxs, starmod->maxs); + VectorCopy (bm->mins, starmod->mins); + starmod->radius = bm->radius; + + if (i == 0) + *loadmodel = *starmod; + + starmod->numleafs = bm->visleafs; + } +} + +/* +============================================================================== + +ALIAS MODELS + +============================================================================== +*/ + +/* +================= +Mod_LoadAliasModel +================= +*/ +void Mod_LoadAliasModel (model_t *mod, void *buffer) +{ + int i, j; + dmdl_t *pinmodel, *pheader; + dstvert_t *pinst, *poutst; + dtriangle_t *pintri, *pouttri; + daliasframe_t *pinframe, *poutframe; + int *pincmd, *poutcmd; + int version; + + pinmodel = (dmdl_t *)buffer; + + version = LittleLong (pinmodel->version); + if (version != ALIAS_VERSION) + ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)", + mod->name, version, ALIAS_VERSION); + + pheader = Hunk_Alloc (LittleLong(pinmodel->ofs_end)); + + // byte swap the header fields and sanity check + for (i=0 ; iskinheight > MAX_LBM_HEIGHT) + ri.Sys_Error (ERR_DROP, "model %s has a skin taller than %d", mod->name, + MAX_LBM_HEIGHT); + + if (pheader->num_xyz <= 0) + ri.Sys_Error (ERR_DROP, "model %s has no vertices", mod->name); + + if (pheader->num_xyz > MAX_VERTS) + ri.Sys_Error (ERR_DROP, "model %s has too many vertices", mod->name); + + if (pheader->num_st <= 0) + ri.Sys_Error (ERR_DROP, "model %s has no st vertices", mod->name); + + if (pheader->num_tris <= 0) + ri.Sys_Error (ERR_DROP, "model %s has no triangles", mod->name); + + if (pheader->num_frames <= 0) + ri.Sys_Error (ERR_DROP, "model %s has no frames", mod->name); + +// +// load base s and t vertices (not used in gl version) +// + pinst = (dstvert_t *) ((byte *)pinmodel + pheader->ofs_st); + poutst = (dstvert_t *) ((byte *)pheader + pheader->ofs_st); + + for (i=0 ; inum_st ; i++) + { + poutst[i].s = LittleShort (pinst[i].s); + poutst[i].t = LittleShort (pinst[i].t); + } + +// +// load triangle lists +// + pintri = (dtriangle_t *) ((byte *)pinmodel + pheader->ofs_tris); + pouttri = (dtriangle_t *) ((byte *)pheader + pheader->ofs_tris); + + for (i=0 ; inum_tris ; i++) + { + for (j=0 ; j<3 ; j++) + { + pouttri[i].index_xyz[j] = LittleShort (pintri[i].index_xyz[j]); + pouttri[i].index_st[j] = LittleShort (pintri[i].index_st[j]); + } + } + +// +// load the frames +// + for (i=0 ; inum_frames ; i++) + { + pinframe = (daliasframe_t *) ((byte *)pinmodel + + pheader->ofs_frames + i * pheader->framesize); + poutframe = (daliasframe_t *) ((byte *)pheader + + pheader->ofs_frames + i * pheader->framesize); + + memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name)); + for (j=0 ; j<3 ; j++) + { + poutframe->scale[j] = LittleFloat (pinframe->scale[j]); + poutframe->translate[j] = LittleFloat (pinframe->translate[j]); + } + // verts are all 8 bit, so no swapping needed + memcpy (poutframe->verts, pinframe->verts, + pheader->num_xyz*sizeof(dtrivertx_t)); + + } + + mod->type = mod_alias; + + // + // load the glcmds + // + pincmd = (int *) ((byte *)pinmodel + pheader->ofs_glcmds); + poutcmd = (int *) ((byte *)pheader + pheader->ofs_glcmds); + for (i=0 ; inum_glcmds ; i++) + poutcmd[i] = LittleLong (pincmd[i]); + + + // register all skins + memcpy ((char *)pheader + pheader->ofs_skins, (char *)pinmodel + pheader->ofs_skins, + pheader->num_skins*MAX_SKINNAME); + for (i=0 ; inum_skins ; i++) + { + mod->skins[i] = GL_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME + , it_skin); + } + + mod->mins[0] = -32; + mod->mins[1] = -32; + mod->mins[2] = -32; + mod->maxs[0] = 32; + mod->maxs[1] = 32; + mod->maxs[2] = 32; +} + +/* +============================================================================== + +SPRITE MODELS + +============================================================================== +*/ + +/* +================= +Mod_LoadSpriteModel +================= +*/ +void Mod_LoadSpriteModel (model_t *mod, void *buffer) +{ + dsprite_t *sprin, *sprout; + int i; + + sprin = (dsprite_t *)buffer; + sprout = Hunk_Alloc (modfilelen); + + sprout->ident = LittleLong (sprin->ident); + sprout->version = LittleLong (sprin->version); + sprout->numframes = LittleLong (sprin->numframes); + + if (sprout->version != SPRITE_VERSION) + ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)", + mod->name, sprout->version, SPRITE_VERSION); + + if (sprout->numframes > MAX_MD2SKINS) + ri.Sys_Error (ERR_DROP, "%s has too many frames (%i > %i)", + mod->name, sprout->numframes, MAX_MD2SKINS); + + // byte swap everything + for (i=0 ; inumframes ; i++) + { + sprout->frames[i].width = LittleLong (sprin->frames[i].width); + sprout->frames[i].height = LittleLong (sprin->frames[i].height); + sprout->frames[i].origin_x = LittleLong (sprin->frames[i].origin_x); + sprout->frames[i].origin_y = LittleLong (sprin->frames[i].origin_y); + memcpy (sprout->frames[i].name, sprin->frames[i].name, MAX_SKINNAME); + mod->skins[i] = GL_FindImage (sprout->frames[i].name, + it_sprite); + } + + mod->type = mod_sprite; +} + +//============================================================================= + +/* +@@@@@@@@@@@@@@@@@@@@@ +R_BeginRegistration + +Specifies the model that will be used as the world +@@@@@@@@@@@@@@@@@@@@@ +*/ +void R_BeginRegistration (char *model) +{ + char fullname[MAX_QPATH]; + cvar_t *flushmap; + + registration_sequence++; + r_oldviewcluster = -1; // force markleafs + + Com_sprintf (fullname, sizeof(fullname), "maps/%s.bsp", model); + + // explicitly free the old map if different + // this guarantees that mod_known[0] is the world map + flushmap = ri.Cvar_Get ("flushmap", "0", 0); + if ( strcmp(mod_known[0].name, fullname) || flushmap->value) + Mod_Free (&mod_known[0]); + r_worldmodel = Mod_ForName(fullname, true); + + r_viewcluster = -1; +} + + +/* +@@@@@@@@@@@@@@@@@@@@@ +R_RegisterModel + +@@@@@@@@@@@@@@@@@@@@@ +*/ +struct model_s *R_RegisterModel (char *name) +{ + model_t *mod; + int i; + dsprite_t *sprout; + dmdl_t *pheader; + + mod = Mod_ForName (name, false); + if (mod) + { + mod->registration_sequence = registration_sequence; + + // register any images used by the models + if (mod->type == mod_sprite) + { + sprout = (dsprite_t *)mod->extradata; + for (i=0 ; inumframes ; i++) + mod->skins[i] = GL_FindImage (sprout->frames[i].name, it_sprite); + } + else if (mod->type == mod_alias) + { + pheader = (dmdl_t *)mod->extradata; + for (i=0 ; inum_skins ; i++) + mod->skins[i] = GL_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin); +//PGM + mod->numframes = pheader->num_frames; +//PGM + } + else if (mod->type == mod_brush) + { + for (i=0 ; inumtexinfo ; i++) + mod->texinfo[i].image->registration_sequence = registration_sequence; + } + } + return mod; +} + + +/* +@@@@@@@@@@@@@@@@@@@@@ +R_EndRegistration + +@@@@@@@@@@@@@@@@@@@@@ +*/ +void R_EndRegistration (void) +{ + int i; + model_t *mod; + + for (i=0, mod=mod_known ; iname[0]) + continue; + if (mod->registration_sequence != registration_sequence) + { // don't need this model + Mod_Free (mod); + } + } + + GL_FreeUnusedImages (); +} + + +//============================================================================= + + +/* +================ +Mod_Free +================ +*/ +void Mod_Free (model_t *mod) +{ + Hunk_Free (mod->extradata); + memset (mod, 0, sizeof(*mod)); +} + +/* +================ +Mod_FreeAll +================ +*/ +void Mod_FreeAll (void) +{ + int i; + + for (i=0 ; isurfedges[], negative numbers + int numedges; // are backwards edges + + short texturemins[2]; + short extents[2]; + + int light_s, light_t; // gl lightmap coordinates + int dlight_s, dlight_t; // gl lightmap coordinates for dynamic lightmaps + + glpoly_t *polys; // multiple if warped + struct msurface_s *texturechain; + struct msurface_s *lightmapchain; + + mtexinfo_t *texinfo; + +// lighting info + int dlightframe; + int dlightbits; + + int lightmaptexturenum; + byte styles[MAXLIGHTMAPS]; + float cached_light[MAXLIGHTMAPS]; // values currently used in lightmap + byte *samples; // [numstyles*surfsize] +} msurface_t; + +typedef struct mnode_s +{ +// common with leaf + int contents; // -1, to differentiate from leafs + int visframe; // node needs to be traversed if current + + float minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + +// node specific + cplane_t *plane; + struct mnode_s *children[2]; + + unsigned short firstsurface; + unsigned short numsurfaces; +} mnode_t; + + + +typedef struct mleaf_s +{ +// common with node + int contents; // wil be a negative contents number + int visframe; // node needs to be traversed if current + + float minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + +// leaf specific + int cluster; + int area; + + msurface_t **firstmarksurface; + int nummarksurfaces; +} mleaf_t; + + +//=================================================================== + +// +// Whole model +// + +typedef enum {mod_bad, mod_brush, mod_sprite, mod_alias } modtype_t; + +typedef struct model_s +{ + char name[MAX_QPATH]; + + int registration_sequence; + + modtype_t type; + int numframes; + + int flags; + +// +// volume occupied by the model graphics +// + vec3_t mins, maxs; + float radius; + +// +// solid volume for clipping +// + qboolean clipbox; + vec3_t clipmins, clipmaxs; + +// +// brush model +// + int firstmodelsurface, nummodelsurfaces; + int lightmap; // only for submodels + + int numsubmodels; + mmodel_t *submodels; + + int numplanes; + cplane_t *planes; + + int numleafs; // number of visible leafs, not counting 0 + mleaf_t *leafs; + + int numvertexes; + mvertex_t *vertexes; + + int numedges; + medge_t *edges; + + int numnodes; + int firstnode; + mnode_t *nodes; + + int numtexinfo; + mtexinfo_t *texinfo; + + int numsurfaces; + msurface_t *surfaces; + + int numsurfedges; + int *surfedges; + + int nummarksurfaces; + msurface_t **marksurfaces; + + dvis_t *vis; + + byte *lightdata; + + // for alias models and skins + image_t *skins[MAX_MD2SKINS]; + + int extradatasize; + void *extradata; +} model_t; + +//============================================================================ + +void Mod_Init (void); +void Mod_ClearAll (void); +model_t *Mod_ForName (char *name, qboolean crash); +mleaf_t *Mod_PointInLeaf (float *p, model_t *model); +byte *Mod_ClusterPVS (int cluster, model_t *model); + +void Mod_Modellist_f (void); + +void *Hunk_Begin (int maxsize); +void *Hunk_Alloc (int size); +int Hunk_End (void); +void Hunk_Free (void *base); + +void Mod_FreeAll (void); +void Mod_Free (model_t *mod); diff --git a/ref_gl/gl_rmain.c b/ref_gl/gl_rmain.c new file mode 100644 index 000000000..e37a4683a --- /dev/null +++ b/ref_gl/gl_rmain.c @@ -0,0 +1,1692 @@ +/* +Copyright (C) 1997-2001 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_main.c +#include "gl_local.h" + +void R_Clear (void); + +viddef_t vid; + +refimport_t ri; + +model_t *r_worldmodel; + +float gldepthmin, gldepthmax; + +glconfig_t gl_config; +glstate_t gl_state; + +image_t *r_notexture; // use for bad textures +image_t *r_particletexture; // little dot for particles + +entity_t *currententity; +model_t *currentmodel; + +cplane_t frustum[4]; + +int r_visframecount; // bumped when going to a new PVS +int r_framecount; // used for dlight push checking + +int c_brush_polys, c_alias_polys; + +float v_blend[4]; // final blending color + +void GL_Strings_f( void ); + +// +// view origin +// +vec3_t vup; +vec3_t vpn; +vec3_t vright; +vec3_t r_origin; + +float r_world_matrix[16]; +float r_base_world_matrix[16]; + +// +// screen size info +// +refdef_t r_newrefdef; + +int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2; + +cvar_t *r_norefresh; +cvar_t *r_drawentities; +cvar_t *r_drawworld; +cvar_t *r_speeds; +cvar_t *r_fullbright; +cvar_t *r_novis; +cvar_t *r_nocull; +cvar_t *r_lerpmodels; +cvar_t *r_lefthand; + +cvar_t *r_lightlevel; // FIXME: This is a HACK to get the client's light level + +cvar_t *gl_nosubimage; +cvar_t *gl_allow_software; + +cvar_t *gl_vertex_arrays; + +cvar_t *gl_particle_min_size; +cvar_t *gl_particle_max_size; +cvar_t *gl_particle_size; +cvar_t *gl_particle_att_a; +cvar_t *gl_particle_att_b; +cvar_t *gl_particle_att_c; + +cvar_t *gl_ext_swapinterval; +cvar_t *gl_ext_palettedtexture; +cvar_t *gl_ext_multitexture; +cvar_t *gl_ext_pointparameters; +cvar_t *gl_ext_compiled_vertex_array; + +cvar_t *gl_log; +cvar_t *gl_bitdepth; +cvar_t *gl_drawbuffer; +cvar_t *gl_driver; +cvar_t *gl_lightmap; +cvar_t *gl_shadows; +cvar_t *gl_mode; +cvar_t *gl_dynamic; +cvar_t *gl_monolightmap; +cvar_t *gl_modulate; +cvar_t *gl_nobind; +cvar_t *gl_round_down; +cvar_t *gl_picmip; +cvar_t *gl_skymip; +cvar_t *gl_showtris; +cvar_t *gl_ztrick; +cvar_t *gl_finish; +cvar_t *gl_clear; +cvar_t *gl_cull; +cvar_t *gl_polyblend; +cvar_t *gl_flashblend; +cvar_t *gl_playermip; +cvar_t *gl_saturatelighting; +cvar_t *gl_swapinterval; +cvar_t *gl_texturemode; +cvar_t *gl_texturealphamode; +cvar_t *gl_texturesolidmode; +cvar_t *gl_lockpvs; + +cvar_t *gl_3dlabs_broken; + +cvar_t *vid_fullscreen; +cvar_t *vid_gamma; +cvar_t *vid_ref; + +/* +================= +R_CullBox + +Returns true if the box is completely outside the frustom +================= +*/ +qboolean R_CullBox (vec3_t mins, vec3_t maxs) +{ + int i; + + if (r_nocull->value) + return false; + + for (i=0 ; i<4 ; i++) + if ( BOX_ON_PLANE_SIDE(mins, maxs, &frustum[i]) == 2) + return true; + return false; +} + + +void R_RotateForEntity (entity_t *e) +{ + qglTranslatef (e->origin[0], e->origin[1], e->origin[2]); + + qglRotatef (e->angles[1], 0, 0, 1); + qglRotatef (-e->angles[0], 0, 1, 0); + qglRotatef (-e->angles[2], 1, 0, 0); +} + +/* +============================================================= + + SPRITE MODELS + +============================================================= +*/ + + +/* +================= +R_DrawSpriteModel + +================= +*/ +void R_DrawSpriteModel (entity_t *e) +{ + float alpha = 1.0F; + vec3_t point; + dsprframe_t *frame; + float *up, *right; + dsprite_t *psprite; + + // don't even bother culling, because it's just a single + // polygon without a surface cache + + psprite = (dsprite_t *)currentmodel->extradata; + +#if 0 + if (e->frame < 0 || e->frame >= psprite->numframes) + { + ri.Con_Printf (PRINT_ALL, "no such sprite frame %i\n", e->frame); + e->frame = 0; + } +#endif + e->frame %= psprite->numframes; + + frame = &psprite->frames[e->frame]; + +#if 0 + if (psprite->type == SPR_ORIENTED) + { // bullet marks on walls + vec3_t v_forward, v_right, v_up; + + AngleVectors (currententity->angles, v_forward, v_right, v_up); + up = v_up; + right = v_right; + } + else +#endif + { // normal sprite + up = vup; + right = vright; + } + + if ( e->flags & RF_TRANSLUCENT ) + alpha = e->alpha; + + if ( alpha != 1.0F ) + qglEnable( GL_BLEND ); + + qglColor4f( 1, 1, 1, alpha ); + + GL_Bind(currentmodel->skins[e->frame]->texnum); + + GL_TexEnv( GL_MODULATE ); + + if ( alpha == 1.0 ) + qglEnable (GL_ALPHA_TEST); + else + qglDisable( GL_ALPHA_TEST ); + + qglBegin (GL_QUADS); + + qglTexCoord2f (0, 1); + VectorMA (e->origin, -frame->origin_y, up, point); + VectorMA (point, -frame->origin_x, right, point); + qglVertex3fv (point); + + qglTexCoord2f (0, 0); + VectorMA (e->origin, frame->height - frame->origin_y, up, point); + VectorMA (point, -frame->origin_x, right, point); + qglVertex3fv (point); + + qglTexCoord2f (1, 0); + VectorMA (e->origin, frame->height - frame->origin_y, up, point); + VectorMA (point, frame->width - frame->origin_x, right, point); + qglVertex3fv (point); + + qglTexCoord2f (1, 1); + VectorMA (e->origin, -frame->origin_y, up, point); + VectorMA (point, frame->width - frame->origin_x, right, point); + qglVertex3fv (point); + + qglEnd (); + + qglDisable (GL_ALPHA_TEST); + GL_TexEnv( GL_REPLACE ); + + if ( alpha != 1.0F ) + qglDisable( GL_BLEND ); + + qglColor4f( 1, 1, 1, 1 ); +} + +//================================================================================== + +/* +============= +R_DrawNullModel +============= +*/ +void R_DrawNullModel (void) +{ + vec3_t shadelight; + int i; + + if ( currententity->flags & RF_FULLBRIGHT ) + shadelight[0] = shadelight[1] = shadelight[2] = 1.0F; + else + R_LightPoint (currententity->origin, shadelight); + + qglPushMatrix (); + R_RotateForEntity (currententity); + + qglDisable (GL_TEXTURE_2D); + qglColor3fv (shadelight); + + qglBegin (GL_TRIANGLE_FAN); + qglVertex3f (0, 0, -16); + for (i=0 ; i<=4 ; i++) + qglVertex3f (16*cos(i*M_PI/2), 16*sin(i*M_PI/2), 0); + qglEnd (); + + qglBegin (GL_TRIANGLE_FAN); + qglVertex3f (0, 0, 16); + for (i=4 ; i>=0 ; i--) + qglVertex3f (16*cos(i*M_PI/2), 16*sin(i*M_PI/2), 0); + qglEnd (); + + qglColor3f (1,1,1); + qglPopMatrix (); + qglEnable (GL_TEXTURE_2D); +} + +/* +============= +R_DrawEntitiesOnList +============= +*/ +void R_DrawEntitiesOnList (void) +{ + int i; + + if (!r_drawentities->value) + return; + + // draw non-transparent first + for (i=0 ; iflags & RF_TRANSLUCENT) + continue; // solid + + if ( currententity->flags & RF_BEAM ) + { + R_DrawBeam( currententity ); + } + else + { + currentmodel = currententity->model; + if (!currentmodel) + { + R_DrawNullModel (); + continue; + } + switch (currentmodel->type) + { + case mod_alias: + R_DrawAliasModel (currententity); + break; + case mod_brush: + R_DrawBrushModel (currententity); + break; + case mod_sprite: + R_DrawSpriteModel (currententity); + break; + default: + ri.Sys_Error (ERR_DROP, "Bad modeltype"); + break; + } + } + } + + // draw transparent entities + // we could sort these if it ever becomes a problem... + qglDepthMask (0); // no z writes + for (i=0 ; iflags & RF_TRANSLUCENT)) + continue; // solid + + if ( currententity->flags & RF_BEAM ) + { + R_DrawBeam( currententity ); + } + else + { + currentmodel = currententity->model; + + if (!currentmodel) + { + R_DrawNullModel (); + continue; + } + switch (currentmodel->type) + { + case mod_alias: + R_DrawAliasModel (currententity); + break; + case mod_brush: + R_DrawBrushModel (currententity); + break; + case mod_sprite: + R_DrawSpriteModel (currententity); + break; + default: + ri.Sys_Error (ERR_DROP, "Bad modeltype"); + break; + } + } + } + qglDepthMask (1); // back to writing + +} + +/* +** GL_DrawParticles +** +*/ +void GL_DrawParticles( int num_particles, const particle_t particles[], const unsigned colortable[768] ) +{ + const particle_t *p; + int i; + vec3_t up, right; + float scale; + byte color[4]; + + GL_Bind(r_particletexture->texnum); + qglDepthMask( GL_FALSE ); // no z buffering + qglEnable( GL_BLEND ); + GL_TexEnv( GL_MODULATE ); + qglBegin( GL_TRIANGLES ); + + VectorScale (vup, 1.5, up); + VectorScale (vright, 1.5, right); + + for ( p = particles, i=0 ; i < num_particles ; i++,p++) + { + // hack a scale up to keep particles from disapearing + scale = ( p->origin[0] - r_origin[0] ) * vpn[0] + + ( p->origin[1] - r_origin[1] ) * vpn[1] + + ( p->origin[2] - r_origin[2] ) * vpn[2]; + + if (scale < 20) + scale = 1; + else + scale = 1 + scale * 0.004; + + *(int *)color = colortable[p->color]; + color[3] = p->alpha*255; + + qglColor4ubv( color ); + + qglTexCoord2f( 0.0625, 0.0625 ); + qglVertex3fv( p->origin ); + + qglTexCoord2f( 1.0625, 0.0625 ); + qglVertex3f( p->origin[0] + up[0]*scale, + p->origin[1] + up[1]*scale, + p->origin[2] + up[2]*scale); + + qglTexCoord2f( 0.0625, 1.0625 ); + qglVertex3f( p->origin[0] + right[0]*scale, + p->origin[1] + right[1]*scale, + p->origin[2] + right[2]*scale); + } + + qglEnd (); + qglDisable( GL_BLEND ); + qglColor4f( 1,1,1,1 ); + qglDepthMask( 1 ); // back to normal Z buffering + GL_TexEnv( GL_REPLACE ); +} + +/* +=============== +R_DrawParticles +=============== +*/ +void R_DrawParticles (void) +{ + if ( gl_ext_pointparameters->value && qglPointParameterfEXT ) + { + int i; + unsigned char color[4]; + const particle_t *p; + + qglDepthMask( GL_FALSE ); + qglEnable( GL_BLEND ); + qglDisable( GL_TEXTURE_2D ); + + qglPointSize( gl_particle_size->value ); + + qglBegin( GL_POINTS ); + for ( i = 0, p = r_newrefdef.particles; i < r_newrefdef.num_particles; i++, p++ ) + { + *(int *)color = d_8to24table[p->color]; + color[3] = p->alpha*255; + + qglColor4ubv( color ); + + qglVertex3fv( p->origin ); + } + qglEnd(); + + qglDisable( GL_BLEND ); + qglColor4f( 1.0F, 1.0F, 1.0F, 1.0F ); + qglDepthMask( GL_TRUE ); + qglEnable( GL_TEXTURE_2D ); + + } + else + { + GL_DrawParticles( r_newrefdef.num_particles, r_newrefdef.particles, d_8to24table ); + } +} + +/* +============ +R_PolyBlend +============ +*/ +void R_PolyBlend (void) +{ + if (!gl_polyblend->value) + return; + if (!v_blend[3]) + return; + + qglDisable (GL_ALPHA_TEST); + qglEnable (GL_BLEND); + qglDisable (GL_DEPTH_TEST); + qglDisable (GL_TEXTURE_2D); + + qglLoadIdentity (); + + // FIXME: get rid of these + qglRotatef (-90, 1, 0, 0); // put Z going up + qglRotatef (90, 0, 0, 1); // put Z going up + + qglColor4fv (v_blend); + + qglBegin (GL_QUADS); + + qglVertex3f (10, 100, 100); + qglVertex3f (10, -100, 100); + qglVertex3f (10, -100, -100); + qglVertex3f (10, 100, -100); + qglEnd (); + + qglDisable (GL_BLEND); + qglEnable (GL_TEXTURE_2D); + qglEnable (GL_ALPHA_TEST); + + qglColor4f(1,1,1,1); +} + +//======================================================================= + +int SignbitsForPlane (cplane_t *out) +{ + int bits, j; + + // for fast box on planeside test + + bits = 0; + for (j=0 ; j<3 ; j++) + { + if (out->normal[j] < 0) + bits |= 1<cluster; + + // check above and below so crossing solid water doesn't draw wrong + if (!leaf->contents) + { // look down a bit + vec3_t temp; + + VectorCopy (r_origin, temp); + temp[2] -= 16; + leaf = Mod_PointInLeaf (temp, r_worldmodel); + if ( !(leaf->contents & CONTENTS_SOLID) && + (leaf->cluster != r_viewcluster2) ) + r_viewcluster2 = leaf->cluster; + } + else + { // look up a bit + vec3_t temp; + + VectorCopy (r_origin, temp); + temp[2] += 16; + leaf = Mod_PointInLeaf (temp, r_worldmodel); + if ( !(leaf->contents & CONTENTS_SOLID) && + (leaf->cluster != r_viewcluster2) ) + r_viewcluster2 = leaf->cluster; + } + } + + for (i=0 ; i<4 ; i++) + v_blend[i] = r_newrefdef.blend[i]; + + c_brush_polys = 0; + c_alias_polys = 0; + + // clear out the portion of the screen that the NOWORLDMODEL defines + if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) + { + qglEnable( GL_SCISSOR_TEST ); + qglClearColor( 0.3, 0.3, 0.3, 1 ); + qglScissor( r_newrefdef.x, vid.height - r_newrefdef.height - r_newrefdef.y, r_newrefdef.width, r_newrefdef.height ); + qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + qglClearColor( 1, 0, 0.5, 0.5 ); + qglDisable( GL_SCISSOR_TEST ); + } +} + + +void MYgluPerspective( GLdouble fovy, GLdouble aspect, + GLdouble zNear, GLdouble zFar ) +{ + GLdouble xmin, xmax, ymin, ymax; + + ymax = zNear * tan( fovy * M_PI / 360.0 ); + ymin = -ymax; + + xmin = ymin * aspect; + xmax = ymax * aspect; + + xmin += -( 2 * gl_state.camera_separation ) / zNear; + xmax += -( 2 * gl_state.camera_separation ) / zNear; + + qglFrustum( xmin, xmax, ymin, ymax, zNear, zFar ); +} + + +/* +============= +R_SetupGL +============= +*/ +void R_SetupGL (void) +{ + float screenaspect; +// float yfov; + int x, x2, y2, y, w, h; + + // + // set up viewport + // + x = floor(r_newrefdef.x * vid.width / vid.width); + x2 = ceil((r_newrefdef.x + r_newrefdef.width) * vid.width / vid.width); + y = floor(vid.height - r_newrefdef.y * vid.height / vid.height); + y2 = ceil(vid.height - (r_newrefdef.y + r_newrefdef.height) * vid.height / vid.height); + + w = x2 - x; + h = y - y2; + + qglViewport (x, y2, w, h); + + // + // set up projection matrix + // + screenaspect = (float)r_newrefdef.width/r_newrefdef.height; +// yfov = 2*atan((float)r_newrefdef.height/r_newrefdef.width)*180/M_PI; + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + MYgluPerspective (r_newrefdef.fov_y, screenaspect, 4, 4096); + + qglCullFace(GL_FRONT); + + qglMatrixMode(GL_MODELVIEW); + qglLoadIdentity (); + + qglRotatef (-90, 1, 0, 0); // put Z going up + qglRotatef (90, 0, 0, 1); // put Z going up + qglRotatef (-r_newrefdef.viewangles[2], 1, 0, 0); + qglRotatef (-r_newrefdef.viewangles[0], 0, 1, 0); + qglRotatef (-r_newrefdef.viewangles[1], 0, 0, 1); + qglTranslatef (-r_newrefdef.vieworg[0], -r_newrefdef.vieworg[1], -r_newrefdef.vieworg[2]); + +// if ( gl_state.camera_separation != 0 && gl_state.stereo_enabled ) +// qglTranslatef ( gl_state.camera_separation, 0, 0 ); + + qglGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix); + + // + // set drawing parms + // + if (gl_cull->value) + qglEnable(GL_CULL_FACE); + else + qglDisable(GL_CULL_FACE); + + qglDisable(GL_BLEND); + qglDisable(GL_ALPHA_TEST); + qglEnable(GL_DEPTH_TEST); +} + +/* +============= +R_Clear +============= +*/ +void R_Clear (void) +{ + if (gl_ztrick->value) + { + static int trickframe; + + if (gl_clear->value) + qglClear (GL_COLOR_BUFFER_BIT); + + trickframe++; + if (trickframe & 1) + { + gldepthmin = 0; + gldepthmax = 0.49999; + qglDepthFunc (GL_LEQUAL); + } + else + { + gldepthmin = 1; + gldepthmax = 0.5; + qglDepthFunc (GL_GEQUAL); + } + } + else + { + if (gl_clear->value) + qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + else + qglClear (GL_DEPTH_BUFFER_BIT); + gldepthmin = 0; + gldepthmax = 1; + qglDepthFunc (GL_LEQUAL); + } + + qglDepthRange (gldepthmin, gldepthmax); + +} + +void R_Flash( void ) +{ + R_PolyBlend (); +} + +/* +================ +R_RenderView + +r_newrefdef must be set before the first call +================ +*/ +void R_RenderView (refdef_t *fd) +{ + if (r_norefresh->value) + return; + + r_newrefdef = *fd; + + if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) ) + ri.Sys_Error (ERR_DROP, "R_RenderView: NULL worldmodel"); + + if (r_speeds->value) + { + c_brush_polys = 0; + c_alias_polys = 0; + } + + R_PushDlights (); + + if (gl_finish->value) + qglFinish (); + + R_SetupFrame (); + + R_SetFrustum (); + + R_SetupGL (); + + R_MarkLeaves (); // done here so we know if we're in water + + R_DrawWorld (); + + R_DrawEntitiesOnList (); + + R_RenderDlights (); + + R_DrawParticles (); + + R_DrawAlphaSurfaces (); + + R_Flash(); + + if (r_speeds->value) + { + ri.Con_Printf (PRINT_ALL, "%4i wpoly %4i epoly %i tex %i lmaps\n", + c_brush_polys, + c_alias_polys, + c_visible_textures, + c_visible_lightmaps); + } +} + + +void R_SetGL2D (void) +{ + // set 2D virtual screen size + qglViewport (0,0, vid.width, vid.height); + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + qglOrtho (0, vid.width, vid.height, 0, -99999, 99999); + qglMatrixMode(GL_MODELVIEW); + qglLoadIdentity (); + qglDisable (GL_DEPTH_TEST); + qglDisable (GL_CULL_FACE); + qglDisable (GL_BLEND); + qglEnable (GL_ALPHA_TEST); + qglColor4f (1,1,1,1); +} + +static void GL_DrawColoredStereoLinePair( float r, float g, float b, float y ) +{ + qglColor3f( r, g, b ); + qglVertex2f( 0, y ); + qglVertex2f( vid.width, y ); + qglColor3f( 0, 0, 0 ); + qglVertex2f( 0, y + 1 ); + qglVertex2f( vid.width, y + 1 ); +} + +static void GL_DrawStereoPattern( void ) +{ + int i; + + if ( !( gl_config.renderer & GL_RENDERER_INTERGRAPH ) ) + return; + + if ( !gl_state.stereo_enabled ) + return; + + R_SetGL2D(); + + qglDrawBuffer( GL_BACK_LEFT ); + + for ( i = 0; i < 20; i++ ) + { + qglBegin( GL_LINES ); + GL_DrawColoredStereoLinePair( 1, 0, 0, 0 ); + GL_DrawColoredStereoLinePair( 1, 0, 0, 2 ); + GL_DrawColoredStereoLinePair( 1, 0, 0, 4 ); + GL_DrawColoredStereoLinePair( 1, 0, 0, 6 ); + GL_DrawColoredStereoLinePair( 0, 1, 0, 8 ); + GL_DrawColoredStereoLinePair( 1, 1, 0, 10); + GL_DrawColoredStereoLinePair( 1, 1, 0, 12); + GL_DrawColoredStereoLinePair( 0, 1, 0, 14); + qglEnd(); + + GLimp_EndFrame(); + } +} + + +/* +==================== +R_SetLightLevel + +==================== +*/ +void R_SetLightLevel (void) +{ + vec3_t shadelight; + + if (r_newrefdef.rdflags & RDF_NOWORLDMODEL) + return; + + // save off light value for server to look at (BIG HACK!) + + R_LightPoint (r_newrefdef.vieworg, shadelight); + + // pick the greatest component, which should be the same + // as the mono value returned by software + if (shadelight[0] > shadelight[1]) + { + if (shadelight[0] > shadelight[2]) + r_lightlevel->value = 150*shadelight[0]; + else + r_lightlevel->value = 150*shadelight[2]; + } + else + { + if (shadelight[1] > shadelight[2]) + r_lightlevel->value = 150*shadelight[1]; + else + r_lightlevel->value = 150*shadelight[2]; + } + +} + +/* +@@@@@@@@@@@@@@@@@@@@@ +R_RenderFrame + +@@@@@@@@@@@@@@@@@@@@@ +*/ +void R_RenderFrame (refdef_t *fd) +{ + R_RenderView( fd ); + R_SetLightLevel (); + R_SetGL2D (); +} + + +void R_Register( void ) +{ + r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE ); + r_norefresh = ri.Cvar_Get ("r_norefresh", "0", 0); + r_fullbright = ri.Cvar_Get ("r_fullbright", "0", 0); + r_drawentities = ri.Cvar_Get ("r_drawentities", "1", 0); + r_drawworld = ri.Cvar_Get ("r_drawworld", "1", 0); + r_novis = ri.Cvar_Get ("r_novis", "0", 0); + r_nocull = ri.Cvar_Get ("r_nocull", "0", 0); + r_lerpmodels = ri.Cvar_Get ("r_lerpmodels", "1", 0); + r_speeds = ri.Cvar_Get ("r_speeds", "0", 0); + + r_lightlevel = ri.Cvar_Get ("r_lightlevel", "0", 0); + + gl_nosubimage = ri.Cvar_Get( "gl_nosubimage", "0", 0 ); + gl_allow_software = ri.Cvar_Get( "gl_allow_software", "0", 0 ); + + gl_particle_min_size = ri.Cvar_Get( "gl_particle_min_size", "2", CVAR_ARCHIVE ); + gl_particle_max_size = ri.Cvar_Get( "gl_particle_max_size", "40", CVAR_ARCHIVE ); + gl_particle_size = ri.Cvar_Get( "gl_particle_size", "40", CVAR_ARCHIVE ); + gl_particle_att_a = ri.Cvar_Get( "gl_particle_att_a", "0.01", CVAR_ARCHIVE ); + gl_particle_att_b = ri.Cvar_Get( "gl_particle_att_b", "0.0", CVAR_ARCHIVE ); + gl_particle_att_c = ri.Cvar_Get( "gl_particle_att_c", "0.01", CVAR_ARCHIVE ); + + gl_modulate = ri.Cvar_Get ("gl_modulate", "1", CVAR_ARCHIVE ); + gl_log = ri.Cvar_Get( "gl_log", "0", 0 ); + gl_bitdepth = ri.Cvar_Get( "gl_bitdepth", "0", 0 ); + gl_mode = ri.Cvar_Get( "gl_mode", "3", CVAR_ARCHIVE ); + gl_lightmap = ri.Cvar_Get ("gl_lightmap", "0", 0); + gl_shadows = ri.Cvar_Get ("gl_shadows", "0", CVAR_ARCHIVE ); + gl_dynamic = ri.Cvar_Get ("gl_dynamic", "1", 0); + gl_nobind = ri.Cvar_Get ("gl_nobind", "0", 0); + gl_round_down = ri.Cvar_Get ("gl_round_down", "1", 0); + gl_picmip = ri.Cvar_Get ("gl_picmip", "0", 0); + gl_skymip = ri.Cvar_Get ("gl_skymip", "0", 0); + gl_showtris = ri.Cvar_Get ("gl_showtris", "0", 0); + gl_ztrick = ri.Cvar_Get ("gl_ztrick", "0", 0); + gl_finish = ri.Cvar_Get ("gl_finish", "0", CVAR_ARCHIVE); + gl_clear = ri.Cvar_Get ("gl_clear", "0", 0); + gl_cull = ri.Cvar_Get ("gl_cull", "1", 0); + gl_polyblend = ri.Cvar_Get ("gl_polyblend", "1", 0); + gl_flashblend = ri.Cvar_Get ("gl_flashblend", "0", 0); + gl_playermip = ri.Cvar_Get ("gl_playermip", "0", 0); + gl_monolightmap = ri.Cvar_Get( "gl_monolightmap", "0", 0 ); + gl_driver = ri.Cvar_Get( "gl_driver", "opengl32", CVAR_ARCHIVE ); + gl_texturemode = ri.Cvar_Get( "gl_texturemode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE ); + gl_texturealphamode = ri.Cvar_Get( "gl_texturealphamode", "default", CVAR_ARCHIVE ); + gl_texturesolidmode = ri.Cvar_Get( "gl_texturesolidmode", "default", CVAR_ARCHIVE ); + gl_lockpvs = ri.Cvar_Get( "gl_lockpvs", "0", 0 ); + + gl_vertex_arrays = ri.Cvar_Get( "gl_vertex_arrays", "0", CVAR_ARCHIVE ); + + gl_ext_swapinterval = ri.Cvar_Get( "gl_ext_swapinterval", "1", CVAR_ARCHIVE ); + gl_ext_palettedtexture = ri.Cvar_Get( "gl_ext_palettedtexture", "1", CVAR_ARCHIVE ); + gl_ext_multitexture = ri.Cvar_Get( "gl_ext_multitexture", "1", CVAR_ARCHIVE ); + gl_ext_pointparameters = ri.Cvar_Get( "gl_ext_pointparameters", "1", CVAR_ARCHIVE ); + gl_ext_compiled_vertex_array = ri.Cvar_Get( "gl_ext_compiled_vertex_array", "1", CVAR_ARCHIVE ); + + gl_drawbuffer = ri.Cvar_Get( "gl_drawbuffer", "GL_BACK", 0 ); + gl_swapinterval = ri.Cvar_Get( "gl_swapinterval", "1", CVAR_ARCHIVE ); + + gl_saturatelighting = ri.Cvar_Get( "gl_saturatelighting", "0", 0 ); + + gl_3dlabs_broken = ri.Cvar_Get( "gl_3dlabs_broken", "1", CVAR_ARCHIVE ); + + vid_fullscreen = ri.Cvar_Get( "vid_fullscreen", "0", CVAR_ARCHIVE ); + vid_gamma = ri.Cvar_Get( "vid_gamma", "1.0", CVAR_ARCHIVE ); + vid_ref = ri.Cvar_Get( "vid_ref", "soft", CVAR_ARCHIVE ); + + ri.Cmd_AddCommand( "imagelist", GL_ImageList_f ); + ri.Cmd_AddCommand( "screenshot", GL_ScreenShot_f ); + ri.Cmd_AddCommand( "modellist", Mod_Modellist_f ); + ri.Cmd_AddCommand( "gl_strings", GL_Strings_f ); +} + +/* +================== +R_SetMode +================== +*/ +qboolean R_SetMode (void) +{ + rserr_t err; + qboolean fullscreen; + + if ( vid_fullscreen->modified && !gl_config.allow_cds ) + { + ri.Con_Printf( PRINT_ALL, "R_SetMode() - CDS not allowed with this driver\n" ); + ri.Cvar_SetValue( "vid_fullscreen", !vid_fullscreen->value ); + vid_fullscreen->modified = false; + } + + fullscreen = vid_fullscreen->value; + + vid_fullscreen->modified = false; + gl_mode->modified = false; + + if ( ( err = GLimp_SetMode( &vid.width, &vid.height, gl_mode->value, fullscreen ) ) == rserr_ok ) + { + gl_state.prev_mode = gl_mode->value; + } + else + { + if ( err == rserr_invalid_fullscreen ) + { + ri.Cvar_SetValue( "vid_fullscreen", 0); + vid_fullscreen->modified = false; + ri.Con_Printf( PRINT_ALL, "ref_gl::R_SetMode() - fullscreen unavailable in this mode\n" ); + if ( ( err = GLimp_SetMode( &vid.width, &vid.height, gl_mode->value, false ) ) == rserr_ok ) + return true; + } + else if ( err == rserr_invalid_mode ) + { + ri.Cvar_SetValue( "gl_mode", gl_state.prev_mode ); + gl_mode->modified = false; + ri.Con_Printf( PRINT_ALL, "ref_gl::R_SetMode() - invalid mode\n" ); + } + + // try setting it back to something safe + if ( ( err = GLimp_SetMode( &vid.width, &vid.height, gl_state.prev_mode, false ) ) != rserr_ok ) + { + ri.Con_Printf( PRINT_ALL, "ref_gl::R_SetMode() - could not revert to safe mode\n" ); + return false; + } + } + return true; +} + +/* +=============== +R_Init +=============== +*/ +int R_Init( void *hinstance, void *hWnd ) +{ + char renderer_buffer[1000]; + char vendor_buffer[1000]; + int err; + int j; + extern float r_turbsin[256]; + + for ( j = 0; j < 256; j++ ) + { + r_turbsin[j] *= 0.5; + } + + ri.Con_Printf (PRINT_ALL, "ref_gl version: "REF_VERSION"\n"); + + Draw_GetPalette (); + + R_Register(); + + // initialize our QGL dynamic bindings + if ( !QGL_Init( gl_driver->string ) ) + { + QGL_Shutdown(); + ri.Con_Printf (PRINT_ALL, "ref_gl::R_Init() - could not load \"%s\"\n", gl_driver->string ); + return -1; + } + + // initialize OS-specific parts of OpenGL + if ( !GLimp_Init( hinstance, hWnd ) ) + { + QGL_Shutdown(); + return -1; + } + + // set our "safe" modes + gl_state.prev_mode = 3; + + // create the window and set up the context + if ( !R_SetMode () ) + { + QGL_Shutdown(); + ri.Con_Printf (PRINT_ALL, "ref_gl::R_Init() - could not R_SetMode()\n" ); + return -1; + } + + ri.Vid_MenuInit(); + + /* + ** get our various GL strings + */ + gl_config.vendor_string = qglGetString (GL_VENDOR); + ri.Con_Printf (PRINT_ALL, "GL_VENDOR: %s\n", gl_config.vendor_string ); + gl_config.renderer_string = qglGetString (GL_RENDERER); + ri.Con_Printf (PRINT_ALL, "GL_RENDERER: %s\n", gl_config.renderer_string ); + gl_config.version_string = qglGetString (GL_VERSION); + ri.Con_Printf (PRINT_ALL, "GL_VERSION: %s\n", gl_config.version_string ); + gl_config.extensions_string = qglGetString (GL_EXTENSIONS); + ri.Con_Printf (PRINT_ALL, "GL_EXTENSIONS: %s\n", gl_config.extensions_string ); + + strcpy( renderer_buffer, gl_config.renderer_string ); + strlwr( renderer_buffer ); + + strcpy( vendor_buffer, gl_config.vendor_string ); + strlwr( vendor_buffer ); + + if ( strstr( renderer_buffer, "voodoo" ) ) + { + if ( !strstr( renderer_buffer, "rush" ) ) + gl_config.renderer = GL_RENDERER_VOODOO; + else + gl_config.renderer = GL_RENDERER_VOODOO_RUSH; + } + else if ( strstr( vendor_buffer, "sgi" ) ) + gl_config.renderer = GL_RENDERER_SGI; + else if ( strstr( renderer_buffer, "permedia" ) ) + gl_config.renderer = GL_RENDERER_PERMEDIA2; + else if ( strstr( renderer_buffer, "glint" ) ) + gl_config.renderer = GL_RENDERER_GLINT_MX; + else if ( strstr( renderer_buffer, "glzicd" ) ) + gl_config.renderer = GL_RENDERER_REALIZM; + else if ( strstr( renderer_buffer, "gdi" ) ) + gl_config.renderer = GL_RENDERER_MCD; + else if ( strstr( renderer_buffer, "pcx2" ) ) + gl_config.renderer = GL_RENDERER_PCX2; + else if ( strstr( renderer_buffer, "verite" ) ) + gl_config.renderer = GL_RENDERER_RENDITION; + else + gl_config.renderer = GL_RENDERER_OTHER; + + if ( toupper( gl_monolightmap->string[1] ) != 'F' ) + { + if ( gl_config.renderer == GL_RENDERER_PERMEDIA2 ) + { + ri.Cvar_Set( "gl_monolightmap", "A" ); + ri.Con_Printf( PRINT_ALL, "...using gl_monolightmap 'a'\n" ); + } + else if ( gl_config.renderer & GL_RENDERER_POWERVR ) + { + ri.Cvar_Set( "gl_monolightmap", "0" ); + } + else + { + ri.Cvar_Set( "gl_monolightmap", "0" ); + } + } + + // power vr can't have anything stay in the framebuffer, so + // the screen needs to redraw the tiled background every frame + if ( gl_config.renderer & GL_RENDERER_POWERVR ) + { + ri.Cvar_Set( "scr_drawall", "1" ); + } + else + { + ri.Cvar_Set( "scr_drawall", "0" ); + } + + // MCD has buffering issues + if ( gl_config.renderer == GL_RENDERER_MCD ) + { + ri.Cvar_SetValue( "gl_finish", 1 ); + } + + if ( gl_config.renderer & GL_RENDERER_3DLABS ) + { + if ( gl_3dlabs_broken->value ) + gl_config.allow_cds = false; + else + gl_config.allow_cds = true; + } + else + { + gl_config.allow_cds = true; + } + + if ( gl_config.allow_cds ) + ri.Con_Printf( PRINT_ALL, "...allowing CDS\n" ); + else + ri.Con_Printf( PRINT_ALL, "...disabling CDS\n" ); + + /* + ** grab extensions + */ +#ifdef WIN32 + if ( strstr( gl_config.extensions_string, "GL_EXT_compiled_vertex_array" ) || + strstr( gl_config.extensions_string, "GL_SGI_compiled_vertex_array" ) ) + { + ri.Con_Printf( PRINT_ALL, "...enabling GL_EXT_compiled_vertex_array\n" ); + qglLockArraysEXT = ( void * ) qwglGetProcAddress( "glLockArraysEXT" ); + qglUnlockArraysEXT = ( void * ) qwglGetProcAddress( "glUnlockArraysEXT" ); + } + else + { + ri.Con_Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); + } + + if ( strstr( gl_config.extensions_string, "WGL_EXT_swap_control" ) ) + { + qwglSwapIntervalEXT = ( BOOL (WINAPI *)(int)) qwglGetProcAddress( "wglSwapIntervalEXT" ); + ri.Con_Printf( PRINT_ALL, "...enabling WGL_EXT_swap_control\n" ); + } + else + { + ri.Con_Printf( PRINT_ALL, "...WGL_EXT_swap_control not found\n" ); + } + + if ( strstr( gl_config.extensions_string, "GL_EXT_point_parameters" ) ) + { + if ( gl_ext_pointparameters->value ) + { + qglPointParameterfEXT = ( void (APIENTRY *)( GLenum, GLfloat ) ) qwglGetProcAddress( "glPointParameterfEXT" ); + qglPointParameterfvEXT = ( void (APIENTRY *)( GLenum, const GLfloat * ) ) qwglGetProcAddress( "glPointParameterfvEXT" ); + ri.Con_Printf( PRINT_ALL, "...using GL_EXT_point_parameters\n" ); + } + else + { + ri.Con_Printf( PRINT_ALL, "...ignoring GL_EXT_point_parameters\n" ); + } + } + else + { + ri.Con_Printf( PRINT_ALL, "...GL_EXT_point_parameters not found\n" ); + } + + if ( strstr( gl_config.extensions_string, "GL_EXT_paletted_texture" ) && + strstr( gl_config.extensions_string, "GL_EXT_shared_texture_palette" ) ) + { + if ( gl_ext_palettedtexture->value ) + { + ri.Con_Printf( PRINT_ALL, "...using GL_EXT_shared_texture_palette\n" ); + qglColorTableEXT = ( void ( APIENTRY * ) ( int, int, int, int, int, const void * ) ) qwglGetProcAddress( "glColorTableEXT" ); + } + else + { + ri.Con_Printf( PRINT_ALL, "...ignoring GL_EXT_shared_texture_palette\n" ); + } + } + else + { + ri.Con_Printf( PRINT_ALL, "...GL_EXT_shared_texture_palette not found\n" ); + } + + if ( strstr( gl_config.extensions_string, "GL_SGIS_multitexture" ) ) + { + if ( gl_ext_multitexture->value ) + { + ri.Con_Printf( PRINT_ALL, "...using GL_SGIS_multitexture\n" ); + qglMTexCoord2fSGIS = ( void * ) qwglGetProcAddress( "glMTexCoord2fSGIS" ); + qglSelectTextureSGIS = ( void * ) qwglGetProcAddress( "glSelectTextureSGIS" ); + } + else + { + ri.Con_Printf( PRINT_ALL, "...ignoring GL_SGIS_multitexture\n" ); + } + } + else + { + ri.Con_Printf( PRINT_ALL, "...GL_SGIS_multitexture not found\n" ); + } +#endif + + GL_SetDefaultState(); + + /* + ** draw our stereo patterns + */ +#if 0 // commented out until H3D pays us the money they owe us + GL_DrawStereoPattern(); +#endif + + GL_InitImages (); + Mod_Init (); + R_InitParticleTexture (); + Draw_InitLocal (); + + err = qglGetError(); + if ( err != GL_NO_ERROR ) + ri.Con_Printf (PRINT_ALL, "glGetError() = 0x%x\n", err); +} + +/* +=============== +R_Shutdown +=============== +*/ +void R_Shutdown (void) +{ + ri.Cmd_RemoveCommand ("modellist"); + ri.Cmd_RemoveCommand ("screenshot"); + ri.Cmd_RemoveCommand ("imagelist"); + ri.Cmd_RemoveCommand ("gl_strings"); + + Mod_FreeAll (); + + GL_ShutdownImages (); + + /* + ** shut down OS specific OpenGL stuff like contexts, etc. + */ + GLimp_Shutdown(); + + /* + ** shutdown our QGL subsystem + */ + QGL_Shutdown(); +} + + + +/* +@@@@@@@@@@@@@@@@@@@@@ +R_BeginFrame +@@@@@@@@@@@@@@@@@@@@@ +*/ +void R_BeginFrame( float camera_separation ) +{ + + gl_state.camera_separation = camera_separation; + + /* + ** change modes if necessary + */ + if ( gl_mode->modified || vid_fullscreen->modified ) + { // FIXME: only restart if CDS is required + cvar_t *ref; + + ref = ri.Cvar_Get ("vid_ref", "gl", 0); + ref->modified = true; + } + + if ( gl_log->modified ) + { + GLimp_EnableLogging( gl_log->value ); + gl_log->modified = false; + } + + if ( gl_log->value ) + { + GLimp_LogNewFrame(); + } + + /* + ** update 3Dfx gamma -- it is expected that a user will do a vid_restart + ** after tweaking this value + */ + if ( vid_gamma->modified ) + { + vid_gamma->modified = false; + + if ( gl_config.renderer & ( GL_RENDERER_VOODOO ) ) + { + char envbuffer[1024]; + float g; + + g = 2.00 * ( 0.8 - ( vid_gamma->value - 0.5 ) ) + 1.0F; + Com_sprintf( envbuffer, sizeof(envbuffer), "SSTV2_GAMMA=%f", g ); + putenv( envbuffer ); + Com_sprintf( envbuffer, sizeof(envbuffer), "SST_GAMMA=%f", g ); + putenv( envbuffer ); + } + } + + GLimp_BeginFrame( camera_separation ); + + /* + ** go into 2D mode + */ + qglViewport (0,0, vid.width, vid.height); + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + qglOrtho (0, vid.width, vid.height, 0, -99999, 99999); + qglMatrixMode(GL_MODELVIEW); + qglLoadIdentity (); + qglDisable (GL_DEPTH_TEST); + qglDisable (GL_CULL_FACE); + qglDisable (GL_BLEND); + qglEnable (GL_ALPHA_TEST); + qglColor4f (1,1,1,1); + + /* + ** draw buffer stuff + */ + if ( gl_drawbuffer->modified ) + { + gl_drawbuffer->modified = false; + + if ( gl_state.camera_separation == 0 || !gl_state.stereo_enabled ) + { + if ( Q_stricmp( gl_drawbuffer->string, "GL_FRONT" ) == 0 ) + qglDrawBuffer( GL_FRONT ); + else + qglDrawBuffer( GL_BACK ); + } + } + + /* + ** texturemode stuff + */ + if ( gl_texturemode->modified ) + { + GL_TextureMode( gl_texturemode->string ); + gl_texturemode->modified = false; + } + + if ( gl_texturealphamode->modified ) + { + GL_TextureAlphaMode( gl_texturealphamode->string ); + gl_texturealphamode->modified = false; + } + + if ( gl_texturesolidmode->modified ) + { + GL_TextureSolidMode( gl_texturesolidmode->string ); + gl_texturesolidmode->modified = false; + } + + /* + ** swapinterval stuff + */ + GL_UpdateSwapInterval(); + + // + // clear screen if desired + // + R_Clear (); +} + +/* +============= +R_SetPalette +============= +*/ +unsigned r_rawpalette[256]; + +void R_SetPalette ( const unsigned char *palette) +{ + int i; + + byte *rp = ( byte * ) r_rawpalette; + + if ( palette ) + { + for ( i = 0; i < 256; i++ ) + { + rp[i*4+0] = palette[i*3+0]; + rp[i*4+1] = palette[i*3+1]; + rp[i*4+2] = palette[i*3+2]; + rp[i*4+3] = 0xff; + } + } + else + { + for ( i = 0; i < 256; i++ ) + { + rp[i*4+0] = d_8to24table[i] & 0xff; + rp[i*4+1] = ( d_8to24table[i] >> 8 ) & 0xff; + rp[i*4+2] = ( d_8to24table[i] >> 16 ) & 0xff; + rp[i*4+3] = 0xff; + } + } + GL_SetTexturePalette( r_rawpalette ); + + qglClearColor (0,0,0,0); + qglClear (GL_COLOR_BUFFER_BIT); + qglClearColor (1,0, 0.5 , 0.5); +} + +/* +** R_DrawBeam +*/ +void R_DrawBeam( entity_t *e ) +{ +#define NUM_BEAM_SEGS 6 + + int i; + float r, g, b; + + vec3_t perpvec; + vec3_t direction, normalized_direction; + vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS]; + vec3_t oldorigin, origin; + + oldorigin[0] = e->oldorigin[0]; + oldorigin[1] = e->oldorigin[1]; + oldorigin[2] = e->oldorigin[2]; + + origin[0] = e->origin[0]; + origin[1] = e->origin[1]; + origin[2] = e->origin[2]; + + normalized_direction[0] = direction[0] = oldorigin[0] - origin[0]; + normalized_direction[1] = direction[1] = oldorigin[1] - origin[1]; + normalized_direction[2] = direction[2] = oldorigin[2] - origin[2]; + + if ( VectorNormalize( normalized_direction ) == 0 ) + return; + + PerpendicularVector( perpvec, normalized_direction ); + VectorScale( perpvec, e->frame / 2, perpvec ); + + for ( i = 0; i < 6; i++ ) + { + RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i ); + VectorAdd( start_points[i], origin, start_points[i] ); + VectorAdd( start_points[i], direction, end_points[i] ); + } + + qglDisable( GL_TEXTURE_2D ); + qglEnable( GL_BLEND ); + qglDepthMask( GL_FALSE ); + + r = ( d_8to24table[e->skinnum & 0xFF] ) & 0xFF; + g = ( d_8to24table[e->skinnum & 0xFF] >> 8 ) & 0xFF; + b = ( d_8to24table[e->skinnum & 0xFF] >> 16 ) & 0xFF; + + r *= 1/255.0F; + g *= 1/255.0F; + b *= 1/255.0F; + + qglColor4f( r, g, b, e->alpha ); + + qglBegin( GL_TRIANGLE_STRIP ); + for ( i = 0; i < NUM_BEAM_SEGS; i++ ) + { + qglVertex3fv( start_points[i] ); + qglVertex3fv( end_points[i] ); + qglVertex3fv( start_points[(i+1)%NUM_BEAM_SEGS] ); + qglVertex3fv( end_points[(i+1)%NUM_BEAM_SEGS] ); + } + qglEnd(); + + qglEnable( GL_TEXTURE_2D ); + qglDisable( GL_BLEND ); + qglDepthMask( GL_TRUE ); +} + +//=================================================================== + + +void R_BeginRegistration (char *map); +struct model_s *R_RegisterModel (char *name); +struct image_s *R_RegisterSkin (char *name); +void R_SetSky (char *name, float rotate, vec3_t axis); +void R_EndRegistration (void); + +void R_RenderFrame (refdef_t *fd); + +struct image_s *Draw_FindPic (char *name); + +void Draw_Pic (int x, int y, char *name); +void Draw_Char (int x, int y, int c); +void Draw_TileClear (int x, int y, int w, int h, char *name); +void Draw_Fill (int x, int y, int w, int h, int c); +void Draw_FadeScreen (void); + +/* +@@@@@@@@@@@@@@@@@@@@@ +GetRefAPI + +@@@@@@@@@@@@@@@@@@@@@ +*/ +refexport_t GetRefAPI (refimport_t rimp ) +{ + refexport_t re; + + ri = rimp; + + re.api_version = API_VERSION; + + re.BeginRegistration = R_BeginRegistration; + re.RegisterModel = R_RegisterModel; + re.RegisterSkin = R_RegisterSkin; + re.RegisterPic = Draw_FindPic; + re.SetSky = R_SetSky; + re.EndRegistration = R_EndRegistration; + + re.RenderFrame = R_RenderFrame; + + re.DrawGetPicSize = Draw_GetPicSize; + re.DrawPic = Draw_Pic; + re.DrawStretchPic = Draw_StretchPic; + re.DrawChar = Draw_Char; + re.DrawTileClear = Draw_TileClear; + re.DrawFill = Draw_Fill; + re.DrawFadeScreen= Draw_FadeScreen; + + re.DrawStretchRaw = Draw_StretchRaw; + + re.Init = R_Init; + re.Shutdown = R_Shutdown; + + re.CinematicSetPalette = R_SetPalette; + re.BeginFrame = R_BeginFrame; + re.EndFrame = GLimp_EndFrame; + + re.AppActivate = GLimp_AppActivate; + + Swap_Init (); + + return re; +} + + +#ifndef REF_HARD_LINKED +// this is only here so the functions in q_shared.c and q_shwin.c can link +void Sys_Error (char *error, ...) +{ + va_list argptr; + char text[1024]; + + va_start (argptr, error); + vsprintf (text, error, argptr); + va_end (argptr); + + ri.Sys_Error (ERR_FATAL, "%s", text); +} + +void Com_Printf (char *fmt, ...) +{ + va_list argptr; + char text[1024]; + + va_start (argptr, fmt); + vsprintf (text, fmt, argptr); + va_end (argptr); + + ri.Con_Printf (PRINT_ALL, "%s", text); +} + +#endif diff --git a/ref_gl/gl_rmisc.c b/ref_gl/gl_rmisc.c new file mode 100644 index 000000000..1038ba0eb --- /dev/null +++ b/ref_gl/gl_rmisc.c @@ -0,0 +1,246 @@ +/* +Copyright (C) 1997-2001 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 "gl_local.h" + +/* +================== +R_InitParticleTexture +================== +*/ +byte dottexture[8][8] = +{ + {0,0,0,0,0,0,0,0}, + {0,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}, +}; + +void R_InitParticleTexture (void) +{ + int x,y; + byte data[8][8][4]; + + // + // particle texture + // + 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; + } + } + r_particletexture = GL_LoadPic ("***particle***", (byte *)data, 8, 8, it_sprite, 32); + + // + // also use this for bad textures, but without alpha + // + for (x=0 ; x<8 ; x++) + { + for (y=0 ; y<8 ; y++) + { + data[y][x][0] = dottexture[x&3][y&3]*255; + data[y][x][1] = 0; // dottexture[x&3][y&3]*255; + data[y][x][2] = 0; //dottexture[x&3][y&3]*255; + data[y][x][3] = 255; + } + } + r_notexture = GL_LoadPic ("***r_notexture***", (byte *)data, 8, 8, it_wall, 32); +} + + +/* +============================================================================== + + SCREEN SHOTS + +============================================================================== +*/ + +typedef struct _TargaHeader { + unsigned char id_length, colormap_type, image_type; + unsigned short colormap_index, colormap_length; + unsigned char colormap_size; + unsigned short x_origin, y_origin, width, height; + unsigned char pixel_size, attributes; +} TargaHeader; + + +/* +================== +GL_ScreenShot_f +================== +*/ +void GL_ScreenShot_f (void) +{ + byte *buffer; + char picname[80]; + char checkname[MAX_OSPATH]; + int i, c, temp; + FILE *f; + + // create the scrnshots directory if it doesn't exist + Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir()); + Sys_Mkdir (checkname); + +// +// find a file name to save it to +// + strcpy(picname,"quake00.tga"); + + for (i=0 ; i<=99 ; i++) + { + picname[5] = i/10 + '0'; + picname[6] = i%10 + '0'; + Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), picname); + f = fopen (checkname, "rb"); + if (!f) + break; // file doesn't exist + fclose (f); + } + if (i==100) + { + ri.Con_Printf (PRINT_ALL, "SCR_ScreenShot_f: Couldn't create a file\n"); + return; + } + + + buffer = malloc(vid.width*vid.height*3 + 18); + memset (buffer, 0, 18); + buffer[2] = 2; // uncompressed type + buffer[12] = vid.width&255; + buffer[13] = vid.width>>8; + buffer[14] = vid.height&255; + buffer[15] = vid.height>>8; + buffer[16] = 24; // pixel size + + qglReadPixels (0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); + + // swap rgb to bgr + c = 18+vid.width*vid.height*3; + for (i=18 ; istring ); + GL_TextureAlphaMode( gl_texturealphamode->string ); + GL_TextureSolidMode( gl_texturesolidmode->string ); + + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + GL_TexEnv( GL_REPLACE ); + + if ( qglPointParameterfEXT ) + { + float attenuations[3]; + + attenuations[0] = gl_particle_att_a->value; + attenuations[1] = gl_particle_att_b->value; + attenuations[2] = gl_particle_att_c->value; + + qglEnable( GL_POINT_SMOOTH ); + qglPointParameterfEXT( GL_POINT_SIZE_MIN_EXT, gl_particle_min_size->value ); + qglPointParameterfEXT( GL_POINT_SIZE_MAX_EXT, gl_particle_max_size->value ); + qglPointParameterfvEXT( GL_DISTANCE_ATTENUATION_EXT, attenuations ); + } + + if ( qglColorTableEXT && gl_ext_palettedtexture->value ) + { + qglEnable( GL_SHARED_TEXTURE_PALETTE_EXT ); + + GL_SetTexturePalette( d_8to24table ); + } + + GL_UpdateSwapInterval(); +} + +void GL_UpdateSwapInterval( void ) +{ + if ( gl_swapinterval->modified ) + { + gl_swapinterval->modified = false; + + if ( !gl_state.stereo_enabled ) + { +#ifdef _WIN32 + if ( qwglSwapIntervalEXT ) + qwglSwapIntervalEXT( gl_swapinterval->value ); +#endif + } + } +} \ No newline at end of file diff --git a/ref_gl/gl_rsurf.c b/ref_gl/gl_rsurf.c new file mode 100644 index 000000000..d8235a8e5 --- /dev/null +++ b/ref_gl/gl_rsurf.c @@ -0,0 +1,1660 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +// GL_RSURF.C: surface-related refresh code +#include + +#include "gl_local.h" + +static vec3_t modelorg; // relative to viewpoint + +msurface_t *r_alpha_surfaces; + +#define DYNAMIC_LIGHT_WIDTH 128 +#define DYNAMIC_LIGHT_HEIGHT 128 + +#define LIGHTMAP_BYTES 4 + +#define BLOCK_WIDTH 128 +#define BLOCK_HEIGHT 128 + +#define MAX_LIGHTMAPS 128 + +int c_visible_lightmaps; +int c_visible_textures; + +#define GL_LIGHTMAP_FORMAT GL_RGBA + +typedef struct +{ + int internal_format; + int current_lightmap_texture; + + msurface_t *lightmap_surfaces[MAX_LIGHTMAPS]; + + int allocated[BLOCK_WIDTH]; + + // the lightmap texture data needs to be kept in + // main memory so texsubimage can update properly + byte lightmap_buffer[4*BLOCK_WIDTH*BLOCK_HEIGHT]; +} gllightmapstate_t; + +static gllightmapstate_t gl_lms; + + +static void LM_InitBlock( void ); +static void LM_UploadBlock( qboolean dynamic ); +static qboolean LM_AllocBlock (int w, int h, int *x, int *y); + +extern void R_SetCacheState( msurface_t *surf ); +extern void R_BuildLightMap (msurface_t *surf, byte *dest, int stride); + +/* +============================================================= + + BRUSH MODELS + +============================================================= +*/ + +/* +=============== +R_TextureAnimation + +Returns the proper texture for a given time and base texture +=============== +*/ +image_t *R_TextureAnimation (mtexinfo_t *tex) +{ + int c; + + if (!tex->next) + return tex->image; + + c = currententity->frame % tex->numframes; + while (c) + { + tex = tex->next; + c--; + } + + return tex->image; +} + +#if 0 +/* +================= +WaterWarpPolyVerts + +Mangles the x and y coordinates in a copy of the poly +so that any drawing routine can be water warped +================= +*/ +glpoly_t *WaterWarpPolyVerts (glpoly_t *p) +{ + int i; + float *v, *nv; + static byte buffer[1024]; + glpoly_t *out; + + out = (glpoly_t *)buffer; + + out->numverts = p->numverts; + v = p->verts[0]; + nv = out->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE, nv+=VERTEXSIZE) + { + nv[0] = v[0] + 4*sin(v[1]*0.05+r_newrefdef.time)*sin(v[2]*0.05+r_newrefdef.time); + nv[1] = v[1] + 4*sin(v[0]*0.05+r_newrefdef.time)*sin(v[2]*0.05+r_newrefdef.time); + + nv[2] = v[2]; + nv[3] = v[3]; + nv[4] = v[4]; + nv[5] = v[5]; + nv[6] = v[6]; + } + + return out; +} + +/* +================ +DrawGLWaterPoly + +Warp the vertex coordinates +================ +*/ +void DrawGLWaterPoly (glpoly_t *p) +{ + int i; + float *v; + + p = WaterWarpPolyVerts (p); + qglBegin (GL_TRIANGLE_FAN); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + qglTexCoord2f (v[3], v[4]); + qglVertex3fv (v); + } + qglEnd (); +} +void DrawGLWaterPolyLightmap (glpoly_t *p) +{ + int i; + float *v; + + p = WaterWarpPolyVerts (p); + qglBegin (GL_TRIANGLE_FAN); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + qglTexCoord2f (v[5], v[6]); + qglVertex3fv (v); + } + qglEnd (); +} +#endif + +/* +================ +DrawGLPoly +================ +*/ +void DrawGLPoly (glpoly_t *p) +{ + int i; + float *v; + + qglBegin (GL_POLYGON); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + qglTexCoord2f (v[3], v[4]); + qglVertex3fv (v); + } + qglEnd (); +} + +//============ +//PGM +/* +================ +DrawGLFlowingPoly -- version of DrawGLPoly that handles scrolling texture +================ +*/ +void DrawGLFlowingPoly (msurface_t *fa) +{ + int i; + float *v; + glpoly_t *p; + float scroll; + + p = fa->polys; + + scroll = -64 * ( (r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0) ); + if(scroll == 0.0) + scroll = -64.0; + + qglBegin (GL_POLYGON); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + qglTexCoord2f ((v[3] + scroll), v[4]); + qglVertex3fv (v); + } + qglEnd (); +} +//PGM +//============ + +/* +** R_DrawTriangleOutlines +*/ +void R_DrawTriangleOutlines (void) +{ + int i, j; + glpoly_t *p; + + if (!gl_showtris->value) + return; + + qglDisable (GL_TEXTURE_2D); + qglDisable (GL_DEPTH_TEST); + qglColor4f (1,1,1,1); + + for (i=0 ; ilightmapchain ) + { + p = surf->polys; + for ( ; p ; p=p->chain) + { + for (j=2 ; jnumverts ; j++ ) + { + qglBegin (GL_LINE_STRIP); + qglVertex3fv (p->verts[0]); + qglVertex3fv (p->verts[j-1]); + qglVertex3fv (p->verts[j]); + qglVertex3fv (p->verts[0]); + qglEnd (); + } + } + } + } + + qglEnable (GL_DEPTH_TEST); + qglEnable (GL_TEXTURE_2D); +} + +/* +** DrawGLPolyChain +*/ +void DrawGLPolyChain( glpoly_t *p, float soffset, float toffset ) +{ + if ( soffset == 0 && toffset == 0 ) + { + for ( ; p != 0; p = p->chain ) + { + float *v; + int j; + + qglBegin (GL_POLYGON); + v = p->verts[0]; + for (j=0 ; jnumverts ; j++, v+= VERTEXSIZE) + { + qglTexCoord2f (v[5], v[6] ); + qglVertex3fv (v); + } + qglEnd (); + } + } + else + { + for ( ; p != 0; p = p->chain ) + { + float *v; + int j; + + qglBegin (GL_POLYGON); + v = p->verts[0]; + for (j=0 ; jnumverts ; j++, v+= VERTEXSIZE) + { + qglTexCoord2f (v[5] - soffset, v[6] - toffset ); + qglVertex3fv (v); + } + qglEnd (); + } + } +} + +/* +** R_BlendLightMaps +** +** This routine takes all the given light mapped surfaces in the world and +** blends them into the framebuffer. +*/ +void R_BlendLightmaps (void) +{ + int i; + msurface_t *surf, *newdrawsurf = 0; + + // don't bother if we're set to fullbright + if (r_fullbright->value) + return; + if (!r_worldmodel->lightdata) + return; + + // don't bother writing Z + qglDepthMask( 0 ); + + /* + ** set the appropriate blending mode unless we're only looking at the + ** lightmaps. + */ + if (!gl_lightmap->value) + { + qglEnable (GL_BLEND); + + if ( gl_saturatelighting->value ) + { + qglBlendFunc( GL_ONE, GL_ONE ); + } + else + { + if ( gl_monolightmap->string[0] != '0' ) + { + switch ( toupper( gl_monolightmap->string[0] ) ) + { + case 'I': + qglBlendFunc (GL_ZERO, GL_SRC_COLOR ); + break; + case 'L': + qglBlendFunc (GL_ZERO, GL_SRC_COLOR ); + break; + case 'A': + default: + qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + break; + } + } + else + { + qglBlendFunc (GL_ZERO, GL_SRC_COLOR ); + } + } + } + + if ( currentmodel == r_worldmodel ) + c_visible_lightmaps = 0; + + /* + ** render static lightmaps first + */ + for ( i = 1; i < MAX_LIGHTMAPS; i++ ) + { + if ( gl_lms.lightmap_surfaces[i] ) + { + if (currentmodel == r_worldmodel) + c_visible_lightmaps++; + GL_Bind( gl_state.lightmap_textures + i); + + for ( surf = gl_lms.lightmap_surfaces[i]; surf != 0; surf = surf->lightmapchain ) + { + if ( surf->polys ) + DrawGLPolyChain( surf->polys, 0, 0 ); + } + } + } + + /* + ** render dynamic lightmaps + */ + if ( gl_dynamic->value ) + { + LM_InitBlock(); + + GL_Bind( gl_state.lightmap_textures+0 ); + + if (currentmodel == r_worldmodel) + c_visible_lightmaps++; + + newdrawsurf = gl_lms.lightmap_surfaces[0]; + + for ( surf = gl_lms.lightmap_surfaces[0]; surf != 0; surf = surf->lightmapchain ) + { + int smax, tmax; + byte *base; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + + if ( LM_AllocBlock( smax, tmax, &surf->dlight_s, &surf->dlight_t ) ) + { + base = gl_lms.lightmap_buffer; + base += ( surf->dlight_t * BLOCK_WIDTH + surf->dlight_s ) * LIGHTMAP_BYTES; + + R_BuildLightMap (surf, base, BLOCK_WIDTH*LIGHTMAP_BYTES); + } + else + { + msurface_t *drawsurf; + + // upload what we have so far + LM_UploadBlock( true ); + + // draw all surfaces that use this lightmap + for ( drawsurf = newdrawsurf; drawsurf != surf; drawsurf = drawsurf->lightmapchain ) + { + if ( drawsurf->polys ) + DrawGLPolyChain( drawsurf->polys, + ( drawsurf->light_s - drawsurf->dlight_s ) * ( 1.0 / 128.0 ), + ( drawsurf->light_t - drawsurf->dlight_t ) * ( 1.0 / 128.0 ) ); + } + + newdrawsurf = drawsurf; + + // clear the block + LM_InitBlock(); + + // try uploading the block now + if ( !LM_AllocBlock( smax, tmax, &surf->dlight_s, &surf->dlight_t ) ) + { + ri.Sys_Error( ERR_FATAL, "Consecutive calls to LM_AllocBlock(%d,%d) failed (dynamic)\n", smax, tmax ); + } + + base = gl_lms.lightmap_buffer; + base += ( surf->dlight_t * BLOCK_WIDTH + surf->dlight_s ) * LIGHTMAP_BYTES; + + R_BuildLightMap (surf, base, BLOCK_WIDTH*LIGHTMAP_BYTES); + } + } + + /* + ** draw remainder of dynamic lightmaps that haven't been uploaded yet + */ + if ( newdrawsurf ) + LM_UploadBlock( true ); + + for ( surf = newdrawsurf; surf != 0; surf = surf->lightmapchain ) + { + if ( surf->polys ) + DrawGLPolyChain( surf->polys, ( surf->light_s - surf->dlight_s ) * ( 1.0 / 128.0 ), ( surf->light_t - surf->dlight_t ) * ( 1.0 / 128.0 ) ); + } + } + + /* + ** restore state + */ + qglDisable (GL_BLEND); + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglDepthMask( 1 ); +} + +/* +================ +R_RenderBrushPoly +================ +*/ +void R_RenderBrushPoly (msurface_t *fa) +{ + int maps; + image_t *image; + qboolean is_dynamic = false; + + c_brush_polys++; + + image = R_TextureAnimation (fa->texinfo); + + if (fa->flags & SURF_DRAWTURB) + { + GL_Bind( image->texnum ); + + // warp texture, no lightmaps + GL_TexEnv( GL_MODULATE ); + qglColor4f( gl_state.inverse_intensity, + gl_state.inverse_intensity, + gl_state.inverse_intensity, + 1.0F ); + EmitWaterPolys (fa); + GL_TexEnv( GL_REPLACE ); + + return; + } + else + { + GL_Bind( image->texnum ); + + GL_TexEnv( GL_REPLACE ); + } + +//====== +//PGM + if(fa->texinfo->flags & SURF_FLOWING) + DrawGLFlowingPoly (fa); + else + DrawGLPoly (fa->polys); +//PGM +//====== + + /* + ** check for lightmap modification + */ + for ( maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++ ) + { + if ( r_newrefdef.lightstyles[fa->styles[maps]].white != fa->cached_light[maps] ) + goto dynamic; + } + + // dynamic this frame or dynamic previously + if ( ( fa->dlightframe == r_framecount ) ) + { +dynamic: + if ( gl_dynamic->value ) + { + if (!( fa->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP ) ) ) + { + is_dynamic = true; + } + } + } + + if ( is_dynamic ) + { + if ( ( fa->styles[maps] >= 32 || fa->styles[maps] == 0 ) && ( fa->dlightframe != r_framecount ) ) + { + unsigned temp[34*34]; + int smax, tmax; + + smax = (fa->extents[0]>>4)+1; + tmax = (fa->extents[1]>>4)+1; + + R_BuildLightMap( fa, (void *)temp, smax*4 ); + R_SetCacheState( fa ); + + GL_Bind( gl_state.lightmap_textures + fa->lightmaptexturenum ); + + qglTexSubImage2D( GL_TEXTURE_2D, 0, + fa->light_s, fa->light_t, + smax, tmax, + GL_LIGHTMAP_FORMAT, + GL_UNSIGNED_BYTE, temp ); + + fa->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum]; + gl_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa; + } + else + { + fa->lightmapchain = gl_lms.lightmap_surfaces[0]; + gl_lms.lightmap_surfaces[0] = fa; + } + } + else + { + fa->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum]; + gl_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa; + } +} + + +/* +================ +R_DrawAlphaSurfaces + +Draw water surfaces and windows. +The BSP tree is waled front to back, so unwinding the chain +of alpha_surfaces will draw back to front, giving proper ordering. +================ +*/ +void R_DrawAlphaSurfaces (void) +{ + msurface_t *s; + float intens; + + // + // go back to the world matrix + // + qglLoadMatrixf (r_world_matrix); + + qglEnable (GL_BLEND); + GL_TexEnv( GL_MODULATE ); + + // the textures are prescaled up for a better lighting range, + // so scale it back down + intens = gl_state.inverse_intensity; + + for (s=r_alpha_surfaces ; s ; s=s->texturechain) + { + GL_Bind(s->texinfo->image->texnum); + c_brush_polys++; + if (s->texinfo->flags & SURF_TRANS33) + qglColor4f (intens,intens,intens,0.33); + else if (s->texinfo->flags & SURF_TRANS66) + qglColor4f (intens,intens,intens,0.66); + else + qglColor4f (intens,intens,intens,1); + if (s->flags & SURF_DRAWTURB) + EmitWaterPolys (s); + else + DrawGLPoly (s->polys); + } + + GL_TexEnv( GL_REPLACE ); + qglColor4f (1,1,1,1); + qglDisable (GL_BLEND); + + r_alpha_surfaces = NULL; +} + +/* +================ +DrawTextureChains +================ +*/ +void DrawTextureChains (void) +{ + int i; + msurface_t *s; + image_t *image; + + c_visible_textures = 0; + +// GL_TexEnv( GL_REPLACE ); + + if ( !qglSelectTextureSGIS ) + { + for ( i = 0, image=gltextures ; iregistration_sequence) + continue; + s = image->texturechain; + if (!s) + continue; + c_visible_textures++; + + for ( ; s ; s=s->texturechain) + R_RenderBrushPoly (s); + + image->texturechain = NULL; + } + } + else + { + for ( i = 0, image=gltextures ; iregistration_sequence) + continue; + if (!image->texturechain) + continue; + c_visible_textures++; + + for ( s = image->texturechain; s ; s=s->texturechain) + { + if ( !( s->flags & SURF_DRAWTURB ) ) + R_RenderBrushPoly (s); + } + } + + GL_EnableMultitexture( false ); + for ( i = 0, image=gltextures ; iregistration_sequence) + continue; + s = image->texturechain; + if (!s) + continue; + + for ( ; s ; s=s->texturechain) + { + if ( s->flags & SURF_DRAWTURB ) + R_RenderBrushPoly (s); + } + + image->texturechain = NULL; + } +// GL_EnableMultitexture( true ); + } + + GL_TexEnv( GL_REPLACE ); +} + + +static void GL_RenderLightmappedPoly( msurface_t *surf ) +{ + int i, nv = surf->polys->numverts; + int map; + float *v; + image_t *image = R_TextureAnimation( surf->texinfo ); + qboolean is_dynamic = false; + unsigned lmtex = surf->lightmaptexturenum; + glpoly_t *p; + + for ( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ ) + { + if ( r_newrefdef.lightstyles[surf->styles[map]].white != surf->cached_light[map] ) + goto dynamic; + } + + // dynamic this frame or dynamic previously + if ( ( surf->dlightframe == r_framecount ) ) + { +dynamic: + if ( gl_dynamic->value ) + { + if ( !(surf->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP ) ) ) + { + is_dynamic = true; + } + } + } + + if ( is_dynamic ) + { + unsigned temp[128*128]; + int smax, tmax; + + if ( ( surf->styles[map] >= 32 || surf->styles[map] == 0 ) && ( surf->dlightframe != r_framecount ) ) + { + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + + R_BuildLightMap( surf, (void *)temp, smax*4 ); + R_SetCacheState( surf ); + + GL_MBind( GL_TEXTURE1_SGIS, gl_state.lightmap_textures + surf->lightmaptexturenum ); + + lmtex = surf->lightmaptexturenum; + + qglTexSubImage2D( GL_TEXTURE_2D, 0, + surf->light_s, surf->light_t, + smax, tmax, + GL_LIGHTMAP_FORMAT, + GL_UNSIGNED_BYTE, temp ); + + } + else + { + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + + R_BuildLightMap( surf, (void *)temp, smax*4 ); + + GL_MBind( GL_TEXTURE1_SGIS, gl_state.lightmap_textures + 0 ); + + lmtex = 0; + + qglTexSubImage2D( GL_TEXTURE_2D, 0, + surf->light_s, surf->light_t, + smax, tmax, + GL_LIGHTMAP_FORMAT, + GL_UNSIGNED_BYTE, temp ); + + } + + c_brush_polys++; + + GL_MBind( GL_TEXTURE0_SGIS, image->texnum ); + GL_MBind( GL_TEXTURE1_SGIS, gl_state.lightmap_textures + lmtex ); + +//========== +//PGM + if (surf->texinfo->flags & SURF_FLOWING) + { + float scroll; + + scroll = -64 * ( (r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0) ); + if(scroll == 0.0) + scroll = -64.0; + + for ( p = surf->polys; p; p = p->chain ) + { + v = p->verts[0]; + qglBegin (GL_POLYGON); + for (i=0 ; i< nv; i++, v+= VERTEXSIZE) + { + qglMTexCoord2fSGIS( GL_TEXTURE0_SGIS, (v[3]+scroll), v[4]); + qglMTexCoord2fSGIS( GL_TEXTURE1_SGIS, v[5], v[6]); + qglVertex3fv (v); + } + qglEnd (); + } + } + else + { + for ( p = surf->polys; p; p = p->chain ) + { + v = p->verts[0]; + qglBegin (GL_POLYGON); + for (i=0 ; i< nv; i++, v+= VERTEXSIZE) + { + qglMTexCoord2fSGIS( GL_TEXTURE0_SGIS, v[3], v[4]); + qglMTexCoord2fSGIS( GL_TEXTURE1_SGIS, v[5], v[6]); + qglVertex3fv (v); + } + qglEnd (); + } + } +//PGM +//========== + } + else + { + c_brush_polys++; + + GL_MBind( GL_TEXTURE0_SGIS, image->texnum ); + GL_MBind( GL_TEXTURE1_SGIS, gl_state.lightmap_textures + lmtex ); + +//========== +//PGM + if (surf->texinfo->flags & SURF_FLOWING) + { + float scroll; + + scroll = -64 * ( (r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0) ); + if(scroll == 0.0) + scroll = -64.0; + + for ( p = surf->polys; p; p = p->chain ) + { + v = p->verts[0]; + qglBegin (GL_POLYGON); + for (i=0 ; i< nv; i++, v+= VERTEXSIZE) + { + qglMTexCoord2fSGIS( GL_TEXTURE0_SGIS, (v[3]+scroll), v[4]); + qglMTexCoord2fSGIS( GL_TEXTURE1_SGIS, v[5], v[6]); + qglVertex3fv (v); + } + qglEnd (); + } + } + else + { +//PGM +//========== + for ( p = surf->polys; p; p = p->chain ) + { + v = p->verts[0]; + qglBegin (GL_POLYGON); + for (i=0 ; i< nv; i++, v+= VERTEXSIZE) + { + qglMTexCoord2fSGIS( GL_TEXTURE0_SGIS, v[3], v[4]); + qglMTexCoord2fSGIS( GL_TEXTURE1_SGIS, v[5], v[6]); + qglVertex3fv (v); + } + qglEnd (); + } +//========== +//PGM + } +//PGM +//========== + } +} + +/* +================= +R_DrawInlineBModel +================= +*/ +void R_DrawInlineBModel (void) +{ + int i, k; + cplane_t *pplane; + float dot; + msurface_t *psurf; + dlight_t *lt; + + // calculate dynamic lighting for bmodel + if ( !gl_flashblend->value ) + { + lt = r_newrefdef.dlights; + for (k=0 ; knodes + currentmodel->firstnode); + } + } + + psurf = ¤tmodel->surfaces[currentmodel->firstmodelsurface]; + + if ( currententity->flags & RF_TRANSLUCENT ) + { + qglEnable (GL_BLEND); + qglColor4f (1,1,1,0.25); + GL_TexEnv( GL_MODULATE ); + } + + // + // draw texture + // + for (i=0 ; inummodelsurfaces ; i++, psurf++) + { + // find which side of the node we are on + pplane = psurf->plane; + + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + + // draw the polygon + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + if (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66) ) + { // add to the translucent chain + psurf->texturechain = r_alpha_surfaces; + r_alpha_surfaces = psurf; + } + else if ( qglMTexCoord2fSGIS && !( psurf->flags & SURF_DRAWTURB ) ) + { + GL_RenderLightmappedPoly( psurf ); + } + else + { + GL_EnableMultitexture( false ); + R_RenderBrushPoly( psurf ); + GL_EnableMultitexture( true ); + } + } + } + + if ( !(currententity->flags & RF_TRANSLUCENT) ) + { + if ( !qglMTexCoord2fSGIS ) + R_BlendLightmaps (); + } + else + { + qglDisable (GL_BLEND); + qglColor4f (1,1,1,1); + GL_TexEnv( GL_REPLACE ); + } +} + +/* +================= +R_DrawBrushModel +================= +*/ +void R_DrawBrushModel (entity_t *e) +{ + vec3_t mins, maxs; + int i; + qboolean rotated; + + if (currentmodel->nummodelsurfaces == 0) + return; + + currententity = e; + gl_state.currenttextures[0] = gl_state.currenttextures[1] = -1; + + if (e->angles[0] || e->angles[1] || e->angles[2]) + { + rotated = true; + for (i=0 ; i<3 ; i++) + { + mins[i] = e->origin[i] - currentmodel->radius; + maxs[i] = e->origin[i] + currentmodel->radius; + } + } + else + { + rotated = false; + VectorAdd (e->origin, currentmodel->mins, mins); + VectorAdd (e->origin, currentmodel->maxs, maxs); + } + + if (R_CullBox (mins, maxs)) + return; + + qglColor3f (1,1,1); + memset (gl_lms.lightmap_surfaces, 0, sizeof(gl_lms.lightmap_surfaces)); + + VectorSubtract (r_newrefdef.vieworg, e->origin, modelorg); + if (rotated) + { + vec3_t temp; + vec3_t forward, right, up; + + VectorCopy (modelorg, temp); + AngleVectors (e->angles, forward, right, up); + modelorg[0] = DotProduct (temp, forward); + modelorg[1] = -DotProduct (temp, right); + modelorg[2] = DotProduct (temp, up); + } + + qglPushMatrix (); +e->angles[0] = -e->angles[0]; // stupid quake bug +e->angles[2] = -e->angles[2]; // stupid quake bug + R_RotateForEntity (e); +e->angles[0] = -e->angles[0]; // stupid quake bug +e->angles[2] = -e->angles[2]; // stupid quake bug + + GL_EnableMultitexture( true ); + GL_SelectTexture( GL_TEXTURE0_SGIS ); + GL_TexEnv( GL_REPLACE ); + GL_SelectTexture( GL_TEXTURE1_SGIS ); + GL_TexEnv( GL_MODULATE ); + + R_DrawInlineBModel (); + GL_EnableMultitexture( false ); + + qglPopMatrix (); +} + +/* +============================================================= + + WORLD MODEL + +============================================================= +*/ + +/* +================ +R_RecursiveWorldNode +================ +*/ +void R_RecursiveWorldNode (mnode_t *node) +{ + int c, side, sidebit; + cplane_t *plane; + msurface_t *surf, **mark; + mleaf_t *pleaf; + float dot; + image_t *image; + + if (node->contents == CONTENTS_SOLID) + return; // solid + + if (node->visframe != r_visframecount) + return; + if (R_CullBox (node->minmaxs, node->minmaxs+3)) + return; + +// if a leaf node, draw stuff + if (node->contents != -1) + { + pleaf = (mleaf_t *)node; + + // check for door connected areas + if (r_newrefdef.areabits) + { + if (! (r_newrefdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) ) + return; // not visible + } + + mark = pleaf->firstmarksurface; + c = pleaf->nummarksurfaces; + + if (c) + { + do + { + (*mark)->visframe = r_framecount; + mark++; + } while (--c); + } + + return; + } + +// node is just a decision point, so go down the apropriate sides + +// find which side of the node we are on + plane = node->plane; + + switch (plane->type) + { + case PLANE_X: + dot = modelorg[0] - plane->dist; + break; + case PLANE_Y: + dot = modelorg[1] - plane->dist; + break; + case PLANE_Z: + dot = modelorg[2] - plane->dist; + break; + default: + dot = DotProduct (modelorg, plane->normal) - plane->dist; + break; + } + + if (dot >= 0) + { + side = 0; + sidebit = 0; + } + else + { + side = 1; + sidebit = SURF_PLANEBACK; + } + +// recurse down the children, front side first + R_RecursiveWorldNode (node->children[side]); + + // draw stuff + for ( c = node->numsurfaces, surf = r_worldmodel->surfaces + node->firstsurface; c ; c--, surf++) + { + if (surf->visframe != r_framecount) + continue; + + if ( (surf->flags & SURF_PLANEBACK) != sidebit ) + continue; // wrong side + + if (surf->texinfo->flags & SURF_SKY) + { // just adds to visible sky bounds + R_AddSkySurface (surf); + } + else if (surf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66)) + { // add to the translucent chain + surf->texturechain = r_alpha_surfaces; + r_alpha_surfaces = surf; + } + else + { + if ( qglMTexCoord2fSGIS && !( surf->flags & SURF_DRAWTURB ) ) + { + GL_RenderLightmappedPoly( surf ); + } + else + { + // the polygon is visible, so add it to the texture + // sorted chain + // FIXME: this is a hack for animation + image = R_TextureAnimation (surf->texinfo); + surf->texturechain = image->texturechain; + image->texturechain = surf; + } + } + } + + // recurse down the back side + R_RecursiveWorldNode (node->children[!side]); +/* + for ( ; c ; c--, surf++) + { + if (surf->visframe != r_framecount) + continue; + + if ( (surf->flags & SURF_PLANEBACK) != sidebit ) + continue; // wrong side + + if (surf->texinfo->flags & SURF_SKY) + { // just adds to visible sky bounds + R_AddSkySurface (surf); + } + else if (surf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66)) + { // add to the translucent chain +// surf->texturechain = alpha_surfaces; +// alpha_surfaces = surf; + } + else + { + if ( qglMTexCoord2fSGIS && !( surf->flags & SURF_DRAWTURB ) ) + { + GL_RenderLightmappedPoly( surf ); + } + else + { + // the polygon is visible, so add it to the texture + // sorted chain + // FIXME: this is a hack for animation + image = R_TextureAnimation (surf->texinfo); + surf->texturechain = image->texturechain; + image->texturechain = surf; + } + } + } +*/ +} + + +/* +============= +R_DrawWorld +============= +*/ +void R_DrawWorld (void) +{ + entity_t ent; + + if (!r_drawworld->value) + return; + + if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) + return; + + currentmodel = r_worldmodel; + + VectorCopy (r_newrefdef.vieworg, modelorg); + + // auto cycle the world frame for texture animation + memset (&ent, 0, sizeof(ent)); + ent.frame = (int)(r_newrefdef.time*2); + currententity = &ent; + + gl_state.currenttextures[0] = gl_state.currenttextures[1] = -1; + + qglColor3f (1,1,1); + memset (gl_lms.lightmap_surfaces, 0, sizeof(gl_lms.lightmap_surfaces)); + R_ClearSkyBox (); + + if ( qglMTexCoord2fSGIS ) + { + GL_EnableMultitexture( true ); + + GL_SelectTexture( GL_TEXTURE0_SGIS ); + GL_TexEnv( GL_REPLACE ); + GL_SelectTexture( GL_TEXTURE1_SGIS ); + + if ( gl_lightmap->value ) + GL_TexEnv( GL_REPLACE ); + else + GL_TexEnv( GL_MODULATE ); + + R_RecursiveWorldNode (r_worldmodel->nodes); + + GL_EnableMultitexture( false ); + } + else + { + R_RecursiveWorldNode (r_worldmodel->nodes); + } + + /* + ** theoretically nothing should happen in the next two functions + ** if multitexture is enabled + */ + DrawTextureChains (); + R_BlendLightmaps (); + + R_DrawSkyBox (); + + R_DrawTriangleOutlines (); +} + + +/* +=============== +R_MarkLeaves + +Mark the leaves and nodes that are in the PVS for the current +cluster +=============== +*/ +void R_MarkLeaves (void) +{ + byte *vis; + byte fatvis[MAX_MAP_LEAFS/8]; + mnode_t *node; + int i, c; + mleaf_t *leaf; + int cluster; + + if (r_oldviewcluster == r_viewcluster && r_oldviewcluster2 == r_viewcluster2 && !r_novis->value && r_viewcluster != -1) + return; + + // development aid to let you run around and see exactly where + // the pvs ends + if (gl_lockpvs->value) + return; + + r_visframecount++; + r_oldviewcluster = r_viewcluster; + r_oldviewcluster2 = r_viewcluster2; + + if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis) + { + // mark everything + for (i=0 ; inumleafs ; i++) + r_worldmodel->leafs[i].visframe = r_visframecount; + for (i=0 ; inumnodes ; i++) + r_worldmodel->nodes[i].visframe = r_visframecount; + return; + } + + vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel); + // may have to combine two clusters because of solid water boundaries + if (r_viewcluster2 != r_viewcluster) + { + memcpy (fatvis, vis, (r_worldmodel->numleafs+7)/8); + vis = Mod_ClusterPVS (r_viewcluster2, r_worldmodel); + c = (r_worldmodel->numleafs+31)/32; + for (i=0 ; ileafs ; inumleafs ; i++, leaf++) + { + cluster = leaf->cluster; + if (cluster == -1) + continue; + if (vis[cluster>>3] & (1<<(cluster&7))) + { + node = (mnode_t *)leaf; + do + { + if (node->visframe == r_visframecount) + break; + node->visframe = r_visframecount; + node = node->parent; + } while (node); + } + } + +#if 0 + for (i=0 ; ivis->numclusters ; i++) + { + if (vis[i>>3] & (1<<(i&7))) + { + node = (mnode_t *)&r_worldmodel->leafs[i]; // FIXME: cluster + do + { + if (node->visframe == r_visframecount) + break; + node->visframe = r_visframecount; + node = node->parent; + } while (node); + } + } +#endif +} + + + +/* +============================================================================= + + LIGHTMAP ALLOCATION + +============================================================================= +*/ + +static void LM_InitBlock( void ) +{ + memset( gl_lms.allocated, 0, sizeof( gl_lms.allocated ) ); +} + +static void LM_UploadBlock( qboolean dynamic ) +{ + int texture; + int height = 0; + + if ( dynamic ) + { + texture = 0; + } + else + { + texture = gl_lms.current_lightmap_texture; + } + + GL_Bind( gl_state.lightmap_textures + texture ); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + if ( dynamic ) + { + int i; + + for ( i = 0; i < BLOCK_WIDTH; i++ ) + { + if ( gl_lms.allocated[i] > height ) + height = gl_lms.allocated[i]; + } + + qglTexSubImage2D( GL_TEXTURE_2D, + 0, + 0, 0, + BLOCK_WIDTH, height, + GL_LIGHTMAP_FORMAT, + GL_UNSIGNED_BYTE, + gl_lms.lightmap_buffer ); + } + else + { + qglTexImage2D( GL_TEXTURE_2D, + 0, + gl_lms.internal_format, + BLOCK_WIDTH, BLOCK_HEIGHT, + 0, + GL_LIGHTMAP_FORMAT, + GL_UNSIGNED_BYTE, + gl_lms.lightmap_buffer ); + if ( ++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS ) + ri.Sys_Error( ERR_DROP, "LM_UploadBlock() - MAX_LIGHTMAPS exceeded\n" ); + } +} + +// returns a texture number and the position inside it +static qboolean LM_AllocBlock (int w, int h, int *x, int *y) +{ + int i, j; + int best, best2; + + best = BLOCK_HEIGHT; + + for (i=0 ; i= best) + break; + if (gl_lms.allocated[i+j] > best2) + best2 = gl_lms.allocated[i+j]; + } + if (j == w) + { // this is a valid spot + *x = i; + *y = best = best2; + } + } + + if (best + h > BLOCK_HEIGHT) + return false; + + for (i=0 ; iedges; + lnumverts = fa->numedges; + vertpage = 0; + + VectorClear (total); + // + // draw texture + // + poly = Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float)); + poly->next = fa->polys; + poly->flags = fa->flags; + fa->polys = poly; + poly->numverts = lnumverts; + + for (i=0 ; isurfedges[fa->firstedge + i]; + + if (lindex > 0) + { + r_pedge = &pedges[lindex]; + vec = currentmodel->vertexes[r_pedge->v[0]].position; + } + else + { + r_pedge = &pedges[-lindex]; + vec = currentmodel->vertexes[r_pedge->v[1]].position; + } + s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; + s /= fa->texinfo->image->width; + + t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; + t /= fa->texinfo->image->height; + + VectorAdd (total, vec, total); + VectorCopy (vec, poly->verts[i]); + poly->verts[i][3] = s; + poly->verts[i][4] = t; + + // + // lightmap texture coordinates + // + s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; + s -= fa->texturemins[0]; + s += fa->light_s*16; + s += 8; + s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width; + + t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; + t -= fa->texturemins[1]; + t += fa->light_t*16; + t += 8; + t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height; + + poly->verts[i][5] = s; + poly->verts[i][6] = t; + } + + poly->numverts = lnumverts; + +} + +/* +======================== +GL_CreateSurfaceLightmap +======================== +*/ +void GL_CreateSurfaceLightmap (msurface_t *surf) +{ + int smax, tmax; + byte *base; + + if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB)) + return; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + + if ( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) ) + { + LM_UploadBlock( false ); + LM_InitBlock(); + if ( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) ) + { + ri.Sys_Error( ERR_FATAL, "Consecutive calls to LM_AllocBlock(%d,%d) failed\n", smax, tmax ); + } + } + + surf->lightmaptexturenum = gl_lms.current_lightmap_texture; + + base = gl_lms.lightmap_buffer; + base += (surf->light_t * BLOCK_WIDTH + surf->light_s) * LIGHTMAP_BYTES; + + R_SetCacheState( surf ); + R_BuildLightMap (surf, base, BLOCK_WIDTH*LIGHTMAP_BYTES); +} + + +/* +================== +GL_BeginBuildingLightmaps + +================== +*/ +void GL_BeginBuildingLightmaps (model_t *m) +{ + static lightstyle_t lightstyles[MAX_LIGHTSTYLES]; + int i; + unsigned dummy[128*128]; + + memset( gl_lms.allocated, 0, sizeof(gl_lms.allocated) ); + + r_framecount = 1; // no dlightcache + + GL_EnableMultitexture( true ); + GL_SelectTexture( GL_TEXTURE1_SGIS ); + + /* + ** setup the base lightstyles so the lightmaps won't have to be regenerated + ** the first time they're seen + */ + for (i=0 ; istring[0] ) == 'A' ) + { + gl_lms.internal_format = gl_tex_alpha_format; + } + /* + ** try to do hacked colored lighting with a blended texture + */ + else if ( toupper( gl_monolightmap->string[0] ) == 'C' ) + { + gl_lms.internal_format = gl_tex_alpha_format; + } + else if ( toupper( gl_monolightmap->string[0] ) == 'I' ) + { + gl_lms.internal_format = GL_INTENSITY8; + } + else if ( toupper( gl_monolightmap->string[0] ) == 'L' ) + { + gl_lms.internal_format = GL_LUMINANCE8; + } + else + { + gl_lms.internal_format = gl_tex_solid_format; + } + + /* + ** initialize the dynamic lightmap texture + */ + GL_Bind( gl_state.lightmap_textures + 0 ); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + qglTexImage2D( GL_TEXTURE_2D, + 0, + gl_lms.internal_format, + BLOCK_WIDTH, BLOCK_HEIGHT, + 0, + GL_LIGHTMAP_FORMAT, + GL_UNSIGNED_BYTE, + dummy ); +} + +/* +======================= +GL_EndBuildingLightmaps +======================= +*/ +void GL_EndBuildingLightmaps (void) +{ + LM_UploadBlock( false ); + GL_EnableMultitexture( false ); +} + diff --git a/ref_gl/gl_warp.c b/ref_gl/gl_warp.c new file mode 100644 index 000000000..3a35d7722 --- /dev/null +++ b/ref_gl/gl_warp.c @@ -0,0 +1,662 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +// gl_warp.c -- sky and water polygons + +#include "gl_local.h" + +extern model_t *loadmodel; + +char skyname[MAX_QPATH]; +float skyrotate; +vec3_t skyaxis; +image_t *sky_images[6]; + +msurface_t *warpface; + +#define SUBDIVIDE_SIZE 64 +//#define SUBDIVIDE_SIZE 1024 + +void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs) +{ + int i, j; + float *v; + + mins[0] = mins[1] = mins[2] = 9999; + maxs[0] = maxs[1] = maxs[2] = -9999; + v = verts; + for (i=0 ; i maxs[j]) + maxs[j] = *v; + } +} + +void SubdividePolygon (int numverts, float *verts) +{ + int i, j, k; + vec3_t mins, maxs; + float m; + float *v; + vec3_t front[64], back[64]; + int f, b; + float dist[64]; + float frac; + glpoly_t *poly; + float s, t; + vec3_t total; + float total_s, total_t; + + if (numverts > 60) + ri.Sys_Error (ERR_DROP, "numverts = %i", numverts); + + BoundPoly (numverts, verts, mins, maxs); + + for (i=0 ; i<3 ; i++) + { + m = (mins[i] + maxs[i]) * 0.5; + m = SUBDIVIDE_SIZE * floor (m/SUBDIVIDE_SIZE + 0.5); + if (maxs[i] - m < 8) + continue; + if (m - mins[i] < 8) + continue; + + // cut it + v = verts + i; + for (j=0 ; j= 0) + { + VectorCopy (v, front[f]); + f++; + } + if (dist[j] <= 0) + { + VectorCopy (v, back[b]); + b++; + } + if (dist[j] == 0 || dist[j+1] == 0) + continue; + if ( (dist[j] > 0) != (dist[j+1] > 0) ) + { + // clip point + frac = dist[j] / (dist[j] - dist[j+1]); + for (k=0 ; k<3 ; k++) + front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]); + f++; + b++; + } + } + + SubdividePolygon (f, front[0]); + SubdividePolygon (b, back[0]); + return; + } + + // add a point in the center to help keep warp valid + poly = Hunk_Alloc (sizeof(glpoly_t) + ((numverts-4)+2) * VERTEXSIZE*sizeof(float)); + poly->next = warpface->polys; + warpface->polys = poly; + poly->numverts = numverts+2; + VectorClear (total); + total_s = 0; + total_t = 0; + for (i=0 ; iverts[i+1]); + s = DotProduct (verts, warpface->texinfo->vecs[0]); + t = DotProduct (verts, warpface->texinfo->vecs[1]); + + total_s += s; + total_t += t; + VectorAdd (total, verts, total); + + poly->verts[i+1][3] = s; + poly->verts[i+1][4] = t; + } + + VectorScale (total, (1.0/numverts), poly->verts[0]); + poly->verts[0][3] = total_s/numverts; + poly->verts[0][4] = total_t/numverts; + + // copy first vertex to last + memcpy (poly->verts[i+1], poly->verts[1], sizeof(poly->verts[0])); +} + +/* +================ +GL_SubdivideSurface + +Breaks a polygon up along axial 64 unit +boundaries so that turbulent and sky warps +can be done reasonably. +================ +*/ +void GL_SubdivideSurface (msurface_t *fa) +{ + vec3_t verts[64]; + int numverts; + int i; + int lindex; + float *vec; + + warpface = fa; + + // + // convert edges back to a normal polygon + // + numverts = 0; + for (i=0 ; inumedges ; i++) + { + lindex = loadmodel->surfedges[fa->firstedge + i]; + + if (lindex > 0) + vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position; + else + vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position; + VectorCopy (vec, verts[numverts]); + numverts++; + } + + SubdividePolygon (numverts, verts[0]); +} + +//========================================================= + + + +// speed up sin calculations - Ed +float r_turbsin[] = +{ + #include "warpsin.h" +}; +#define TURBSCALE (256.0 / (2 * M_PI)) + +/* +============= +EmitWaterPolys + +Does a water warp on the pre-fragmented glpoly_t chain +============= +*/ +void EmitWaterPolys (msurface_t *fa) +{ + glpoly_t *p, *bp; + float *v; + int i; + float s, t, os, ot; + float scroll; + float rdt = r_newrefdef.time; + + if (fa->texinfo->flags & SURF_FLOWING) + scroll = -64 * ( (r_newrefdef.time*0.5) - (int)(r_newrefdef.time*0.5) ); + else + scroll = 0; + for (bp=fa->polys ; bp ; bp=bp->next) + { + p = bp; + + qglBegin (GL_TRIANGLE_FAN); + for (i=0,v=p->verts[0] ; inumverts ; i++, v+=VERTEXSIZE) + { + os = v[3]; + ot = v[4]; + +#if !id386 + s = os + r_turbsin[(int)((ot*0.125+r_newrefdef.time) * TURBSCALE) & 255]; +#else + s = os + r_turbsin[Q_ftol( ((ot*0.125+rdt) * TURBSCALE) ) & 255]; +#endif + s += scroll; + s *= (1.0/64); + +#if !id386 + t = ot + r_turbsin[(int)((os*0.125+rdt) * TURBSCALE) & 255]; +#else + t = ot + r_turbsin[Q_ftol( ((os*0.125+rdt) * TURBSCALE) ) & 255]; +#endif + t *= (1.0/64); + + qglTexCoord2f (s, t); + qglVertex3fv (v); + } + qglEnd (); + } +} + + +//=================================================================== + + +vec3_t skyclip[6] = { + {1,1,0}, + {1,-1,0}, + {0,-1,1}, + {0,1,1}, + {1,0,1}, + {-1,0,1} +}; +int c_sky; + +// 1 = s, 2 = t, 3 = 2048 +int st_to_vec[6][3] = +{ + {3,-1,2}, + {-3,1,2}, + + {1,3,2}, + {-1,-3,2}, + + {-2,-1,3}, // 0 degrees yaw, look straight up + {2,-1,-3} // look straight down + +// {-1,2,3}, +// {1,2,-3} +}; + +// s = [0]/[2], t = [1]/[2] +int vec_to_st[6][3] = +{ + {-2,3,1}, + {2,3,-1}, + + {1,3,2}, + {-1,3,-2}, + + {-2,-1,3}, + {-2,1,-3} + +// {-1,2,3}, +// {1,2,-3} +}; + +float skymins[2][6], skymaxs[2][6]; +float sky_min, sky_max; + +void DrawSkyPolygon (int nump, vec3_t vecs) +{ + int i,j; + vec3_t v, av; + float s, t, dv; + int axis; + float *vp; + + c_sky++; +#if 0 +glBegin (GL_POLYGON); +for (i=0 ; i av[1] && av[0] > av[2]) + { + if (v[0] < 0) + axis = 1; + else + axis = 0; + } + else if (av[1] > av[2] && av[1] > av[0]) + { + if (v[1] < 0) + axis = 3; + else + axis = 2; + } + else + { + if (v[2] < 0) + axis = 5; + else + axis = 4; + } + + // project new texture coords + for (i=0 ; i 0) + dv = vecs[j - 1]; + else + dv = -vecs[-j - 1]; + if (dv < 0.001) + continue; // don't divide by zero + j = vec_to_st[axis][0]; + if (j < 0) + s = -vecs[-j -1] / dv; + else + s = vecs[j-1] / dv; + j = vec_to_st[axis][1]; + if (j < 0) + t = -vecs[-j -1] / dv; + else + t = vecs[j-1] / dv; + + if (s < skymins[0][axis]) + skymins[0][axis] = s; + if (t < skymins[1][axis]) + skymins[1][axis] = t; + if (s > skymaxs[0][axis]) + skymaxs[0][axis] = s; + if (t > skymaxs[1][axis]) + skymaxs[1][axis] = t; + } +} + +#define ON_EPSILON 0.1 // point on plane side epsilon +#define MAX_CLIP_VERTS 64 +void ClipSkyPolygon (int nump, vec3_t vecs, int stage) +{ + float *norm; + float *v; + qboolean front, back; + float d, e; + float dists[MAX_CLIP_VERTS]; + int sides[MAX_CLIP_VERTS]; + vec3_t newv[2][MAX_CLIP_VERTS]; + int newc[2]; + int i, j; + + if (nump > MAX_CLIP_VERTS-2) + ri.Sys_Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); + if (stage == 6) + { // fully clipped, so draw it + DrawSkyPolygon (nump, vecs); + return; + } + + front = back = false; + norm = skyclip[stage]; + for (i=0, v = vecs ; i ON_EPSILON) + { + front = true; + sides[i] = SIDE_FRONT; + } + else if (d < -ON_EPSILON) + { + back = true; + sides[i] = SIDE_BACK; + } + else + sides[i] = SIDE_ON; + dists[i] = d; + } + + if (!front || !back) + { // not clipped + ClipSkyPolygon (nump, vecs, stage+1); + return; + } + + // clip it + sides[i] = sides[0]; + dists[i] = dists[0]; + VectorCopy (vecs, (vecs+(i*3)) ); + newc[0] = newc[1] = 0; + + for (i=0, v = vecs ; ipolys ; p ; p=p->next) + { + for (i=0 ; inumverts ; i++) + { + VectorSubtract (p->verts[i], r_origin, verts[i]); + } + ClipSkyPolygon (p->numverts, verts[0], 0); + } +} + + +/* +============== +R_ClearSkyBox +============== +*/ +void R_ClearSkyBox (void) +{ + int i; + + for (i=0 ; i<6 ; i++) + { + skymins[0][i] = skymins[1][i] = 9999; + skymaxs[0][i] = skymaxs[1][i] = -9999; + } +} + + +void MakeSkyVec (float s, float t, int axis) +{ + vec3_t v, b; + int j, k; + + b[0] = s*2300; + b[1] = t*2300; + b[2] = 2300; + + for (j=0 ; j<3 ; j++) + { + k = st_to_vec[axis][j]; + if (k < 0) + v[j] = -b[-k - 1]; + else + v[j] = b[k - 1]; + } + + // avoid bilerp seam + s = (s+1)*0.5; + t = (t+1)*0.5; + + if (s < sky_min) + s = sky_min; + else if (s > sky_max) + s = sky_max; + if (t < sky_min) + t = sky_min; + else if (t > sky_max) + t = sky_max; + + t = 1.0 - t; + qglTexCoord2f (s, t); + qglVertex3fv (v); +} + +/* +============== +R_DrawSkyBox +============== +*/ +int skytexorder[6] = {0,2,1,3,4,5}; +void R_DrawSkyBox (void) +{ + int i; + +#if 0 +qglEnable (GL_BLEND); +GL_TexEnv( GL_MODULATE ); +qglColor4f (1,1,1,0.5); +qglDisable (GL_DEPTH_TEST); +#endif + if (skyrotate) + { // check for no sky at all + for (i=0 ; i<6 ; i++) + if (skymins[0][i] < skymaxs[0][i] + && skymins[1][i] < skymaxs[1][i]) + break; + if (i == 6) + return; // nothing visible + } + +qglPushMatrix (); +qglTranslatef (r_origin[0], r_origin[1], r_origin[2]); +qglRotatef (r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]); + + for (i=0 ; i<6 ; i++) + { + if (skyrotate) + { // hack, forces full sky to draw when rotating + skymins[0][i] = -1; + skymins[1][i] = -1; + skymaxs[0][i] = 1; + skymaxs[1][i] = 1; + } + + if (skymins[0][i] >= skymaxs[0][i] + || skymins[1][i] >= skymaxs[1][i]) + continue; + + GL_Bind (sky_images[skytexorder[i]]->texnum); + + qglBegin (GL_QUADS); + MakeSkyVec (skymins[0][i], skymins[1][i], i); + MakeSkyVec (skymins[0][i], skymaxs[1][i], i); + MakeSkyVec (skymaxs[0][i], skymaxs[1][i], i); + MakeSkyVec (skymaxs[0][i], skymins[1][i], i); + qglEnd (); + } +qglPopMatrix (); +#if 0 +glDisable (GL_BLEND); +glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +glColor4f (1,1,1,0.5); +glEnable (GL_DEPTH_TEST); +#endif +} + + +/* +============ +R_SetSky +============ +*/ +// 3dstudio environment map names +char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; +void R_SetSky (char *name, float rotate, vec3_t axis) +{ + int i; + char pathname[MAX_QPATH]; + + strncpy (skyname, name, sizeof(skyname)-1); + skyrotate = rotate; + VectorCopy (axis, skyaxis); + + for (i=0 ; i<6 ; i++) + { + // chop down rotating skies for less memory + if (gl_skymip->value || skyrotate) + gl_picmip->value++; + + if ( qglColorTableEXT && gl_ext_palettedtexture->value ) + Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[i]); + else + Com_sprintf (pathname, sizeof(pathname), "env/%s%s.tga", skyname, suf[i]); + + sky_images[i] = GL_FindImage (pathname, it_sky); + if (!sky_images[i]) + sky_images[i] = r_notexture; + + if (gl_skymip->value || skyrotate) + { // take less memory + gl_picmip->value--; + sky_min = 1.0/256; + sky_max = 255.0/256; + } + else + { + sky_min = 1.0/512; + sky_max = 511.0/512; + } + } +} diff --git a/ref_gl/qgl.h b/ref_gl/qgl.h new file mode 100644 index 000000000..bf2f04ba0 --- /dev/null +++ b/ref_gl/qgl.h @@ -0,0 +1,442 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +/* +** QGL.H +*/ + +#ifndef __QGL_H__ +#define __QGL_H__ + +#ifdef _WIN32 +# include +#endif + +#include + +qboolean QGL_Init( const char *dllname ); +void QGL_Shutdown( void ); + +#ifndef APIENTRY +# define APIENTRY +#endif + +extern void ( APIENTRY * qglAccum )(GLenum op, GLfloat value); +extern void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref); +extern GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); +extern void ( APIENTRY * qglArrayElement )(GLint i); +extern void ( APIENTRY * qglBegin )(GLenum mode); +extern void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture); +extern void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +extern void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor); +extern void ( APIENTRY * qglCallList )(GLuint list); +extern void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists); +extern void ( APIENTRY * qglClear )(GLbitfield mask); +extern void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +extern void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +extern void ( APIENTRY * qglClearDepth )(GLclampd depth); +extern void ( APIENTRY * qglClearIndex )(GLfloat c); +extern void ( APIENTRY * qglClearStencil )(GLint s); +extern void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation); +extern void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue); +extern void ( APIENTRY * qglColor3bv )(const GLbyte *v); +extern void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue); +extern void ( APIENTRY * qglColor3dv )(const GLdouble *v); +extern void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue); +extern void ( APIENTRY * qglColor3fv )(const GLfloat *v); +extern void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue); +extern void ( APIENTRY * qglColor3iv )(const GLint *v); +extern void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue); +extern void ( APIENTRY * qglColor3sv )(const GLshort *v); +extern void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue); +extern void ( APIENTRY * qglColor3ubv )(const GLubyte *v); +extern void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue); +extern void ( APIENTRY * qglColor3uiv )(const GLuint *v); +extern void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue); +extern void ( APIENTRY * qglColor3usv )(const GLushort *v); +extern void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +extern void ( APIENTRY * qglColor4bv )(const GLbyte *v); +extern void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +extern void ( APIENTRY * qglColor4dv )(const GLdouble *v); +extern void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +extern void ( APIENTRY * qglColor4fv )(const GLfloat *v); +extern void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha); +extern void ( APIENTRY * qglColor4iv )(const GLint *v); +extern void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha); +extern void ( APIENTRY * qglColor4sv )(const GLshort *v); +extern void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +extern void ( APIENTRY * qglColor4ubv )(const GLubyte *v); +extern void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha); +extern void ( APIENTRY * qglColor4uiv )(const GLuint *v); +extern void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha); +extern void ( APIENTRY * qglColor4usv )(const GLushort *v); +extern void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +extern void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode); +extern void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +extern void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); +extern void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +extern void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +extern void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +extern void ( APIENTRY * qglCullFace )(GLenum mode); +extern void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range); +extern void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures); +extern void ( APIENTRY * qglDepthFunc )(GLenum func); +extern void ( APIENTRY * qglDepthMask )(GLboolean flag); +extern void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar); +extern void ( APIENTRY * qglDisable )(GLenum cap); +extern void ( APIENTRY * qglDisableClientState )(GLenum array); +extern void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count); +extern void ( APIENTRY * qglDrawBuffer )(GLenum mode); +extern void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +extern void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglEdgeFlag )(GLboolean flag); +extern void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag); +extern void ( APIENTRY * qglEnable )(GLenum cap); +extern void ( APIENTRY * qglEnableClientState )(GLenum array); +extern void ( APIENTRY * qglEnd )(void); +extern void ( APIENTRY * qglEndList )(void); +extern void ( APIENTRY * qglEvalCoord1d )(GLdouble u); +extern void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u); +extern void ( APIENTRY * qglEvalCoord1f )(GLfloat u); +extern void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u); +extern void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v); +extern void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u); +extern void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v); +extern void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u); +extern void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2); +extern void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +extern void ( APIENTRY * qglEvalPoint1 )(GLint i); +extern void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j); +extern void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer); +extern void ( APIENTRY * qglFinish )(void); +extern void ( APIENTRY * qglFlush )(void); +extern void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param); +extern void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglFogi )(GLenum pname, GLint param); +extern void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params); +extern void ( APIENTRY * qglFrontFace )(GLenum mode); +extern void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +extern GLuint ( APIENTRY * qglGenLists )(GLsizei range); +extern void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures); +extern void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params); +extern void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation); +extern void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params); +extern GLenum ( APIENTRY * qglGetError )(void); +extern void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v); +extern void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v); +extern void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v); +extern void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values); +extern void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values); +extern void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values); +extern void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params); +extern void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask); +extern const GLubyte * ( APIENTRY * qglGetString )(GLenum name); +extern void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params); +extern void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +extern void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params); +extern void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params); +extern void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params); +extern void ( APIENTRY * qglHint )(GLenum target, GLenum mode); +extern void ( APIENTRY * qglIndexMask )(GLuint mask); +extern void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglIndexd )(GLdouble c); +extern void ( APIENTRY * qglIndexdv )(const GLdouble *c); +extern void ( APIENTRY * qglIndexf )(GLfloat c); +extern void ( APIENTRY * qglIndexfv )(const GLfloat *c); +extern void ( APIENTRY * qglIndexi )(GLint c); +extern void ( APIENTRY * qglIndexiv )(const GLint *c); +extern void ( APIENTRY * qglIndexs )(GLshort c); +extern void ( APIENTRY * qglIndexsv )(const GLshort *c); +extern void ( APIENTRY * qglIndexub )(GLubyte c); +extern void ( APIENTRY * qglIndexubv )(const GLubyte *c); +extern void ( APIENTRY * qglInitNames )(void); +extern void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); +extern GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap); +extern GLboolean ( APIENTRY * qglIsList )(GLuint list); +extern GLboolean ( APIENTRY * qglIsTexture )(GLuint texture); +extern void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param); +extern void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param); +extern void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params); +extern void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param); +extern void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern); +extern void ( APIENTRY * qglLineWidth )(GLfloat width); +extern void ( APIENTRY * qglListBase )(GLuint base); +extern void ( APIENTRY * qglLoadIdentity )(void); +extern void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m); +extern void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m); +extern void ( APIENTRY * qglLoadName )(GLuint name); +extern void ( APIENTRY * qglLogicOp )(GLenum opcode); +extern void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +extern void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +extern void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +extern void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +extern void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2); +extern void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2); +extern void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +extern void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +extern void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param); +extern void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglMatrixMode )(GLenum mode); +extern void ( APIENTRY * qglMultMatrixd )(const GLdouble *m); +extern void ( APIENTRY * qglMultMatrixf )(const GLfloat *m); +extern void ( APIENTRY * qglNewList )(GLuint list, GLenum mode); +extern void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz); +extern void ( APIENTRY * qglNormal3bv )(const GLbyte *v); +extern void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz); +extern void ( APIENTRY * qglNormal3dv )(const GLdouble *v); +extern void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz); +extern void ( APIENTRY * qglNormal3fv )(const GLfloat *v); +extern void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz); +extern void ( APIENTRY * qglNormal3iv )(const GLint *v); +extern void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz); +extern void ( APIENTRY * qglNormal3sv )(const GLshort *v); +extern void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +extern void ( APIENTRY * qglPassThrough )(GLfloat token); +extern void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values); +extern void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values); +extern void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values); +extern void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param); +extern void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param); +extern void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param); +extern void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param); +extern void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor); +extern void ( APIENTRY * qglPointSize )(GLfloat size); +extern void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode); +extern void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units); +extern void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask); +extern void ( APIENTRY * qglPopAttrib )(void); +extern void ( APIENTRY * qglPopClientAttrib )(void); +extern void ( APIENTRY * qglPopMatrix )(void); +extern void ( APIENTRY * qglPopName )(void); +extern void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); +extern void ( APIENTRY * qglPushAttrib )(GLbitfield mask); +extern void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask); +extern void ( APIENTRY * qglPushMatrix )(void); +extern void ( APIENTRY * qglPushName )(GLuint name); +extern void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y); +extern void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v); +extern void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y); +extern void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v); +extern void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y); +extern void ( APIENTRY * qglRasterPos2iv )(const GLint *v); +extern void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y); +extern void ( APIENTRY * qglRasterPos2sv )(const GLshort *v); +extern void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v); +extern void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v); +extern void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z); +extern void ( APIENTRY * qglRasterPos3iv )(const GLint *v); +extern void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z); +extern void ( APIENTRY * qglRasterPos3sv )(const GLshort *v); +extern void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +extern void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v); +extern void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +extern void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v); +extern void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w); +extern void ( APIENTRY * qglRasterPos4iv )(const GLint *v); +extern void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w); +extern void ( APIENTRY * qglRasterPos4sv )(const GLshort *v); +extern void ( APIENTRY * qglReadBuffer )(GLenum mode); +extern void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +extern void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +extern void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2); +extern void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +extern void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2); +extern void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2); +extern void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2); +extern void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +extern void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2); +extern GLint ( APIENTRY * qglRenderMode )(GLenum mode); +extern void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height); +extern void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer); +extern void ( APIENTRY * qglShadeModel )(GLenum mode); +extern void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask); +extern void ( APIENTRY * qglStencilMask )(GLuint mask); +extern void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass); +extern void ( APIENTRY * qglTexCoord1d )(GLdouble s); +extern void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v); +extern void ( APIENTRY * qglTexCoord1f )(GLfloat s); +extern void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v); +extern void ( APIENTRY * qglTexCoord1i )(GLint s); +extern void ( APIENTRY * qglTexCoord1iv )(const GLint *v); +extern void ( APIENTRY * qglTexCoord1s )(GLshort s); +extern void ( APIENTRY * qglTexCoord1sv )(const GLshort *v); +extern void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t); +extern void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v); +extern void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t); +extern void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v); +extern void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t); +extern void ( APIENTRY * qglTexCoord2iv )(const GLint *v); +extern void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t); +extern void ( APIENTRY * qglTexCoord2sv )(const GLshort *v); +extern void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r); +extern void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v); +extern void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r); +extern void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v); +extern void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r); +extern void ( APIENTRY * qglTexCoord3iv )(const GLint *v); +extern void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r); +extern void ( APIENTRY * qglTexCoord3sv )(const GLshort *v); +extern void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +extern void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v); +extern void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +extern void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v); +extern void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q); +extern void ( APIENTRY * qglTexCoord4iv )(const GLint *v); +extern void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q); +extern void ( APIENTRY * qglTexCoord4sv )(const GLshort *v); +extern void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param); +extern void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param); +extern void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params); +extern void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param); +extern void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param); +extern void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params); +extern void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param); +extern void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params); +extern void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +extern void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y); +extern void ( APIENTRY * qglVertex2dv )(const GLdouble *v); +extern void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y); +extern void ( APIENTRY * qglVertex2fv )(const GLfloat *v); +extern void ( APIENTRY * qglVertex2i )(GLint x, GLint y); +extern void ( APIENTRY * qglVertex2iv )(const GLint *v); +extern void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y); +extern void ( APIENTRY * qglVertex2sv )(const GLshort *v); +extern void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z); +extern void ( APIENTRY * qglVertex3dv )(const GLdouble *v); +extern void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z); +extern void ( APIENTRY * qglVertex3fv )(const GLfloat *v); +extern void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z); +extern void ( APIENTRY * qglVertex3iv )(const GLint *v); +extern void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z); +extern void ( APIENTRY * qglVertex3sv )(const GLshort *v); +extern void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +extern void ( APIENTRY * qglVertex4dv )(const GLdouble *v); +extern void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +extern void ( APIENTRY * qglVertex4fv )(const GLfloat *v); +extern void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w); +extern void ( APIENTRY * qglVertex4iv )(const GLint *v); +extern void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w); +extern void ( APIENTRY * qglVertex4sv )(const GLshort *v); +extern void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +extern void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height); + +extern void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value ); +extern void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value ); +extern void ( APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * ); + +extern void ( APIENTRY * qglLockArraysEXT) (int , int); +extern void ( APIENTRY * qglUnlockArraysEXT) (void); + +extern void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat ); +extern void ( APIENTRY * qglSelectTextureSGIS)( GLenum ); + +#ifdef _WIN32 + +extern int ( WINAPI * qwglChoosePixelFormat )(HDC, CONST PIXELFORMATDESCRIPTOR *); +extern int ( WINAPI * qwglDescribePixelFormat) (HDC, int, UINT, LPPIXELFORMATDESCRIPTOR); +extern int ( WINAPI * qwglGetPixelFormat)(HDC); +extern BOOL ( WINAPI * qwglSetPixelFormat)(HDC, int, CONST PIXELFORMATDESCRIPTOR *); +extern BOOL ( WINAPI * qwglSwapBuffers)(HDC); + +extern BOOL ( WINAPI * qwglCopyContext)(HGLRC, HGLRC, UINT); +extern HGLRC ( WINAPI * qwglCreateContext)(HDC); +extern HGLRC ( WINAPI * qwglCreateLayerContext)(HDC, int); +extern BOOL ( WINAPI * qwglDeleteContext)(HGLRC); +extern HGLRC ( WINAPI * qwglGetCurrentContext)(VOID); +extern HDC ( WINAPI * qwglGetCurrentDC)(VOID); +extern PROC ( WINAPI * qwglGetProcAddress)(LPCSTR); +extern BOOL ( WINAPI * qwglMakeCurrent)(HDC, HGLRC); +extern BOOL ( WINAPI * qwglShareLists)(HGLRC, HGLRC); +extern BOOL ( WINAPI * qwglUseFontBitmaps)(HDC, DWORD, DWORD, DWORD); + +extern BOOL ( WINAPI * qwglUseFontOutlines)(HDC, DWORD, DWORD, DWORD, FLOAT, + FLOAT, int, LPGLYPHMETRICSFLOAT); + +extern BOOL ( WINAPI * qwglDescribeLayerPlane)(HDC, int, int, UINT, + LPLAYERPLANEDESCRIPTOR); +extern int ( WINAPI * qwglSetLayerPaletteEntries)(HDC, int, int, int, + CONST COLORREF *); +extern int ( WINAPI * qwglGetLayerPaletteEntries)(HDC, int, int, int, + COLORREF *); +extern BOOL ( WINAPI * qwglRealizeLayerPalette)(HDC, int, BOOL); +extern BOOL ( WINAPI * qwglSwapLayerBuffers)(HDC, UINT); + +extern BOOL ( WINAPI * qwglSwapIntervalEXT)( int interval ); + +extern BOOL ( WINAPI * qwglGetDeviceGammaRampEXT ) ( unsigned char *pRed, unsigned char *pGreen, unsigned char *pBlue ); +extern BOOL ( WINAPI * qwglSetDeviceGammaRampEXT ) ( const unsigned char *pRed, const unsigned char *pGreen, const unsigned char *pBlue ); + +#endif + +/* +** extension constants +*/ +#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 + +#ifdef __sgi +#define GL_SHARED_TEXTURE_PALETTE_EXT GL_TEXTURE_COLOR_TABLE_SGI +#else +#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB +#endif + +#define GL_TEXTURE0_SGIS 0x835E +#define GL_TEXTURE1_SGIS 0x835F + +#endif diff --git a/ref_gl/ref_gl.001 b/ref_gl/ref_gl.001 new file mode 100644 index 000000000..eef41bf20 --- /dev/null +++ b/ref_gl/ref_gl.001 @@ -0,0 +1,752 @@ +# Microsoft Developer Studio Project File - Name="ref_gl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 +# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602 + +CFG=ref_gl - Win32 Debug Alpha +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ref_gl.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ref_gl.mak" CFG="ref_gl - Win32 Debug Alpha" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ref_gl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "ref_gl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "ref_gl - Win32 Debug Alpha" (based on\ + "Win32 (ALPHA) Dynamic-Link Library") +!MESSAGE "ref_gl - Win32 Release Alpha" (based on\ + "Win32 (ALPHA) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\ref_gl__" +# PROP BASE Intermediate_Dir ".\ref_gl__" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\release" +# PROP Intermediate_Dir ".\release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "." +CPP=cl.exe +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /G5 /MT /W4 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /YX /FD /c +MTL=midl.exe +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /machine:I386 +# SUBTRACT LINK32 /incremental:yes /debug + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\ref_gl__" +# PROP BASE Intermediate_Dir ".\ref_gl__" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\debug" +# PROP Intermediate_Dir ".\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "." +CPP=cl.exe +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /FR /YX /FD /c +MTL=midl.exe +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 +# SUBTRACT LINK32 /profile + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug Alpha" +# PROP BASE Intermediate_Dir "Debug Alpha" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\DebugAxp" +# PROP Intermediate_Dir ".\DebugAxp" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +MTL=midl.exe +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +CPP=cl.exe +# ADD BASE CPP /nologo /MTd /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /QA21164 /MTd /Gt0 /W3 /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 winmm.lib opengl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:ALPHA +# ADD LINK32 opengl32.lib kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /debug /machine:ALPHA + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ref_gl__" +# PROP BASE Intermediate_Dir "ref_gl__" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\ReleaseAXP" +# PROP Intermediate_Dir ".\ReleaseAXP" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +MTL=midl.exe +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +CPP=cl.exe +# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /QA21164 /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c +# SUBTRACT CPP /Z /Fr +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:ALPHA +# SUBTRACT BASE LINK32 /debug +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /machine:ALPHA +# SUBTRACT LINK32 /debug + +!ENDIF + +# Begin Target + +# Name "ref_gl - Win32 Release" +# Name "ref_gl - Win32 Debug" +# Name "ref_gl - Win32 Debug Alpha" +# Name "ref_gl - Win32 Release Alpha" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\gl_draw.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_DR=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_DR=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_DR=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + {$(INCLUDE)}"GL\gl.h"\ + {$(INCLUDE)}"GL\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_image.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_IM=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_IM=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_IM=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + {$(INCLUDE)}"GL\gl.h"\ + {$(INCLUDE)}"GL\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_light.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_LI=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_LI=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_LI=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + {$(INCLUDE)}"GL\gl.h"\ + {$(INCLUDE)}"GL\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_mesh.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_ME=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\anorms.h"\ + ".\anormtab.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_ME=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_ME=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\anorms.h"\ + ".\anormtab.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + {$(INCLUDE)}"GL\gl.h"\ + {$(INCLUDE)}"GL\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_model.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_MO=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_MO=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_MO=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + {$(INCLUDE)}"GL\gl.h"\ + {$(INCLUDE)}"GL\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_rmain.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_RM=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_RM=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_RM=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + {$(INCLUDE)}"GL\gl.h"\ + {$(INCLUDE)}"GL\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_rmisc.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_RMI=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_RMI=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_RMI=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + {$(INCLUDE)}"GL\gl.h"\ + {$(INCLUDE)}"GL\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_rsurf.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_RS=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_RS=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_RS=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + {$(INCLUDE)}"GL\gl.h"\ + {$(INCLUDE)}"GL\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_warp.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_WA=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + ".\warpsin.h"\ + +NODEP_CPP_GL_WA=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_WA=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + ".\warpsin.h"\ + {$(INCLUDE)}"GL\gl.h"\ + {$(INCLUDE)}"GL\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\win32\glw_imp.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GLW_I=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + "..\win32\glw_win.h"\ + "..\win32\winquake.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GLW_I=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GLW_I=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + "..\win32\glw_win.h"\ + "..\win32\winquake.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + {$(INCLUDE)}"GL\gl.h"\ + {$(INCLUDE)}"GL\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\game\q_shared.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_Q_SHA=\ + "..\game\q_shared.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_Q_SHA=\ + "..\game\q_shared.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\win32\q_shwin.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_Q_SHW=\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + "..\win32\winquake.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_Q_SHW=\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + "..\win32\winquake.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\win32\qgl_win.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_QGL_W=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + "..\win32\glw_win.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_QGL_W=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_QGL_W=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + "..\win32\glw_win.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + {$(INCLUDE)}"GL\gl.h"\ + {$(INCLUDE)}"GL\glu.h"\ + + +!ENDIF + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\anorms.h +# End Source File +# Begin Source File + +SOURCE=.\anormtab.h +# End Source File +# Begin Source File + +SOURCE=.\gl_local.h +# End Source File +# Begin Source File + +SOURCE=.\gl_model.h +# End Source File +# Begin Source File + +SOURCE=..\win32\glw_win.h +# End Source File +# Begin Source File + +SOURCE=..\game\q_shared.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\qcommon.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\qfiles.h +# End Source File +# Begin Source File + +SOURCE=.\qgl.h +# End Source File +# Begin Source File + +SOURCE=.\qmenu.h +# End Source File +# Begin Source File + +SOURCE=..\client\ref.h +# End Source File +# Begin Source File + +SOURCE=.\ref_gl.h +# End Source File +# Begin Source File + +SOURCE=.\warpsin.h +# End Source File +# Begin Source File + +SOURCE=..\win32\winquake.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\ref_gl.def +# End Source File +# End Group +# End Target +# End Project diff --git a/ref_gl/ref_gl.def b/ref_gl/ref_gl.def new file mode 100644 index 000000000..cfbb47133 --- /dev/null +++ b/ref_gl/ref_gl.def @@ -0,0 +1,2 @@ +EXPORTS + GetRefAPI diff --git a/ref_gl/ref_gl.dsp b/ref_gl/ref_gl.dsp new file mode 100644 index 000000000..4c12284ab --- /dev/null +++ b/ref_gl/ref_gl.dsp @@ -0,0 +1,773 @@ +# Microsoft Developer Studio Project File - Name="ref_gl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 +# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602 + +CFG=ref_gl - Win32 Debug Alpha +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ref_gl.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ref_gl.mak" CFG="ref_gl - Win32 Debug Alpha" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ref_gl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "ref_gl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "ref_gl - Win32 Debug Alpha" (based on "Win32 (ALPHA) Dynamic-Link Library") +!MESSAGE "ref_gl - Win32 Release Alpha" (based on "Win32 (ALPHA) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\ref_gl__" +# PROP BASE Intermediate_Dir ".\ref_gl__" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\release" +# PROP Intermediate_Dir ".\release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "." +CPP=cl.exe +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /G5 /MT /W4 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /YX /FD /c +MTL=midl.exe +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /machine:I386 +# SUBTRACT LINK32 /incremental:yes /debug + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\ref_gl__" +# PROP BASE Intermediate_Dir ".\ref_gl__" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\debug" +# PROP Intermediate_Dir ".\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "." +CPP=cl.exe +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /FR /YX /FD /c +MTL=midl.exe +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 +# SUBTRACT LINK32 /profile + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug Alpha" +# PROP BASE Intermediate_Dir "Debug Alpha" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\DebugAxp" +# PROP Intermediate_Dir ".\DebugAxp" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MTd /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /QA21164 /MTd /Gt0 /W3 /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c +MTL=midl.exe +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 winmm.lib opengl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:ALPHA +# ADD LINK32 opengl32.lib kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /debug /machine:ALPHA + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ref_gl__" +# PROP BASE Intermediate_Dir "ref_gl__" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\ReleaseAXP" +# PROP Intermediate_Dir ".\ReleaseAXP" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /QA21164 /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c +# SUBTRACT CPP /Z /Fr +MTL=midl.exe +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:ALPHA +# SUBTRACT BASE LINK32 /debug +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /machine:ALPHA +# SUBTRACT LINK32 /debug + +!ENDIF + +# Begin Target + +# Name "ref_gl - Win32 Release" +# Name "ref_gl - Win32 Debug" +# Name "ref_gl - Win32 Debug Alpha" +# Name "ref_gl - Win32 Release Alpha" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\gl_draw.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_DR=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_DR=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_DR=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_DR=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_image.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_IM=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_IM=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_IM=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_IM=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_light.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_LI=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_LI=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_LI=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_LI=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_mesh.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_ME=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\anorms.h"\ + ".\anormtab.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_ME=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_ME=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\anorms.h"\ + ".\anormtab.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_ME=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_model.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_MO=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_MO=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_MO=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_MO=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_rmain.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_RM=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_RM=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_RM=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_RM=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_rmisc.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_RMI=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_RMI=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_RMI=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_RMI=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_rsurf.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_RS=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_RS=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_RS=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GL_RS=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gl_warp.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GL_WA=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + ".\warpsin.h"\ + +NODEP_CPP_GL_WA=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GL_WA=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + ".\warpsin.h"\ + +NODEP_CPP_GL_WA=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\win32\glw_imp.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_GLW_I=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + "..\win32\glw_win.h"\ + "..\win32\winquake.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GLW_I=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_GLW_I=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + "..\win32\glw_win.h"\ + "..\win32\winquake.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_GLW_I=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\game\q_shared.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_Q_SHA=\ + "..\game\q_shared.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_Q_SHA=\ + "..\game\q_shared.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\win32\q_shwin.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_Q_SHW=\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + "..\win32\winquake.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_Q_SHW=\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + "..\win32\winquake.h"\ + + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\win32\qgl_win.c + +!IF "$(CFG)" == "ref_gl - Win32 Release" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug" + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Debug Alpha" + +DEP_CPP_QGL_W=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + "..\win32\glw_win.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_QGL_W=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ELSEIF "$(CFG)" == "ref_gl - Win32 Release Alpha" + +DEP_CPP_QGL_W=\ + "..\client\ref.h"\ + "..\game\q_shared.h"\ + "..\qcommon\qcommon.h"\ + "..\qcommon\qfiles.h"\ + "..\win32\glw_win.h"\ + ".\gl_local.h"\ + ".\gl_model.h"\ + ".\qgl.h"\ + +NODEP_CPP_QGL_W=\ + ".\L\gl.h"\ + ".\L\glu.h"\ + + +!ENDIF + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\anorms.h +# End Source File +# Begin Source File + +SOURCE=.\anormtab.h +# End Source File +# Begin Source File + +SOURCE=.\gl_local.h +# End Source File +# Begin Source File + +SOURCE=.\gl_model.h +# End Source File +# Begin Source File + +SOURCE=..\win32\glw_win.h +# End Source File +# Begin Source File + +SOURCE=..\game\q_shared.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\qcommon.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\qfiles.h +# End Source File +# Begin Source File + +SOURCE=.\qgl.h +# End Source File +# Begin Source File + +SOURCE=.\qmenu.h +# End Source File +# Begin Source File + +SOURCE=..\client\ref.h +# End Source File +# Begin Source File + +SOURCE=.\ref_gl.h +# End Source File +# Begin Source File + +SOURCE=.\warpsin.h +# End Source File +# Begin Source File + +SOURCE=..\win32\winquake.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\ref_gl.def +# End Source File +# End Group +# End Target +# End Project diff --git a/ref_gl/ref_gl.plg b/ref_gl/ref_gl.plg new file mode 100644 index 000000000..7119ee2d2 --- /dev/null +++ b/ref_gl/ref_gl.plg @@ -0,0 +1,17 @@ +--------------------Configuration: ref_gl - Win32 Release Alpha-------------------- +Begining build with project "G:\quake2\code\ref_gl\ref_gl.dsp", at root. +Active configuration is Win32 (ALPHA) Dynamic-Link Library (based on Win32 (ALPHA) Dynamic-Link Library) + +Project's tools are: + "OLE Type Library Maker" with flags "/nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 " + "C/C++ Compiler for Alpha" with flags "/nologo /QA21164 /MT /Gt0 /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /Fp".\ReleaseAXP/ref_gl.pch" /YX /Fo".\ReleaseAXP/" /Fd".\ReleaseAXP/" /FD /QAieee1 /c " + "Win32 Resource Compiler" with flags "/l 0x409 /d "NDEBUG" " + "Browser Database Maker" with flags "/nologo /o"..\ReleaseAXP/ref_gl.bsc" " + "COFF Linker for Alpha" with flags "kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"..\ReleaseAXP/ref_gl.pdb" /debug /machine:ALPHA /def:".\ref_gl.def" /out:"..\ReleaseAXP/ref_gl.dll" /implib:"..\ReleaseAXP/ref_gl.lib" " + "Custom Build" with flags "" + "" with flags "" + + + + +ref_gl.dll - 0 error(s), 0 warning(s) diff --git a/ref_gl/warpsin.h b/ref_gl/warpsin.h new file mode 100644 index 000000000..17289e171 --- /dev/null +++ b/ref_gl/warpsin.h @@ -0,0 +1,51 @@ +/* +Copyright (C) 1997-2001 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. + +*/ + 0, 0.19633, 0.392541, 0.588517, 0.784137, 0.979285, 1.17384, 1.3677, + 1.56072, 1.75281, 1.94384, 2.1337, 2.32228, 2.50945, 2.69512, 2.87916, + 3.06147, 3.24193, 3.42044, 3.59689, 3.77117, 3.94319, 4.11282, 4.27998, + 4.44456, 4.60647, 4.76559, 4.92185, 5.07515, 5.22538, 5.37247, 5.51632, + 5.65685, 5.79398, 5.92761, 6.05767, 6.18408, 6.30677, 6.42566, 6.54068, + 6.65176, 6.75883, 6.86183, 6.9607, 7.05537, 7.14579, 7.23191, 7.31368, + 7.39104, 7.46394, 7.53235, 7.59623, 7.65552, 7.71021, 7.76025, 7.80562, + 7.84628, 7.88222, 7.91341, 7.93984, 7.96148, 7.97832, 7.99036, 7.99759, + 8, 7.99759, 7.99036, 7.97832, 7.96148, 7.93984, 7.91341, 7.88222, + 7.84628, 7.80562, 7.76025, 7.71021, 7.65552, 7.59623, 7.53235, 7.46394, + 7.39104, 7.31368, 7.23191, 7.14579, 7.05537, 6.9607, 6.86183, 6.75883, + 6.65176, 6.54068, 6.42566, 6.30677, 6.18408, 6.05767, 5.92761, 5.79398, + 5.65685, 5.51632, 5.37247, 5.22538, 5.07515, 4.92185, 4.76559, 4.60647, + 4.44456, 4.27998, 4.11282, 3.94319, 3.77117, 3.59689, 3.42044, 3.24193, + 3.06147, 2.87916, 2.69512, 2.50945, 2.32228, 2.1337, 1.94384, 1.75281, + 1.56072, 1.3677, 1.17384, 0.979285, 0.784137, 0.588517, 0.392541, 0.19633, + 9.79717e-16, -0.19633, -0.392541, -0.588517, -0.784137, -0.979285, -1.17384, -1.3677, + -1.56072, -1.75281, -1.94384, -2.1337, -2.32228, -2.50945, -2.69512, -2.87916, + -3.06147, -3.24193, -3.42044, -3.59689, -3.77117, -3.94319, -4.11282, -4.27998, + -4.44456, -4.60647, -4.76559, -4.92185, -5.07515, -5.22538, -5.37247, -5.51632, + -5.65685, -5.79398, -5.92761, -6.05767, -6.18408, -6.30677, -6.42566, -6.54068, + -6.65176, -6.75883, -6.86183, -6.9607, -7.05537, -7.14579, -7.23191, -7.31368, + -7.39104, -7.46394, -7.53235, -7.59623, -7.65552, -7.71021, -7.76025, -7.80562, + -7.84628, -7.88222, -7.91341, -7.93984, -7.96148, -7.97832, -7.99036, -7.99759, + -8, -7.99759, -7.99036, -7.97832, -7.96148, -7.93984, -7.91341, -7.88222, + -7.84628, -7.80562, -7.76025, -7.71021, -7.65552, -7.59623, -7.53235, -7.46394, + -7.39104, -7.31368, -7.23191, -7.14579, -7.05537, -6.9607, -6.86183, -6.75883, + -6.65176, -6.54068, -6.42566, -6.30677, -6.18408, -6.05767, -5.92761, -5.79398, + -5.65685, -5.51632, -5.37247, -5.22538, -5.07515, -4.92185, -4.76559, -4.60647, + -4.44456, -4.27998, -4.11282, -3.94319, -3.77117, -3.59689, -3.42044, -3.24193, + -3.06147, -2.87916, -2.69512, -2.50945, -2.32228, -2.1337, -1.94384, -1.75281, + -1.56072, -1.3677, -1.17384, -0.979285, -0.784137, -0.588517, -0.392541, -0.19633, diff --git a/ref_soft/adivtab.h b/ref_soft/adivtab.h new file mode 100644 index 000000000..aad0c5620 --- /dev/null +++ b/ref_soft/adivtab.h @@ -0,0 +1,1077 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +// table of quotients and remainders for [-15...16] / [-15...16] + +// numerator = -15 +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{1, -6}, +{1, -7}, +{2, -1}, +{2, -3}, +{3, 0}, +{3, -3}, +{5, 0}, +{7, -1}, +{15, 0}, +{0, 0}, +{-15, 0}, +{-8, 1}, +{-5, 0}, +{-4, 1}, +{-3, 0}, +{-3, 3}, +{-3, 6}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-2, 7}, +{-2, 9}, +{-2, 11}, +{-2, 13}, +{-1, 0}, +{-1, 1}, +// numerator = -14 +{0, -14}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{1, -6}, +{2, 0}, +{2, -2}, +{2, -4}, +{3, -2}, +{4, -2}, +{7, 0}, +{14, 0}, +{0, 0}, +{-14, 0}, +{-7, 0}, +{-5, 1}, +{-4, 2}, +{-3, 1}, +{-3, 4}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-2, 6}, +{-2, 8}, +{-2, 10}, +{-2, 12}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +// numerator = -13 +{0, -13}, +{0, -13}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{1, -6}, +{2, -1}, +{2, -3}, +{3, -1}, +{4, -1}, +{6, -1}, +{13, 0}, +{0, 0}, +{-13, 0}, +{-7, 1}, +{-5, 2}, +{-4, 3}, +{-3, 2}, +{-3, 5}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-2, 7}, +{-2, 9}, +{-2, 11}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +// numerator = -12 +{0, -12}, +{0, -12}, +{0, -12}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{2, 0}, +{2, -2}, +{3, 0}, +{4, 0}, +{6, 0}, +{12, 0}, +{0, 0}, +{-12, 0}, +{-6, 0}, +{-4, 0}, +{-3, 0}, +{-3, 3}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-2, 6}, +{-2, 8}, +{-2, 10}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +// numerator = -11 +{0, -11}, +{0, -11}, +{0, -11}, +{0, -11}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{2, -1}, +{2, -3}, +{3, -2}, +{5, -1}, +{11, 0}, +{0, 0}, +{-11, 0}, +{-6, 1}, +{-4, 1}, +{-3, 1}, +{-3, 4}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-2, 7}, +{-2, 9}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +// numerator = -10 +{0, -10}, +{0, -10}, +{0, -10}, +{0, -10}, +{0, -10}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{2, 0}, +{2, -2}, +{3, -1}, +{5, 0}, +{10, 0}, +{0, 0}, +{-10, 0}, +{-5, 0}, +{-4, 2}, +{-3, 2}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-2, 6}, +{-2, 8}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +// numerator = -9 +{0, -9}, +{0, -9}, +{0, -9}, +{0, -9}, +{0, -9}, +{0, -9}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{2, -1}, +{3, 0}, +{4, -1}, +{9, 0}, +{0, 0}, +{-9, 0}, +{-5, 1}, +{-3, 0}, +{-3, 3}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-2, 7}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +// numerator = -8 +{0, -8}, +{0, -8}, +{0, -8}, +{0, -8}, +{0, -8}, +{0, -8}, +{0, -8}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{2, 0}, +{2, -2}, +{4, 0}, +{8, 0}, +{0, 0}, +{-8, 0}, +{-4, 0}, +{-3, 1}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-2, 6}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +// numerator = -7 +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{2, -1}, +{3, -1}, +{7, 0}, +{0, 0}, +{-7, 0}, +{-4, 1}, +{-3, 2}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +// numerator = -6 +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{1, 0}, +{1, -1}, +{1, -2}, +{2, 0}, +{3, 0}, +{6, 0}, +{0, 0}, +{-6, 0}, +{-3, 0}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +// numerator = -5 +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{1, 0}, +{1, -1}, +{1, -2}, +{2, -1}, +{5, 0}, +{0, 0}, +{-5, 0}, +{-3, 1}, +{-2, 1}, +{-2, 3}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +// numerator = -4 +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{1, 0}, +{1, -1}, +{2, 0}, +{4, 0}, +{0, 0}, +{-4, 0}, +{-2, 0}, +{-2, 2}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +{-1, 12}, +// numerator = -3 +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{1, 0}, +{1, -1}, +{3, 0}, +{0, 0}, +{-3, 0}, +{-2, 1}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +{-1, 12}, +{-1, 13}, +// numerator = -2 +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{1, 0}, +{2, 0}, +{0, 0}, +{-2, 0}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +{-1, 12}, +{-1, 13}, +{-1, 14}, +// numerator = -1 +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{1, 0}, +{0, 0}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +{-1, 12}, +{-1, 13}, +{-1, 14}, +{-1, 15}, +// numerator = 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}, +// numerator = 1 +{-1, -14}, +{-1, -13}, +{-1, -12}, +{-1, -11}, +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{0, 0}, +{1, 0}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +// numerator = 2 +{-1, -13}, +{-1, -12}, +{-1, -11}, +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, 0}, +{0, 0}, +{2, 0}, +{1, 0}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +// numerator = 3 +{-1, -12}, +{-1, -11}, +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -1}, +{-3, 0}, +{0, 0}, +{3, 0}, +{1, 1}, +{1, 0}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +// numerator = 4 +{-1, -11}, +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -2}, +{-2, 0}, +{-4, 0}, +{0, 0}, +{4, 0}, +{2, 0}, +{1, 1}, +{1, 0}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +// numerator = 5 +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -3}, +{-2, -1}, +{-3, -1}, +{-5, 0}, +{0, 0}, +{5, 0}, +{2, 1}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +// numerator = 6 +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, 0}, +{-6, 0}, +{0, 0}, +{6, 0}, +{3, 0}, +{2, 0}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +// numerator = 7 +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -2}, +{-4, -1}, +{-7, 0}, +{0, 0}, +{7, 0}, +{3, 1}, +{2, 1}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +// numerator = 8 +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -1}, +{-4, 0}, +{-8, 0}, +{0, 0}, +{8, 0}, +{4, 0}, +{2, 2}, +{2, 0}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +// numerator = 9 +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -7}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -3}, +{-3, 0}, +{-5, -1}, +{-9, 0}, +{0, 0}, +{9, 0}, +{4, 1}, +{3, 0}, +{2, 1}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 9}, +{0, 9}, +{0, 9}, +{0, 9}, +{0, 9}, +{0, 9}, +{0, 9}, +// numerator = 10 +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -8}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -2}, +{-4, -2}, +{-5, 0}, +{-10, 0}, +{0, 0}, +{10, 0}, +{5, 0}, +{3, 1}, +{2, 2}, +{2, 0}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 10}, +{0, 10}, +{0, 10}, +{0, 10}, +{0, 10}, +{0, 10}, +// numerator = 11 +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -9}, +{-2, -7}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -4}, +{-3, -1}, +{-4, -1}, +{-6, -1}, +{-11, 0}, +{0, 0}, +{11, 0}, +{5, 1}, +{3, 2}, +{2, 3}, +{2, 1}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 11}, +{0, 11}, +{0, 11}, +{0, 11}, +{0, 11}, +// numerator = 12 +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -10}, +{-2, -8}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -3}, +{-3, 0}, +{-4, 0}, +{-6, 0}, +{-12, 0}, +{0, 0}, +{12, 0}, +{6, 0}, +{4, 0}, +{3, 0}, +{2, 2}, +{2, 0}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 12}, +{0, 12}, +{0, 12}, +{0, 12}, +// numerator = 13 +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -11}, +{-2, -9}, +{-2, -7}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -5}, +{-3, -2}, +{-4, -3}, +{-5, -2}, +{-7, -1}, +{-13, 0}, +{0, 0}, +{13, 0}, +{6, 1}, +{4, 1}, +{3, 1}, +{2, 3}, +{2, 1}, +{1, 6}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 13}, +{0, 13}, +{0, 13}, +// numerator = 14 +{-1, -1}, +{-1, 0}, +{-2, -12}, +{-2, -10}, +{-2, -8}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -4}, +{-3, -1}, +{-4, -2}, +{-5, -1}, +{-7, 0}, +{-14, 0}, +{0, 0}, +{14, 0}, +{7, 0}, +{4, 2}, +{3, 2}, +{2, 4}, +{2, 2}, +{2, 0}, +{1, 6}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 14}, +{0, 14}, +// numerator = 15 +{-1, 0}, +{-2, -13}, +{-2, -11}, +{-2, -9}, +{-2, -7}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -6}, +{-3, -3}, +{-3, 0}, +{-4, -1}, +{-5, 0}, +{-8, -1}, +{-15, 0}, +{0, 0}, +{15, 0}, +{7, 1}, +{5, 0}, +{3, 3}, +{3, 0}, +{2, 3}, +{2, 1}, +{1, 7}, +{1, 6}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 15}, +// numerator = 16 +{-2, -14}, +{-2, -12}, +{-2, -10}, +{-2, -8}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -5}, +{-3, -2}, +{-4, -4}, +{-4, 0}, +{-6, -2}, +{-8, 0}, +{-16, 0}, +{0, 0}, +{16, 0}, +{8, 0}, +{5, 1}, +{4, 0}, +{3, 1}, +{2, 4}, +{2, 2}, +{2, 0}, +{1, 7}, +{1, 6}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, diff --git a/ref_soft/anorms.h b/ref_soft/anorms.h new file mode 100644 index 000000000..011582eb4 --- /dev/null +++ b/ref_soft/anorms.h @@ -0,0 +1,181 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +{-0.525731, 0.000000, 0.850651}, +{-0.442863, 0.238856, 0.864188}, +{-0.295242, 0.000000, 0.955423}, +{-0.309017, 0.500000, 0.809017}, +{-0.162460, 0.262866, 0.951056}, +{0.000000, 0.000000, 1.000000}, +{0.000000, 0.850651, 0.525731}, +{-0.147621, 0.716567, 0.681718}, +{0.147621, 0.716567, 0.681718}, +{0.000000, 0.525731, 0.850651}, +{0.309017, 0.500000, 0.809017}, +{0.525731, 0.000000, 0.850651}, +{0.295242, 0.000000, 0.955423}, +{0.442863, 0.238856, 0.864188}, +{0.162460, 0.262866, 0.951056}, +{-0.681718, 0.147621, 0.716567}, +{-0.809017, 0.309017, 0.500000}, +{-0.587785, 0.425325, 0.688191}, +{-0.850651, 0.525731, 0.000000}, +{-0.864188, 0.442863, 0.238856}, +{-0.716567, 0.681718, 0.147621}, +{-0.688191, 0.587785, 0.425325}, +{-0.500000, 0.809017, 0.309017}, +{-0.238856, 0.864188, 0.442863}, +{-0.425325, 0.688191, 0.587785}, +{-0.716567, 0.681718, -0.147621}, +{-0.500000, 0.809017, -0.309017}, +{-0.525731, 0.850651, 0.000000}, +{0.000000, 0.850651, -0.525731}, +{-0.238856, 0.864188, -0.442863}, +{0.000000, 0.955423, -0.295242}, +{-0.262866, 0.951056, -0.162460}, +{0.000000, 1.000000, 0.000000}, +{0.000000, 0.955423, 0.295242}, +{-0.262866, 0.951056, 0.162460}, +{0.238856, 0.864188, 0.442863}, +{0.262866, 0.951056, 0.162460}, +{0.500000, 0.809017, 0.309017}, +{0.238856, 0.864188, -0.442863}, +{0.262866, 0.951056, -0.162460}, +{0.500000, 0.809017, -0.309017}, +{0.850651, 0.525731, 0.000000}, +{0.716567, 0.681718, 0.147621}, +{0.716567, 0.681718, -0.147621}, +{0.525731, 0.850651, 0.000000}, +{0.425325, 0.688191, 0.587785}, +{0.864188, 0.442863, 0.238856}, +{0.688191, 0.587785, 0.425325}, +{0.809017, 0.309017, 0.500000}, +{0.681718, 0.147621, 0.716567}, +{0.587785, 0.425325, 0.688191}, +{0.955423, 0.295242, 0.000000}, +{1.000000, 0.000000, 0.000000}, +{0.951056, 0.162460, 0.262866}, +{0.850651, -0.525731, 0.000000}, +{0.955423, -0.295242, 0.000000}, +{0.864188, -0.442863, 0.238856}, +{0.951056, -0.162460, 0.262866}, +{0.809017, -0.309017, 0.500000}, +{0.681718, -0.147621, 0.716567}, +{0.850651, 0.000000, 0.525731}, +{0.864188, 0.442863, -0.238856}, +{0.809017, 0.309017, -0.500000}, +{0.951056, 0.162460, -0.262866}, +{0.525731, 0.000000, -0.850651}, +{0.681718, 0.147621, -0.716567}, +{0.681718, -0.147621, -0.716567}, +{0.850651, 0.000000, -0.525731}, +{0.809017, -0.309017, -0.500000}, +{0.864188, -0.442863, -0.238856}, +{0.951056, -0.162460, -0.262866}, +{0.147621, 0.716567, -0.681718}, +{0.309017, 0.500000, -0.809017}, +{0.425325, 0.688191, -0.587785}, +{0.442863, 0.238856, -0.864188}, +{0.587785, 0.425325, -0.688191}, +{0.688191, 0.587785, -0.425325}, +{-0.147621, 0.716567, -0.681718}, +{-0.309017, 0.500000, -0.809017}, +{0.000000, 0.525731, -0.850651}, +{-0.525731, 0.000000, -0.850651}, +{-0.442863, 0.238856, -0.864188}, +{-0.295242, 0.000000, -0.955423}, +{-0.162460, 0.262866, -0.951056}, +{0.000000, 0.000000, -1.000000}, +{0.295242, 0.000000, -0.955423}, +{0.162460, 0.262866, -0.951056}, +{-0.442863, -0.238856, -0.864188}, +{-0.309017, -0.500000, -0.809017}, +{-0.162460, -0.262866, -0.951056}, +{0.000000, -0.850651, -0.525731}, +{-0.147621, -0.716567, -0.681718}, +{0.147621, -0.716567, -0.681718}, +{0.000000, -0.525731, -0.850651}, +{0.309017, -0.500000, -0.809017}, +{0.442863, -0.238856, -0.864188}, +{0.162460, -0.262866, -0.951056}, +{0.238856, -0.864188, -0.442863}, +{0.500000, -0.809017, -0.309017}, +{0.425325, -0.688191, -0.587785}, +{0.716567, -0.681718, -0.147621}, +{0.688191, -0.587785, -0.425325}, +{0.587785, -0.425325, -0.688191}, +{0.000000, -0.955423, -0.295242}, +{0.000000, -1.000000, 0.000000}, +{0.262866, -0.951056, -0.162460}, +{0.000000, -0.850651, 0.525731}, +{0.000000, -0.955423, 0.295242}, +{0.238856, -0.864188, 0.442863}, +{0.262866, -0.951056, 0.162460}, +{0.500000, -0.809017, 0.309017}, +{0.716567, -0.681718, 0.147621}, +{0.525731, -0.850651, 0.000000}, +{-0.238856, -0.864188, -0.442863}, +{-0.500000, -0.809017, -0.309017}, +{-0.262866, -0.951056, -0.162460}, +{-0.850651, -0.525731, 0.000000}, +{-0.716567, -0.681718, -0.147621}, +{-0.716567, -0.681718, 0.147621}, +{-0.525731, -0.850651, 0.000000}, +{-0.500000, -0.809017, 0.309017}, +{-0.238856, -0.864188, 0.442863}, +{-0.262866, -0.951056, 0.162460}, +{-0.864188, -0.442863, 0.238856}, +{-0.809017, -0.309017, 0.500000}, +{-0.688191, -0.587785, 0.425325}, +{-0.681718, -0.147621, 0.716567}, +{-0.442863, -0.238856, 0.864188}, +{-0.587785, -0.425325, 0.688191}, +{-0.309017, -0.500000, 0.809017}, +{-0.147621, -0.716567, 0.681718}, +{-0.425325, -0.688191, 0.587785}, +{-0.162460, -0.262866, 0.951056}, +{0.442863, -0.238856, 0.864188}, +{0.162460, -0.262866, 0.951056}, +{0.309017, -0.500000, 0.809017}, +{0.147621, -0.716567, 0.681718}, +{0.000000, -0.525731, 0.850651}, +{0.425325, -0.688191, 0.587785}, +{0.587785, -0.425325, 0.688191}, +{0.688191, -0.587785, 0.425325}, +{-0.955423, 0.295242, 0.000000}, +{-0.951056, 0.162460, 0.262866}, +{-1.000000, 0.000000, 0.000000}, +{-0.850651, 0.000000, 0.525731}, +{-0.955423, -0.295242, 0.000000}, +{-0.951056, -0.162460, 0.262866}, +{-0.864188, 0.442863, -0.238856}, +{-0.951056, 0.162460, -0.262866}, +{-0.809017, 0.309017, -0.500000}, +{-0.864188, -0.442863, -0.238856}, +{-0.951056, -0.162460, -0.262866}, +{-0.809017, -0.309017, -0.500000}, +{-0.681718, 0.147621, -0.716567}, +{-0.681718, -0.147621, -0.716567}, +{-0.850651, 0.000000, -0.525731}, +{-0.688191, 0.587785, -0.425325}, +{-0.587785, 0.425325, -0.688191}, +{-0.425325, 0.688191, -0.587785}, +{-0.425325, -0.688191, -0.587785}, +{-0.587785, -0.425325, -0.688191}, +{-0.688191, -0.587785, -0.425325}, diff --git a/ref_soft/asm_draw.h b/ref_soft/asm_draw.h new file mode 100644 index 000000000..1d33e41ab --- /dev/null +++ b/ref_soft/asm_draw.h @@ -0,0 +1,121 @@ +// +// asm_draw.h +// +// Include file for asm drawing routines. +// + +// +// !!! note that this file must match the corresponding C structures at all +// times !!! +// + +// !!! if this is changed, it must be changed in r_local.h too !!! +#define NEAR_CLIP 0.01 + +// !!! if this is changed, it must be changed in r_local.h too !!! +#define CYCLE 128 + +// espan_t structure +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define espan_t_u 0 +#define espan_t_v 4 +#define espan_t_count 8 +#define espan_t_pnext 12 +#define espan_t_size 16 + +// sspan_t structure +// !!! if this is changed, it must be changed in d_local.h too !!! +#define sspan_t_u 0 +#define sspan_t_v 4 +#define sspan_t_count 8 +#define sspan_t_pnext 12 +#define sspan_t_size 16 + +// edge_t structure +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define et_u 0 +#define et_u_step 4 +#define et_prev 8 +#define et_next 12 +#define et_surfs 16 +#define et_nextremove 20 +#define et_nearzi 24 +#define et_owner 28 +#define et_size 32 + +// surf_t structure +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define SURF_T_SHIFT 6 +#define st_next 0 +#define st_prev 4 +#define st_spans 8 +#define st_key 12 +#define st_last_u 16 +#define st_spanstate 20 +#define st_flags 24 +#define st_data 28 +#define st_entity 32 +#define st_nearzi 36 +#define st_insubmodel 40 +#define st_d_ziorigin 44 +#define st_d_zistepu 48 +#define st_d_zistepv 52 +#define st_pad 56 +#define st_size 64 + +// clipplane_t structure +// !!! if this is changed, it must be changed in r_local.h too !!! +#define cp_normal 0 +#define cp_dist 12 +#define cp_next 16 +#define cp_leftedge 20 +#define cp_rightedge 21 +#define cp_reserved 22 +#define cp_size 24 + +// medge_t structure +// !!! if this is changed, it must be changed in model.h too !!! +#define me_v 0 +#define me_cachededgeoffset 4 +#define me_size 8 + +// mvertex_t structure +// !!! if this is changed, it must be changed in model.h too !!! +#define mv_position 0 +#define mv_size 12 + +// refdef_t structure +// !!! if this is changed, it must be changed in render.h too !!! +#define rd_vrect 0 +#define rd_aliasvrect 20 +#define rd_vrectright 40 +#define rd_vrectbottom 44 +#define rd_aliasvrectright 48 +#define rd_aliasvrectbottom 52 +#define rd_vrectrightedge 56 +#define rd_fvrectx 60 +#define rd_fvrecty 64 +#define rd_fvrectx_adj 68 +#define rd_fvrecty_adj 72 +#define rd_vrect_x_adj_shift20 76 +#define rd_vrectright_adj_shift20 80 +#define rd_fvrectright_adj 84 +#define rd_fvrectbottom_adj 88 +#define rd_fvrectright 92 +#define rd_fvrectbottom 96 +#define rd_horizontalFieldOfView 100 +#define rd_xOrigin 104 +#define rd_yOrigin 108 +#define rd_vieworg 112 +#define rd_viewangles 124 +#define rd_ambientlight 136 +#define rd_size 140 + +// mtriangle_t structure +// !!! if this is changed, it must be changed in model.h too !!! +#define mtri_facesfront 0 +#define mtri_vertindex 4 +#define mtri_size 16 // !!! if this changes, array indexing in !!! + // !!! d_polysa.s must be changed to match !!! +#define mtri_shift 4 + diff --git a/ref_soft/block16.inc b/ref_soft/block16.inc new file mode 100644 index 000000000..3c6c44cde --- /dev/null +++ b/ref_soft/block16.inc @@ -0,0 +1,116 @@ +LEnter16_16: + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch0: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch1: + mov ds:word ptr[2+edi],cx + add edi,04h + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch2: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch3: + mov ds:word ptr[2+edi],cx + add edi,04h + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch4: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch5: + mov ds:word ptr[2+edi],cx + add edi,04h + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch6: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch7: + mov ds:word ptr[2+edi],cx + add edi,04h +LEnter8_16: + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch8: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch9: + mov ds:word ptr[2+edi],cx + add edi,04h + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch10: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch11: + mov ds:word ptr[2+edi],cx + add edi,04h +LEnter4_16: + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch12: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch13: + mov ds:word ptr[2+edi],cx + add edi,04h +LEnter2_16: + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch14: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch15: + mov ds:word ptr[2+edi],cx + add edi,04h diff --git a/ref_soft/block8.inc b/ref_soft/block8.inc new file mode 100644 index 000000000..3c6c44cde --- /dev/null +++ b/ref_soft/block8.inc @@ -0,0 +1,116 @@ +LEnter16_16: + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch0: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch1: + mov ds:word ptr[2+edi],cx + add edi,04h + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch2: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch3: + mov ds:word ptr[2+edi],cx + add edi,04h + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch4: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch5: + mov ds:word ptr[2+edi],cx + add edi,04h + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch6: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch7: + mov ds:word ptr[2+edi],cx + add edi,04h +LEnter8_16: + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch8: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch9: + mov ds:word ptr[2+edi],cx + add edi,04h + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch10: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch11: + mov ds:word ptr[2+edi],cx + add edi,04h +LEnter4_16: + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch12: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch13: + mov ds:word ptr[2+edi],cx + add edi,04h +LEnter2_16: + mov al,ds:byte ptr[esi] + mov cl,ds:byte ptr[esi+ebx] + mov ah,dh + add edx,ebp + mov ch,dh + lea esi,ds:dword ptr[esi+ebx*2] + mov ax,ds:word ptr[12345678h+eax*2] +LBPatch14: + add edx,ebp + mov ds:word ptr[edi],ax + mov cx,ds:word ptr[12345678h+ecx*2] +LBPatch15: + mov ds:word ptr[2+edi],cx + add edi,04h diff --git a/ref_soft/d_if.inc b/ref_soft/d_if.inc new file mode 100644 index 000000000..39ada4359 --- /dev/null +++ b/ref_soft/d_if.inc @@ -0,0 +1,81 @@ +; +; d_ifacea.h +; +; Include file for asm driver interface. +; + +; +; !!! note that this file must match the corresponding C structures in +; d_iface.h at all times !!! +; + +; !!! if this is changed, it must be changed in r_shared.h too !!! +ALIAS_ONSEAM equ 00020h + +; !!! if this is changed, it must be changed in d_iface.h too !!! +TURB_TEX_SIZE equ 64 + +; !!! if this is changed, it must be changed in d_iface.h too !!! +CYCLE equ 128 + +; !!! if this is changed, it must be changed in r_shared.h too !!! +MAXHEIGHT equ 1024 + +; !!! if this is changed, it must be changed in quakedef.h too !!! +CACHE_SIZE equ 32 + +; particle_t structure +; !!! if this is changed, it must be changed in d_iface.h too !!! +; driver-usable fields +pt_org equ 0 +pt_color equ 12 +; drivers never touch the following fields +pt_next equ 16 +pt_vel equ 20 +pt_ramp equ 32 +pt_die equ 36 +pt_type equ 40 +pt_size equ 44 + +PARTICLE_Z_CLIP equ 8.0 + +; finalvert_t structure +; !!! if this is changed, it must be changed in d_iface.h too !!! +fv_v equ 0 ; !!! if this is moved, cases where the !!! + ; !!! address of this field is pushed in !!! + ; !!! d_polysa.s must be changed !!! +fv_flags equ 24 +fv_reserved equ 28 +fv_size equ 32 +fv_shift equ 5 + + +; stvert_t structure +; !!! if this is changed, it must be changed in modelgen.h too !!! +stv_onseam equ 0 +stv_s equ 4 +stv_t equ 8 +stv_size equ 12 + + +; trivertx_t structure +; !!! if this is changed, it must be changed in modelgen.h too !!! +tv_v equ 0 +tv_lightnormalindex equ 3 +tv_size equ 4 + +; affinetridesc_t structure +; !!! if this is changed, it must be changed in d_iface.h too !!! +atd_pskin equ 0 +atd_pskindesc equ 4 +atd_skinwidth equ 8 +atd_skinheight equ 12 +atd_ptriangles equ 16 +atd_pfinalverts equ 20 +atd_numtriangles equ 24 +atd_drawtype equ 28 +atd_seamfixupX16 equ 32 +atd_do_vis_thresh equ 36 +atd_vis_thresh equ 40 +atd_size equ 44 + diff --git a/ref_soft/d_ifacea.h b/ref_soft/d_ifacea.h new file mode 100644 index 000000000..851fb1806 --- /dev/null +++ b/ref_soft/d_ifacea.h @@ -0,0 +1,76 @@ +// +// d_ifacea.h +// +// Include file for asm driver interface. +// + +// +// !!! note that this file must match the corresponding C structures in +// d_iface.h at all times !!! +// + +// !!! if this is changed, it must be changed in d_iface.h too !!! +#define TURB_TEX_SIZE 64 // base turbulent texture size + +// !!! if this is changed, it must be changed in d_iface.h too !!! +#define CYCLE 128 + +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define MAXHEIGHT 1200 + +// !!! if this is changed, it must be changed in qcommon.h too !!! +#define CACHE_SIZE 32 // used to align key data structures + +// particle_t structure +// !!! if this is changed, it must be changed in d_iface.h too !!! +// driver-usable fields +#define pt_org 0 +#define pt_color 12 +// drivers never touch the following fields +#define pt_next 16 +#define pt_vel 20 +#define pt_ramp 32 +#define pt_die 36 +#define pt_type 40 +#define pt_size 44 + +#define PARTICLE_Z_CLIP 8.0 + +// finalvert_t structure +// !!! if this is changed, it must be changed in d_iface.h too !!! +#define fv_v 0 // !!! if this is moved, cases where the !!! + // !!! address of this field is pushed in !!! + // !!! d_polysa.s must be changed !!! +#define fv_flags 24 +#define fv_reserved 28 +#define fv_size 32 +#define fv_shift 5 + + +// stvert_t structure +// !!! if this is changed, it must be changed in modelgen.h too !!! +#define stv_onseam 0 +#define stv_s 4 +#define stv_t 8 +#define stv_size 12 + + +// trivertx_t structure +// !!! if this is changed, it must be changed in modelgen.h too !!! +#define tv_v 0 +#define tv_lightnormalindex 3 +#define tv_size 4 + +// affinetridesc_t structure +// !!! if this is changed, it must be changed in d_iface.h too !!! +#define atd_pskin 0 +#define atd_pskindesc 4 +#define atd_skinwidth 8 +#define atd_skinheight 12 +#define atd_ptriangles 16 +#define atd_pfinalverts 20 +#define atd_numtriangles 24 +#define atd_drawtype 28 +#define atd_seamfixupX16 32 +#define atd_size 36 + diff --git a/ref_soft/qasm.inc b/ref_soft/qasm.inc new file mode 100644 index 000000000..71d189b6c --- /dev/null +++ b/ref_soft/qasm.inc @@ -0,0 +1,435 @@ +; +; qasm.inc +; +; Include file for asm routines. +; + +; +; !!! note that this file must match the corresponding C structures at all +; times !!! +; + +; set to 0 to skip all asm code +id386 equ 1 + +; !!! must be kept the same as in d_iface.h !!! +TRANSPARENT_COLOR equ 255 + +ifndef GLQUAKE + externdef _d_zistepu:dword + externdef _d_pzbuffer:dword + externdef _d_zistepv:dword + externdef _d_zrowbytes:dword + externdef _d_ziorigin:dword + externdef _r_turb_s:dword + externdef _r_turb_t:dword + externdef _r_turb_pdest:dword + externdef _r_turb_spancount:dword + externdef _r_turb_turb:dword + externdef _r_turb_pbase:dword + externdef _r_turb_sstep:dword + externdef _r_turb_tstep:dword + externdef _r_bmodelactive:dword + externdef _d_sdivzstepu:dword + externdef _d_tdivzstepu:dword + externdef _d_sdivzstepv:dword + externdef _d_tdivzstepv:dword + externdef _d_sdivzorigin:dword + externdef _d_tdivzorigin:dword + externdef _sadjust:dword + externdef _tadjust:dword + externdef _bbextents:dword + externdef _bbextentt:dword + externdef _cacheblock:dword + externdef _d_viewbuffer:dword + externdef _cachewidth:dword + externdef _d_pzbuffer:dword + externdef _d_zrowbytes:dword + externdef _d_zwidth:dword + externdef _d_scantable:dword + externdef _r_lightptr:dword + externdef _r_numvblocks:dword + externdef _prowdestbase:dword + externdef _pbasesource:dword + externdef _r_lightwidth:dword + externdef _lightright:dword + externdef _lightrightstep:dword + externdef _lightdeltastep:dword + externdef _lightdelta:dword + externdef _lightright:dword + externdef _lightdelta:dword + externdef _sourcetstep:dword + externdef _surfrowbytes:dword + externdef _lightrightstep:dword + externdef _lightdeltastep:dword + externdef _r_sourcemax:dword + externdef _r_stepback:dword + externdef _colormap:dword + externdef _blocksize:dword + externdef _sourcesstep:dword + externdef _lightleft:dword + externdef _blockdivshift:dword + externdef _blockdivmask:dword + externdef _lightleftstep:dword + externdef _r_origin:dword + externdef _r_ppn:dword + externdef _r_pup:dword + externdef _r_pright:dword + externdef _ycenter:dword + externdef _xcenter:dword + externdef _d_vrectbottom_particle:dword + externdef _d_vrectright_particle:dword + externdef _d_vrecty:dword + externdef _d_vrectx:dword + externdef _d_pix_shift:dword + externdef _d_pix_min:dword + externdef _d_pix_max:dword + externdef _d_y_aspect_shift:dword + externdef _screenwidth:dword + externdef _r_leftclipped:dword + externdef _r_leftenter:dword + externdef _r_rightclipped:dword + externdef _r_rightenter:dword + externdef _modelorg:dword + externdef _xscale:dword + externdef _r_refdef:dword + externdef _yscale:dword + externdef _r_leftexit:dword + externdef _r_rightexit:dword + externdef _r_lastvertvalid:dword + externdef _cacheoffset:dword + externdef _newedges:dword + externdef _removeedges:dword + externdef _r_pedge:dword + externdef _r_framecount:dword + externdef _r_u1:dword + externdef _r_emitted:dword + externdef _edge_p:dword + externdef _surface_p:dword + externdef _surfaces:dword + externdef _r_lzi1:dword + externdef _r_v1:dword + externdef _r_ceilv1:dword + externdef _r_nearzi:dword + externdef _r_nearzionly:dword + externdef _edge_aftertail:dword + externdef _edge_tail:dword + externdef _current_iv:dword + externdef _edge_head_u_shift20:dword + externdef _span_p:dword + externdef _edge_head:dword + externdef _fv:dword + externdef _edge_tail_u_shift20:dword + externdef _r_apverts:dword + externdef _r_anumverts:dword + externdef _aliastransform:dword + externdef _r_avertexnormals:dword + externdef _r_plightvec:dword + externdef _r_ambientlight:dword + externdef _r_shadelight:dword + externdef _aliasxcenter:dword + externdef _aliasycenter:dword + externdef _a_sstepxfrac:dword + externdef _r_affinetridesc:dword + externdef _acolormap:dword + externdef _d_pcolormap:dword + externdef _r_affinetridesc:dword + externdef _d_sfrac:dword + externdef _d_ptex:dword + externdef _d_pedgespanpackage:dword + externdef _d_tfrac:dword + externdef _d_light:dword + externdef _d_zi:dword + externdef _d_pdest:dword + externdef _d_pz:dword + externdef _d_aspancount:dword + externdef _erroradjustup:dword + externdef _errorterm:dword + externdef _d_xdenom:dword + externdef _r_p0:dword + externdef _r_p1:dword + externdef _r_p2:dword + externdef _a_tstepxfrac:dword + externdef _r_sstepx:dword + externdef _r_tstepx:dword + externdef _a_ststepxwhole:dword + externdef _zspantable:dword + externdef _skintable:dword + externdef _r_zistepx:dword + externdef _erroradjustdown:dword + externdef _d_countextrastep:dword + externdef _ubasestep:dword + externdef _a_ststepxwhole:dword + externdef _a_tstepxfrac:dword + externdef _r_lstepx:dword + externdef _a_spans:dword + externdef _erroradjustdown:dword + externdef _d_pdestextrastep:dword + externdef _d_pzextrastep:dword + externdef _d_sfracextrastep:dword + externdef _d_ptexextrastep:dword + externdef _d_countextrastep:dword + externdef _d_tfracextrastep:dword + externdef _d_lightextrastep:dword + externdef _d_ziextrastep:dword + externdef _d_pdestbasestep:dword + externdef _d_pzbasestep:dword + externdef _d_sfracbasestep:dword + externdef _d_ptexbasestep:dword + externdef _ubasestep:dword + externdef _d_tfracbasestep:dword + externdef _d_lightbasestep:dword + externdef _d_zibasestep:dword + externdef _zspantable:dword + externdef _r_lstepy:dword + externdef _r_sstepy:dword + externdef _r_tstepy:dword + externdef _r_zistepy:dword + externdef _D_PolysetSetEdgeTable:dword + externdef _D_RasterizeAliasPolySmooth:dword + + externdef float_point5:dword + externdef Float2ToThe31nd:dword + externdef izistep:dword + externdef izi:dword + externdef FloatMinus2ToThe31nd:dword + externdef float_1:dword + externdef float_particle_z_clip:dword + externdef float_minus_1:dword + externdef float_0:dword + externdef fp_16:dword + externdef fp_64k:dword + externdef fp_1m:dword + externdef fp_1m_minus_1:dword + externdef fp_8 :dword + externdef entryvec_table:dword + externdef advancetable:dword + externdef sstep:dword + externdef tstep:dword + externdef pspantemp:dword + externdef counttemp:dword + externdef jumptemp:dword + externdef reciprocal_table:dword + externdef DP_Count:dword + externdef DP_u:dword + externdef DP_v:dword + externdef DP_32768:dword + externdef DP_Color:dword + externdef DP_Pix:dword + externdef DP_EntryTable:dword + externdef pbase:dword + externdef s:dword + externdef t:dword + externdef sfracf:dword + externdef tfracf:dword + externdef snext:dword + externdef tnext:dword + externdef spancountminus1:dword + externdef zi16stepu:dword + externdef sdivz16stepu:dword + externdef tdivz16stepu:dword + externdef zi8stepu:dword + externdef sdivz8stepu:dword + externdef tdivz8stepu:dword + externdef reciprocal_table_16:dword + externdef entryvec_table_16:dword + externdef fp_64kx64k:dword + externdef pz:dword + externdef spr8entryvec_table:dword +endif + + externdef _fpu_ceil_cw:dword + externdef _fpu_chop_cw:dword + externdef _snd_scaletable:dword + externdef _paintbuffer:dword + externdef _snd_linear_count:dword + externdef _snd_p:dword + externdef _snd_vol:dword + externdef _snd_out:dword + externdef _vright:dword + externdef _vup:dword + externdef _vpn:dword + externdef _BOPS_Error:dword + +; plane_t structure +; !!! if this is changed, it must be changed in model.h too !!! +; !!! if the size of this is changed, the array lookup in SV_HullPointContents +; must be changed too !!! +pl_normal equ 0 +pl_dist equ 12 +pl_type equ 16 +pl_signbits equ 17 +pl_pad equ 18 +pl_size equ 20 + +; hull_t structure +; !!! if this is changed, it must be changed in model.h too !!! +hu_clipnodes equ 0 +hu_planes equ 4 +hu_firstclipnode equ 8 +hu_lastclipnode equ 12 +hu_clip_mins equ 16 +hu_clip_maxs equ 28 +hu_size equ 40 + +; dnode_t structure +; !!! if this is changed, it must be changed in bspfile.h too !!! +nd_planenum equ 0 +nd_children equ 4 +nd_mins equ 8 +nd_maxs equ 20 +nd_firstface equ 32 +nd_numfaces equ 36 +nd_size equ 40 + +; sfxcache_t structure +; !!! if this is changed, it much be changed in sound.h too !!! +sfxc_length equ 0 +sfxc_loopstart equ 4 +sfxc_speed equ 8 +sfxc_width equ 12 +sfxc_stereo equ 16 +sfxc_data equ 20 + +; channel_t structure +; !!! if this is changed, it much be changed in sound.h too !!! +ch_sfx equ 0 +ch_leftvol equ 4 +ch_rightvol equ 8 +ch_end equ 12 +ch_pos equ 16 +ch_looping equ 20 +ch_entnum equ 24 +ch_entchannel equ 28 +ch_origin equ 32 +ch_dist_mult equ 44 +ch_master_vol equ 48 +ch_size equ 52 + +; portable_samplepair_t structure +; !!! if this is changed, it much be changed in sound.h too !!! +psp_left equ 0 +psp_right equ 4 +psp_size equ 8 + +; !!! if this is changed, it must be changed in r_local.h too !!! +NEAR_CLIP equ 0.01 + +; !!! if this is changed, it must be changed in r_local.h too !!! +CYCLE equ 128 + +; espan_t structure +; !!! if this is changed, it must be changed in r_shared.h too !!! +espan_t_u equ 0 +espan_t_v equ 4 +espan_t_count equ 8 +espan_t_pnext equ 12 +espan_t_size equ 16 + +; sspan_t structure +; !!! if this is changed, it must be changed in d_local.h too !!! +sspan_t_u equ 0 +sspan_t_v equ 4 +sspan_t_count equ 8 +sspan_t_size equ 12 + +; spanpackage_t structure +; !!! if this is changed, it must be changed in d_polyset.c too !!! +spanpackage_t_pdest equ 0 +spanpackage_t_pz equ 4 +spanpackage_t_count equ 8 +spanpackage_t_ptex equ 12 +spanpackage_t_sfrac equ 16 +spanpackage_t_tfrac equ 20 +spanpackage_t_light equ 24 +spanpackage_t_zi equ 28 +spanpackage_t_size equ 32 + +; edge_t structure +; !!! if this is changed, it must be changed in r_shared.h too !!! +et_u equ 0 +et_u_step equ 4 +et_prev equ 8 +et_next equ 12 +et_surfs equ 16 +et_nextremove equ 20 +et_nearzi equ 24 +et_owner equ 28 +et_size equ 32 + +; surf_t structure +; !!! if this is changed, it must be changed in r_shared.h too !!! +SURF_T_SHIFT equ 6 +st_next equ 0 +st_prev equ 4 +st_spans equ 8 +st_key equ 12 +st_last_u equ 16 +st_spanstate equ 20 +st_flags equ 24 +st_data equ 28 +st_entity equ 32 +st_nearzi equ 36 +st_insubmodel equ 40 +st_d_ziorigin equ 44 +st_d_zistepu equ 48 +st_d_zistepv equ 52 +st_pad equ 56 +st_size equ 64 + +; clipplane_t structure +; !!! if this is changed, it must be changed in r_local.h too !!! +cp_normal equ 0 +cp_dist equ 12 +cp_next equ 16 +cp_leftedge equ 20 +cp_rightedge equ 21 +cp_reserved equ 22 +cp_size equ 24 + +; medge_t structure +; !!! if this is changed, it must be changed in model.h too !!! +me_v equ 0 +me_cachededgeoffset equ 4 +me_size equ 8 + +; mvertex_t structure +; !!! if this is changed, it must be changed in model.h too !!! +mv_position equ 0 +mv_size equ 12 + +; refdef_t structure +; !!! if this is changed, it must be changed in render.h too !!! +rd_vrect equ 0 +rd_aliasvrect equ 20 +rd_vrectright equ 40 +rd_vrectbottom equ 44 +rd_aliasvrectright equ 48 +rd_aliasvrectbottom equ 52 +rd_vrectrightedge equ 56 +rd_fvrectx equ 60 +rd_fvrecty equ 64 +rd_fvrectx_adj equ 68 +rd_fvrecty_adj equ 72 +rd_vrect_x_adj_shift20 equ 76 +rd_vrectright_adj_shift20 equ 80 +rd_fvrectright_adj equ 84 +rd_fvrectbottom_adj equ 88 +rd_fvrectright equ 92 +rd_fvrectbottom equ 96 +rd_horizontalFieldOfView equ 100 +rd_xOrigin equ 104 +rd_yOrigin equ 108 +rd_vieworg equ 112 +rd_viewangles equ 124 +rd_ambientlight equ 136 +rd_size equ 140 + +; mtriangle_t structure +; !!! if this is changed, it must be changed in model.h too !!! +mtri_facesfront equ 0 +mtri_vertindex equ 4 +mtri_size equ 16 ; !!! if this changes, array indexing in !!! + ; !!! d_polysa.s must be changed to match !!! +mtri_shift equ 4 + diff --git a/ref_soft/r_aclip.c b/ref_soft/r_aclip.c new file mode 100644 index 000000000..3d4212570 --- /dev/null +++ b/ref_soft/r_aclip.c @@ -0,0 +1,323 @@ +/* +Copyright (C) 1997-2001 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_aclip.c: clip routines for drawing Alias models directly to the screen + +#include "r_local.h" + +static finalvert_t fv[2][8]; + +void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv); +void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out); +void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out); +void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out); +void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out); + + +/* +================ +R_Alias_clip_z + +pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex +================ +*/ +void R_Alias_clip_z (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) +{ + float scale; + + scale = (ALIAS_Z_CLIP_PLANE - pfv0->xyz[2]) / + (pfv1->xyz[2] - pfv0->xyz[2]); + + out->xyz[0] = pfv0->xyz[0] + (pfv1->xyz[0] - pfv0->xyz[0]) * scale; + out->xyz[1] = pfv0->xyz[1] + (pfv1->xyz[1] - pfv0->xyz[1]) * scale; + out->xyz[2] = ALIAS_Z_CLIP_PLANE; + + out->s = pfv0->s + (pfv1->s - pfv0->s) * scale; + out->t = pfv0->t + (pfv1->t - pfv0->t) * scale; + out->l = pfv0->l + (pfv1->l - pfv0->l) * scale; + + R_AliasProjectAndClipTestFinalVert (out); +} + + +#if !id386 + +void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) +{ + float scale; + + if (pfv0->v >= pfv1->v ) + { + scale = (float)(r_refdef.aliasvrect.x - pfv0->u) / + (pfv1->u - pfv0->u); + out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5; + out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5; + out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5; + out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5; + out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5; + out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5; + } + else + { + scale = (float)(r_refdef.aliasvrect.x - pfv1->u) / + (pfv0->u - pfv1->u); + out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5; + out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5; + out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5; + out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5; + out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5; + out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5; + } +} + + +void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) +{ + float scale; + + if ( pfv0->v >= pfv1->v ) + { + scale = (float)(r_refdef.aliasvrectright - pfv0->u ) / + (pfv1->u - pfv0->u ); + out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5; + out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5; + out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5; + out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5; + out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5; + out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5; + } + else + { + scale = (float)(r_refdef.aliasvrectright - pfv1->u ) / + (pfv0->u - pfv1->u ); + out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5; + out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5; + out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5; + out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5; + out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5; + out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5; + } +} + + +void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) +{ + float scale; + + if (pfv0->v >= pfv1->v) + { + scale = (float)(r_refdef.aliasvrect.y - pfv0->v) / + (pfv1->v - pfv0->v); + out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5; + out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5; + out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5; + out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5; + out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5; + out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5; + } + else + { + scale = (float)(r_refdef.aliasvrect.y - pfv1->v) / + (pfv0->v - pfv1->v); + out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5; + out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5; + out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5; + out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5; + out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5; + out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5; + } +} + + +void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out) +{ + float scale; + + if (pfv0->v >= pfv1->v) + { + scale = (float)(r_refdef.aliasvrectbottom - pfv0->v) / + (pfv1->v - pfv0->v); + + out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5; + out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5; + out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5; + out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5; + out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5; + out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5; + } + else + { + scale = (float)(r_refdef.aliasvrectbottom - pfv1->v) / + (pfv0->v - pfv1->v); + + out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5; + out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5; + out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5; + out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5; + out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5; + out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5; + } +} + +#endif + + +int R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count, + void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) ) +{ + int i,j,k; + int flags, oldflags; + + j = count-1; + k = 0; + for (i=0 ; i r_refdef.aliasvrectright) + out[k].flags |= ALIAS_RIGHT_CLIP; + if (out[k].v > r_refdef.aliasvrectbottom) + out[k].flags |= ALIAS_BOTTOM_CLIP; + k++; + } + if (!flags) + { + out[k] = in[i]; + k++; + } + } + + return k; +} + + +/* +================ +R_AliasClipTriangle +================ +*/ +void R_AliasClipTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2) +{ + int i, k, pingpong; + unsigned clipflags; + +// copy vertexes and fix seam texture coordinates + fv[0][0] = *index0; + fv[0][1] = *index1; + fv[0][2] = *index2; + +// clip + clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags; + + if (clipflags & ALIAS_Z_CLIP) + { + k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z); + if (k == 0) + return; + + pingpong = 1; + clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags; + } + else + { + pingpong = 0; + k = 3; + } + + if (clipflags & ALIAS_LEFT_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_LEFT_CLIP, k, R_Alias_clip_left); + if (k == 0) + return; + + pingpong ^= 1; + } + + if (clipflags & ALIAS_RIGHT_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_RIGHT_CLIP, k, R_Alias_clip_right); + if (k == 0) + return; + + pingpong ^= 1; + } + + if (clipflags & ALIAS_BOTTOM_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom); + if (k == 0) + return; + + pingpong ^= 1; + } + + if (clipflags & ALIAS_TOP_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_TOP_CLIP, k, R_Alias_clip_top); + if (k == 0) + return; + + pingpong ^= 1; + } + + for (i=0 ; i r_refdef.aliasvrectright) + fv[pingpong][i].u = r_refdef.aliasvrectright; + + if (fv[pingpong][i].v < r_refdef.aliasvrect.y) + fv[pingpong][i].v = r_refdef.aliasvrect.y; + else if (fv[pingpong][i].v > r_refdef.aliasvrectbottom) + fv[pingpong][i].v = r_refdef.aliasvrectbottom; + + fv[pingpong][i].flags = 0; + } + +// draw triangles + for (i=1 ; itranslate[i]; + maxs[i] = mins[i] + frame->scale[i]*255; + } + + /* + ** transform the min and max values into view space + */ + R_AliasTransformVector( mins, transformed_min, aliastransform ); + R_AliasTransformVector( maxs, transformed_max, aliastransform ); + + if ( transformed_min[2] >= ALIAS_Z_CLIP_PLANE ) + zfullyclipped = false; + if ( transformed_max[2] >= ALIAS_Z_CLIP_PLANE ) + zfullyclipped = false; + + if ( zfullyclipped ) + { + return BBOX_TRIVIAL_REJECT; + } + if ( zclipped ) + { + return ( BBOX_MUST_CLIP_XY | BBOX_MUST_CLIP_Z ); + } + + /* + ** build a transformed bounding box from the given min and max + */ + for ( i = 0; i < 8; i++ ) + { + int j; + vec3_t tmp, transformed; + unsigned long clipcode = 0; + + if ( i & 1 ) + tmp[0] = mins[0]; + else + tmp[0] = maxs[0]; + + if ( i & 2 ) + tmp[1] = mins[1]; + else + tmp[1] = maxs[1]; + + if ( i & 4 ) + tmp[2] = mins[2]; + else + tmp[2] = maxs[2]; + + R_AliasTransformVector( tmp, transformed, worldxf ); + + for ( j = 0; j < 4; j++ ) + { + float dp = DotProduct( transformed, view_clipplanes[j].normal ); + + if ( ( dp - view_clipplanes[j].dist ) < 0.0F ) + clipcode |= 1 << j; + } + + aggregate_and_clipcode &= clipcode; + aggregate_or_clipcode |= clipcode; + } + + if ( aggregate_and_clipcode ) + { + return BBOX_TRIVIAL_REJECT; + } + if ( !aggregate_or_clipcode ) + { + return BBOX_TRIVIAL_ACCEPT; + } + + return BBOX_MUST_CLIP_XY; +} + +qboolean R_AliasCheckBBox (void) +{ + unsigned long ccodes[2] = { 0, 0 }; + + ccodes[0] = R_AliasCheckFrameBBox( r_thisframe, aliasworldtransform ); + + /* + ** non-lerping model + */ + if ( currententity->backlerp == 0 ) + { + if ( ccodes[0] == BBOX_TRIVIAL_ACCEPT ) + return BBOX_TRIVIAL_ACCEPT; + else if ( ccodes[0] & BBOX_TRIVIAL_REJECT ) + return BBOX_TRIVIAL_REJECT; + else + return ( ccodes[0] & ~BBOX_TRIVIAL_REJECT ); + } + + ccodes[1] = R_AliasCheckFrameBBox( r_lastframe, aliasoldworldtransform ); + + if ( ( ccodes[0] | ccodes[1] ) == BBOX_TRIVIAL_ACCEPT ) + return BBOX_TRIVIAL_ACCEPT; + else if ( ( ccodes[0] & ccodes[1] ) & BBOX_TRIVIAL_REJECT ) + return BBOX_TRIVIAL_REJECT; + else + return ( ccodes[0] | ccodes[1] ) & ~BBOX_TRIVIAL_REJECT; +} + + +/* +================ +R_AliasTransformVector +================ +*/ +void R_AliasTransformVector(vec3_t in, vec3_t out, float xf[3][4] ) +{ + out[0] = DotProduct(in, xf[0]) + xf[0][3]; + out[1] = DotProduct(in, xf[1]) + xf[1][3]; + out[2] = DotProduct(in, xf[2]) + xf[2][3]; +} + + +/* +================ +R_AliasPreparePoints + +General clipped case +================ +*/ +typedef struct +{ + int num_points; + dtrivertx_t *last_verts; // verts from the last frame + dtrivertx_t *this_verts; // verts from this frame + finalvert_t *dest_verts; // destination for transformed verts +} aliasbatchedtransformdata_t; + +aliasbatchedtransformdata_t aliasbatchedtransformdata; + +void R_AliasPreparePoints (void) +{ + int i; + dstvert_t *pstverts; + dtriangle_t *ptri; + finalvert_t *pfv[3]; + finalvert_t finalverts[MAXALIASVERTS + + ((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 3]; + finalvert_t *pfinalverts; + +//PGM + iractive = (r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE); +// iractive = 0; +// if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE) +// iractive = 1; +//PGM + + // put work vertexes on stack, cache aligned + pfinalverts = (finalvert_t *) + (((long)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + + aliasbatchedtransformdata.num_points = s_pmdl->num_xyz; + aliasbatchedtransformdata.last_verts = r_lastframe->verts; + aliasbatchedtransformdata.this_verts = r_thisframe->verts; + aliasbatchedtransformdata.dest_verts = pfinalverts; + + R_AliasTransformFinalVerts( aliasbatchedtransformdata.num_points, + aliasbatchedtransformdata.dest_verts, + aliasbatchedtransformdata.last_verts, + aliasbatchedtransformdata.this_verts ); + +// clip and draw all triangles +// + pstverts = (dstvert_t *)((byte *)s_pmdl + s_pmdl->ofs_st); + ptri = (dtriangle_t *)((byte *)s_pmdl + s_pmdl->ofs_tris); + + if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) + { + for (i=0 ; inum_tris ; i++, ptri++) + { + pfv[0] = &pfinalverts[ptri->index_xyz[0]]; + pfv[1] = &pfinalverts[ptri->index_xyz[1]]; + pfv[2] = &pfinalverts[ptri->index_xyz[2]]; + + if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags ) + continue; // completely clipped + + // insert s/t coordinates + pfv[0]->s = pstverts[ptri->index_st[0]].s << 16; + pfv[0]->t = pstverts[ptri->index_st[0]].t << 16; + + pfv[1]->s = pstverts[ptri->index_st[1]].s << 16; + pfv[1]->t = pstverts[ptri->index_st[1]].t << 16; + + pfv[2]->s = pstverts[ptri->index_st[2]].s << 16; + pfv[2]->t = pstverts[ptri->index_st[2]].t << 16; + + if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) ) + { // totally unclipped + aliastriangleparms.a = pfv[2]; + aliastriangleparms.b = pfv[1]; + aliastriangleparms.c = pfv[0]; + + R_DrawTriangle(); + } + else + { + R_AliasClipTriangle (pfv[2], pfv[1], pfv[0]); + } + } + } + else + { + for (i=0 ; inum_tris ; i++, ptri++) + { + pfv[0] = &pfinalverts[ptri->index_xyz[0]]; + pfv[1] = &pfinalverts[ptri->index_xyz[1]]; + pfv[2] = &pfinalverts[ptri->index_xyz[2]]; + + if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags ) + continue; // completely clipped + + // insert s/t coordinates + pfv[0]->s = pstverts[ptri->index_st[0]].s << 16; + pfv[0]->t = pstverts[ptri->index_st[0]].t << 16; + + pfv[1]->s = pstverts[ptri->index_st[1]].s << 16; + pfv[1]->t = pstverts[ptri->index_st[1]].t << 16; + + pfv[2]->s = pstverts[ptri->index_st[2]].s << 16; + pfv[2]->t = pstverts[ptri->index_st[2]].t << 16; + + if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) ) + { // totally unclipped + aliastriangleparms.a = pfv[0]; + aliastriangleparms.b = pfv[1]; + aliastriangleparms.c = pfv[2]; + + R_DrawTriangle(); + } + else + { // partially clipped + R_AliasClipTriangle (pfv[0], pfv[1], pfv[2]); + } + } + } +} + + +/* +================ +R_AliasSetUpTransform +================ +*/ +void R_AliasSetUpTransform (void) +{ + int i; + static float viewmatrix[3][4]; + vec3_t angles; + +// TODO: should really be stored with the entity instead of being reconstructed +// TODO: should use a look-up table +// TODO: could cache lazily, stored in the entity +// + angles[ROLL] = currententity->angles[ROLL]; + angles[PITCH] = currententity->angles[PITCH]; + angles[YAW] = currententity->angles[YAW]; + AngleVectors( angles, s_alias_forward, s_alias_right, s_alias_up ); + +// TODO: can do this with simple matrix rearrangement + + memset( aliasworldtransform, 0, sizeof( aliasworldtransform ) ); + memset( aliasoldworldtransform, 0, sizeof( aliasworldtransform ) ); + + for (i=0 ; i<3 ; i++) + { + aliasoldworldtransform[i][0] = aliasworldtransform[i][0] = s_alias_forward[i]; + aliasoldworldtransform[i][0] = aliasworldtransform[i][1] = -s_alias_right[i]; + aliasoldworldtransform[i][0] = aliasworldtransform[i][2] = s_alias_up[i]; + } + + aliasworldtransform[0][3] = currententity->origin[0]-r_origin[0]; + aliasworldtransform[1][3] = currententity->origin[1]-r_origin[1]; + aliasworldtransform[2][3] = currententity->origin[2]-r_origin[2]; + + aliasoldworldtransform[0][3] = currententity->oldorigin[0]-r_origin[0]; + aliasoldworldtransform[1][3] = currententity->oldorigin[1]-r_origin[1]; + aliasoldworldtransform[2][3] = currententity->oldorigin[2]-r_origin[2]; + +// FIXME: can do more efficiently than full concatenation +// memcpy( rotationmatrix, t2matrix, sizeof( rotationmatrix ) ); + +// R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix); + +// TODO: should be global, set when vright, etc., set + VectorCopy (vright, viewmatrix[0]); + VectorCopy (vup, viewmatrix[1]); + VectorInverse (viewmatrix[1]); + VectorCopy (vpn, viewmatrix[2]); + + viewmatrix[0][3] = 0; + viewmatrix[1][3] = 0; + viewmatrix[2][3] = 0; + +// memcpy( aliasworldtransform, rotationmatrix, sizeof( aliastransform ) ); + + R_ConcatTransforms (viewmatrix, aliasworldtransform, aliastransform); + + aliasworldtransform[0][3] = currententity->origin[0]; + aliasworldtransform[1][3] = currententity->origin[1]; + aliasworldtransform[2][3] = currententity->origin[2]; + + aliasoldworldtransform[0][3] = currententity->oldorigin[0]; + aliasoldworldtransform[1][3] = currententity->oldorigin[1]; + aliasoldworldtransform[2][3] = currententity->oldorigin[2]; +} + + +/* +================ +R_AliasTransformFinalVerts +================ +*/ +#if id386 && !defined __linux__ +void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv ) +{ + float lightcos; + float lerped_vert[3]; + int byte_to_dword_ptr_var; + int tmpint; + + float one = 1.0F; + float zi; + + static float FALIAS_Z_CLIP_PLANE = ALIAS_Z_CLIP_PLANE; + static float PS_SCALE = POWERSUIT_SCALE; + + __asm mov ecx, numpoints + + /* + lerped_vert[0] = r_lerp_move[0] + oldv->v[0]*r_lerp_backv[0] + newv->v[0]*r_lerp_frontv[0]; + lerped_vert[1] = r_lerp_move[1] + oldv->v[1]*r_lerp_backv[1] + newv->v[1]*r_lerp_frontv[1]; + lerped_vert[2] = r_lerp_move[2] + oldv->v[2]*r_lerp_backv[2] + newv->v[2]*r_lerp_frontv[2]; + */ +top_of_loop: + + __asm mov esi, oldv + __asm mov edi, newv + + __asm xor ebx, ebx + + __asm mov bl, byte ptr [esi+DTRIVERTX_V0] + __asm mov byte_to_dword_ptr_var, ebx + __asm fild dword ptr byte_to_dword_ptr_var + __asm fmul dword ptr [r_lerp_backv+0] ; oldv[0]*rlb[0] + + __asm mov bl, byte ptr [esi+DTRIVERTX_V1] + __asm mov byte_to_dword_ptr_var, ebx + __asm fild dword ptr byte_to_dword_ptr_var + __asm fmul dword ptr [r_lerp_backv+4] ; oldv[1]*rlb[1] | oldv[0]*rlb[0] + + __asm mov bl, byte ptr [esi+DTRIVERTX_V2] + __asm mov byte_to_dword_ptr_var, ebx + __asm fild dword ptr byte_to_dword_ptr_var + __asm fmul dword ptr [r_lerp_backv+8] ; oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0] + + __asm mov bl, byte ptr [edi+DTRIVERTX_V0] + __asm mov byte_to_dword_ptr_var, ebx + __asm fild dword ptr byte_to_dword_ptr_var + __asm fmul dword ptr [r_lerp_frontv+0] ; newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0] + + __asm mov bl, byte ptr [edi+DTRIVERTX_V1] + __asm mov byte_to_dword_ptr_var, ebx + __asm fild dword ptr byte_to_dword_ptr_var + __asm fmul dword ptr [r_lerp_frontv+4] ; newv[1]*rlf[1] | newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0] + + __asm mov bl, byte ptr [edi+DTRIVERTX_V2] + __asm mov byte_to_dword_ptr_var, ebx + __asm fild dword ptr byte_to_dword_ptr_var + __asm fmul dword ptr [r_lerp_frontv+8] ; newv[2]*rlf[2] | newv[1]*rlf[1] | newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0] + + __asm fxch st(5) ; oldv[0]*rlb[0] | newv[1]*rlf[1] | newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | newv[2]*rlf[2] + __asm faddp st(2), st ; newv[1]*rlf[1] | oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | newv[2]*rlf[2] + __asm faddp st(3), st ; oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] + newv[1]*rlf[1] | newv[2]*rlf[2] + __asm fxch st(1) ; oldv[2]*rlb[2] | oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[1]*rlb[1] + newv[1]*rlf[1] | newv[2]*rlf[2] + __asm faddp st(3), st ; oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[1]*rlb[1] + newv[1]*rlf[1] | oldv[2]*rlb[2] + newv[2]*rlf[2] + __asm fadd dword ptr [r_lerp_move+0] ; lv0 | oldv[1]*rlb[1] + newv[1]*rlf[1] | oldv[2]*rlb[2] + newv[2]*rlf[2] + __asm fxch st(1) ; oldv[1]*rlb[1] + newv[1]*rlf[1] | lv0 | oldv[2]*rlb[2] + newv[2]*rlf[2] + __asm fadd dword ptr [r_lerp_move+4] ; lv1 | lv0 | oldv[2]*rlb[2] + newv[2]*rlf[2] + __asm fxch st(2) ; oldv[2]*rlb[2] + newv[2]*rlf[2] | lv0 | lv1 + __asm fadd dword ptr [r_lerp_move+8] ; lv2 | lv0 | lv1 + __asm fxch st(1) ; lv0 | lv2 | lv1 + __asm fstp dword ptr [lerped_vert+0] ; lv2 | lv1 + __asm fstp dword ptr [lerped_vert+8] ; lv2 + __asm fstp dword ptr [lerped_vert+4] ; (empty) + + __asm mov eax, currententity + __asm mov eax, dword ptr [eax+ENTITY_FLAGS] + __asm mov ebx, RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM + __asm and eax, ebx + __asm jz not_powersuit + + /* + ** lerped_vert[0] += lightnormal[0] * POWERSUIT_SCALE + ** lerped_vert[1] += lightnormal[1] * POWERSUIT_SCALE + ** lerped_vert[2] += lightnormal[2] * POWERSUIT_SCALE + */ + + __asm xor ebx, ebx + __asm mov bl, byte ptr [edi+DTRIVERTX_LNI] + __asm mov eax, 12 + __asm mul ebx + __asm lea eax, [r_avertexnormals+eax] + + __asm fld dword ptr [eax+0] ; n[0] + __asm fmul PS_SCALE ; n[0] * PS + __asm fld dword ptr [eax+4] ; n[1] | n[0] * PS + __asm fmul PS_SCALE ; n[1] * PS | n[0] * PS + __asm fld dword ptr [eax+8] ; n[2] | n[1] * PS | n[0] * PS + __asm fmul PS_SCALE ; n[2] * PS | n[1] * PS | n[0] * PS + __asm fld dword ptr [lerped_vert+0] ; lv0 | n[2] * PS | n[1] * PS | n[0] * PS + __asm faddp st(3), st ; n[2] * PS | n[1] * PS | n[0] * PS + lv0 + __asm fld dword ptr [lerped_vert+4] ; lv1 | n[2] * PS | n[1] * PS | n[0] * PS + lv0 + __asm faddp st(2), st ; n[2] * PS | n[1] * PS + lv1 | n[0] * PS + lv0 + __asm fadd dword ptr [lerped_vert+8] ; n[2] * PS + lv2 | n[1] * PS + lv1 | n[0] * PS + lv0 + __asm fxch st(2) ; LV0 | LV1 | LV2 + __asm fstp dword ptr [lerped_vert+0] ; LV1 | LV2 + __asm fstp dword ptr [lerped_vert+4] ; LV2 + __asm fstp dword ptr [lerped_vert+8] ; (empty) + +not_powersuit: + + /* + fv->flags = 0; + + fv->xyz[0] = DotProduct(lerped_vert, aliastransform[0]) + aliastransform[0][3]; + fv->xyz[1] = DotProduct(lerped_vert, aliastransform[1]) + aliastransform[1][3]; + fv->xyz[2] = DotProduct(lerped_vert, aliastransform[2]) + aliastransform[2][3]; + */ + __asm mov eax, fv + __asm mov dword ptr [eax+FINALVERT_FLAGS], 0 + + __asm fld dword ptr [lerped_vert+0] ; lv0 + __asm fmul dword ptr [aliastransform+0] ; lv0*at[0][0] + __asm fld dword ptr [lerped_vert+4] ; lv1 | lv0*at[0][0] + __asm fmul dword ptr [aliastransform+4] ; lv1*at[0][1] | lv0*at[0][0] + __asm fld dword ptr [lerped_vert+8] ; lv2 | lv1*at[0][1] | lv0*at[0][0] + __asm fmul dword ptr [aliastransform+8] ; lv2*at[0][2] | lv1*at[0][1] | lv0*at[0][0] + __asm fxch st(2) ; lv0*at[0][0] | lv1*at[0][1] | lv2*at[0][2] + __asm faddp st(1), st ; lv0*at[0][0] + lv1*at[0][1] | lv2*at[0][2] + __asm faddp st(1), st ; lv0*at[0][0] + lv1*at[0][1] + lv2*at[0][2] + __asm fadd dword ptr [aliastransform+12] ; FV.X + + __asm fld dword ptr [lerped_vert+0] ; lv0 + __asm fmul dword ptr [aliastransform+16] ; lv0*at[1][0] + __asm fld dword ptr [lerped_vert+4] ; lv1 | lv0*at[1][0] + __asm fmul dword ptr [aliastransform+20] ; lv1*at[1][1] | lv0*at[1][0] + __asm fld dword ptr [lerped_vert+8] ; lv2 | lv1*at[1][1] | lv0*at[1][0] + __asm fmul dword ptr [aliastransform+24] ; lv2*at[1][2] | lv1*at[1][1] | lv0*at[1][0] + __asm fxch st(2) ; lv0*at[1][0] | lv1*at[1][1] | lv2*at[1][2] + __asm faddp st(1), st ; lv0*at[1][0] + lv1*at[1][1] | lv2*at[1][2] + __asm faddp st(1), st ; lv0*at[1][0] + lv1*at[1][1] + lv2*at[1][2] + __asm fadd dword ptr [aliastransform+28] ; FV.Y | FV.X + __asm fxch st(1) ; FV.X | FV.Y + __asm fstp dword ptr [eax+FINALVERT_X] ; FV.Y + + __asm fld dword ptr [lerped_vert+0] ; lv0 + __asm fmul dword ptr [aliastransform+32] ; lv0*at[2][0] + __asm fld dword ptr [lerped_vert+4] ; lv1 | lv0*at[2][0] + __asm fmul dword ptr [aliastransform+36] ; lv1*at[2][1] | lv0*at[2][0] + __asm fld dword ptr [lerped_vert+8] ; lv2 | lv1*at[2][1] | lv0*at[2][0] + __asm fmul dword ptr [aliastransform+40] ; lv2*at[2][2] | lv1*at[2][1] | lv0*at[2][0] + __asm fxch st(2) ; lv0*at[2][0] | lv1*at[2][1] | lv2*at[2][2] + __asm faddp st(1), st ; lv0*at[2][0] + lv1*at[2][1] | lv2*at[2][2] + __asm faddp st(1), st ; lv0*at[2][0] + lv1*at[2][1] + lv2*at[2][2] + __asm fadd dword ptr [aliastransform+44] ; FV.Z | FV.Y + __asm fxch st(1) ; FV.Y | FV.Z + __asm fstp dword ptr [eax+FINALVERT_Y] ; FV.Z + __asm fstp dword ptr [eax+FINALVERT_Z] ; (empty) + + /* + ** lighting + ** + ** plightnormal = r_avertexnormals[newv->lightnormalindex]; + ** lightcos = DotProduct (plightnormal, r_plightvec); + ** temp = r_ambientlight; + */ + __asm xor ebx, ebx + __asm mov bl, byte ptr [edi+DTRIVERTX_LNI] + __asm mov eax, 12 + __asm mul ebx + __asm lea eax, [r_avertexnormals+eax] + __asm lea ebx, r_plightvec + + __asm fld dword ptr [eax+0] + __asm fmul dword ptr [ebx+0] + __asm fld dword ptr [eax+4] + __asm fmul dword ptr [ebx+4] + __asm fld dword ptr [eax+8] + __asm fmul dword ptr [ebx+8] + __asm fxch st(2) + __asm faddp st(1), st + __asm faddp st(1), st + __asm fstp dword ptr lightcos + __asm mov eax, lightcos + __asm mov ebx, r_ambientlight + + /* + if (lightcos < 0) + { + temp += (int)(r_shadelight * lightcos); + + // clamp; because we limited the minimum ambient and shading light, we + // don't have to clamp low light, just bright + if (temp < 0) + temp = 0; + } + + fv->v[4] = temp; + */ + __asm or eax, eax + __asm jns store_fv4 + + __asm fld dword ptr r_shadelight + __asm fmul dword ptr lightcos + __asm fistp dword ptr tmpint + __asm add ebx, tmpint + + __asm or ebx, ebx + __asm jns store_fv4 + __asm mov ebx, 0 + +store_fv4: + __asm mov edi, fv + __asm mov dword ptr [edi+FINALVERT_V4], ebx + + __asm mov edx, dword ptr [edi+FINALVERT_FLAGS] + + /* + ** do clip testing and projection here + */ + /* + if ( dest_vert->xyz[2] < ALIAS_Z_CLIP_PLANE ) + { + dest_vert->flags |= ALIAS_Z_CLIP; + } + else + { + R_AliasProjectAndClipTestFinalVert( dest_vert ); + } + */ + __asm mov eax, dword ptr [edi+FINALVERT_Z] + __asm and eax, eax + __asm js alias_z_clip + __asm cmp eax, FALIAS_Z_CLIP_PLANE + __asm jl alias_z_clip + + /* + This is the code to R_AliasProjectAndClipTestFinalVert + + float zi; + float x, y, z; + + x = fv->xyz[0]; + y = fv->xyz[1]; + z = fv->xyz[2]; + zi = 1.0 / z; + + fv->v[5] = zi * s_ziscale; + + fv->v[0] = (x * aliasxscale * zi) + aliasxcenter; + fv->v[1] = (y * aliasyscale * zi) + aliasycenter; + */ + __asm fld one ; 1 + __asm fdiv dword ptr [edi+FINALVERT_Z] ; zi + + __asm mov eax, dword ptr [edi+32] + __asm mov eax, dword ptr [edi+64] + + __asm fst zi ; zi + __asm fmul s_ziscale ; fv5 + __asm fld dword ptr [edi+FINALVERT_X] ; x | fv5 + __asm fmul aliasxscale ; x * aliasxscale | fv5 + __asm fld dword ptr [edi+FINALVERT_Y] ; y | x * aliasxscale | fv5 + __asm fmul aliasyscale ; y * aliasyscale | x * aliasxscale | fv5 + __asm fxch st(1) ; x * aliasxscale | y * aliasyscale | fv5 + __asm fmul zi ; x * asx * zi | y * asy | fv5 + __asm fadd aliasxcenter ; fv0 | y * asy | fv5 + __asm fxch st(1) ; y * asy | fv0 | fv5 + __asm fmul zi ; y * asy * zi | fv0 | fv5 + __asm fadd aliasycenter ; fv1 | fv0 | fv5 + __asm fxch st(2) ; fv5 | fv0 | fv1 + __asm fistp dword ptr [edi+FINALVERT_V5] ; fv0 | fv1 + __asm fistp dword ptr [edi+FINALVERT_V0] ; fv1 + __asm fistp dword ptr [edi+FINALVERT_V1] ; (empty) + + /* + if (fv->v[0] < r_refdef.aliasvrect.x) + fv->flags |= ALIAS_LEFT_CLIP; + if (fv->v[1] < r_refdef.aliasvrect.y) + fv->flags |= ALIAS_TOP_CLIP; + if (fv->v[0] > r_refdef.aliasvrectright) + fv->flags |= ALIAS_RIGHT_CLIP; + if (fv->v[1] > r_refdef.aliasvrectbottom) + fv->flags |= ALIAS_BOTTOM_CLIP; + */ + __asm mov eax, dword ptr [edi+FINALVERT_V0] + __asm mov ebx, dword ptr [edi+FINALVERT_V1] + + __asm cmp eax, r_refdef.aliasvrect.x + __asm jge ct_alias_top + __asm or edx, ALIAS_LEFT_CLIP +ct_alias_top: + __asm cmp ebx, r_refdef.aliasvrect.y + __asm jge ct_alias_right + __asm or edx, ALIAS_TOP_CLIP +ct_alias_right: + __asm cmp eax, r_refdef.aliasvrectright + __asm jle ct_alias_bottom + __asm or edx, ALIAS_RIGHT_CLIP +ct_alias_bottom: + __asm cmp ebx, r_refdef.aliasvrectbottom + __asm jle end_of_loop + __asm or edx, ALIAS_BOTTOM_CLIP + + __asm jmp end_of_loop + +alias_z_clip: + __asm or edx, ALIAS_Z_CLIP + +end_of_loop: + + __asm mov dword ptr [edi+FINALVERT_FLAGS], edx + __asm add oldv, DTRIVERTX_SIZE + __asm add newv, DTRIVERTX_SIZE + __asm add fv, FINALVERT_SIZE + + __asm dec ecx + __asm jnz top_of_loop +} +#else +void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv ) +{ + int i; + + for ( i = 0; i < numpoints; i++, fv++, oldv++, newv++ ) + { + int temp; + float lightcos, *plightnormal; + vec3_t lerped_vert; + + lerped_vert[0] = r_lerp_move[0] + oldv->v[0]*r_lerp_backv[0] + newv->v[0]*r_lerp_frontv[0]; + lerped_vert[1] = r_lerp_move[1] + oldv->v[1]*r_lerp_backv[1] + newv->v[1]*r_lerp_frontv[1]; + lerped_vert[2] = r_lerp_move[2] + oldv->v[2]*r_lerp_backv[2] + newv->v[2]*r_lerp_frontv[2]; + + plightnormal = r_avertexnormals[newv->lightnormalindex]; + + // PMM - added double damage shell + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) + { + lerped_vert[0] += plightnormal[0] * POWERSUIT_SCALE; + lerped_vert[1] += plightnormal[1] * POWERSUIT_SCALE; + lerped_vert[2] += plightnormal[2] * POWERSUIT_SCALE; + } + + fv->xyz[0] = DotProduct(lerped_vert, aliastransform[0]) + aliastransform[0][3]; + fv->xyz[1] = DotProduct(lerped_vert, aliastransform[1]) + aliastransform[1][3]; + fv->xyz[2] = DotProduct(lerped_vert, aliastransform[2]) + aliastransform[2][3]; + + fv->flags = 0; + + // lighting + lightcos = DotProduct (plightnormal, r_plightvec); + temp = r_ambientlight; + + if (lightcos < 0) + { + temp += (int)(r_shadelight * lightcos); + + // clamp; because we limited the minimum ambient and shading light, we + // don't have to clamp low light, just bright + if (temp < 0) + temp = 0; + } + + fv->l = temp; + + if ( fv->xyz[2] < ALIAS_Z_CLIP_PLANE ) + { + fv->flags |= ALIAS_Z_CLIP; + } + else + { + R_AliasProjectAndClipTestFinalVert( fv ); + } + } +} + +#endif + +/* +================ +R_AliasProjectAndClipTestFinalVert +================ +*/ +void R_AliasProjectAndClipTestFinalVert( finalvert_t *fv ) +{ + float zi; + float x, y, z; + + // project points + x = fv->xyz[0]; + y = fv->xyz[1]; + z = fv->xyz[2]; + zi = 1.0 / z; + + fv->zi = zi * s_ziscale; + + fv->u = (x * aliasxscale * zi) + aliasxcenter; + fv->v = (y * aliasyscale * zi) + aliasycenter; + + if (fv->u < r_refdef.aliasvrect.x) + fv->flags |= ALIAS_LEFT_CLIP; + if (fv->v < r_refdef.aliasvrect.y) + fv->flags |= ALIAS_TOP_CLIP; + if (fv->u > r_refdef.aliasvrectright) + fv->flags |= ALIAS_RIGHT_CLIP; + if (fv->v > r_refdef.aliasvrectbottom) + fv->flags |= ALIAS_BOTTOM_CLIP; +} + +/* +=============== +R_AliasSetupSkin +=============== +*/ +static qboolean R_AliasSetupSkin (void) +{ + int skinnum; + image_t *pskindesc; + + if (currententity->skin) + pskindesc = currententity->skin; + else + { + skinnum = currententity->skinnum; + if ((skinnum >= s_pmdl->num_skins) || (skinnum < 0)) + { + ri.Con_Printf (PRINT_ALL, "R_AliasSetupSkin %s: no such skin # %d\n", + currentmodel->name, skinnum); + skinnum = 0; + } + + pskindesc = currentmodel->skins[skinnum]; + } + + if ( !pskindesc ) + return false; + + r_affinetridesc.pskin = pskindesc->pixels[0]; + r_affinetridesc.skinwidth = pskindesc->width; + r_affinetridesc.skinheight = pskindesc->height; + + R_PolysetUpdateTables (); // FIXME: precalc edge lookups + + return true; +} + + +/* +================ +R_AliasSetupLighting + + FIXME: put lighting into tables +================ +*/ +void R_AliasSetupLighting (void) +{ + alight_t lighting; + float lightvec[3] = {-1, 0, 0}; + vec3_t light; + int i, j; + + // all components of light should be identical in software + if ( currententity->flags & RF_FULLBRIGHT ) + { + for (i=0 ; i<3 ; i++) + light[i] = 1.0; + } + else + { + R_LightPoint (currententity->origin, light); + } + + // save off light value for server to look at (BIG HACK!) + if ( currententity->flags & RF_WEAPONMODEL ) + r_lightlevel->value = 150.0 * light[0]; + + + if ( currententity->flags & RF_MINLIGHT ) + { + for (i=0 ; i<3 ; i++) + if (light[i] < 0.1) + light[i] = 0.1; + } + + if ( currententity->flags & RF_GLOW ) + { // bonus items will pulse with time + float scale; + float min; + + scale = 0.1 * sin(r_newrefdef.time*7); + for (i=0 ; i<3 ; i++) + { + min = light[i] * 0.8; + light[i] += scale; + if (light[i] < min) + light[i] = min; + } + } + + j = (light[0] + light[1] + light[2])*0.3333*255; + + lighting.ambientlight = j; + lighting.shadelight = j; + + lighting.plightvec = lightvec; + +// clamp lighting so it doesn't overbright as much + if (lighting.ambientlight > 128) + lighting.ambientlight = 128; + if (lighting.ambientlight + lighting.shadelight > 192) + lighting.shadelight = 192 - lighting.ambientlight; + +// guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have +// to clamp off the bottom + r_ambientlight = lighting.ambientlight; + + if (r_ambientlight < LIGHT_MIN) + r_ambientlight = LIGHT_MIN; + + r_ambientlight = (255 - r_ambientlight) << VID_CBITS; + + if (r_ambientlight < LIGHT_MIN) + r_ambientlight = LIGHT_MIN; + + r_shadelight = lighting.shadelight; + + if (r_shadelight < 0) + r_shadelight = 0; + + r_shadelight *= VID_GRADES; + +// rotate the lighting vector into the model's frame of reference + r_plightvec[0] = DotProduct( lighting.plightvec, s_alias_forward ); + r_plightvec[1] = -DotProduct( lighting.plightvec, s_alias_right ); + r_plightvec[2] = DotProduct( lighting.plightvec, s_alias_up ); +} + + +/* +================= +R_AliasSetupFrames + +================= +*/ +void R_AliasSetupFrames( dmdl_t *pmdl ) +{ + int thisframe = currententity->frame; + int lastframe = currententity->oldframe; + + if ( ( thisframe >= pmdl->num_frames ) || ( thisframe < 0 ) ) + { + ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such thisframe %d\n", + currentmodel->name, thisframe); + thisframe = 0; + } + if ( ( lastframe >= pmdl->num_frames ) || ( lastframe < 0 ) ) + { + ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such lastframe %d\n", + currentmodel->name, lastframe); + lastframe = 0; + } + + r_thisframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames + + thisframe * pmdl->framesize); + + r_lastframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames + + lastframe * pmdl->framesize); +} + +/* +** R_AliasSetUpLerpData +** +** Precomputes lerp coefficients used for the whole frame. +*/ +void R_AliasSetUpLerpData( dmdl_t *pmdl, float backlerp ) +{ + float frontlerp; + vec3_t translation, vectors[3]; + int i; + + frontlerp = 1.0F - backlerp; + + /* + ** convert entity's angles into discrete vectors for R, U, and F + */ + AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]); + + /* + ** translation is the vector from last position to this position + */ + VectorSubtract (currententity->oldorigin, currententity->origin, translation); + + /* + ** move should be the delta back to the previous frame * backlerp + */ + r_lerp_move[0] = DotProduct(translation, vectors[0]); // forward + r_lerp_move[1] = -DotProduct(translation, vectors[1]); // left + r_lerp_move[2] = DotProduct(translation, vectors[2]); // up + + VectorAdd( r_lerp_move, r_lastframe->translate, r_lerp_move ); + + for (i=0 ; i<3 ; i++) + { + r_lerp_move[i] = backlerp*r_lerp_move[i] + frontlerp * r_thisframe->translate[i]; + } + + for (i=0 ; i<3 ; i++) + { + r_lerp_frontv[i] = frontlerp * r_thisframe->scale[i]; + r_lerp_backv[i] = backlerp * r_lastframe->scale[i]; + } +} + +/* +================ +R_AliasDrawModel +================ +*/ +void R_AliasDrawModel (void) +{ + extern void (*d_pdrawspans)(void *); + extern void R_PolysetDrawSpans8_Opaque( void * ); + extern void R_PolysetDrawSpans8_33( void * ); + extern void R_PolysetDrawSpans8_66( void * ); + extern void R_PolysetDrawSpansConstant8_33( void * ); + extern void R_PolysetDrawSpansConstant8_66( void * ); + + s_pmdl = (dmdl_t *)currentmodel->extradata; + + if ( r_lerpmodels->value == 0 ) + currententity->backlerp = 0; + + if ( currententity->flags & RF_WEAPONMODEL ) + { + if ( r_lefthand->value == 1.0F ) + aliasxscale = -aliasxscale; + else if ( r_lefthand->value == 2.0F ) + return; + } + + /* + ** we have to set our frame pointers and transformations before + ** doing any real work + */ + R_AliasSetupFrames( s_pmdl ); + R_AliasSetUpTransform(); + + // see if the bounding box lets us trivially reject, also sets + // trivial accept status + if ( R_AliasCheckBBox() == BBOX_TRIVIAL_REJECT ) + { + if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) + { + aliasxscale = -aliasxscale; + } + return; + } + + // set up the skin and verify it exists + if ( !R_AliasSetupSkin () ) + { + ri.Con_Printf( PRINT_ALL, "R_AliasDrawModel %s: NULL skin found\n", + currentmodel->name); + return; + } + + r_amodels_drawn++; + R_AliasSetupLighting (); + + /* + ** select the proper span routine based on translucency + */ + // PMM - added double damage shell + // PMM - reordered to handle blending + if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) + { + int color; + + // PMM - added double + color = currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM); + // PMM - reordered, old code first +/* + if ( color == RF_SHELL_RED ) + r_aliasblendcolor = SHELL_RED_COLOR; + else if ( color == RF_SHELL_GREEN ) + r_aliasblendcolor = SHELL_GREEN_COLOR; + else if ( color == RF_SHELL_BLUE ) + r_aliasblendcolor = SHELL_BLUE_COLOR; + else if ( color == (RF_SHELL_RED | RF_SHELL_GREEN) ) + r_aliasblendcolor = SHELL_RG_COLOR; + else if ( color == (RF_SHELL_RED | RF_SHELL_BLUE) ) + r_aliasblendcolor = SHELL_RB_COLOR; + else if ( color == (RF_SHELL_BLUE | RF_SHELL_GREEN) ) + r_aliasblendcolor = SHELL_BG_COLOR; + // PMM - added this .. it's yellowish + else if ( color == (RF_SHELL_DOUBLE) ) + r_aliasblendcolor = SHELL_DOUBLE_COLOR; + else if ( color == (RF_SHELL_HALF_DAM) ) + r_aliasblendcolor = SHELL_HALF_DAM_COLOR; + // pmm + else + r_aliasblendcolor = SHELL_WHITE_COLOR; +*/ + if ( color & RF_SHELL_RED ) + { + if ( ( color & RF_SHELL_BLUE) && ( color & RF_SHELL_GREEN) ) + r_aliasblendcolor = SHELL_WHITE_COLOR; + else if ( color & (RF_SHELL_BLUE | RF_SHELL_DOUBLE)) + r_aliasblendcolor = SHELL_RB_COLOR; + else + r_aliasblendcolor = SHELL_RED_COLOR; + } + else if ( color & RF_SHELL_BLUE) + { + if ( color & RF_SHELL_DOUBLE ) + r_aliasblendcolor = SHELL_CYAN_COLOR; + else + r_aliasblendcolor = SHELL_BLUE_COLOR; + } + else if ( color & (RF_SHELL_DOUBLE) ) + r_aliasblendcolor = SHELL_DOUBLE_COLOR; + else if ( color & (RF_SHELL_HALF_DAM) ) + r_aliasblendcolor = SHELL_HALF_DAM_COLOR; + else if ( color & RF_SHELL_GREEN ) + r_aliasblendcolor = SHELL_GREEN_COLOR; + else + r_aliasblendcolor = SHELL_WHITE_COLOR; + + + if ( currententity->alpha > 0.33 ) + d_pdrawspans = R_PolysetDrawSpansConstant8_66; + else + d_pdrawspans = R_PolysetDrawSpansConstant8_33; + } + else if ( currententity->flags & RF_TRANSLUCENT ) + { + if ( currententity->alpha > 0.66 ) + d_pdrawspans = R_PolysetDrawSpans8_Opaque; + else if ( currententity->alpha > 0.33 ) + d_pdrawspans = R_PolysetDrawSpans8_66; + else + d_pdrawspans = R_PolysetDrawSpans8_33; + } + else + { + d_pdrawspans = R_PolysetDrawSpans8_Opaque; + } + + /* + ** compute this_frame and old_frame addresses + */ + R_AliasSetUpLerpData( s_pmdl, currententity->backlerp ); + + if (currententity->flags & RF_DEPTHHACK) + s_ziscale = (float)0x8000 * (float)0x10000 * 3.0; + else + s_ziscale = (float)0x8000 * (float)0x10000; + + R_AliasPreparePoints (); + + if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) + { + aliasxscale = -aliasxscale; + } +} + + + diff --git a/ref_soft/r_bsp.c b/ref_soft/r_bsp.c new file mode 100644 index 000000000..b1680b34d --- /dev/null +++ b/ref_soft/r_bsp.c @@ -0,0 +1,637 @@ +/* +Copyright (C) 1997-2001 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_bsp.c + +#include "r_local.h" + +// +// current entity info +// +qboolean insubmodel; +entity_t *currententity; +vec3_t modelorg; // modelorg is the viewpoint reletive to + // the currently rendering entity +vec3_t r_entorigin; // the currently rendering entity in world + // coordinates + +float entity_rotation[3][3]; + +int r_currentbkey; + +typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t; + +#define MAX_BMODEL_VERTS 500 // 6K +#define MAX_BMODEL_EDGES 1000 // 12K + +static mvertex_t *pbverts; +static bedge_t *pbedges; +static int numbverts, numbedges; + +static mvertex_t *pfrontenter, *pfrontexit; + +static qboolean makeclippededge; + + +//=========================================================================== + +/* +================ +R_EntityRotate +================ +*/ +void R_EntityRotate (vec3_t vec) +{ + vec3_t tvec; + + VectorCopy (vec, tvec); + vec[0] = DotProduct (entity_rotation[0], tvec); + vec[1] = DotProduct (entity_rotation[1], tvec); + vec[2] = DotProduct (entity_rotation[2], tvec); +} + + +/* +================ +R_RotateBmodel +================ +*/ +void R_RotateBmodel (void) +{ + float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3]; + +// TODO: should use a look-up table +// TODO: should really be stored with the entity instead of being reconstructed +// TODO: could cache lazily, stored in the entity +// TODO: share work with R_SetUpAliasTransform + +// yaw + angle = currententity->angles[YAW]; + angle = angle * M_PI*2 / 360; + s = sin(angle); + c = cos(angle); + + temp1[0][0] = c; + temp1[0][1] = s; + temp1[0][2] = 0; + temp1[1][0] = -s; + temp1[1][1] = c; + temp1[1][2] = 0; + temp1[2][0] = 0; + temp1[2][1] = 0; + temp1[2][2] = 1; + + +// pitch + angle = currententity->angles[PITCH]; + angle = angle * M_PI*2 / 360; + s = sin(angle); + c = cos(angle); + + temp2[0][0] = c; + temp2[0][1] = 0; + temp2[0][2] = -s; + temp2[1][0] = 0; + temp2[1][1] = 1; + temp2[1][2] = 0; + temp2[2][0] = s; + temp2[2][1] = 0; + temp2[2][2] = c; + + R_ConcatRotations (temp2, temp1, temp3); + +// roll + angle = currententity->angles[ROLL]; + angle = angle * M_PI*2 / 360; + s = sin(angle); + c = cos(angle); + + temp1[0][0] = 1; + temp1[0][1] = 0; + temp1[0][2] = 0; + temp1[1][0] = 0; + temp1[1][1] = c; + temp1[1][2] = s; + temp1[2][0] = 0; + temp1[2][1] = -s; + temp1[2][2] = c; + + R_ConcatRotations (temp1, temp3, entity_rotation); + +// +// rotate modelorg and the transformation matrix +// + R_EntityRotate (modelorg); + R_EntityRotate (vpn); + R_EntityRotate (vright); + R_EntityRotate (vup); + + R_TransformFrustum (); +} + + +/* +================ +R_RecursiveClipBPoly + +Clip a bmodel poly down the world bsp tree +================ +*/ +void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf) +{ + bedge_t *psideedges[2], *pnextedge, *ptedge; + int i, side, lastside; + float dist, frac, lastdist; + mplane_t *splitplane, tplane; + mvertex_t *pvert, *plastvert, *ptvert; + mnode_t *pn; + int area; + + psideedges[0] = psideedges[1] = NULL; + + makeclippededge = false; + +// transform the BSP plane into model space +// FIXME: cache these? + splitplane = pnode->plane; + tplane.dist = splitplane->dist - + DotProduct(r_entorigin, splitplane->normal); + tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal); + tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal); + tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal); + +// clip edges to BSP plane + for ( ; pedges ; pedges = pnextedge) + { + pnextedge = pedges->pnext; + + // set the status for the last point as the previous point + // FIXME: cache this stuff somehow? + plastvert = pedges->v[0]; + lastdist = DotProduct (plastvert->position, tplane.normal) - + tplane.dist; + + if (lastdist > 0) + lastside = 0; + else + lastside = 1; + + pvert = pedges->v[1]; + + dist = DotProduct (pvert->position, tplane.normal) - tplane.dist; + + if (dist > 0) + side = 0; + else + side = 1; + + if (side != lastside) + { + // clipped + if (numbverts >= MAX_BMODEL_VERTS) + return; + + // generate the clipped vertex + frac = lastdist / (lastdist - dist); + ptvert = &pbverts[numbverts++]; + ptvert->position[0] = plastvert->position[0] + + frac * (pvert->position[0] - + plastvert->position[0]); + ptvert->position[1] = plastvert->position[1] + + frac * (pvert->position[1] - + plastvert->position[1]); + ptvert->position[2] = plastvert->position[2] + + frac * (pvert->position[2] - + plastvert->position[2]); + + // split into two edges, one on each side, and remember entering + // and exiting points + // FIXME: share the clip edge by having a winding direction flag? + if (numbedges >= (MAX_BMODEL_EDGES - 1)) + { + ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n"); + return; + } + + ptedge = &pbedges[numbedges]; + ptedge->pnext = psideedges[lastside]; + psideedges[lastside] = ptedge; + ptedge->v[0] = plastvert; + ptedge->v[1] = ptvert; + + ptedge = &pbedges[numbedges + 1]; + ptedge->pnext = psideedges[side]; + psideedges[side] = ptedge; + ptedge->v[0] = ptvert; + ptedge->v[1] = pvert; + + numbedges += 2; + + if (side == 0) + { + // entering for front, exiting for back + pfrontenter = ptvert; + makeclippededge = true; + } + else + { + pfrontexit = ptvert; + makeclippededge = true; + } + } + else + { + // add the edge to the appropriate side + pedges->pnext = psideedges[side]; + psideedges[side] = pedges; + } + } + +// if anything was clipped, reconstitute and add the edges along the clip +// plane to both sides (but in opposite directions) + if (makeclippededge) + { + if (numbedges >= (MAX_BMODEL_EDGES - 2)) + { + ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n"); + return; + } + + ptedge = &pbedges[numbedges]; + ptedge->pnext = psideedges[0]; + psideedges[0] = ptedge; + ptedge->v[0] = pfrontexit; + ptedge->v[1] = pfrontenter; + + ptedge = &pbedges[numbedges + 1]; + ptedge->pnext = psideedges[1]; + psideedges[1] = ptedge; + ptedge->v[0] = pfrontenter; + ptedge->v[1] = pfrontexit; + + numbedges += 2; + } + +// draw or recurse further + for (i=0 ; i<2 ; i++) + { + if (psideedges[i]) + { + // draw if we've reached a non-solid leaf, done if all that's left is a + // solid leaf, and continue down the tree if it's not a leaf + pn = pnode->children[i]; + + // we're done with this branch if the node or leaf isn't in the PVS + if (pn->visframe == r_visframecount) + { + if (pn->contents != CONTENTS_NODE) + { + if (pn->contents != CONTENTS_SOLID) + { + if (r_newrefdef.areabits) + { + area = ((mleaf_t *)pn)->area; + if (! (r_newrefdef.areabits[area>>3] & (1<<(area&7)) ) ) + continue; // not visible + } + + r_currentbkey = ((mleaf_t *)pn)->key; + R_RenderBmodelFace (psideedges[i], psurf); + } + } + else + { + R_RecursiveClipBPoly (psideedges[i], pnode->children[i], + psurf); + } + } + } + } +} + + +/* +================ +R_DrawSolidClippedSubmodelPolygons + +Bmodel crosses multiple leafs +================ +*/ +void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode) +{ + int i, j, lindex; + vec_t dot; + msurface_t *psurf; + int numsurfaces; + mplane_t *pplane; + mvertex_t bverts[MAX_BMODEL_VERTS]; + bedge_t bedges[MAX_BMODEL_EDGES], *pbedge; + medge_t *pedge, *pedges; + +// FIXME: use bounding-box-based frustum clipping info? + + psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; + numsurfaces = pmodel->nummodelsurfaces; + pedges = pmodel->edges; + + for (i=0 ; iplane; + + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + + // draw the polygon + if (( !(psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + ((psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + continue; + + // FIXME: use bounding-box-based frustum clipping info? + + // copy the edges to bedges, flipping if necessary so always + // clockwise winding + // FIXME: if edges and vertices get caches, these assignments must move + // outside the loop, and overflow checking must be done here + pbverts = bverts; + pbedges = bedges; + numbverts = numbedges = 0; + pbedge = &bedges[numbedges]; + numbedges += psurf->numedges; + + for (j=0 ; jnumedges ; j++) + { + lindex = pmodel->surfedges[psurf->firstedge+j]; + + if (lindex > 0) + { + pedge = &pedges[lindex]; + pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]]; + pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]]; + } + else + { + lindex = -lindex; + pedge = &pedges[lindex]; + pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]]; + pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]]; + } + + pbedge[j].pnext = &pbedge[j+1]; + } + + pbedge[j-1].pnext = NULL; // mark end of edges + + if ( !( psurf->texinfo->flags & ( SURF_TRANS66 | SURF_TRANS33 ) ) ) + R_RecursiveClipBPoly (pbedge, topnode, psurf); + else + R_RenderBmodelFace( pbedge, psurf ); + } +} + + +/* +================ +R_DrawSubmodelPolygons + +All in one leaf +================ +*/ +void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode) +{ + int i; + vec_t dot; + msurface_t *psurf; + int numsurfaces; + mplane_t *pplane; + +// FIXME: use bounding-box-based frustum clipping info? + + psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; + numsurfaces = pmodel->nummodelsurfaces; + + for (i=0 ; iplane; + + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + + // draw the polygon + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + r_currentkey = ((mleaf_t *)topnode)->key; + + // FIXME: use bounding-box-based frustum clipping info? + R_RenderFace (psurf, clipflags); + } + } +} + + +int c_drawnode; + +/* +================ +R_RecursiveWorldNode +================ +*/ +void R_RecursiveWorldNode (mnode_t *node, int clipflags) +{ + int i, c, side, *pindex; + vec3_t acceptpt, rejectpt; + mplane_t *plane; + msurface_t *surf, **mark; + float d, dot; + mleaf_t *pleaf; + + if (node->contents == CONTENTS_SOLID) + return; // solid + + if (node->visframe != r_visframecount) + return; + +// cull the clipping planes if not trivial accept +// FIXME: the compiler is doing a lousy job of optimizing here; it could be +// twice as fast in ASM + if (clipflags) + { + for (i=0 ; i<4 ; i++) + { + if (! (clipflags & (1<minmaxs[pindex[0]]; + rejectpt[1] = (float)node->minmaxs[pindex[1]]; + rejectpt[2] = (float)node->minmaxs[pindex[2]]; + + d = DotProduct (rejectpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + if (d <= 0) + return; + acceptpt[0] = (float)node->minmaxs[pindex[3+0]]; + acceptpt[1] = (float)node->minmaxs[pindex[3+1]]; + acceptpt[2] = (float)node->minmaxs[pindex[3+2]]; + + d = DotProduct (acceptpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d >= 0) + clipflags &= ~(1<contents != -1) + { + pleaf = (mleaf_t *)node; + + // check for door connected areas + if (r_newrefdef.areabits) + { + if (! (r_newrefdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) ) + return; // not visible + } + + mark = pleaf->firstmarksurface; + c = pleaf->nummarksurfaces; + + if (c) + { + do + { + (*mark)->visframe = r_framecount; + mark++; + } while (--c); + } + + pleaf->key = r_currentkey; + r_currentkey++; // all bmodels in a leaf share the same key + } + else + { + // node is just a decision point, so go down the apropriate sides + + // find which side of the node we are on + plane = node->plane; + + switch (plane->type) + { + case PLANE_X: + dot = modelorg[0] - plane->dist; + break; + case PLANE_Y: + dot = modelorg[1] - plane->dist; + break; + case PLANE_Z: + dot = modelorg[2] - plane->dist; + break; + default: + dot = DotProduct (modelorg, plane->normal) - plane->dist; + break; + } + + if (dot >= 0) + side = 0; + else + side = 1; + + // recurse down the children, front side first + R_RecursiveWorldNode (node->children[side], clipflags); + + // draw stuff + c = node->numsurfaces; + + if (c) + { + surf = r_worldmodel->surfaces + node->firstsurface; + + if (dot < -BACKFACE_EPSILON) + { + do + { + if ((surf->flags & SURF_PLANEBACK) && + (surf->visframe == r_framecount)) + { + R_RenderFace (surf, clipflags); + } + + surf++; + } while (--c); + } + else if (dot > BACKFACE_EPSILON) + { + do + { + if (!(surf->flags & SURF_PLANEBACK) && + (surf->visframe == r_framecount)) + { + R_RenderFace (surf, clipflags); + } + + surf++; + } while (--c); + } + + // all surfaces on the same node share the same sequence number + r_currentkey++; + } + + // recurse down the back side + R_RecursiveWorldNode (node->children[!side], clipflags); + } +} + + + +/* +================ +R_RenderWorld +================ +*/ +void R_RenderWorld (void) +{ + + if (!r_drawworld->value) + return; + if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) + return; + + c_drawnode=0; + + // auto cycle the world frame for texture animation + r_worldentity.frame = (int)(r_newrefdef.time*2); + currententity = &r_worldentity; + + VectorCopy (r_origin, modelorg); + currentmodel = r_worldmodel; + r_pcurrentvertbase = currentmodel->vertexes; + + R_RecursiveWorldNode (currentmodel->nodes, 15); +} + + diff --git a/ref_soft/r_draw.c b/ref_soft/r_draw.c new file mode 100644 index 000000000..dec9f62a1 --- /dev/null +++ b/ref_soft/r_draw.c @@ -0,0 +1,445 @@ +/* +Copyright (C) 1997-2001 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. + +*/ + +// draw.c + +#include "r_local.h" + + +image_t *draw_chars; // 8*8 graphic characters + +//============================================================================= + +/* +================ +Draw_FindPic +================ +*/ +image_t *Draw_FindPic (char *name) +{ + image_t *image; + char fullname[MAX_QPATH]; + + if (name[0] != '/' && name[0] != '\\') + { + Com_sprintf (fullname, sizeof(fullname), "pics/%s.pcx", name); + image = R_FindImage (fullname, it_pic); + } + else + image = R_FindImage (name+1, it_pic); + + return image; +} + + + +/* +=============== +Draw_InitLocal +=============== +*/ +void Draw_InitLocal (void) +{ + draw_chars = Draw_FindPic ("conchars"); +} + + + +/* +================ +Draw_Char + +Draws one 8*8 graphics character +It can be clipped to the top of the screen to allow the console to be +smoothly scrolled off. +================ +*/ +void Draw_Char (int x, int y, int num) +{ + byte *dest; + byte *source; + int drawline; + int row, col; + + num &= 255; + + if (num == 32 || num == 32+128) + return; + + if (y <= -8) + return; // totally off screen + +// if ( ( y + 8 ) >= vid.height ) + if ( ( y + 8 ) > vid.height ) // PGM - status text was missing in sw... + return; + +#ifdef PARANOID + if (y > vid.height - 8 || x < 0 || x > vid.width - 8) + ri.Sys_Error (ERR_FATAL,"Con_DrawCharacter: (%i, %i)", x, y); + if (num < 0 || num > 255) + ri.Sys_Error (ERR_FATAL,"Con_DrawCharacter: char %i", num); +#endif + + row = num>>4; + col = num&15; + source = draw_chars->pixels[0] + (row<<10) + (col<<3); + + if (y < 0) + { // clipped + drawline = 8 + y; + source -= 128*y; + y = 0; + } + else + drawline = 8; + + + dest = vid.buffer + y*vid.rowbytes + x; + + while (drawline--) + { + if (source[0] != TRANSPARENT_COLOR) + dest[0] = source[0]; + if (source[1] != TRANSPARENT_COLOR) + dest[1] = source[1]; + if (source[2] != TRANSPARENT_COLOR) + dest[2] = source[2]; + if (source[3] != TRANSPARENT_COLOR) + dest[3] = source[3]; + if (source[4] != TRANSPARENT_COLOR) + dest[4] = source[4]; + if (source[5] != TRANSPARENT_COLOR) + dest[5] = source[5]; + if (source[6] != TRANSPARENT_COLOR) + dest[6] = source[6]; + if (source[7] != TRANSPARENT_COLOR) + dest[7] = source[7]; + source += 128; + dest += vid.rowbytes; + } +} + +/* +============= +Draw_GetPicSize +============= +*/ +void Draw_GetPicSize (int *w, int *h, char *pic) +{ + image_t *gl; + + gl = Draw_FindPic (pic); + if (!gl) + { + *w = *h = -1; + return; + } + *w = gl->width; + *h = gl->height; +} + +/* +============= +Draw_StretchPicImplementation +============= +*/ +void Draw_StretchPicImplementation (int x, int y, int w, int h, image_t *pic) +{ + byte *dest, *source; + int v, u, sv; + int height; + int f, fstep; + int skip; + + if ((x < 0) || + (x + w > vid.width) || + (y + h > vid.height)) + { + ri.Sys_Error (ERR_FATAL,"Draw_Pic: bad coordinates"); + } + + height = h; + if (y < 0) + { + skip = -y; + height += y; + y = 0; + } + else + skip = 0; + + dest = vid.buffer + y * vid.rowbytes + x; + + for (v=0 ; vheight/h; + source = pic->pixels[0] + sv*pic->width; + if (w == pic->width) + memcpy (dest, source, w); + else + { + f = 0; + fstep = pic->width*0x10000/w; + for (u=0 ; u>16]; + f += fstep; + dest[u+1] = source[f>>16]; + f += fstep; + dest[u+2] = source[f>>16]; + f += fstep; + dest[u+3] = source[f>>16]; + f += fstep; + } + } + } +} + +/* +============= +Draw_StretchPic +============= +*/ +void Draw_StretchPic (int x, int y, int w, int h, char *name) +{ + image_t *pic; + + pic = Draw_FindPic (name); + if (!pic) + { + ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name); + return; + } + Draw_StretchPicImplementation (x, y, w, h, pic); +} + +/* +============= +Draw_StretchRaw +============= +*/ +void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data) +{ + image_t pic; + + pic.pixels[0] = data; + pic.width = cols; + pic.height = rows; + Draw_StretchPicImplementation (x, y, w, h, &pic); +} + +/* +============= +Draw_Pic +============= +*/ +void Draw_Pic (int x, int y, char *name) +{ + image_t *pic; + byte *dest, *source; + int v, u; + int tbyte; + int height; + + pic = Draw_FindPic (name); + if (!pic) + { + ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name); + return; + } + + if ((x < 0) || + (x + pic->width > vid.width) || + (y + pic->height > vid.height)) + return; // ri.Sys_Error (ERR_FATAL,"Draw_Pic: bad coordinates"); + + height = pic->height; + source = pic->pixels[0]; + if (y < 0) + { + height += y; + source += pic->width*-y; + y = 0; + } + + dest = vid.buffer + y * vid.rowbytes + x; + + if (!pic->transparent) + { + for (v=0 ; vwidth); + dest += vid.rowbytes; + source += pic->width; + } + } + else + { + if (pic->width & 7) + { // general + for (v=0 ; vwidth ; u++) + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + dest[u] = tbyte; + + dest += vid.rowbytes; + source += pic->width; + } + } + else + { // unwound + for (v=0 ; vwidth ; u+=8) + { + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + dest[u] = tbyte; + if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR) + dest[u+1] = tbyte; + if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR) + dest[u+2] = tbyte; + if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR) + dest[u+3] = tbyte; + if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR) + dest[u+4] = tbyte; + if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR) + dest[u+5] = tbyte; + if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR) + dest[u+6] = tbyte; + if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR) + dest[u+7] = tbyte; + } + dest += vid.rowbytes; + source += pic->width; + } + } + } +} + +/* +============= +Draw_TileClear + +This repeats a 64*64 tile graphic to fill the screen around a sized down +refresh window. +============= +*/ +void Draw_TileClear (int x, int y, int w, int h, char *name) +{ + int i, j; + byte *psrc; + byte *pdest; + image_t *pic; + int x2; + + if (x < 0) + { + w += x; + x = 0; + } + if (y < 0) + { + h += y; + y = 0; + } + if (x + w > vid.width) + w = vid.width - x; + if (y + h > vid.height) + h = vid.height - y; + if (w <= 0 || h <= 0) + return; + + pic = Draw_FindPic (name); + if (!pic) + { + ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name); + return; + } + x2 = x + w; + pdest = vid.buffer + y*vid.rowbytes; + for (i=0 ; ipixels[0] + pic->width * ((i+y)&63); + for (j=x ; j vid.width) + w = vid.width - x; + if (y+h > vid.height) + h = vid.height - y; + if (x < 0) + { + w += x; + x = 0; + } + if (y < 0) + { + h += y; + y = 0; + } + if (w < 0 || h < 0) + return; + dest = vid.buffer + y*vid.rowbytes + x; + for (v=0 ; vu]; + mov ecx,ds:dword ptr[espan_t_count+ebx] + +; +; now start the FDIV for the end of the span +; + cmp ecx,16 + ja LSetupNotLast1 + + dec ecx + jz LCleanup1 ; if only one pixel, no need to start an FDIV + mov ds:dword ptr[spancountminus1],ecx + +; finish up the s and t calcs + fxch st(1) ; z*64k | 1/z | t/z | s/z + + fld st(0) ; z*64k | z*64k | 1/z | t/z | s/z + fmul st(0),st(4) ; s | z*64k | 1/z | t/z | s/z + fxch st(1) ; z*64k | s | 1/z | t/z | s/z + fmul st(0),st(3) ; t | s | 1/z | t/z | s/z + fxch st(1) ; s | t | 1/z | t/z | s/z + fistp ds:dword ptr[s] ; 1/z | t | t/z | s/z + fistp ds:dword ptr[t] ; 1/z | t/z | s/z + + fild ds:dword ptr[spancountminus1] + + fld ds:dword ptr[_d_tdivzstepu] ; C(d_tdivzstepu) | spancountminus1 + fld ds:dword ptr[_d_zistepu] ; C(d_zistepu) | C(d_tdivzstepu) | spancountminus1 + fmul st(0),st(2) ; C(d_zistepu)*scm1 | C(d_tdivzstepu) | scm1 + fxch st(1) ; C(d_tdivzstepu) | C(d_zistepu)*scm1 | scm1 + fmul st(0),st(2) ; C(d_tdivzstepu)*scm1 | C(d_zistepu)*scm1 | scm1 + fxch st(2) ; scm1 | C(d_zistepu)*scm1 | C(d_tdivzstepu)*scm1 + fmul ds:dword ptr[_d_sdivzstepu] ; C(d_sdivzstepu)*scm1 | C(d_zistepu)*scm1 | +; C(d_tdivzstepu)*scm1 + fxch st(1) ; C(d_zistepu)*scm1 | C(d_sdivzstepu)*scm1 | +; C(d_tdivzstepu)*scm1 + faddp st(3),st(0) ; C(d_sdivzstepu)*scm1 | C(d_tdivzstepu)*scm1 + fxch st(1) ; C(d_tdivzstepu)*scm1 | C(d_sdivzstepu)*scm1 + faddp st(3),st(0) ; C(d_sdivzstepu)*scm1 + faddp st(3),st(0) + + fld ds:dword ptr[fp_64k] + fdiv st(0),st(1) ; this is what we've gone to all this trouble to +; overlap + jmp LFDIVInFlight1 + +LCleanup1: +; finish up the s and t calcs + fxch st(1) ; z*64k | 1/z | t/z | s/z + + fld st(0) ; z*64k | z*64k | 1/z | t/z | s/z + fmul st(0),st(4) ; s | z*64k | 1/z | t/z | s/z + fxch st(1) ; z*64k | s | 1/z | t/z | s/z + fmul st(0),st(3) ; t | s | 1/z | t/z | s/z + fxch st(1) ; s | t | 1/z | t/z | s/z + fistp ds:dword ptr[s] ; 1/z | t | t/z | s/z + fistp ds:dword ptr[t] ; 1/z | t/z | s/z + jmp LFDIVInFlight1 + + align 4 +LSetupNotLast1: +; finish up the s and t calcs + fxch st(1) ; z*64k | 1/z | t/z | s/z + + fld st(0) ; z*64k | z*64k | 1/z | t/z | s/z + fmul st(0),st(4) ; s | z*64k | 1/z | t/z | s/z + fxch st(1) ; z*64k | s | 1/z | t/z | s/z + fmul st(0),st(3) ; t | s | 1/z | t/z | s/z + fxch st(1) ; s | t | 1/z | t/z | s/z + fistp ds:dword ptr[s] ; 1/z | t | t/z | s/z + fistp ds:dword ptr[t] ; 1/z | t/z | s/z + + fadd ds:dword ptr[zi16stepu] + fxch st(2) + fadd ds:dword ptr[sdivz16stepu] + fxch st(2) + fld ds:dword ptr[tdivz16stepu] + faddp st(2),st(0) + fld ds:dword ptr[fp_64k] + fdiv st(0),st(1) ; z = 1/1/z +; this is what we've gone to all this trouble to +; overlap +LFDIVInFlight1: + + add esi,ds:dword ptr[s] + add edx,ds:dword ptr[t] + mov ebx,ds:dword ptr[_bbextents] + mov ebp,ds:dword ptr[_bbextentt] + cmp esi,ebx + ja LClampHighOrLow0 +LClampReentry0: + mov ds:dword ptr[s],esi + mov ebx,ds:dword ptr[pbase] + shl esi,16 + cmp edx,ebp + mov ds:dword ptr[sfracf],esi + ja LClampHighOrLow1 +LClampReentry1: + mov ds:dword ptr[t],edx + mov esi,ds:dword ptr[s] ; sfrac = scans->sfrac; + shl edx,16 + mov eax,ds:dword ptr[t] ; tfrac = scans->tfrac; + sar esi,16 + mov ds:dword ptr[tfracf],edx + +; +; calculate the texture starting address +; + sar eax,16 + mov edx,ds:dword ptr[_cachewidth] + imul eax,edx ; (tfrac >> 16) * cachewidth + add esi,ebx + add esi,eax ; psource = pbase + (sfrac >> 16) + +; ((tfrac >> 16) * cachewidth); +; +; determine whether last span or not +; + cmp ecx,16 + jna LLastSegment + +; +; not the last segment; do full 16-wide segment +; +LNotLastSegment: + +; +; advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to +; get there +; + +; pick up after the FDIV that was left in flight previously + + fld st(0) ; duplicate it + fmul st(0),st(4) ; s = s/z * z + fxch st(1) + fmul st(0),st(3) ; t = t/z * z + fxch st(1) + fistp ds:dword ptr[snext] + fistp ds:dword ptr[tnext] + mov eax,ds:dword ptr[snext] + mov edx,ds:dword ptr[tnext] + + mov bl,ds:byte ptr[esi] ; get first source texel + sub ecx,16 ; count off this segments' pixels + mov ebp,ds:dword ptr[_sadjust] + mov ds:dword ptr[counttemp],ecx ; remember count of remaining pixels + + mov ecx,ds:dword ptr[_tadjust] + mov ds:byte ptr[edi],bl ; store first dest pixel + + add ebp,eax + add ecx,edx + + mov eax,ds:dword ptr[_bbextents] + mov edx,ds:dword ptr[_bbextentt] + + cmp ebp,4096 + jl LClampLow2 + cmp ebp,eax + ja LClampHigh2 +LClampReentry2: + + cmp ecx,4096 + jl LClampLow3 + cmp ecx,edx + ja LClampHigh3 +LClampReentry3: + + mov ds:dword ptr[snext],ebp + mov ds:dword ptr[tnext],ecx + + sub ebp,ds:dword ptr[s] + sub ecx,ds:dword ptr[t] + +; +; set up advancetable +; + mov eax,ecx + mov edx,ebp + sar eax,20 ; tstep >>= 16; + jz LZero + sar edx,20 ; sstep >>= 16; + mov ebx,ds:dword ptr[_cachewidth] + imul eax,ebx + jmp LSetUp1 + +LZero: + sar edx,20 ; sstep >>= 16; + mov ebx,ds:dword ptr[_cachewidth] + +LSetUp1: + + add eax,edx ; add in sstep +; (tstep >> 16) * cachewidth + (sstep >> 16); + mov edx,ds:dword ptr[tfracf] + mov ds:dword ptr[advancetable+4],eax ; advance base in t + add eax,ebx ; ((tstep >> 16) + 1) * cachewidth + +; (sstep >> 16); + shl ebp,12 ; left-justify sstep fractional part + mov ebx,ds:dword ptr[sfracf] + shl ecx,12 ; left-justify tstep fractional part + mov ds:dword ptr[advancetable],eax ; advance extra in t + + mov ds:dword ptr[tstep],ecx + add edx,ecx ; advance tfrac fractional part by tstep frac + + sbb ecx,ecx ; turn tstep carry into -1 (0 if none) + add ebx,ebp ; advance sfrac fractional part by sstep frac + adc esi,ds:dword ptr[advancetable+4+ecx*4] ; point to next source texel + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov al,ds:byte ptr[esi] + add ebx,ebp + mov ds:byte ptr[1+edi],al + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov ds:byte ptr[2+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov ds:byte ptr[3+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov ds:byte ptr[4+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov ds:byte ptr[5+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov ds:byte ptr[6+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov ds:byte ptr[7+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + +; +; start FDIV for end of next segment in flight, so it can overlap +; + mov ecx,ds:dword ptr[counttemp] + cmp ecx,16 ; more than one segment after this? + ja LSetupNotLast2 ; yes + + dec ecx + jz LFDIVInFlight2 ; if only one pixel, no need to start an FDIV + mov ds:dword ptr[spancountminus1],ecx + fild ds:dword ptr[spancountminus1] + + fld ds:dword ptr[_d_zistepu] ; C(d_zistepu) | spancountminus1 + fmul st(0),st(1) ; C(d_zistepu)*scm1 | scm1 + fld ds:dword ptr[_d_tdivzstepu] ; C(d_tdivzstepu) | C(d_zistepu)*scm1 | scm1 + fmul st(0),st(2) ; C(d_tdivzstepu)*scm1 | C(d_zistepu)*scm1 | scm1 + fxch st(1) ; C(d_zistepu)*scm1 | C(d_tdivzstepu)*scm1 | scm1 + faddp st(3),st(0) ; C(d_tdivzstepu)*scm1 | scm1 + fxch st(1) ; scm1 | C(d_tdivzstepu)*scm1 + fmul ds:dword ptr[_d_sdivzstepu] ; C(d_sdivzstepu)*scm1 | C(d_tdivzstepu)*scm1 + fxch st(1) ; C(d_tdivzstepu)*scm1 | C(d_sdivzstepu)*scm1 + faddp st(3),st(0) ; C(d_sdivzstepu)*scm1 + fld ds:dword ptr[fp_64k] ; 64k | C(d_sdivzstepu)*scm1 + fxch st(1) ; C(d_sdivzstepu)*scm1 | 64k + faddp st(4),st(0) ; 64k + + fdiv st(0),st(1) ; this is what we've gone to all this trouble to +; overlap + jmp LFDIVInFlight2 + + align 4 +LSetupNotLast2: + fadd ds:dword ptr[zi16stepu] + fxch st(2) + fadd ds:dword ptr[sdivz16stepu] + fxch st(2) + fld ds:dword ptr[tdivz16stepu] + faddp st(2),st(0) + fld ds:dword ptr[fp_64k] + fdiv st(0),st(1) ; z = 1/1/z +; this is what we've gone to all this trouble to +; overlap +LFDIVInFlight2: + mov ds:dword ptr[counttemp],ecx + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov ds:byte ptr[8+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov ds:byte ptr[9+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov ds:byte ptr[10+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov ds:byte ptr[11+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov ds:byte ptr[12+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov ds:byte ptr[13+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov ds:byte ptr[14+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edi,16 + mov ds:dword ptr[tfracf],edx + mov edx,ds:dword ptr[snext] + mov ds:dword ptr[sfracf],ebx + mov ebx,ds:dword ptr[tnext] + mov ds:dword ptr[s],edx + mov ds:dword ptr[t],ebx + + mov ecx,ds:dword ptr[counttemp] ; retrieve count + +; +; determine whether last span or not +; + cmp ecx,16 ; are there multiple segments remaining? + mov ds:byte ptr[-1+edi],al + ja LNotLastSegment ; yes + +; +; last segment of scan +; +LLastSegment: + +; +; advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to +; get there. The number of pixels left is variable, and we want to land on the +; last pixel, not step one past it, so we can't run into arithmetic problems +; + test ecx,ecx + jz LNoSteps ; just draw the last pixel and we're done + +; pick up after the FDIV that was left in flight previously + + + fld st(0) ; duplicate it + fmul st(0),st(4) ; s = s/z * z + fxch st(1) + fmul st(0),st(3) ; t = t/z * z + fxch st(1) + fistp ds:dword ptr[snext] + fistp ds:dword ptr[tnext] + + mov al,ds:byte ptr[esi] ; load first texel in segment + mov ebx,ds:dword ptr[_tadjust] + mov ds:byte ptr[edi],al ; store first pixel in segment + mov eax,ds:dword ptr[_sadjust] + + add eax,ds:dword ptr[snext] + add ebx,ds:dword ptr[tnext] + + mov ebp,ds:dword ptr[_bbextents] + mov edx,ds:dword ptr[_bbextentt] + + cmp eax,4096 + jl LClampLow4 + cmp eax,ebp + ja LClampHigh4 +LClampReentry4: + mov ds:dword ptr[snext],eax + + cmp ebx,4096 + jl LClampLow5 + cmp ebx,edx + ja LClampHigh5 +LClampReentry5: + + cmp ecx,1 ; don't bother + je LOnlyOneStep ; if two pixels in segment, there's only one step, +; of the segment length + sub eax,ds:dword ptr[s] + sub ebx,ds:dword ptr[t] + + add eax,eax ; convert to 15.17 format so multiply by 1.31 + add ebx,ebx ; reciprocal yields 16.48 + + imul ds:dword ptr[reciprocal_table_16-8+ecx*4] ; sstep = (snext - s) / +; (spancount-1) + mov ebp,edx + + mov eax,ebx + imul ds:dword ptr[reciprocal_table_16-8+ecx*4] ; tstep = (tnext - t) / +; (spancount-1) +LSetEntryvec: +; +; set up advancetable +; + mov ebx,ds:dword ptr[entryvec_table_16+ecx*4] + mov eax,edx + mov ds:dword ptr[jumptemp],ebx ; entry point into code for RET later + mov ecx,ebp + sar edx,16 ; tstep >>= 16; + mov ebx,ds:dword ptr[_cachewidth] + sar ecx,16 ; sstep >>= 16; + imul edx,ebx + + add edx,ecx ; add in sstep +; (tstep >> 16) * cachewidth + (sstep >> 16); + mov ecx,ds:dword ptr[tfracf] + mov ds:dword ptr[advancetable+4],edx ; advance base in t + add edx,ebx ; ((tstep >> 16) + 1) * cachewidth + +; (sstep >> 16); + shl ebp,16 ; left-justify sstep fractional part + mov ebx,ds:dword ptr[sfracf] + shl eax,16 ; left-justify tstep fractional part + mov ds:dword ptr[advancetable],edx ; advance extra in t + + mov ds:dword ptr[tstep],eax + mov edx,ecx + add edx,eax + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + jmp dword ptr[jumptemp] ; jump to the number-of-pixels handler + +;---------------------------------------- + +LNoSteps: + mov al,ds:byte ptr[esi] ; load first texel in segment + sub edi,15 ; adjust for hardwired offset + jmp LEndSpan + + +LOnlyOneStep: + sub eax,ds:dword ptr[s] + sub ebx,ds:dword ptr[t] + mov ebp,eax + mov edx,ebx + jmp LSetEntryvec + +;---------------------------------------- + + public Entry2_16, Entry3_16, Entry4_16, Entry5_16 + public Entry6_16, Entry7_16, Entry8_16, Entry9_16 + public Entry10_16, Entry11_16, Entry12_16, Entry13_16 + public Entry14_16, Entry15_16, Entry16_16 + +Entry2_16: + sub edi,14 ; adjust for hardwired offsets + mov al,ds:byte ptr[esi] + jmp LEntry2_16 + +;---------------------------------------- + +Entry3_16: + sub edi,13 ; adjust for hardwired offsets + add edx,eax + mov al,ds:byte ptr[esi] + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + jmp LEntry3_16 + +;---------------------------------------- + +Entry4_16: + sub edi,12 ; adjust for hardwired offsets + add edx,eax + mov al,ds:byte ptr[esi] + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] + jmp LEntry4_16 + +;---------------------------------------- + +Entry5_16: + sub edi,11 ; adjust for hardwired offsets + add edx,eax + mov al,ds:byte ptr[esi] + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] + jmp LEntry5_16 + +;---------------------------------------- + +Entry6_16: + sub edi,10 ; adjust for hardwired offsets + add edx,eax + mov al,ds:byte ptr[esi] + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] + jmp LEntry6_16 + +;---------------------------------------- + +Entry7_16: + sub edi,9 ; adjust for hardwired offsets + add edx,eax + mov al,ds:byte ptr[esi] + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] + jmp LEntry7_16 + +;---------------------------------------- + +Entry8_16: + sub edi,8 ; adjust for hardwired offsets + add edx,eax + mov al,ds:byte ptr[esi] + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] + jmp LEntry8_16 + +;---------------------------------------- + +Entry9_16: + sub edi,7 ; adjust for hardwired offsets + add edx,eax + mov al,ds:byte ptr[esi] + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] + jmp LEntry9_16 + +;---------------------------------------- + +Entry10_16: + sub edi,6 ; adjust for hardwired offsets + add edx,eax + mov al,ds:byte ptr[esi] + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] + jmp LEntry10_16 + +;---------------------------------------- + +Entry11_16: + sub edi,5 ; adjust for hardwired offsets + add edx,eax + mov al,ds:byte ptr[esi] + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] + jmp LEntry11_16 + +;---------------------------------------- + +Entry12_16: + sub edi,4 ; adjust for hardwired offsets + add edx,eax + mov al,ds:byte ptr[esi] + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] + jmp LEntry12_16 + +;---------------------------------------- + +Entry13_16: + sub edi,3 ; adjust for hardwired offsets + add edx,eax + mov al,ds:byte ptr[esi] + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] + jmp LEntry13_16 + +;---------------------------------------- + +Entry14_16: + sub edi,2 ; adjust for hardwired offsets + add edx,eax + mov al,ds:byte ptr[esi] + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] + jmp LEntry14_16 + +;---------------------------------------- + +Entry15_16: + dec edi ; adjust for hardwired offsets + add edx,eax + mov al,ds:byte ptr[esi] + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] + jmp LEntry15_16 + +;---------------------------------------- + +Entry16_16: + add edx,eax + mov al,ds:byte ptr[esi] + sbb ecx,ecx + add ebx,ebp + adc esi,ds:dword ptr[advancetable+4+ecx*4] + + add edx,ds:dword ptr[tstep] + sbb ecx,ecx + mov ds:byte ptr[1+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] +LEntry15_16: + sbb ecx,ecx + mov ds:byte ptr[2+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] +LEntry14_16: + sbb ecx,ecx + mov ds:byte ptr[3+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] +LEntry13_16: + sbb ecx,ecx + mov ds:byte ptr[4+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] +LEntry12_16: + sbb ecx,ecx + mov ds:byte ptr[5+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] +LEntry11_16: + sbb ecx,ecx + mov ds:byte ptr[6+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] +LEntry10_16: + sbb ecx,ecx + mov ds:byte ptr[7+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] +LEntry9_16: + sbb ecx,ecx + mov ds:byte ptr[8+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] +LEntry8_16: + sbb ecx,ecx + mov ds:byte ptr[9+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] +LEntry7_16: + sbb ecx,ecx + mov ds:byte ptr[10+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] +LEntry6_16: + sbb ecx,ecx + mov ds:byte ptr[11+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] +LEntry5_16: + sbb ecx,ecx + mov ds:byte ptr[12+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] + add edx,ds:dword ptr[tstep] +LEntry4_16: + sbb ecx,ecx + mov ds:byte ptr[13+edi],al + add ebx,ebp + mov al,ds:byte ptr[esi] + adc esi,ds:dword ptr[advancetable+4+ecx*4] +LEntry3_16: + mov ds:byte ptr[14+edi],al + mov al,ds:byte ptr[esi] +LEntry2_16: + +LEndSpan: + +; +; clear s/z, t/z, 1/z from FP stack +; + fstp st(0) + fstp st(0) + fstp st(0) + + mov ebx,ds:dword ptr[pspantemp] ; restore spans pointer + mov ebx,ds:dword ptr[espan_t_pnext+ebx] ; point to next span + test ebx,ebx ; any more spans? + mov ds:byte ptr[15+edi],al + jnz LSpanLoop ; more spans + + pop ebx ; restore register variables + pop esi + pop edi + pop ebp ; restore the caller's stack frame + ret + + +;---------------------------------------------------------------------- +; 8-bpp horizontal span z drawing codefor polygons, with no transparency. +; +; Assumes there is at least one span in pzspans, and that every span +; contains at least one pixel +;---------------------------------------------------------------------- + + + +; z-clamp on a non-negative gradient span +LClamp: + mov edx,040000000h + xor ebx,ebx + fstp st(0) + jmp LZDraw + +; z-clamp on a negative gradient span +LClampNeg: + mov edx,040000000h + xor ebx,ebx + fstp st(0) + jmp LZDrawNeg + + +pzspans equ 4+16 + + public _D_DrawZSpans +_D_DrawZSpans: + push ebp ; preserve caller's stack frame + push edi + push esi ; preserve register variables + push ebx + + fld ds:dword ptr[_d_zistepu] + mov eax,ds:dword ptr[_d_zistepu] + mov esi,ds:dword ptr[pzspans+esp] + test eax,eax + jz LFNegSpan + + fmul ds:dword ptr[Float2ToThe31nd] + fistp ds:dword ptr[izistep] ; note: we are relying on FP exceptions being turned +; off here to avoid range problems + mov ebx,ds:dword ptr[izistep] ; remains loaded for all spans + +LFSpanLoop: +; set up the initial 1/z value + fild ds:dword ptr[espan_t_v+esi] + fild ds:dword ptr[espan_t_u+esi] + mov ecx,ds:dword ptr[espan_t_v+esi] + mov edi,ds:dword ptr[_d_pzbuffer] + fmul ds:dword ptr[_d_zistepu] + fxch st(1) + fmul ds:dword ptr[_d_zistepv] + fxch st(1) + fadd ds:dword ptr[_d_ziorigin] + imul ecx,ds:dword ptr[_d_zrowbytes] + faddp st(1),st(0) + +; clamp if z is nearer than 2 (1/z > 0.5) + fcom ds:dword ptr[float_point5] + add edi,ecx + mov edx,ds:dword ptr[espan_t_u+esi] + add edx,edx ; word count + mov ecx,ds:dword ptr[espan_t_count+esi] + add edi,edx ; pdest = &pdestspan[scans->u]; + push esi ; preserve spans pointer + fnstsw ax + test ah,045h + jz LClamp + + fmul ds:dword ptr[Float2ToThe31nd] + fistp ds:dword ptr[izi] ; note: we are relying on FP exceptions being turned +; off here to avoid problems when the span is closer +; than 1/(2**31) + mov edx,ds:dword ptr[izi] + +; at this point: +; %ebx = izistep +; %ecx = count +; %edx = izi +; %edi = pdest + +LZDraw: + +; do a single pixel up front, if necessary to dword align the destination + test edi,2 + jz LFMiddle + mov eax,edx + add edx,ebx + shr eax,16 + dec ecx + mov ds:word ptr[edi],ax + add edi,2 + +; do middle a pair of aligned dwords at a time +LFMiddle: + push ecx + shr ecx,1 ; count / 2 + jz LFLast ; no aligned dwords to do + shr ecx,1 ; (count / 2) / 2 + jnc LFMiddleLoop ; even number of aligned dwords to do + + mov eax,edx + add edx,ebx + shr eax,16 + mov esi,edx + add edx,ebx + and esi,0FFFF0000h + or eax,esi + mov ds:dword ptr[edi],eax + add edi,4 + and ecx,ecx + jz LFLast + +LFMiddleLoop: + mov eax,edx + add edx,ebx + shr eax,16 + mov esi,edx + add edx,ebx + and esi,0FFFF0000h + or eax,esi + mov ebp,edx + mov ds:dword ptr[edi],eax + add edx,ebx + shr ebp,16 + mov esi,edx + add edx,ebx + and esi,0FFFF0000h + or ebp,esi + mov ds:dword ptr[4+edi],ebp ; FIXME: eliminate register contention + add edi,8 + + dec ecx + jnz LFMiddleLoop + +LFLast: + pop ecx ; retrieve count + pop esi ; retrieve span pointer + +; do the last, unaligned pixel, if there is one + and ecx,1 ; is there an odd pixel left to do? + jz LFSpanDone ; no + shr edx,16 + mov ds:word ptr[edi],dx ; do the final pixel's z + +LFSpanDone: + mov esi,ds:dword ptr[espan_t_pnext+esi] + test esi,esi + jnz LFSpanLoop + + jmp LFDone + +LFNegSpan: + fmul ds:dword ptr[FloatMinus2ToThe31nd] + fistp ds:dword ptr[izistep] ; note: we are relying on FP exceptions being turned +; off here to avoid range problems + mov ebx,ds:dword ptr[izistep] ; remains loaded for all spans + +LFNegSpanLoop: +; set up the initial 1/z value + fild ds:dword ptr[espan_t_v+esi] + fild ds:dword ptr[espan_t_u+esi] + mov ecx,ds:dword ptr[espan_t_v+esi] + mov edi,ds:dword ptr[_d_pzbuffer] + fmul ds:dword ptr[_d_zistepu] + fxch st(1) + fmul ds:dword ptr[_d_zistepv] + fxch st(1) + fadd ds:dword ptr[_d_ziorigin] + imul ecx,ds:dword ptr[_d_zrowbytes] + faddp st(1),st(0) + +; clamp if z is nearer than 2 (1/z > 0.5) + fcom ds:dword ptr[float_point5] + add edi,ecx + mov edx,ds:dword ptr[espan_t_u+esi] + add edx,edx ; word count + mov ecx,ds:dword ptr[espan_t_count+esi] + add edi,edx ; pdest = &pdestspan[scans->u]; + push esi ; preserve spans pointer + fnstsw ax + test ah,045h + jz LClampNeg + + fmul ds:dword ptr[Float2ToThe31nd] + fistp ds:dword ptr[izi] ; note: we are relying on FP exceptions being turned +; off here to avoid problems when the span is closer +; than 1/(2**31) + mov edx,ds:dword ptr[izi] + +; at this point: +; %ebx = izistep +; %ecx = count +; %edx = izi +; %edi = pdest + +LZDrawNeg: + +; do a single pixel up front, if necessary to dword align the destination + test edi,2 + jz LFNegMiddle + mov eax,edx + sub edx,ebx + shr eax,16 + dec ecx + mov ds:word ptr[edi],ax + add edi,2 + +; do middle a pair of aligned dwords at a time +LFNegMiddle: + push ecx + shr ecx,1 ; count / 2 + jz LFNegLast ; no aligned dwords to do + shr ecx,1 ; (count / 2) / 2 + jnc LFNegMiddleLoop ; even number of aligned dwords to do + + mov eax,edx + sub edx,ebx + shr eax,16 + mov esi,edx + sub edx,ebx + and esi,0FFFF0000h + or eax,esi + mov ds:dword ptr[edi],eax + add edi,4 + and ecx,ecx + jz LFNegLast + +LFNegMiddleLoop: + mov eax,edx + sub edx,ebx + shr eax,16 + mov esi,edx + sub edx,ebx + and esi,0FFFF0000h + or eax,esi + mov ebp,edx + mov ds:dword ptr[edi],eax + sub edx,ebx + shr ebp,16 + mov esi,edx + sub edx,ebx + and esi,0FFFF0000h + or ebp,esi + mov ds:dword ptr[4+edi],ebp ; FIXME: eliminate register contention + add edi,8 + + dec ecx + jnz LFNegMiddleLoop + +LFNegLast: + pop ecx ; retrieve count + pop esi ; retrieve span pointer + +; do the last, unaligned pixel, if there is one + and ecx,1 ; is there an odd pixel left to do? + jz LFNegSpanDone ; no + shr edx,16 + mov ds:word ptr[edi],dx ; do the final pixel's z + +LFNegSpanDone: + mov esi,ds:dword ptr[espan_t_pnext+esi] + test esi,esi + jnz LFNegSpanLoop + +LFDone: + pop ebx ; restore register variables + pop esi + pop edi + pop ebp ; restore the caller's stack frame + ret + + + +_TEXT ENDS +endif ;id386 + END diff --git a/ref_soft/r_drawa.asm b/ref_soft/r_drawa.asm new file mode 100644 index 000000000..ab25f178a --- /dev/null +++ b/ref_soft/r_drawa.asm @@ -0,0 +1,822 @@ + .386P + .model FLAT +; +; r_drawa.s +; x86 assembly-language edge clipping and emission code +; + +include qasm.inc +include d_if.inc + +if id386 + +; !!! if these are changed, they must be changed in r_draw.c too !!! +FULLY_CLIPPED_CACHED equ 080000000h +FRAMECOUNT_MASK equ 07FFFFFFFh + +_DATA SEGMENT + +Ld0 dd 0.0 +Ld1 dd 0.0 +Lstack dd 0 +Lfp_near_clip dd NEAR_CLIP +Lceilv0 dd 0 +Lv dd 0 +Lu0 dd 0 +Lv0 dd 0 +Lzi0 dd 0 + +_DATA ENDS +_TEXT SEGMENT + +;---------------------------------------------------------------------- +; edge clipping code +;---------------------------------------------------------------------- + +pv0 equ 4+12 +pv1 equ 8+12 +clip equ 12+12 + + align 4 + public _R_ClipEdge +_R_ClipEdge: + push esi ; preserve register variables + push edi + push ebx + mov ds:dword ptr[Lstack],esp ; for clearing the stack later + +; float d0, d1, f; +; mvertex_t clipvert; + + mov ebx,ds:dword ptr[clip+esp] + mov esi,ds:dword ptr[pv0+esp] + mov edx,ds:dword ptr[pv1+esp] + +; if (clip) +; { + test ebx,ebx + jz Lemit + +; do +; { + +Lcliploop: + +; d0 = DotProduct (pv0->position, clip->normal) - clip->dist; +; d1 = DotProduct (pv1->position, clip->normal) - clip->dist; + fld ds:dword ptr[mv_position+0+esi] + fmul ds:dword ptr[cp_normal+0+ebx] + fld ds:dword ptr[mv_position+4+esi] + fmul ds:dword ptr[cp_normal+4+ebx] + fld ds:dword ptr[mv_position+8+esi] + fmul ds:dword ptr[cp_normal+8+ebx] + fxch st(1) + faddp st(2),st(0) ; d0mul2 | d0add0 + + fld ds:dword ptr[mv_position+0+edx] + fmul ds:dword ptr[cp_normal+0+ebx] + fld ds:dword ptr[mv_position+4+edx] + fmul ds:dword ptr[cp_normal+4+ebx] + fld ds:dword ptr[mv_position+8+edx] + fmul ds:dword ptr[cp_normal+8+ebx] + fxch st(1) + faddp st(2),st(0) ; d1mul2 | d1add0 | d0mul2 | d0add0 + fxch st(3) ; d0add0 | d1add0 | d0mul2 | d1mul2 + + faddp st(2),st(0) ; d1add0 | dot0 | d1mul2 + faddp st(2),st(0) ; dot0 | dot1 + + fsub ds:dword ptr[cp_dist+ebx] ; d0 | dot1 + fxch st(1) ; dot1 | d0 + fsub ds:dword ptr[cp_dist+ebx] ; d1 | d0 + fxch st(1) + fstp ds:dword ptr[Ld0] + fstp ds:dword ptr[Ld1] + +; if (d0 >= 0) +; { + mov eax,ds:dword ptr[Ld0] + mov ecx,ds:dword ptr[Ld1] + or ecx,eax + js Lp2 + +; both points are unclipped + +Lcontinue: + +; +; R_ClipEdge (&clipvert, pv1, clip->next); +; return; +; } +; } while ((clip = clip->next) != NULL); + mov ebx,ds:dword ptr[cp_next+ebx] + test ebx,ebx + jnz Lcliploop + +; } + +;// add the edge +; R_EmitEdge (pv0, pv1); +Lemit: + +; +; set integer rounding to ceil mode, set to single precision +; +; FIXME: do away with by manually extracting integers from floats? +; FIXME: set less often + fldcw ds:word ptr[_fpu_ceil_cw] + +; edge_t *edge, *pcheck; +; int u_check; +; float u, u_step; +; vec3_t local, transformed; +; float *world; +; int v, v2, ceilv0; +; float scale, lzi0, u0, v0; +; int side; + +; if (r_lastvertvalid) +; { + cmp ds:dword ptr[_r_lastvertvalid],0 + jz LCalcFirst + +; u0 = r_u1; +; v0 = r_v1; +; lzi0 = r_lzi1; +; ceilv0 = r_ceilv1; + mov eax,ds:dword ptr[_r_lzi1] + mov ecx,ds:dword ptr[_r_u1] + mov ds:dword ptr[Lzi0],eax + mov ds:dword ptr[Lu0],ecx + mov ecx,ds:dword ptr[_r_v1] + mov eax,ds:dword ptr[_r_ceilv1] + mov ds:dword ptr[Lv0],ecx + mov ds:dword ptr[Lceilv0],eax + jmp LCalcSecond + +; } + +LCalcFirst: + +; else +; { +; world = &pv0->position[0]; + + call near ptr LTransformAndProject ; v0 | lzi0 | u0 + + fst ds:dword ptr[Lv0] + fxch st(2) ; u0 | lzi0 | v0 + fstp ds:dword ptr[Lu0] ; lzi0 | v0 + fstp ds:dword ptr[Lzi0] ; v0 + +; ceilv0 = (int)(v0 - 2000) + 2000; // ceil(v0); + fistp ds:dword ptr[Lceilv0] + +; } + +LCalcSecond: + +; world = &pv1->position[0]; + mov esi,edx + + call near ptr LTransformAndProject ; v1 | lzi1 | u1 + + fld ds:dword ptr[Lu0] ; u0 | v1 | lzi1 | u1 + fxch st(3) ; u1 | v1 | lzi1 | u0 + fld ds:dword ptr[Lzi0] ; lzi0 | u1 | v1 | lzi1 | u0 + fxch st(3) ; lzi1 | u1 | v1 | lzi0 | u0 + fld ds:dword ptr[Lv0] ; v0 | lzi1 | u1 | v1 | lzi0 | u0 + fxch st(3) ; v1 | lzi1 | u1 | v0 | lzi0 | u0 + +; r_ceilv1 = (int)(r_v1 - 2000) + 2000; // ceil(r_v1); + fist ds:dword ptr[_r_ceilv1] + + fldcw ds:word ptr[_fpu_chop_cw] ; put back normal floating-point state + + fst ds:dword ptr[_r_v1] + fxch st(4) ; lzi0 | lzi1 | u1 | v0 | v1 | u0 + +; if (r_lzi1 > lzi0) +; lzi0 = r_lzi1; + fcom st(1) + fnstsw ax + test ah,1 + jz LP0 + fstp st(0) + fld st(0) +LP0: + + fxch st(1) ; lzi1 | lzi0 | u1 | v0 | v1 | u0 + fstp ds:dword ptr[_r_lzi1] ; lzi0 | u1 | v0 | v1 | u0 + fxch st(1) + fst ds:dword ptr[_r_u1] + fxch st(1) + +; if (lzi0 > r_nearzi) // for mipmap finding +; r_nearzi = lzi0; + fcom ds:dword ptr[_r_nearzi] + fnstsw ax + test ah,045h + jnz LP1 + fst ds:dword ptr[_r_nearzi] +LP1: + +; // for right edges, all we want is the effect on 1/z +; if (r_nearzionly) +; return; + mov eax,ds:dword ptr[_r_nearzionly] + test eax,eax + jz LP2 +LPop5AndDone: + mov eax,ds:dword ptr[_cacheoffset] + mov edx,ds:dword ptr[_r_framecount] + cmp eax,07FFFFFFFh + jz LDoPop + and edx,offset FRAMECOUNT_MASK + or edx,offset FULLY_CLIPPED_CACHED + mov ds:dword ptr[_cacheoffset],edx + +LDoPop: + fstp st(0) ; u1 | v0 | v1 | u0 + fstp st(0) ; v0 | v1 | u0 + fstp st(0) ; v1 | u0 + fstp st(0) ; u0 + fstp st(0) + jmp Ldone + +LP2: + +; // create the edge +; if (ceilv0 == r_ceilv1) +; return; // horizontal edge + mov ebx,ds:dword ptr[Lceilv0] + mov edi,ds:dword ptr[_edge_p] + mov ecx,ds:dword ptr[_r_ceilv1] + mov edx,edi + mov esi,ds:dword ptr[_r_pedge] + add edx,offset et_size + cmp ebx,ecx + jz LPop5AndDone + + mov eax,ds:dword ptr[_r_pedge] + mov ds:dword ptr[et_owner+edi],eax + +; side = ceilv0 > r_ceilv1; +; +; edge->nearzi = lzi0; + fstp ds:dword ptr[et_nearzi+edi] ; u1 | v0 | v1 | u0 + +; if (side == 1) +; { + jc LSide0 + +LSide1: + +; // leading edge (go from p2 to p1) + +; u_step = ((u0 - r_u1) / (v0 - r_v1)); + fsubp st(3),st(0) ; v0 | v1 | u0-u1 + fsub st(0),st(1) ; v0-v1 | v1 | u0-u1 + fdivp st(2),st(0) ; v1 | ustep + +; r_emitted = 1; + mov ds:dword ptr[_r_emitted],1 + +; edge = edge_p++; + mov ds:dword ptr[_edge_p],edx + +; pretouch next edge + mov eax,ds:dword ptr[edx] + +; v2 = ceilv0 - 1; +; v = r_ceilv1; + mov eax,ecx + lea ecx,ds:dword ptr[-1+ebx] + mov ebx,eax + +; edge->surfs[0] = 0; +; edge->surfs[1] = surface_p - surfaces; + mov eax,ds:dword ptr[_surface_p] + mov esi,ds:dword ptr[_surfaces] + sub edx,edx + sub eax,esi + shr eax,offset SURF_T_SHIFT + mov ds:dword ptr[et_surfs+edi],edx + mov ds:dword ptr[et_surfs+2+edi],eax + + sub esi,esi + +; u = r_u1 + ((float)v - r_v1) * u_step; + mov ds:dword ptr[Lv],ebx + fild ds:dword ptr[Lv] ; v | v1 | ustep + fsubrp st(1),st(0) ; v-v1 | ustep + fmul st(0),st(1) ; (v-v1)*ustep | ustep + fadd ds:dword ptr[_r_u1] ; u | ustep + + jmp LSideDone + +; } + +LSide0: + +; else +; { +; // trailing edge (go from p1 to p2) + +; u_step = ((r_u1 - u0) / (r_v1 - v0)); + fsub st(0),st(3) ; u1-u0 | v0 | v1 | u0 + fxch st(2) ; v1 | v0 | u1-u0 | u0 + fsub st(0),st(1) ; v1-v0 | v0 | u1-u0 | u0 + fdivp st(2),st(0) ; v0 | ustep | u0 + +; r_emitted = 1; + mov ds:dword ptr[_r_emitted],1 + +; edge = edge_p++; + mov ds:dword ptr[_edge_p],edx + +; pretouch next edge + mov eax,ds:dword ptr[edx] + +; v = ceilv0; +; v2 = r_ceilv1 - 1; + dec ecx + +; edge->surfs[0] = surface_p - surfaces; +; edge->surfs[1] = 0; + mov eax,ds:dword ptr[_surface_p] + mov esi,ds:dword ptr[_surfaces] + sub edx,edx + sub eax,esi + shr eax,offset SURF_T_SHIFT + mov ds:dword ptr[et_surfs+2+edi],edx + mov ds:dword ptr[et_surfs+edi],eax + + mov esi,1 + +; u = u0 + ((float)v - v0) * u_step; + mov ds:dword ptr[Lv],ebx + fild ds:dword ptr[Lv] ; v | v0 | ustep | u0 + fsubrp st(1),st(0) ; v-v0 | ustep | u0 + fmul st(0),st(1) ; (v-v0)*ustep | ustep | u0 + faddp st(2),st(0) ; ustep | u + fxch st(1) ; u | ustep + +; } + +LSideDone: + +; edge->u_step = u_step*0x100000; +; edge->u = u*0x100000 + 0xFFFFF; + + fmul ds:dword ptr[fp_1m] ; u*0x100000 | ustep + fxch st(1) ; ustep | u*0x100000 + fmul ds:dword ptr[fp_1m] ; ustep*0x100000 | u*0x100000 + fxch st(1) ; u*0x100000 | ustep*0x100000 + fadd ds:dword ptr[fp_1m_minus_1] ; u*0x100000 + 0xFFFFF | ustep*0x100000 + fxch st(1) ; ustep*0x100000 | u*0x100000 + 0xFFFFF + fistp ds:dword ptr[et_u_step+edi] ; u*0x100000 + 0xFFFFF + fistp ds:dword ptr[et_u+edi] + +; // we need to do this to avoid stepping off the edges if a very nearly +; // horizontal edge is less than epsilon above a scan, and numeric error +; // causes it to incorrectly extend to the scan, and the extension of the +; // line goes off the edge of the screen +; // FIXME: is this actually needed? +; if (edge->u < r_refdef.vrect_x_adj_shift20) +; edge->u = r_refdef.vrect_x_adj_shift20; +; if (edge->u > r_refdef.vrectright_adj_shift20) +; edge->u = r_refdef.vrectright_adj_shift20; + mov eax,ds:dword ptr[et_u+edi] + mov edx,ds:dword ptr[_r_refdef+rd_vrect_x_adj_shift20] + cmp eax,edx + jl LP4 + mov edx,ds:dword ptr[_r_refdef+rd_vrectright_adj_shift20] + cmp eax,edx + jng LP5 +LP4: + mov ds:dword ptr[et_u+edi],edx + mov eax,edx +LP5: + +; // sort the edge in normally +; u_check = edge->u; +; +; if (edge->surfs[0]) +; u_check++; // sort trailers after leaders + add eax,esi + +; if (!newedges[v] || newedges[v]->u >= u_check) +; { + mov esi,ds:dword ptr[_newedges+ebx*4] + test esi,esi + jz LDoFirst + cmp ds:dword ptr[et_u+esi],eax + jl LNotFirst +LDoFirst: + +; edge->next = newedges[v]; +; newedges[v] = edge; + mov ds:dword ptr[et_next+edi],esi + mov ds:dword ptr[_newedges+ebx*4],edi + + jmp LSetRemove + +; } + +LNotFirst: + +; else +; { +; pcheck = newedges[v]; +; +; while (pcheck->next && pcheck->next->u < u_check) +; pcheck = pcheck->next; +LFindInsertLoop: + mov edx,esi + mov esi,ds:dword ptr[et_next+esi] + test esi,esi + jz LInsertFound + cmp ds:dword ptr[et_u+esi],eax + jl LFindInsertLoop + +LInsertFound: + +; edge->next = pcheck->next; +; pcheck->next = edge; + mov ds:dword ptr[et_next+edi],esi + mov ds:dword ptr[et_next+edx],edi + +; } + +LSetRemove: + +; edge->nextremove = removeedges[v2]; +; removeedges[v2] = edge; + mov eax,ds:dword ptr[_removeedges+ecx*4] + mov ds:dword ptr[_removeedges+ecx*4],edi + mov ds:dword ptr[et_nextremove+edi],eax + +Ldone: + mov esp,ds:dword ptr[Lstack] ; clear temporary variables from stack + + pop ebx ; restore register variables + pop edi + pop esi + ret + +; at least one point is clipped + +Lp2: + test eax,eax + jns Lp1 + +; else +; { +; // point 0 is clipped + +; if (d1 < 0) +; { + mov eax,ds:dword ptr[Ld1] + test eax,eax + jns Lp3 + +; // both points are clipped +; // we do cache fully clipped edges +; if (!leftclipped) + mov eax,ds:dword ptr[_r_leftclipped] + mov ecx,ds:dword ptr[_r_pedge] + test eax,eax + jnz Ldone + +; r_pedge->framecount = r_framecount; + mov eax,ds:dword ptr[_r_framecount] + and eax,offset FRAMECOUNT_MASK + or eax,offset FULLY_CLIPPED_CACHED + mov ds:dword ptr[_cacheoffset],eax + +; return; + jmp Ldone + +; } + +Lp1: + +; // point 0 is unclipped +; if (d1 >= 0) +; { +; // both points are unclipped +; continue; + +; // only point 1 is clipped + +; f = d0 / (d0 - d1); + fld ds:dword ptr[Ld0] + fld ds:dword ptr[Ld1] + fsubr st(0),st(1) + +; // we don't cache partially clipped edges + mov ds:dword ptr[_cacheoffset],07FFFFFFFh + + fdivp st(1),st(0) + + sub esp,offset mv_size ; allocate space for clipvert + +; clipvert.position[0] = pv0->position[0] + +; f * (pv1->position[0] - pv0->position[0]); +; clipvert.position[1] = pv0->position[1] + +; f * (pv1->position[1] - pv0->position[1]); +; clipvert.position[2] = pv0->position[2] + +; f * (pv1->position[2] - pv0->position[2]); + fld ds:dword ptr[mv_position+8+edx] + fsub ds:dword ptr[mv_position+8+esi] + fld ds:dword ptr[mv_position+4+edx] + fsub ds:dword ptr[mv_position+4+esi] + fld ds:dword ptr[mv_position+0+edx] + fsub ds:dword ptr[mv_position+0+esi] ; 0 | 1 | 2 + +; replace pv1 with the clip point + mov edx,esp + mov eax,ds:dword ptr[cp_leftedge+ebx] + test al,al + + fmul st(0),st(3) + fxch st(1) ; 1 | 0 | 2 + fmul st(0),st(3) + fxch st(2) ; 2 | 0 | 1 + fmulp st(3),st(0) ; 0 | 1 | 2 + fadd ds:dword ptr[mv_position+0+esi] + fxch st(1) ; 1 | 0 | 2 + fadd ds:dword ptr[mv_position+4+esi] + fxch st(2) ; 2 | 0 | 1 + fadd ds:dword ptr[mv_position+8+esi] + fxch st(1) ; 0 | 2 | 1 + fstp ds:dword ptr[mv_position+0+esp] ; 2 | 1 + fstp ds:dword ptr[mv_position+8+esp] ; 1 + fstp ds:dword ptr[mv_position+4+esp] + +; if (clip->leftedge) +; { + jz Ltestright + +; r_leftclipped = true; +; r_leftexit = clipvert; + mov ds:dword ptr[_r_leftclipped],1 + mov eax,ds:dword ptr[mv_position+0+esp] + mov ds:dword ptr[_r_leftexit+mv_position+0],eax + mov eax,ds:dword ptr[mv_position+4+esp] + mov ds:dword ptr[_r_leftexit+mv_position+4],eax + mov eax,ds:dword ptr[mv_position+8+esp] + mov ds:dword ptr[_r_leftexit+mv_position+8],eax + + jmp Lcontinue + +; } + +Ltestright: +; else if (clip->rightedge) +; { + test ah,ah + jz Lcontinue + +; r_rightclipped = true; +; r_rightexit = clipvert; + mov ds:dword ptr[_r_rightclipped],1 + mov eax,ds:dword ptr[mv_position+0+esp] + mov ds:dword ptr[_r_rightexit+mv_position+0],eax + mov eax,ds:dword ptr[mv_position+4+esp] + mov ds:dword ptr[_r_rightexit+mv_position+4],eax + mov eax,ds:dword ptr[mv_position+8+esp] + mov ds:dword ptr[_r_rightexit+mv_position+8],eax + +; } +; +; R_ClipEdge (pv0, &clipvert, clip->next); +; return; +; } + jmp Lcontinue + +; } + +Lp3: + +; // only point 0 is clipped +; r_lastvertvalid = false; + + mov ds:dword ptr[_r_lastvertvalid],0 + +; f = d0 / (d0 - d1); + fld ds:dword ptr[Ld0] + fld ds:dword ptr[Ld1] + fsubr st(0),st(1) + +; // we don't cache partially clipped edges + mov ds:dword ptr[_cacheoffset],07FFFFFFFh + + fdivp st(1),st(0) + + sub esp,offset mv_size ; allocate space for clipvert + +; clipvert.position[0] = pv0->position[0] + +; f * (pv1->position[0] - pv0->position[0]); +; clipvert.position[1] = pv0->position[1] + +; f * (pv1->position[1] - pv0->position[1]); +; clipvert.position[2] = pv0->position[2] + +; f * (pv1->position[2] - pv0->position[2]); + fld ds:dword ptr[mv_position+8+edx] + fsub ds:dword ptr[mv_position+8+esi] + fld ds:dword ptr[mv_position+4+edx] + fsub ds:dword ptr[mv_position+4+esi] + fld ds:dword ptr[mv_position+0+edx] + fsub ds:dword ptr[mv_position+0+esi] ; 0 | 1 | 2 + + mov eax,ds:dword ptr[cp_leftedge+ebx] + test al,al + + fmul st(0),st(3) + fxch st(1) ; 1 | 0 | 2 + fmul st(0),st(3) + fxch st(2) ; 2 | 0 | 1 + fmulp st(3),st(0) ; 0 | 1 | 2 + fadd ds:dword ptr[mv_position+0+esi] + fxch st(1) ; 1 | 0 | 2 + fadd ds:dword ptr[mv_position+4+esi] + fxch st(2) ; 2 | 0 | 1 + fadd ds:dword ptr[mv_position+8+esi] + fxch st(1) ; 0 | 2 | 1 + fstp ds:dword ptr[mv_position+0+esp] ; 2 | 1 + fstp ds:dword ptr[mv_position+8+esp] ; 1 + fstp ds:dword ptr[mv_position+4+esp] + +; replace pv0 with the clip point + mov esi,esp + +; if (clip->leftedge) +; { + jz Ltestright2 + +; r_leftclipped = true; +; r_leftenter = clipvert; + mov ds:dword ptr[_r_leftclipped],1 + mov eax,ds:dword ptr[mv_position+0+esp] + mov ds:dword ptr[_r_leftenter+mv_position+0],eax + mov eax,ds:dword ptr[mv_position+4+esp] + mov ds:dword ptr[_r_leftenter+mv_position+4],eax + mov eax,ds:dword ptr[mv_position+8+esp] + mov ds:dword ptr[_r_leftenter+mv_position+8],eax + + jmp Lcontinue + +; } + +Ltestright2: +; else if (clip->rightedge) +; { + test ah,ah + jz Lcontinue + +; r_rightclipped = true; +; r_rightenter = clipvert; + mov ds:dword ptr[_r_rightclipped],1 + mov eax,ds:dword ptr[mv_position+0+esp] + mov ds:dword ptr[_r_rightenter+mv_position+0],eax + mov eax,ds:dword ptr[mv_position+4+esp] + mov ds:dword ptr[_r_rightenter+mv_position+4],eax + mov eax,ds:dword ptr[mv_position+8+esp] + mov ds:dword ptr[_r_rightenter+mv_position+8],eax + +; } + jmp Lcontinue + +; %esi = vec3_t point to transform and project +; %edx preserved +LTransformAndProject: + +; // transform and project +; VectorSubtract (world, modelorg, local); + fld ds:dword ptr[mv_position+0+esi] + fsub ds:dword ptr[_modelorg+0] + fld ds:dword ptr[mv_position+4+esi] + fsub ds:dword ptr[_modelorg+4] + fld ds:dword ptr[mv_position+8+esi] + fsub ds:dword ptr[_modelorg+8] + fxch st(2) ; local[0] | local[1] | local[2] + +; TransformVector (local, transformed); +; +; if (transformed[2] < NEAR_CLIP) +; transformed[2] = NEAR_CLIP; +; +; lzi0 = 1.0 / transformed[2]; + fld st(0) ; local[0] | local[0] | local[1] | local[2] + fmul ds:dword ptr[_vpn+0] ; zm0 | local[0] | local[1] | local[2] + fld st(1) ; local[0] | zm0 | local[0] | local[1] | +; local[2] + fmul ds:dword ptr[_vright+0] ; xm0 | zm0 | local[0] | local[1] | local[2] + fxch st(2) ; local[0] | zm0 | xm0 | local[1] | local[2] + fmul ds:dword ptr[_vup+0] ; ym0 | zm0 | xm0 | local[1] | local[2] + fld st(3) ; local[1] | ym0 | zm0 | xm0 | local[1] | +; local[2] + fmul ds:dword ptr[_vpn+4] ; zm1 | ym0 | zm0 | xm0 | local[1] | +; local[2] + fld st(4) ; local[1] | zm1 | ym0 | zm0 | xm0 | +; local[1] | local[2] + fmul ds:dword ptr[_vright+4] ; xm1 | zm1 | ym0 | zm0 | xm0 | +; local[1] | local[2] + fxch st(5) ; local[1] | zm1 | ym0 | zm0 | xm0 | +; xm1 | local[2] + fmul ds:dword ptr[_vup+4] ; ym1 | zm1 | ym0 | zm0 | xm0 | +; xm1 | local[2] + fxch st(1) ; zm1 | ym1 | ym0 | zm0 | xm0 | +; xm1 | local[2] + faddp st(3),st(0) ; ym1 | ym0 | zm2 | xm0 | xm1 | local[2] + fxch st(3) ; xm0 | ym0 | zm2 | ym1 | xm1 | local[2] + faddp st(4),st(0) ; ym0 | zm2 | ym1 | xm2 | local[2] + faddp st(2),st(0) ; zm2 | ym2 | xm2 | local[2] + fld st(3) ; local[2] | zm2 | ym2 | xm2 | local[2] + fmul ds:dword ptr[_vpn+8] ; zm3 | zm2 | ym2 | xm2 | local[2] + fld st(4) ; local[2] | zm3 | zm2 | ym2 | xm2 | local[2] + fmul ds:dword ptr[_vright+8] ; xm3 | zm3 | zm2 | ym2 | xm2 | local[2] + fxch st(5) ; local[2] | zm3 | zm2 | ym2 | xm2 | xm3 + fmul ds:dword ptr[_vup+8] ; ym3 | zm3 | zm2 | ym2 | xm2 | xm3 + fxch st(1) ; zm3 | ym3 | zm2 | ym2 | xm2 | xm3 + faddp st(2),st(0) ; ym3 | zm4 | ym2 | xm2 | xm3 + fxch st(4) ; xm3 | zm4 | ym2 | xm2 | ym3 + faddp st(3),st(0) ; zm4 | ym2 | xm4 | ym3 + fxch st(1) ; ym2 | zm4 | xm4 | ym3 + faddp st(3),st(0) ; zm4 | xm4 | ym4 + + fcom ds:dword ptr[Lfp_near_clip] + fnstsw ax + test ah,1 + jz LNoClip + fstp st(0) + fld ds:dword ptr[Lfp_near_clip] + +LNoClip: + + fdivr ds:dword ptr[float_1] ; lzi0 | x | y + fxch st(1) ; x | lzi0 | y + +; // FIXME: build x/yscale into transform? +; scale = xscale * lzi0; +; u0 = (xcenter + scale*transformed[0]); + fld ds:dword ptr[_xscale] ; xscale | x | lzi0 | y + fmul st(0),st(2) ; scale | x | lzi0 | y + fmulp st(1),st(0) ; scale*x | lzi0 | y + fadd ds:dword ptr[_xcenter] ; u0 | lzi0 | y + +; if (u0 < r_refdef.fvrectx_adj) +; u0 = r_refdef.fvrectx_adj; +; if (u0 > r_refdef.fvrectright_adj) +; u0 = r_refdef.fvrectright_adj; +; FIXME: use integer compares of floats? + fcom ds:dword ptr[_r_refdef+rd_fvrectx_adj] + fnstsw ax + test ah,1 + jz LClampP0 + fstp st(0) + fld ds:dword ptr[_r_refdef+rd_fvrectx_adj] +LClampP0: + fcom ds:dword ptr[_r_refdef+rd_fvrectright_adj] + fnstsw ax + test ah,045h + jnz LClampP1 + fstp st(0) + fld ds:dword ptr[_r_refdef+rd_fvrectright_adj] +LClampP1: + + fld st(1) ; lzi0 | u0 | lzi0 | y + +; scale = yscale * lzi0; +; v0 = (ycenter - scale*transformed[1]); + fmul ds:dword ptr[_yscale] ; scale | u0 | lzi0 | y + fmulp st(3),st(0) ; u0 | lzi0 | scale*y + fxch st(2) ; scale*y | lzi0 | u0 + fsubr ds:dword ptr[_ycenter] ; v0 | lzi0 | u0 + +; if (v0 < r_refdef.fvrecty_adj) +; v0 = r_refdef.fvrecty_adj; +; if (v0 > r_refdef.fvrectbottom_adj) +; v0 = r_refdef.fvrectbottom_adj; +; FIXME: use integer compares of floats? + fcom ds:dword ptr[_r_refdef+rd_fvrecty_adj] + fnstsw ax + test ah,1 + jz LClampP2 + fstp st(0) + fld ds:dword ptr[_r_refdef+rd_fvrecty_adj] +LClampP2: + fcom ds:dword ptr[_r_refdef+rd_fvrectbottom_adj] + fnstsw ax + test ah,045h + jnz LClampP3 + fstp st(0) + fld ds:dword ptr[_r_refdef+rd_fvrectbottom_adj] +LClampP3: + ret + + +_TEXT ENDS +endif ;id386 + END diff --git a/ref_soft/r_edge.c b/ref_soft/r_edge.c new file mode 100644 index 000000000..389dc1022 --- /dev/null +++ b/ref_soft/r_edge.c @@ -0,0 +1,1125 @@ +/* +Copyright (C) 1997-2001 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_edge.c + +#include "r_local.h" + +#ifndef id386 +void R_SurfacePatch (void) +{ +} + +void R_EdgeCodeStart (void) +{ +} + +void R_EdgeCodeEnd (void) +{ +} +#endif + + +#if 0 +the complex cases add new polys on most lines, so dont optimize for keeping them the same +have multiple free span lists to try to get better coherence? +low depth complexity -- 1 to 3 or so + +have a sentinal at both ends? +#endif + + +edge_t *auxedges; +edge_t *r_edges, *edge_p, *edge_max; + +surf_t *surfaces, *surface_p, *surf_max; + +// surfaces are generated in back to front order by the bsp, so if a surf +// pointer is greater than another one, it should be drawn in front +// surfaces[1] is the background, and is used as the active surface stack + +edge_t *newedges[MAXHEIGHT]; +edge_t *removeedges[MAXHEIGHT]; + +espan_t *span_p, *max_span_p; + +int r_currentkey; + +int current_iv; + +int edge_head_u_shift20, edge_tail_u_shift20; + +static void (*pdrawfunc)(void); + +edge_t edge_head; +edge_t edge_tail; +edge_t edge_aftertail; +edge_t edge_sentinel; + +float fv; + +static int miplevel; + +float scale_for_mip; +int ubasestep, errorterm, erroradjustup, erroradjustdown; + +// FIXME: should go away +extern void R_RotateBmodel (void); +extern void R_TransformFrustum (void); + + + +void R_GenerateSpans (void); +void R_GenerateSpansBackward (void); + +void R_LeadingEdge (edge_t *edge); +void R_LeadingEdgeBackwards (edge_t *edge); +void R_TrailingEdge (surf_t *surf, edge_t *edge); + + +/* +=============================================================================== + +EDGE SCANNING + +=============================================================================== +*/ + +/* +============== +R_BeginEdgeFrame +============== +*/ +void R_BeginEdgeFrame (void) +{ + int v; + + edge_p = r_edges; + edge_max = &r_edges[r_numallocatededges]; + + surface_p = &surfaces[2]; // background is surface 1, + // surface 0 is a dummy + surfaces[1].spans = NULL; // no background spans yet + surfaces[1].flags = SURF_DRAWBACKGROUND; + +// put the background behind everything in the world + if (sw_draworder->value) + { + pdrawfunc = R_GenerateSpansBackward; + surfaces[1].key = 0; + r_currentkey = 1; + } + else + { + pdrawfunc = R_GenerateSpans; + surfaces[1].key = 0x7FFfFFFF; + r_currentkey = 0; + } + +// FIXME: set with memset + for (v=r_refdef.vrect.y ; vnext; +edgesearch: + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + goto edgesearch; + + // insert edgestoadd before edgelist +addedge: + edgestoadd->next = edgelist; + edgestoadd->prev = edgelist->prev; + edgelist->prev->next = edgestoadd; + edgelist->prev = edgestoadd; + } while ((edgestoadd = next_edge) != NULL); +} + +#endif // !id386 + + +#if !id386 + +/* +============== +R_RemoveEdges +============== +*/ +void R_RemoveEdges (edge_t *pedge) +{ + + do + { + pedge->next->prev = pedge->prev; + pedge->prev->next = pedge->next; + } while ((pedge = pedge->nextremove) != NULL); +} + +#endif // !id386 + + +#if !id386 + +/* +============== +R_StepActiveU +============== +*/ +void R_StepActiveU (edge_t *pedge) +{ + edge_t *pnext_edge, *pwedge; + + while (1) + { +nextedge: + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + goto nextedge; + +pushback: + if (pedge == &edge_aftertail) + return; + + // push it back to keep it sorted + pnext_edge = pedge->next; + + // pull the edge out of the edge list + pedge->next->prev = pedge->prev; + pedge->prev->next = pedge->next; + + // find out where the edge goes in the edge list + pwedge = pedge->prev->prev; + + while (pwedge->u > pedge->u) + { + pwedge = pwedge->prev; + } + + // put the edge back into the edge list + pedge->next = pwedge->next; + pedge->prev = pwedge; + pedge->next->prev = pedge; + pwedge->next = pedge; + + pedge = pnext_edge; + if (pedge == &edge_tail) + return; + } +} + +#endif // !id386 + + +/* +============== +R_CleanupSpan +============== +*/ +void R_CleanupSpan (void) +{ + surf_t *surf; + int iu; + espan_t *span; + +// now that we've reached the right edge of the screen, we're done with any +// unfinished surfaces, so emit a span for whatever's on top + surf = surfaces[1].next; + iu = edge_tail_u_shift20; + if (iu > surf->last_u) + { + span = span_p++; + span->u = surf->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf->spans; + surf->spans = span; + } + +// reset spanstate for all surfaces in the surface stack + do + { + surf->spanstate = 0; + surf = surf->next; + } while (surf != &surfaces[1]); +} + + +/* +============== +R_LeadingEdgeBackwards +============== +*/ +void R_LeadingEdgeBackwards (edge_t *edge) +{ + espan_t *span; + surf_t *surf, *surf2; + int iu; + +// it's adding a new surface in, so find the correct place + surf = &surfaces[edge->surfs[1]]; + +// don't start a span if this is an inverted span, with the end +// edge preceding the start edge (that is, we've already seen the +// end edge) + if (++surf->spanstate == 1) + { + surf2 = surfaces[1].next; + + if (surf->key > surf2->key) + goto newtop; + + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (surf->insubmodel && (surf->key == surf2->key)) + { + // must be two bmodels in the same leaf; don't care, because they'll + // never be farthest anyway + goto newtop; + } + +continue_search: + + do + { + surf2 = surf2->next; + } while (surf->key < surf2->key); + + if (surf->key == surf2->key) + { + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (!surf->insubmodel) + goto continue_search; + + // must be two bmodels in the same leaf; don't care which is really + // in front, because they'll never be farthest anyway + } + + goto gotposition; + +newtop: + // emit a span (obscures current top) + iu = edge->u >> 20; + + if (iu > surf2->last_u) + { + span = span_p++; + span->u = surf2->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf2->spans; + surf2->spans = span; + } + + // set last_u on the new span + surf->last_u = iu; + +gotposition: + // insert before surf2 + surf->next = surf2; + surf->prev = surf2->prev; + surf2->prev->next = surf; + surf2->prev = surf; + } +} + + +/* +============== +R_TrailingEdge +============== +*/ +void R_TrailingEdge (surf_t *surf, edge_t *edge) +{ + espan_t *span; + int iu; + +// don't generate a span if this is an inverted span, with the end +// edge preceding the start edge (that is, we haven't seen the +// start edge yet) + if (--surf->spanstate == 0) + { + if (surf == surfaces[1].next) + { + // emit a span (current top going away) + iu = edge->u >> 20; + if (iu > surf->last_u) + { + span = span_p++; + span->u = surf->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf->spans; + surf->spans = span; + } + + // set last_u on the surface below + surf->next->last_u = iu; + } + + surf->prev->next = surf->next; + surf->next->prev = surf->prev; + } +} + + +#if !id386 + +/* +============== +R_LeadingEdge +============== +*/ +void R_LeadingEdge (edge_t *edge) +{ + espan_t *span; + surf_t *surf, *surf2; + int iu; + float fu, newzi, testzi, newzitop, newzibottom; + + if (edge->surfs[1]) + { + // it's adding a new surface in, so find the correct place + surf = &surfaces[edge->surfs[1]]; + + // don't start a span if this is an inverted span, with the end + // edge preceding the start edge (that is, we've already seen the + // end edge) + if (++surf->spanstate == 1) + { + surf2 = surfaces[1].next; + + if (surf->key < surf2->key) + goto newtop; + + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (surf->insubmodel && (surf->key == surf2->key)) + { + // must be two bmodels in the same leaf; sort on 1/z + fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000); + newzi = surf->d_ziorigin + fv*surf->d_zistepv + + fu*surf->d_zistepu; + newzibottom = newzi * 0.99; + + testzi = surf2->d_ziorigin + fv*surf2->d_zistepv + + fu*surf2->d_zistepu; + + if (newzibottom >= testzi) + { + goto newtop; + } + + newzitop = newzi * 1.01; + if (newzitop >= testzi) + { + if (surf->d_zistepu >= surf2->d_zistepu) + { + goto newtop; + } + } + } + +continue_search: + + do + { + surf2 = surf2->next; + } while (surf->key > surf2->key); + + if (surf->key == surf2->key) + { + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (!surf->insubmodel) + goto continue_search; + + // must be two bmodels in the same leaf; sort on 1/z + fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000); + newzi = surf->d_ziorigin + fv*surf->d_zistepv + + fu*surf->d_zistepu; + newzibottom = newzi * 0.99; + + testzi = surf2->d_ziorigin + fv*surf2->d_zistepv + + fu*surf2->d_zistepu; + + if (newzibottom >= testzi) + { + goto gotposition; + } + + newzitop = newzi * 1.01; + if (newzitop >= testzi) + { + if (surf->d_zistepu >= surf2->d_zistepu) + { + goto gotposition; + } + } + + goto continue_search; + } + + goto gotposition; + +newtop: + // emit a span (obscures current top) + iu = edge->u >> 20; + + if (iu > surf2->last_u) + { + span = span_p++; + span->u = surf2->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf2->spans; + surf2->spans = span; + } + + // set last_u on the new span + surf->last_u = iu; + +gotposition: + // insert before surf2 + surf->next = surf2; + surf->prev = surf2->prev; + surf2->prev->next = surf; + surf2->prev = surf; + } + } +} + + +/* +============== +R_GenerateSpans +============== +*/ +void R_GenerateSpans (void) +{ + edge_t *edge; + surf_t *surf; + +// clear active surfaces to just the background surface + surfaces[1].next = surfaces[1].prev = &surfaces[1]; + surfaces[1].last_u = edge_head_u_shift20; + +// generate spans + for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next) + { + if (edge->surfs[0]) + { + // it has a left surface, so a surface is going away for this span + surf = &surfaces[edge->surfs[0]]; + + R_TrailingEdge (surf, edge); + + if (!edge->surfs[1]) + continue; + } + + R_LeadingEdge (edge); + } + + R_CleanupSpan (); +} + +#endif // !id386 + + +/* +============== +R_GenerateSpansBackward +============== +*/ +void R_GenerateSpansBackward (void) +{ + edge_t *edge; + +// clear active surfaces to just the background surface + surfaces[1].next = surfaces[1].prev = &surfaces[1]; + surfaces[1].last_u = edge_head_u_shift20; + +// generate spans + for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next) + { + if (edge->surfs[0]) + R_TrailingEdge (&surfaces[edge->surfs[0]], edge); + + if (edge->surfs[1]) + R_LeadingEdgeBackwards (edge); + } + + R_CleanupSpan (); +} + + +/* +============== +R_ScanEdges + +Input: +newedges[] array + this has links to edges, which have links to surfaces + +Output: +Each surface has a linked list of its visible spans +============== +*/ +void R_ScanEdges (void) +{ + int iv, bottom; + byte basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE]; + espan_t *basespan_p; + surf_t *s; + + basespan_p = (espan_t *) + ((long)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width]; + + span_p = basespan_p; + +// clear active edges to just the background edges around the whole screen +// FIXME: most of this only needs to be set up once + edge_head.u = r_refdef.vrect.x << 20; + edge_head_u_shift20 = edge_head.u >> 20; + edge_head.u_step = 0; + edge_head.prev = NULL; + edge_head.next = &edge_tail; + edge_head.surfs[0] = 0; + edge_head.surfs[1] = 1; + + edge_tail.u = (r_refdef.vrectright << 20) + 0xFFFFF; + edge_tail_u_shift20 = edge_tail.u >> 20; + edge_tail.u_step = 0; + edge_tail.prev = &edge_head; + edge_tail.next = &edge_aftertail; + edge_tail.surfs[0] = 1; + edge_tail.surfs[1] = 0; + + edge_aftertail.u = -1; // force a move + edge_aftertail.u_step = 0; + edge_aftertail.next = &edge_sentinel; + edge_aftertail.prev = &edge_tail; + +// FIXME: do we need this now that we clamp x in r_draw.c? + edge_sentinel.u = 2000 << 24; // make sure nothing sorts past this + edge_sentinel.prev = &edge_aftertail; + +// +// process all scan lines +// + bottom = r_refdef.vrectbottom - 1; + + for (iv=r_refdef.vrect.y ; iv max_span_p) + { + D_DrawSurfaces (); + + // clear the surface span pointers + for (s = &surfaces[1] ; sspans = NULL; + + span_p = basespan_p; + } + + if (removeedges[iv]) + R_RemoveEdges (removeedges[iv]); + + if (edge_head.next != &edge_tail) + R_StepActiveU (edge_head.next); + } + +// do the last scan (no need to step or sort or remove on the last scan) + + current_iv = iv; + fv = (float)iv; + +// mark that the head (background start) span is pre-included + surfaces[1].spanstate = 1; + + if (newedges[iv]) + R_InsertNewEdges (newedges[iv], edge_head.next); + + (*pdrawfunc) (); + +// draw whatever's left in the span list + D_DrawSurfaces (); +} + + +/* +========================================================================= + +SURFACE FILLING + +========================================================================= +*/ + +msurface_t *pface; +surfcache_t *pcurrentcache; +vec3_t transformed_modelorg; +vec3_t world_transformed_modelorg; +vec3_t local_modelorg; + +/* +============= +D_MipLevelForScale +============= +*/ +int D_MipLevelForScale (float scale) +{ + int lmiplevel; + + if (scale >= d_scalemip[0] ) + lmiplevel = 0; + else if (scale >= d_scalemip[1] ) + lmiplevel = 1; + else if (scale >= d_scalemip[2] ) + lmiplevel = 2; + else + lmiplevel = 3; + + if (lmiplevel < d_minmip) + lmiplevel = d_minmip; + + return lmiplevel; +} + + +/* +============== +D_FlatFillSurface + +Simple single color fill with no texture mapping +============== +*/ +void D_FlatFillSurface (surf_t *surf, int color) +{ + espan_t *span; + byte *pdest; + int u, u2; + + for (span=surf->spans ; span ; span=span->pnext) + { + pdest = (byte *)d_viewbuffer + r_screenwidth*span->v; + u = span->u; + u2 = span->u + span->count - 1; + for ( ; u <= u2 ; u++) + pdest[u] = color; + } +} + + +/* +============== +D_CalcGradients +============== +*/ +void D_CalcGradients (msurface_t *pface) +{ + mplane_t *pplane; + float mipscale; + vec3_t p_temp1; + vec3_t p_saxis, p_taxis; + float t; + + pplane = pface->plane; + + mipscale = 1.0 / (float)(1 << miplevel); + + TransformVector (pface->texinfo->vecs[0], p_saxis); + TransformVector (pface->texinfo->vecs[1], p_taxis); + + t = xscaleinv * mipscale; + d_sdivzstepu = p_saxis[0] * t; + d_tdivzstepu = p_taxis[0] * t; + + t = yscaleinv * mipscale; + d_sdivzstepv = -p_saxis[1] * t; + d_tdivzstepv = -p_taxis[1] * t; + + d_sdivzorigin = p_saxis[2] * mipscale - xcenter * d_sdivzstepu - + ycenter * d_sdivzstepv; + d_tdivzorigin = p_taxis[2] * mipscale - xcenter * d_tdivzstepu - + ycenter * d_tdivzstepv; + + VectorScale (transformed_modelorg, mipscale, p_temp1); + + t = 0x10000*mipscale; + sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) - + ((pface->texturemins[0] << 16) >> miplevel) + + pface->texinfo->vecs[0][3]*t; + tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) - + ((pface->texturemins[1] << 16) >> miplevel) + + pface->texinfo->vecs[1][3]*t; + + // PGM - changing flow speed for non-warping textures. + if (pface->texinfo->flags & SURF_FLOWING) + { + if(pface->texinfo->flags & SURF_WARP) + sadjust += 0x10000 * (-128 * ( (r_newrefdef.time * 0.25) - (int)(r_newrefdef.time * 0.25) )); + else + sadjust += 0x10000 * (-128 * ( (r_newrefdef.time * 0.77) - (int)(r_newrefdef.time * 0.77) )); + } + // PGM + +// +// -1 (-epsilon) so we never wander off the edge of the texture +// + bbextents = ((pface->extents[0] << 16) >> miplevel) - 1; + bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1; +} + + +/* +============== +D_BackgroundSurf + +The grey background filler seen when there is a hole in the map +============== +*/ +void D_BackgroundSurf (surf_t *s) +{ +// set up a gradient for the background surface that places it +// effectively at infinity distance from the viewpoint + d_zistepu = 0; + d_zistepv = 0; + d_ziorigin = -0.9; + + D_FlatFillSurface (s, (int)sw_clearcolor->value & 0xFF); + D_DrawZSpans (s->spans); +} + +/* +================= +D_TurbulentSurf +================= +*/ +void D_TurbulentSurf (surf_t *s) +{ + d_zistepu = s->d_zistepu; + d_zistepv = s->d_zistepv; + d_ziorigin = s->d_ziorigin; + + pface = s->msurf; + miplevel = 0; + cacheblock = pface->texinfo->image->pixels[0]; + cachewidth = 64; + + if (s->insubmodel) + { + // FIXME: we don't want to do all this for every polygon! + // TODO: store once at start of frame + currententity = s->entity; //FIXME: make this passed in to + // R_RotateBmodel () + VectorSubtract (r_origin, currententity->origin, + local_modelorg); + TransformVector (local_modelorg, transformed_modelorg); + + R_RotateBmodel (); // FIXME: don't mess with the frustum, + // make entity passed in + } + + D_CalcGradients (pface); + +//============ +//PGM + // textures that aren't warping are just flowing. Use NonTurbulent8 instead + if(!(pface->texinfo->flags & SURF_WARP)) + NonTurbulent8 (s->spans); + else + Turbulent8 (s->spans); +//PGM +//============ + + D_DrawZSpans (s->spans); + + if (s->insubmodel) + { + // + // restore the old drawing state + // FIXME: we don't want to do this every time! + // TODO: speed up + // + currententity = NULL; // &r_worldentity; + VectorCopy (world_transformed_modelorg, + transformed_modelorg); + VectorCopy (base_vpn, vpn); + VectorCopy (base_vup, vup); + VectorCopy (base_vright, vright); + R_TransformFrustum (); + } +} + +/* +============== +D_SkySurf +============== +*/ +void D_SkySurf (surf_t *s) +{ + pface = s->msurf; + miplevel = 0; + if (!pface->texinfo->image) + return; + cacheblock = pface->texinfo->image->pixels[0]; + cachewidth = 256; + + d_zistepu = s->d_zistepu; + d_zistepv = s->d_zistepv; + d_ziorigin = s->d_ziorigin; + + D_CalcGradients (pface); + + D_DrawSpans16 (s->spans); + +// set up a gradient for the background surface that places it +// effectively at infinity distance from the viewpoint + d_zistepu = 0; + d_zistepv = 0; + d_ziorigin = -0.9; + + D_DrawZSpans (s->spans); +} + +/* +============== +D_SolidSurf + +Normal surface cached, texture mapped surface +============== +*/ +void D_SolidSurf (surf_t *s) +{ + d_zistepu = s->d_zistepu; + d_zistepv = s->d_zistepv; + d_ziorigin = s->d_ziorigin; + + if (s->insubmodel) + { + // FIXME: we don't want to do all this for every polygon! + // TODO: store once at start of frame + currententity = s->entity; //FIXME: make this passed in to + // R_RotateBmodel () + VectorSubtract (r_origin, currententity->origin, local_modelorg); + TransformVector (local_modelorg, transformed_modelorg); + + R_RotateBmodel (); // FIXME: don't mess with the frustum, + // make entity passed in + } + else + currententity = &r_worldentity; + + pface = s->msurf; +#if 1 + miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip * pface->texinfo->mipadjust); +#else + { + float dot; + float normal[3]; + + if ( s->insubmodel ) + { + VectorCopy( pface->plane->normal, normal ); +// TransformVector( pface->plane->normal, normal); + dot = DotProduct( normal, vpn ); + } + else + { + VectorCopy( pface->plane->normal, normal ); + dot = DotProduct( normal, vpn ); + } + + if ( pface->flags & SURF_PLANEBACK ) + dot = -dot; + + if ( dot > 0 ) + printf( "blah" ); + + miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip * pface->texinfo->mipadjust); + } +#endif + +// FIXME: make this passed in to D_CacheSurface + pcurrentcache = D_CacheSurface (pface, miplevel); + + cacheblock = (pixel_t *)pcurrentcache->data; + cachewidth = pcurrentcache->width; + + D_CalcGradients (pface); + + D_DrawSpans16 (s->spans); + + D_DrawZSpans (s->spans); + + if (s->insubmodel) + { + // + // restore the old drawing state + // FIXME: we don't want to do this every time! + // TODO: speed up + // + VectorCopy (world_transformed_modelorg, + transformed_modelorg); + VectorCopy (base_vpn, vpn); + VectorCopy (base_vup, vup); + VectorCopy (base_vright, vright); + R_TransformFrustum (); + currententity = NULL; //&r_worldentity; + } +} + +/* +============= +D_DrawflatSurfaces + +To allow developers to see the polygon carving of the world +============= +*/ +void D_DrawflatSurfaces (void) +{ + surf_t *s; + + for (s = &surfaces[1] ; sspans) + continue; + + d_zistepu = s->d_zistepu; + d_zistepv = s->d_zistepv; + d_ziorigin = s->d_ziorigin; + + // make a stable color for each surface by taking the low + // bits of the msurface pointer + D_FlatFillSurface (s, (int)s->msurf & 0xFF); + D_DrawZSpans (s->spans); + } +} + +/* +============== +D_DrawSurfaces + +Rasterize all the span lists. Guaranteed zero overdraw. +May be called more than once a frame if the surf list overflows (higher res) +============== +*/ +void D_DrawSurfaces (void) +{ + surf_t *s; + +// currententity = NULL; //&r_worldentity; + VectorSubtract (r_origin, vec3_origin, modelorg); + TransformVector (modelorg, transformed_modelorg); + VectorCopy (transformed_modelorg, world_transformed_modelorg); + + if (!sw_drawflat->value) + { + for (s = &surfaces[1] ; sspans) + continue; + + r_drawnpolycount++; + + if (! (s->flags & (SURF_DRAWSKYBOX|SURF_DRAWBACKGROUND|SURF_DRAWTURB) ) ) + D_SolidSurf (s); + else if (s->flags & SURF_DRAWSKYBOX) + D_SkySurf (s); + else if (s->flags & SURF_DRAWBACKGROUND) + D_BackgroundSurf (s); + else if (s->flags & SURF_DRAWTURB) + D_TurbulentSurf (s); + } + } + else + D_DrawflatSurfaces (); + + currententity = NULL; //&r_worldentity; + VectorSubtract (r_origin, vec3_origin, modelorg); + R_TransformFrustum (); +} + diff --git a/ref_soft/r_edgea.asm b/ref_soft/r_edgea.asm new file mode 100644 index 000000000..8d82c4d5e --- /dev/null +++ b/ref_soft/r_edgea.asm @@ -0,0 +1,733 @@ + .386P + .model FLAT +; +; r_edgea.s +; x86 assembly-language edge-processing code. +; + +include qasm.inc + +if id386 + +_DATA SEGMENT +Ltemp dd 0 +float_1_div_0100000h dd 035800000h ; 1.0/(float)0x100000 +float_point_999 dd 0.999 +float_1_point_001 dd 1.001 + +_DATA ENDS +_TEXT SEGMENT + +;-------------------------------------------------------------------- + +edgestoadd equ 4+8 ; note odd stack offsets because of interleaving +edgelist equ 8+12 ; with pushes + + public _R_EdgeCodeStart +_R_EdgeCodeStart: + + public _R_InsertNewEdges +_R_InsertNewEdges: + push edi + push esi ; preserve register variables + mov edx,ds:dword ptr[edgestoadd+esp] + push ebx + mov ecx,ds:dword ptr[edgelist+esp] + +LDoNextEdge: + mov eax,ds:dword ptr[et_u+edx] + mov edi,edx + +LContinueSearch: + mov ebx,ds:dword ptr[et_u+ecx] + mov esi,ds:dword ptr[et_next+ecx] + cmp eax,ebx + jle LAddedge + mov ebx,ds:dword ptr[et_u+esi] + mov ecx,ds:dword ptr[et_next+esi] + cmp eax,ebx + jle LAddedge2 + mov ebx,ds:dword ptr[et_u+ecx] + mov esi,ds:dword ptr[et_next+ecx] + cmp eax,ebx + jle LAddedge + mov ebx,ds:dword ptr[et_u+esi] + mov ecx,ds:dword ptr[et_next+esi] + cmp eax,ebx + jg LContinueSearch + +LAddedge2: + mov edx,ds:dword ptr[et_next+edx] + mov ebx,ds:dword ptr[et_prev+esi] + mov ds:dword ptr[et_next+edi],esi + mov ds:dword ptr[et_prev+edi],ebx + mov ds:dword ptr[et_next+ebx],edi + mov ds:dword ptr[et_prev+esi],edi + mov ecx,esi + + cmp edx,0 + jnz LDoNextEdge + jmp LDone + + align 4 +LAddedge: + mov edx,ds:dword ptr[et_next+edx] + mov ebx,ds:dword ptr[et_prev+ecx] + mov ds:dword ptr[et_next+edi],ecx + mov ds:dword ptr[et_prev+edi],ebx + mov ds:dword ptr[et_next+ebx],edi + mov ds:dword ptr[et_prev+ecx],edi + + cmp edx,0 + jnz LDoNextEdge + +LDone: + pop ebx ; restore register variables + pop esi + pop edi + + ret + +;-------------------------------------------------------------------- + +predge equ 4+4 + + public _R_RemoveEdges +_R_RemoveEdges: + push ebx + mov eax,ds:dword ptr[predge+esp] + +Lre_loop: + mov ecx,ds:dword ptr[et_next+eax] + mov ebx,ds:dword ptr[et_nextremove+eax] + mov edx,ds:dword ptr[et_prev+eax] + test ebx,ebx + mov ds:dword ptr[et_prev+ecx],edx + jz Lre_done + mov ds:dword ptr[et_next+edx],ecx + + mov ecx,ds:dword ptr[et_next+ebx] + mov edx,ds:dword ptr[et_prev+ebx] + mov eax,ds:dword ptr[et_nextremove+ebx] + mov ds:dword ptr[et_prev+ecx],edx + test eax,eax + mov ds:dword ptr[et_next+edx],ecx + jnz Lre_loop + + pop ebx + ret + +Lre_done: + mov ds:dword ptr[et_next+edx],ecx + pop ebx + + ret + +;-------------------------------------------------------------------- + +pedgelist equ 4+4 ; note odd stack offset because of interleaving + ; with pushes + + public _R_StepActiveU +_R_StepActiveU: + push edi + mov edx,ds:dword ptr[pedgelist+esp] + push esi ; preserve register variables + push ebx + + mov esi,ds:dword ptr[et_prev+edx] + +LNewEdge: + mov edi,ds:dword ptr[et_u+esi] + +LNextEdge: + mov eax,ds:dword ptr[et_u+edx] + mov ebx,ds:dword ptr[et_u_step+edx] + add eax,ebx + mov esi,ds:dword ptr[et_next+edx] + mov ds:dword ptr[et_u+edx],eax + cmp eax,edi + jl LPushBack + + mov edi,ds:dword ptr[et_u+esi] + mov ebx,ds:dword ptr[et_u_step+esi] + add edi,ebx + mov edx,ds:dword ptr[et_next+esi] + mov ds:dword ptr[et_u+esi],edi + cmp edi,eax + jl LPushBack2 + + mov eax,ds:dword ptr[et_u+edx] + mov ebx,ds:dword ptr[et_u_step+edx] + add eax,ebx + mov esi,ds:dword ptr[et_next+edx] + mov ds:dword ptr[et_u+edx],eax + cmp eax,edi + jl LPushBack + + mov edi,ds:dword ptr[et_u+esi] + mov ebx,ds:dword ptr[et_u_step+esi] + add edi,ebx + mov edx,ds:dword ptr[et_next+esi] + mov ds:dword ptr[et_u+esi],edi + cmp edi,eax + jnl LNextEdge + +LPushBack2: + mov ebx,edx + mov eax,edi + mov edx,esi + mov esi,ebx + +LPushBack: +; push it back to keep it sorted + mov ecx,ds:dword ptr[et_prev+edx] + mov ebx,ds:dword ptr[et_next+edx] + +; done if the -1 in edge_aftertail triggered this + cmp edx,offset _edge_aftertail + jz LUDone + +; pull the edge out of the edge list + mov edi,ds:dword ptr[et_prev+ecx] + mov ds:dword ptr[et_prev+esi],ecx + mov ds:dword ptr[et_next+ecx],ebx + +; find out where the edge goes in the edge list +LPushBackLoop: + mov ecx,ds:dword ptr[et_prev+edi] + mov ebx,ds:dword ptr[et_u+edi] + cmp eax,ebx + jnl LPushBackFound + + mov edi,ds:dword ptr[et_prev+ecx] + mov ebx,ds:dword ptr[et_u+ecx] + cmp eax,ebx + jl LPushBackLoop + + mov edi,ecx + +; put the edge back into the edge list +LPushBackFound: + mov ebx,ds:dword ptr[et_next+edi] + mov ds:dword ptr[et_prev+edx],edi + mov ds:dword ptr[et_next+edx],ebx + mov ds:dword ptr[et_next+edi],edx + mov ds:dword ptr[et_prev+ebx],edx + + mov edx,esi + mov esi,ds:dword ptr[et_prev+esi] + + cmp edx,offset _edge_tail + jnz LNewEdge + +LUDone: + pop ebx ; restore register variables + pop esi + pop edi + + ret + +;-------------------------------------------------------------------- + +surf equ 4 ; note this is loaded before any pushes + + align 4 +TrailingEdge: + mov eax,ds:dword ptr[st_spanstate+esi] ; check for edge inversion + dec eax + jnz LInverted + + mov ds:dword ptr[st_spanstate+esi],eax + mov ecx,ds:dword ptr[st_insubmodel+esi] + mov edx,ds:dword ptr[12345678h] ; surfaces[1].st_next +LPatch0: + mov eax,ds:dword ptr[_r_bmodelactive] + sub eax,ecx + cmp edx,esi + mov ds:dword ptr[_r_bmodelactive],eax + jnz LNoEmit ; surface isn't on top, just remove + +; emit a span (current top going away) + mov eax,ds:dword ptr[et_u+ebx] + shr eax,20 ; iu = integral pixel u + mov edx,ds:dword ptr[st_last_u+esi] + mov ecx,ds:dword ptr[st_next+esi] + cmp eax,edx + jle LNoEmit2 ; iu <= surf->last_u, so nothing to emit + + mov ds:dword ptr[st_last_u+ecx],eax ; surf->next->last_u = iu; + sub eax,edx + mov ds:dword ptr[espan_t_u+ebp],edx ; span->u = surf->last_u; + + mov ds:dword ptr[espan_t_count+ebp],eax ; span->count = iu - span->u; + mov eax,ds:dword ptr[_current_iv] + mov ds:dword ptr[espan_t_v+ebp],eax ; span->v = current_iv; + mov eax,ds:dword ptr[st_spans+esi] + mov ds:dword ptr[espan_t_pnext+ebp],eax ; span->pnext = surf->spans; + mov ds:dword ptr[st_spans+esi],ebp ; surf->spans = span; + add ebp,offset espan_t_size + + mov edx,ds:dword ptr[st_next+esi] ; remove the surface from the surface + mov esi,ds:dword ptr[st_prev+esi] ; stack + + mov ds:dword ptr[st_next+esi],edx + mov ds:dword ptr[st_prev+edx],esi + ret + +LNoEmit2: + mov ds:dword ptr[st_last_u+ecx],eax ; surf->next->last_u = iu; + mov edx,ds:dword ptr[st_next+esi] ; remove the surface from the surface + mov esi,ds:dword ptr[st_prev+esi] ; stack + + mov ds:dword ptr[st_next+esi],edx + mov ds:dword ptr[st_prev+edx],esi + ret + +LNoEmit: + mov edx,ds:dword ptr[st_next+esi] ; remove the surface from the surface + mov esi,ds:dword ptr[st_prev+esi] ; stack + + mov ds:dword ptr[st_next+esi],edx + mov ds:dword ptr[st_prev+edx],esi + ret + +LInverted: + mov ds:dword ptr[st_spanstate+esi],eax + ret + +;-------------------------------------------------------------------- + +; trailing edge only +Lgs_trailing: + push offset Lgs_nextedge + jmp TrailingEdge + + + public _R_GenerateSpans +_R_GenerateSpans: + push ebp ; preserve caller's stack frame + push edi + push esi ; preserve register variables + push ebx + +; clear active surfaces to just the background surface + mov eax,ds:dword ptr[_surfaces] + mov edx,ds:dword ptr[_edge_head_u_shift20] + add eax,offset st_size +; %ebp = span_p throughout + mov ebp,ds:dword ptr[_span_p] + + mov ds:dword ptr[_r_bmodelactive],0 + + mov ds:dword ptr[st_next+eax],eax + mov ds:dword ptr[st_prev+eax],eax + mov ds:dword ptr[st_last_u+eax],edx + mov ebx,ds:dword ptr[_edge_head+et_next] ; edge=edge_head.next + +; generate spans + cmp ebx,offset _edge_tail ; done if empty list + jz Lgs_lastspan + +Lgs_edgeloop: + + mov edi,ds:dword ptr[et_surfs+ebx] + mov eax,ds:dword ptr[_surfaces] + mov esi,edi + and edi,0FFFF0000h + and esi,0FFFFh + jz Lgs_leading ; not a trailing edge + +; it has a left surface, so a surface is going away for this span + shl esi,offset SURF_T_SHIFT + add esi,eax + test edi,edi + jz Lgs_trailing + +; both leading and trailing + call near ptr TrailingEdge + mov eax,ds:dword ptr[_surfaces] + +; --------------------------------------------------------------- +; handle a leading edge +; --------------------------------------------------------------- + +Lgs_leading: + shr edi,16-SURF_T_SHIFT + mov eax,ds:dword ptr[_surfaces] + add edi,eax + mov esi,ds:dword ptr[12345678h] ; surf2 = surfaces[1].next; +LPatch2: + mov edx,ds:dword ptr[st_spanstate+edi] + mov eax,ds:dword ptr[st_insubmodel+edi] + test eax,eax + jnz Lbmodel_leading + +; handle a leading non-bmodel edge + +; don't start a span if this is an inverted span, with the end edge preceding +; the start edge (that is, we've already seen the end edge) + test edx,edx + jnz Lxl_done + + +; if (surf->key < surf2->key) +; goto newtop; + inc edx + mov eax,ds:dword ptr[st_key+edi] + mov ds:dword ptr[st_spanstate+edi],edx + mov ecx,ds:dword ptr[st_key+esi] + cmp eax,ecx + jl Lnewtop + +; main sorting loop to search through surface stack until insertion point +; found. Always terminates because background surface is sentinel +; do +; { +; surf2 = surf2->next; +; } while (surf->key >= surf2->key); +Lsortloopnb: + mov esi,ds:dword ptr[st_next+esi] + mov ecx,ds:dword ptr[st_key+esi] + cmp eax,ecx + jge Lsortloopnb + + jmp LInsertAndExit + + +; handle a leading bmodel edge + align 4 +Lbmodel_leading: + +; don't start a span if this is an inverted span, with the end edge preceding +; the start edge (that is, we've already seen the end edge) + test edx,edx + jnz Lxl_done + + mov ecx,ds:dword ptr[_r_bmodelactive] + inc edx + inc ecx + mov ds:dword ptr[st_spanstate+edi],edx + mov ds:dword ptr[_r_bmodelactive],ecx + +; if (surf->key < surf2->key) +; goto newtop; + mov eax,ds:dword ptr[st_key+edi] + mov ecx,ds:dword ptr[st_key+esi] + cmp eax,ecx + jl Lnewtop + +; if ((surf->key == surf2->key) && surf->insubmodel) +; { + jz Lzcheck_for_newtop + +; main sorting loop to search through surface stack until insertion point +; found. Always terminates because background surface is sentinel +; do +; { +; surf2 = surf2->next; +; } while (surf->key > surf2->key); +Lsortloop: + mov esi,ds:dword ptr[st_next+esi] + mov ecx,ds:dword ptr[st_key+esi] + cmp eax,ecx + jg Lsortloop + + jne LInsertAndExit + +; Do 1/z sorting to see if we've arrived in the right position + mov eax,ds:dword ptr[et_u+ebx] + sub eax,0FFFFFh + mov ds:dword ptr[Ltemp],eax + fild ds:dword ptr[Ltemp] + + fmul ds:dword ptr[float_1_div_0100000h] ; fu = (float)(edge->u - 0xFFFFF) * +; (1.0 / 0x100000); + + fld st(0) ; fu | fu + fmul ds:dword ptr[st_d_zistepu+edi] ; fu*surf->d_zistepu | fu + fld ds:dword ptr[_fv] ; fv | fu*surf->d_zistepu | fu + fmul ds:dword ptr[st_d_zistepv+edi] ; fv*surf->d_zistepv | fu*surf->d_zistepu | fu + fxch st(1) ; fu*surf->d_zistepu | fv*surf->d_zistepv | fu + fadd ds:dword ptr[st_d_ziorigin+edi] ; fu*surf->d_zistepu + surf->d_ziorigin | +; fv*surf->d_zistepv | fu + + fld ds:dword ptr[st_d_zistepu+esi] ; surf2->d_zistepu | +; fu*surf->d_zistepu + surf->d_ziorigin | +; fv*surf->d_zistepv | fu + fmul st(0),st(3) ; fu*surf2->d_zistepu | +; fu*surf->d_zistepu + surf->d_ziorigin | +; fv*surf->d_zistepv | fu + fxch st(1) ; fu*surf->d_zistepu + surf->d_ziorigin | +; fu*surf2->d_zistepu | +; fv*surf->d_zistepv | fu + faddp st(2),st(0) ; fu*surf2->d_zistepu | newzi | fu + + fld ds:dword ptr[_fv] ; fv | fu*surf2->d_zistepu | newzi | fu + fmul ds:dword ptr[st_d_zistepv+esi] ; fv*surf2->d_zistepv | +; fu*surf2->d_zistepu | newzi | fu + fld st(2) ; newzi | fv*surf2->d_zistepv | +; fu*surf2->d_zistepu | newzi | fu + fmul ds:dword ptr[float_point_999] ; newzibottom | fv*surf2->d_zistepv | +; fu*surf2->d_zistepu | newzi | fu + + fxch st(2) ; fu*surf2->d_zistepu | fv*surf2->d_zistepv | +; newzibottom | newzi | fu + fadd ds:dword ptr[st_d_ziorigin+esi] ; fu*surf2->d_zistepu + surf2->d_ziorigin | +; fv*surf2->d_zistepv | newzibottom | newzi | +; fu + faddp st(1),st(0) ; testzi | newzibottom | newzi | fu + fxch st(1) ; newzibottom | testzi | newzi | fu + +; if (newzibottom >= testzi) +; goto Lgotposition; + + fcomp st(1) ; testzi | newzi | fu + + fxch st(1) ; newzi | testzi | fu + fmul ds:dword ptr[float_1_point_001] ; newzitop | testzi | fu + fxch st(1) ; testzi | newzitop | fu + + fnstsw ax + test ah,001h + jz Lgotposition_fpop3 + +; if (newzitop >= testzi) +; { + + fcomp st(1) ; newzitop | fu + fnstsw ax + test ah,045h + jz Lsortloop_fpop2 + +; if (surf->d_zistepu >= surf2->d_zistepu) +; goto newtop; + + fld ds:dword ptr[st_d_zistepu+edi] ; surf->d_zistepu | newzitop| fu + fcomp ds:dword ptr[st_d_zistepu+esi] ; newzitop | fu + fnstsw ax + test ah,001h + jz Lgotposition_fpop2 + + fstp st(0) ; clear the FPstack + fstp st(0) + mov eax,ds:dword ptr[st_key+edi] + jmp Lsortloop + + +Lgotposition_fpop3: + fstp st(0) +Lgotposition_fpop2: + fstp st(0) + fstp st(0) + jmp LInsertAndExit + + +; emit a span (obscures current top) + +Lnewtop_fpop3: + fstp st(0) +Lnewtop_fpop2: + fstp st(0) + fstp st(0) + mov eax,ds:dword ptr[st_key+edi] ; reload the sorting key + +Lnewtop: + mov eax,ds:dword ptr[et_u+ebx] + mov edx,ds:dword ptr[st_last_u+esi] + shr eax,20 ; iu = integral pixel u + mov ds:dword ptr[st_last_u+edi],eax ; surf->last_u = iu; + cmp eax,edx + jle LInsertAndExit ; iu <= surf->last_u, so nothing to emit + + sub eax,edx + mov ds:dword ptr[espan_t_u+ebp],edx ; span->u = surf->last_u; + + mov ds:dword ptr[espan_t_count+ebp],eax ; span->count = iu - span->u; + mov eax,ds:dword ptr[_current_iv] + mov ds:dword ptr[espan_t_v+ebp],eax ; span->v = current_iv; + mov eax,ds:dword ptr[st_spans+esi] + mov ds:dword ptr[espan_t_pnext+ebp],eax ; span->pnext = surf->spans; + mov ds:dword ptr[st_spans+esi],ebp ; surf->spans = span; + add ebp,offset espan_t_size + +LInsertAndExit: +; insert before surf2 + mov ds:dword ptr[st_next+edi],esi ; surf->next = surf2; + mov eax,ds:dword ptr[st_prev+esi] + mov ds:dword ptr[st_prev+edi],eax ; surf->prev = surf2->prev; + mov ds:dword ptr[st_prev+esi],edi ; surf2->prev = surf; + mov ds:dword ptr[st_next+eax],edi ; surf2->prev->next = surf; + +; --------------------------------------------------------------- +; leading edge done +; --------------------------------------------------------------- + +; --------------------------------------------------------------- +; see if there are any more edges +; --------------------------------------------------------------- + +Lgs_nextedge: + mov ebx,ds:dword ptr[et_next+ebx] + cmp ebx,offset _edge_tail + jnz Lgs_edgeloop + +; clean up at the right edge +Lgs_lastspan: + +; now that we've reached the right edge of the screen, we're done with any +; unfinished surfaces, so emit a span for whatever's on top + mov esi,ds:dword ptr[12345678h] ; surfaces[1].st_next +LPatch3: + mov eax,ds:dword ptr[_edge_tail_u_shift20] + xor ecx,ecx + mov edx,ds:dword ptr[st_last_u+esi] + sub eax,edx + jle Lgs_resetspanstate + + mov ds:dword ptr[espan_t_u+ebp],edx + mov ds:dword ptr[espan_t_count+ebp],eax + mov eax,ds:dword ptr[_current_iv] + mov ds:dword ptr[espan_t_v+ebp],eax + mov eax,ds:dword ptr[st_spans+esi] + mov ds:dword ptr[espan_t_pnext+ebp],eax + mov ds:dword ptr[st_spans+esi],ebp + add ebp,offset espan_t_size + +; reset spanstate for all surfaces in the surface stack +Lgs_resetspanstate: + mov ds:dword ptr[st_spanstate+esi],ecx + mov esi,ds:dword ptr[st_next+esi] + cmp esi,012345678h ; &surfaces[1] +LPatch4: + jnz Lgs_resetspanstate + +; store the final span_p + mov ds:dword ptr[_span_p],ebp + + pop ebx ; restore register variables + pop esi + pop edi + pop ebp ; restore the caller's stack frame + ret + + +; --------------------------------------------------------------- +; 1/z sorting for bmodels in the same leaf +; --------------------------------------------------------------- + align 4 +Lxl_done: + inc edx + mov ds:dword ptr[st_spanstate+edi],edx + + jmp Lgs_nextedge + + + align 4 +Lzcheck_for_newtop: + mov eax,ds:dword ptr[et_u+ebx] + sub eax,0FFFFFh + mov ds:dword ptr[Ltemp],eax + fild ds:dword ptr[Ltemp] + + fmul ds:dword ptr[float_1_div_0100000h] ; fu = (float)(edge->u - 0xFFFFF) * +; (1.0 / 0x100000); + + fld st(0) ; fu | fu + fmul ds:dword ptr[st_d_zistepu+edi] ; fu*surf->d_zistepu | fu + fld ds:dword ptr[_fv] ; fv | fu*surf->d_zistepu | fu + fmul ds:dword ptr[st_d_zistepv+edi] ; fv*surf->d_zistepv | fu*surf->d_zistepu | fu + fxch st(1) ; fu*surf->d_zistepu | fv*surf->d_zistepv | fu + fadd ds:dword ptr[st_d_ziorigin+edi] ; fu*surf->d_zistepu + surf->d_ziorigin | +; fv*surf->d_zistepv | fu + + fld ds:dword ptr[st_d_zistepu+esi] ; surf2->d_zistepu | +; fu*surf->d_zistepu + surf->d_ziorigin | +; fv*surf->d_zistepv | fu + fmul st(0),st(3) ; fu*surf2->d_zistepu | +; fu*surf->d_zistepu + surf->d_ziorigin | +; fv*surf->d_zistepv | fu + fxch st(1) ; fu*surf->d_zistepu + surf->d_ziorigin | +; fu*surf2->d_zistepu | +; fv*surf->d_zistepv | fu + faddp st(2),st(0) ; fu*surf2->d_zistepu | newzi | fu + + fld ds:dword ptr[_fv] ; fv | fu*surf2->d_zistepu | newzi | fu + fmul ds:dword ptr[st_d_zistepv+esi] ; fv*surf2->d_zistepv | +; fu*surf2->d_zistepu | newzi | fu + fld st(2) ; newzi | fv*surf2->d_zistepv | +; fu*surf2->d_zistepu | newzi | fu + fmul ds:dword ptr[float_point_999] ; newzibottom | fv*surf2->d_zistepv | +; fu*surf2->d_zistepu | newzi | fu + + fxch st(2) ; fu*surf2->d_zistepu | fv*surf2->d_zistepv | +; newzibottom | newzi | fu + fadd ds:dword ptr[st_d_ziorigin+esi] ; fu*surf2->d_zistepu + surf2->d_ziorigin | +; fv*surf2->d_zistepv | newzibottom | newzi | +; fu + faddp st(1),st(0) ; testzi | newzibottom | newzi | fu + fxch st(1) ; newzibottom | testzi | newzi | fu + +; if (newzibottom >= testzi) +; goto newtop; + + fcomp st(1) ; testzi | newzi | fu + + fxch st(1) ; newzi | testzi | fu + fmul ds:dword ptr[float_1_point_001] ; newzitop | testzi | fu + fxch st(1) ; testzi | newzitop | fu + + fnstsw ax + test ah,001h + jz Lnewtop_fpop3 + +; if (newzitop >= testzi) +; { + + fcomp st(1) ; newzitop | fu + fnstsw ax + test ah,045h + jz Lsortloop_fpop2 + +; if (surf->d_zistepu >= surf2->d_zistepu) +; goto newtop; + + fld ds:dword ptr[st_d_zistepu+edi] ; surf->d_zistepu | newzitop | fu + fcomp ds:dword ptr[st_d_zistepu+esi] ; newzitop | fu + fnstsw ax + test ah,001h + jz Lnewtop_fpop2 + +Lsortloop_fpop2: + fstp st(0) ; clear the FP stack + fstp st(0) + mov eax,ds:dword ptr[st_key+edi] + jmp Lsortloop + + + public _R_EdgeCodeEnd +_R_EdgeCodeEnd: + + +;---------------------------------------------------------------------- +; Surface array address code patching routine +;---------------------------------------------------------------------- + + align 4 + public _R_SurfacePatch +_R_SurfacePatch: + + mov eax,ds:dword ptr[_surfaces] + add eax,offset st_size + mov ds:dword ptr[LPatch4-4],eax + + add eax,offset st_next + mov ds:dword ptr[LPatch0-4],eax + mov ds:dword ptr[LPatch2-4],eax + mov ds:dword ptr[LPatch3-4],eax + + ret + +_TEXT ENDS +endif ;id386 + END diff --git a/ref_soft/r_image.c b/ref_soft/r_image.c new file mode 100644 index 000000000..9622d00ec --- /dev/null +++ b/ref_soft/r_image.c @@ -0,0 +1,617 @@ +/* +Copyright (C) 1997-2001 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. + +*/ + +#include "r_local.h" + + +#define MAX_RIMAGES 1024 +image_t r_images[MAX_RIMAGES]; +int numr_images; + + +/* +=============== +R_ImageList_f +=============== +*/ +void R_ImageList_f (void) +{ + int i; + image_t *image; + int texels; + + ri.Con_Printf (PRINT_ALL, "------------------\n"); + texels = 0; + + for (i=0, image=r_images ; iregistration_sequence <= 0) + continue; + texels += image->width*image->height; + switch (image->type) + { + case it_skin: + ri.Con_Printf (PRINT_ALL, "M"); + break; + case it_sprite: + ri.Con_Printf (PRINT_ALL, "S"); + break; + case it_wall: + ri.Con_Printf (PRINT_ALL, "W"); + break; + case it_pic: + ri.Con_Printf (PRINT_ALL, "P"); + break; + default: + ri.Con_Printf (PRINT_ALL, " "); + break; + } + + ri.Con_Printf (PRINT_ALL, " %3i %3i : %s\n", + image->width, image->height, image->name); + } + ri.Con_Printf (PRINT_ALL, "Total texel count: %i\n", texels); +} + + +/* +================================================================= + +PCX LOADING + +================================================================= +*/ + +/* +============== +LoadPCX +============== +*/ +void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height) +{ + byte *raw; + pcx_t *pcx; + int x, y; + int len; + int dataByte, runLength; + byte *out, *pix; + + *pic = NULL; + + // + // load the file + // + len = ri.FS_LoadFile (filename, (void **)&raw); + if (!raw) + { + ri.Con_Printf (PRINT_DEVELOPER, "Bad pcx file %s\n", filename); + return; + } + + // + // parse the PCX file + // + pcx = (pcx_t *)raw; + + pcx->xmin = LittleShort(pcx->xmin); + pcx->ymin = LittleShort(pcx->ymin); + pcx->xmax = LittleShort(pcx->xmax); + pcx->ymax = LittleShort(pcx->ymax); + pcx->hres = LittleShort(pcx->hres); + pcx->vres = LittleShort(pcx->vres); + pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); + pcx->palette_type = LittleShort(pcx->palette_type); + + raw = &pcx->data; + + if (pcx->manufacturer != 0x0a + || pcx->version != 5 + || pcx->encoding != 1 + || pcx->bits_per_pixel != 8 + || pcx->xmax >= 640 + || pcx->ymax >= 480) + { + ri.Con_Printf (PRINT_ALL, "Bad pcx file %s\n", filename); + return; + } + + out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); + + *pic = out; + + pix = out; + + if (palette) + { + *palette = malloc(768); + memcpy (*palette, (byte *)pcx + len - 768, 768); + } + + if (width) + *width = pcx->xmax+1; + if (height) + *height = pcx->ymax+1; + + for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1) + { + for (x=0 ; x<=pcx->xmax ; ) + { + dataByte = *raw++; + + if((dataByte & 0xC0) == 0xC0) + { + runLength = dataByte & 0x3F; + dataByte = *raw++; + } + else + runLength = 1; + + while(runLength-- > 0) + pix[x++] = dataByte; + } + + } + + if ( raw - (byte *)pcx > len) + { + ri.Con_Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename); + free (*pic); + *pic = NULL; + } + + ri.FS_FreeFile (pcx); +} + +/* +========================================================= + +TARGA LOADING + +========================================================= +*/ + +typedef struct _TargaHeader { + unsigned char id_length, colormap_type, image_type; + unsigned short colormap_index, colormap_length; + unsigned char colormap_size; + unsigned short x_origin, y_origin, width, height; + unsigned char pixel_size, attributes; +} TargaHeader; + + +/* +============= +LoadTGA +============= +*/ +void LoadTGA (char *name, byte **pic, int *width, int *height) +{ + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + byte *buf_p; + byte *buffer; + int length; + TargaHeader targa_header; + byte *targa_rgba; + + *pic = NULL; + + // + // load the file + // + length = ri.FS_LoadFile (name, (void **)&buffer); + if (!buffer) + { + ri.Con_Printf (PRINT_DEVELOPER, "Bad tga file %s\n", name); + return; + } + + buf_p = buffer; + + targa_header.id_length = *buf_p++; + targa_header.colormap_type = *buf_p++; + targa_header.image_type = *buf_p++; + + targa_header.colormap_index = LittleShort ( *((short *)buf_p) ); + buf_p+=2; + targa_header.colormap_length = LittleShort ( *((short *)buf_p) ); + buf_p+=2; + targa_header.colormap_size = *buf_p++; + targa_header.x_origin = LittleShort ( *((short *)buf_p) ); + buf_p+=2; + targa_header.y_origin = LittleShort ( *((short *)buf_p) ); + buf_p+=2; + targa_header.width = LittleShort ( *((short *)buf_p) ); + buf_p+=2; + targa_header.height = LittleShort ( *((short *)buf_p) ); + buf_p+=2; + targa_header.pixel_size = *buf_p++; + targa_header.attributes = *buf_p++; + + if (targa_header.image_type!=2 + && targa_header.image_type!=10) + ri.Sys_Error (ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n"); + + if (targa_header.colormap_type !=0 + || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24)) + ri.Sys_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + if (width) + *width = columns; + if (height) + *height = rows; + + targa_rgba = malloc (numPixels*4); + *pic = targa_rgba; + + if (targa_header.id_length != 0) + buf_p += targa_header.id_length; // skip TARGA image comment + + if (targa_header.image_type==2) { // Uncompressed, RGB images + for(row=rows-1; row>=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + else { // non run-length packet + for(j=0;j0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + } + breakOut:; + } + } + + ri.FS_FreeFile (buffer); +} + + +//======================================================= + +image_t *R_FindFreeImage (void) +{ + image_t *image; + int i; + + // find a free image_t + for (i=0, image=r_images ; iregistration_sequence) + break; + } + if (i == numr_images) + { + if (numr_images == MAX_RIMAGES) + ri.Sys_Error (ERR_DROP, "MAX_RIMAGES"); + numr_images++; + } + image = &r_images[i]; + + return image; +} + +/* +================ +GL_LoadPic + +================ +*/ +image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type) +{ + image_t *image; + int i, c, b; + + image = R_FindFreeImage (); + if (strlen(name) >= sizeof(image->name)) + ri.Sys_Error (ERR_DROP, "Draw_LoadPic: \"%s\" is too long", name); + strcpy (image->name, name); + image->registration_sequence = registration_sequence; + + image->width = width; + image->height = height; + image->type = type; + + c = width*height; + image->pixels[0] = malloc (c); + image->transparent = false; + for (i=0 ; itransparent = true; + image->pixels[0][i] = b; + } + + return image; +} + +/* +================ +R_LoadWal +================ +*/ +image_t *R_LoadWal (char *name) +{ + miptex_t *mt; + int ofs; + image_t *image; + int size; + + ri.FS_LoadFile (name, (void **)&mt); + if (!mt) + { + ri.Con_Printf (PRINT_ALL, "R_LoadWal: can't load %s\n", name); + return r_notexture_mip; + } + + image = R_FindFreeImage (); + strcpy (image->name, name); + image->width = LittleLong (mt->width); + image->height = LittleLong (mt->height); + image->type = it_wall; + image->registration_sequence = registration_sequence; + + size = image->width*image->height * (256+64+16+4)/256; + image->pixels[0] = malloc (size); + image->pixels[1] = image->pixels[0] + image->width*image->height; + image->pixels[2] = image->pixels[1] + image->width*image->height/4; + image->pixels[3] = image->pixels[2] + image->width*image->height/16; + + ofs = LittleLong (mt->offsets[0]); + memcpy ( image->pixels[0], (byte *)mt + ofs, size); + + ri.FS_FreeFile ((void *)mt); + + return image; +} + + +/* +=============== +R_FindImage + +Finds or loads the given image +=============== +*/ +image_t *R_FindImage (char *name, imagetype_t type) +{ + image_t *image; + int i, len; + byte *pic, *palette; + int width, height; + + if (!name) + return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: NULL name"); + len = strlen(name); + if (len<5) + return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: bad name: %s", name); + + // look for it + for (i=0, image=r_images ; iname)) + { + image->registration_sequence = registration_sequence; + return image; + } + } + + // + // load the pic from disk + // + pic = NULL; + palette = NULL; + if (!strcmp(name+len-4, ".pcx")) + { + LoadPCX (name, &pic, &palette, &width, &height); + if (!pic) + return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s", name); + image = GL_LoadPic (name, pic, width, height, type); + } + else if (!strcmp(name+len-4, ".wal")) + { + image = R_LoadWal (name); + } + else if (!strcmp(name+len-4, ".tga")) + return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s in software renderer", name); + else + return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: bad extension on: %s", name); + + if (pic) + free(pic); + if (palette) + free(palette); + + return image; +} + + + +/* +=============== +R_RegisterSkin +=============== +*/ +struct image_s *R_RegisterSkin (char *name) +{ + return R_FindImage (name, it_skin); +} + + +/* +================ +R_FreeUnusedImages + +Any image that was not touched on this registration sequence +will be freed. +================ +*/ +void R_FreeUnusedImages (void) +{ + int i; + image_t *image; + + for (i=0, image=r_images ; iregistration_sequence == registration_sequence) + { + Com_PageInMemory ((byte *)image->pixels[0], image->width*image->height); + continue; // used this sequence + } + if (!image->registration_sequence) + continue; // free texture + if (image->type == it_pic) + continue; // don't free pics + // free it + free (image->pixels[0]); // the other mip levels just follow + memset (image, 0, sizeof(*image)); + } +} + + + +/* +=============== +R_InitImages +=============== +*/ +void R_InitImages (void) +{ + registration_sequence = 1; +} + +/* +=============== +R_ShutdownImages +=============== +*/ +void R_ShutdownImages (void) +{ + int i; + image_t *image; + + for (i=0, image=r_images ; iregistration_sequence) + continue; // free texture + // free it + free (image->pixels[0]); // the other mip levels just follow + memset (image, 0, sizeof(*image)); + } +} + diff --git a/ref_soft/r_light.c b/ref_soft/r_light.c new file mode 100644 index 000000000..34faa4437 --- /dev/null +++ b/ref_soft/r_light.c @@ -0,0 +1,442 @@ +/* +Copyright (C) 1997-2001 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_light.c + +#include "r_local.h" + +int r_dlightframecount; + + +/* +============================================================================= + +DYNAMIC LIGHTS + +============================================================================= +*/ + +/* +============= +R_MarkLights +============= +*/ +void R_MarkLights (dlight_t *light, int bit, mnode_t *node) +{ + mplane_t *splitplane; + float dist; + msurface_t *surf; + int i; + + if (node->contents != -1) + return; + + splitplane = node->plane; + dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; + +//===== +//PGM + i=light->intensity; + if(i<0) + i=-i; +//PGM +//===== + + if (dist > i) // PGM (dist > light->intensity) + { + R_MarkLights (light, bit, node->children[0]); + return; + } + if (dist < -i) // PGM (dist < -light->intensity) + { + R_MarkLights (light, bit, node->children[1]); + return; + } + +// mark the polygons + surf = r_worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->dlightframe != r_dlightframecount) + { + surf->dlightbits = 0; + surf->dlightframe = r_dlightframecount; + } + surf->dlightbits |= bit; + } + + R_MarkLights (light, bit, node->children[0]); + R_MarkLights (light, bit, node->children[1]); +} + + +/* +============= +R_PushDlights +============= +*/ +void R_PushDlights (model_t *model) +{ + int i; + dlight_t *l; + + r_dlightframecount = r_framecount; + for (i=0, l = r_newrefdef.dlights ; inodes + model->firstnode); + } +} + + +/* +============================================================================= + +LIGHT SAMPLING + +============================================================================= +*/ + +vec3_t pointcolor; +mplane_t *lightplane; // used as shadow plane +vec3_t lightspot; + +int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) +{ + float front, back, frac; + int side; + mplane_t *plane; + vec3_t mid; + msurface_t *surf; + int s, t, ds, dt; + int i; + mtexinfo_t *tex; + byte *lightmap; + float *scales; + int maps; + float samp; + int r; + + if (node->contents != -1) + return -1; // didn't hit anything + +// calculate mid point + +// FIXME: optimize for axial + plane = node->plane; + front = DotProduct (start, plane->normal) - plane->dist; + back = DotProduct (end, plane->normal) - plane->dist; + side = front < 0; + + if ( (back < 0) == side) + return RecursiveLightPoint (node->children[side], start, end); + + frac = front / (front-back); + mid[0] = start[0] + (end[0] - start[0])*frac; + mid[1] = start[1] + (end[1] - start[1])*frac; + mid[2] = start[2] + (end[2] - start[2])*frac; + if (plane->type < 3) // axial planes + mid[plane->type] = plane->dist; + +// go down front side + r = RecursiveLightPoint (node->children[side], start, mid); + if (r >= 0) + return r; // hit something + + if ( (back < 0) == side ) + return -1; // didn't hit anuthing + +// check for impact on this node + VectorCopy (mid, lightspot); + lightplane = plane; + + surf = r_worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->flags&(SURF_DRAWTURB|SURF_DRAWSKY)) + continue; // no lightmaps + + tex = surf->texinfo; + + s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3]; + t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3]; + if (s < surf->texturemins[0] || + t < surf->texturemins[1]) + continue; + + ds = s - surf->texturemins[0]; + dt = t - surf->texturemins[1]; + + if ( ds > surf->extents[0] || dt > surf->extents[1] ) + continue; + + if (!surf->samples) + return 0; + + ds >>= 4; + dt >>= 4; + + lightmap = surf->samples; + VectorCopy (vec3_origin, pointcolor); + if (lightmap) + { + lightmap += dt * ((surf->extents[0]>>4)+1) + ds; + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + samp = *lightmap * /* 0.5 * */ (1.0/255); // adjust for gl scale + scales = r_newrefdef.lightstyles[surf->styles[maps]].rgb; + VectorMA (pointcolor, samp, scales, pointcolor); + lightmap += ((surf->extents[0]>>4)+1) * + ((surf->extents[1]>>4)+1); + } + } + + return 1; + } + +// go down back side + return RecursiveLightPoint (node->children[!side], mid, end); +} + +/* +=============== +R_LightPoint +=============== +*/ +void R_LightPoint (vec3_t p, vec3_t color) +{ + vec3_t end; + float r; + int lnum; + dlight_t *dl; + float light; + vec3_t dist; + float add; + + if (!r_worldmodel->lightdata) + { + color[0] = color[1] = color[2] = 1.0; + return; + } + + end[0] = p[0]; + end[1] = p[1]; + end[2] = p[2] - 2048; + + r = RecursiveLightPoint (r_worldmodel->nodes, p, end); + + if (r == -1) + { + VectorCopy (vec3_origin, color); + } + else + { + VectorCopy (pointcolor, color); + } + + // + // add dynamic lights + // + light = 0; + for (lnum=0 ; lnumorigin, + dl->origin, + dist); + add = dl->intensity - VectorLength(dist); + add *= (1.0/256); + if (add > 0) + { + VectorMA (color, add, dl->color, color); + } + } +} + +//=================================================================== + + +unsigned blocklights[1024]; // allow some very large lightmaps + +/* +=============== +R_AddDynamicLights +=============== +*/ +void R_AddDynamicLights (void) +{ + msurface_t *surf; + int lnum; + int sd, td; + float dist, rad, minlight; + vec3_t impact, local; + int s, t; + int i; + int smax, tmax; + mtexinfo_t *tex; + dlight_t *dl; + int negativeLight; //PGM + + surf = r_drawsurf.surf; + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + for (lnum=0 ; lnumdlightbits & (1<intensity; + +//===== +//PGM + negativeLight = 0; + if(rad < 0) + { + negativeLight = 1; + rad = -rad; + } +//PGM +//===== + + dist = DotProduct (dl->origin, surf->plane->normal) - + surf->plane->dist; + rad -= fabs(dist); + minlight = 32; // dl->minlight; + if (rad < minlight) + continue; + minlight = rad - minlight; + + for (i=0 ; i<3 ; i++) + { + impact[i] = dl->origin[i] - + surf->plane->normal[i]*dist; + } + + local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; + local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; + + local[0] -= surf->texturemins[0]; + local[1] -= surf->texturemins[1]; + + for (t = 0 ; t td) + dist = sd + (td>>1); + else + dist = td + (sd>>1); +//==== +//PGM + if(!negativeLight) + { + if (dist < minlight) + blocklights[t*smax + s] += (rad - dist)*256; + } + else + { + if (dist < minlight) + blocklights[t*smax + s] -= (rad - dist)*256; + if(blocklights[t*smax + s] < minlight) + blocklights[t*smax + s] = minlight; + } +//PGM +//==== + } + } + } +} + +/* +=============== +R_BuildLightMap + +Combine and scale multiple lightmaps into the 8.8 format in blocklights +=============== +*/ +void R_BuildLightMap (void) +{ + int smax, tmax; + int t; + int i, size; + byte *lightmap; + unsigned scale; + int maps; + msurface_t *surf; + + surf = r_drawsurf.surf; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + size = smax*tmax; + + if (r_fullbright->value || !r_worldmodel->lightdata) + { + for (i=0 ; isamples; + if (lightmap) + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + scale = r_drawsurf.lightadj[maps]; // 8.8 fraction + for (i=0 ; idlightframe == r_framecount) + R_AddDynamicLights (); + +// bound, invert, and shift + for (i=0 ; i> (8 - VID_CBITS); + + if (t < (1 << 6)) + t = (1 << 6); + + blocklights[i] = t; + } +} + diff --git a/ref_soft/r_local.h b/ref_soft/r_local.h new file mode 100644 index 000000000..3d25f11e7 --- /dev/null +++ b/ref_soft/r_local.h @@ -0,0 +1,849 @@ +/* +Copyright (C) 1997-2001 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. + +*/ + +#include +#include +#include +#include +#include + +#include "../client/ref.h" + +#define REF_VERSION "SOFT 0.01" + +// up / down +#define PITCH 0 + +// left / right +#define YAW 1 + +// fall over +#define ROLL 2 + + +/* + + skins will be outline flood filled and mip mapped + pics and sprites with alpha will be outline flood filled + pic won't be mip mapped + + model skin + sprite frame + wall texture + pic + +*/ + +typedef enum +{ + it_skin, + it_sprite, + it_wall, + it_pic, + it_sky +} imagetype_t; + +typedef struct image_s +{ + char name[MAX_QPATH]; // game path, including extension + imagetype_t type; + int width, height; + qboolean transparent; // true if any 255 pixels in image + int registration_sequence; // 0 = free + byte *pixels[4]; // mip levels +} image_t; + + +//=================================================================== + +typedef unsigned char pixel_t; + +typedef struct vrect_s +{ + int x,y,width,height; + struct vrect_s *pnext; +} vrect_t; + +typedef struct +{ + pixel_t *buffer; // invisible buffer + pixel_t *colormap; // 256 * VID_GRADES size + pixel_t *alphamap; // 256 * 256 translucency map + int rowbytes; // may be > width if displayed in a window + // can be negative for stupid dibs + int width; + int height; +} viddef_t; + +typedef enum +{ + rserr_ok, + + rserr_invalid_fullscreen, + rserr_invalid_mode, + + rserr_unknown +} rserr_t; + +extern viddef_t vid; + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct +{ + vrect_t vrect; // subwindow in video for refresh + // FIXME: not need vrect next field here? + vrect_t aliasvrect; // scaled Alias version + int vrectright, vrectbottom; // right & bottom screen coords + int aliasvrectright, aliasvrectbottom; // scaled Alias versions + float vrectrightedge; // rightmost right edge we care about, + // for use in edge list + float fvrectx, fvrecty; // for floating-point compares + float fvrectx_adj, fvrecty_adj; // left and top edges, for clamping + int vrect_x_adj_shift20; // (vrect.x + 0.5 - epsilon) << 20 + int vrectright_adj_shift20; // (vrectright + 0.5 - epsilon) << 20 + float fvrectright_adj, fvrectbottom_adj; + // right and bottom edges, for clamping + float fvrectright; // rightmost edge, for Alias clamping + float fvrectbottom; // bottommost edge, for Alias clamping + float horizontalFieldOfView; // at Z = 1.0, this many X is visible + // 2.0 = 90 degrees + float xOrigin; // should probably always be 0.5 + float yOrigin; // between be around 0.3 to 0.5 + + vec3_t vieworg; + vec3_t viewangles; + + int ambientlight; +} oldrefdef_t; + +extern oldrefdef_t r_refdef; + +#include "r_model.h" + +#define CACHE_SIZE 32 + +/* +==================================================== + + CONSTANTS + +==================================================== +*/ + +#define VID_CBITS 6 +#define VID_GRADES (1 << VID_CBITS) + + +// r_shared.h: general refresh-related stuff shared between the refresh and the +// driver + + +#define MAXVERTS 64 // max points in a surface polygon +#define MAXWORKINGVERTS (MAXVERTS+4) // max points in an intermediate + // polygon (while processing) +// !!! if this is changed, it must be changed in d_ifacea.h too !!! +#define MAXHEIGHT 1200 +#define MAXWIDTH 1600 + +#define INFINITE_DISTANCE 0x10000 // distance that's always guaranteed to + // be farther away than anything in + // the scene + + +// d_iface.h: interface header file for rasterization driver modules + +#define WARP_WIDTH 320 +#define WARP_HEIGHT 240 + +#define MAX_LBM_HEIGHT 480 + + +#define PARTICLE_Z_CLIP 8.0 + +// !!! must be kept the same as in quakeasm.h !!! +#define TRANSPARENT_COLOR 0xFF + + +// !!! if this is changed, it must be changed in d_ifacea.h too !!! +#define TURB_TEX_SIZE 64 // base turbulent texture size + +// !!! if this is changed, it must be changed in d_ifacea.h too !!! +#define CYCLE 128 // turbulent cycle size + +#define SCANBUFFERPAD 0x1000 + +#define DS_SPAN_LIST_END -128 + +#define NUMSTACKEDGES 2000 +#define MINEDGES NUMSTACKEDGES +#define NUMSTACKSURFACES 1000 +#define MINSURFACES NUMSTACKSURFACES +#define MAXSPANS 3000 + +// flags in finalvert_t.flags +#define ALIAS_LEFT_CLIP 0x0001 +#define ALIAS_TOP_CLIP 0x0002 +#define ALIAS_RIGHT_CLIP 0x0004 +#define ALIAS_BOTTOM_CLIP 0x0008 +#define ALIAS_Z_CLIP 0x0010 +#define ALIAS_XY_CLIP_MASK 0x000F + +#define SURFCACHE_SIZE_AT_320X240 1024*768 + +#define BMODEL_FULLY_CLIPPED 0x10 // value returned by R_BmodelCheckBBox () + // if bbox is trivially rejected + +#define XCENTERING (1.0 / 2.0) +#define YCENTERING (1.0 / 2.0) + +#define CLIP_EPSILON 0.001 + +#define BACKFACE_EPSILON 0.01 + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +#define NEAR_CLIP 0.01 + + +#define MAXALIASVERTS 2000 // TODO: tune this +#define ALIAS_Z_CLIP_PLANE 4 + +// turbulence stuff + +#define AMP 8*0x10000 +#define AMP2 3 +#define SPEED 20 + + +/* +==================================================== + +TYPES + +==================================================== +*/ + +typedef struct +{ + float u, v; + float s, t; + float zi; +} emitpoint_t; + +/* +** if you change this structure be sure to change the #defines +** listed after it! +*/ +#define SMALL_FINALVERT 0 + +#if SMALL_FINALVERT + +typedef struct finalvert_s { + short u, v, s, t; + int l; + int zi; + int flags; + float xyz[3]; // eye space +} finalvert_t; + +#define FINALVERT_V0 0 +#define FINALVERT_V1 2 +#define FINALVERT_V2 4 +#define FINALVERT_V3 6 +#define FINALVERT_V4 8 +#define FINALVERT_V5 12 +#define FINALVERT_FLAGS 16 +#define FINALVERT_X 20 +#define FINALVERT_Y 24 +#define FINALVERT_Z 28 +#define FINALVERT_SIZE 32 + +#else + +typedef struct finalvert_s { + int u, v, s, t; + int l; + int zi; + int flags; + float xyz[3]; // eye space +} finalvert_t; + +#define FINALVERT_V0 0 +#define FINALVERT_V1 4 +#define FINALVERT_V2 8 +#define FINALVERT_V3 12 +#define FINALVERT_V4 16 +#define FINALVERT_V5 20 +#define FINALVERT_FLAGS 24 +#define FINALVERT_X 28 +#define FINALVERT_Y 32 +#define FINALVERT_Z 36 +#define FINALVERT_SIZE 40 + +#endif + +typedef struct +{ + void *pskin; + int pskindesc; + int skinwidth; + int skinheight; + dtriangle_t *ptriangles; + finalvert_t *pfinalverts; + int numtriangles; + int drawtype; + int seamfixupX16; + qboolean do_vis_thresh; + int vis_thresh; +} affinetridesc_t; + +typedef struct +{ + byte *surfdat; // destination for generated surface + int rowbytes; // destination logical width in bytes + msurface_t *surf; // description for surface to generate + fixed8_t lightadj[MAXLIGHTMAPS]; + // adjust for lightmap levels for dynamic lighting + image_t *image; + int surfmip; // mipmapped ratio of surface texels / world pixels + int surfwidth; // in mipmapped texels + int surfheight; // in mipmapped texels +} drawsurf_t; + + + +typedef struct { + int ambientlight; + int shadelight; + float *plightvec; +} alight_t; + +// clipped bmodel edges + +typedef struct bedge_s +{ + mvertex_t *v[2]; + struct bedge_s *pnext; +} bedge_t; + + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct clipplane_s +{ + vec3_t normal; + float dist; + struct clipplane_s *next; + byte leftedge; + byte rightedge; + byte reserved[2]; +} clipplane_t; + + +typedef struct surfcache_s +{ + struct surfcache_s *next; + struct surfcache_s **owner; // NULL is an empty chunk of memory + int lightadj[MAXLIGHTMAPS]; // checked for strobe flush + int dlight; + int size; // including header + unsigned width; + unsigned height; // DEBUG only needed for debug + float mipscale; + image_t *image; + byte data[4]; // width*height elements +} surfcache_t; + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct espan_s +{ + int u, v, count; + struct espan_s *pnext; +} espan_t; + +// used by the polygon drawer (R_POLY.C) and sprite setup code (R_SPRITE.C) +typedef struct +{ + int nump; + emitpoint_t *pverts; + byte *pixels; // image + int pixel_width; // image width + int pixel_height; // image height + vec3_t vup, vright, vpn; // in worldspace, for plane eq + float dist; + float s_offset, t_offset; + float viewer_position[3]; + void (*drawspanlet)( void ); + int stipple_parity; +} polydesc_t; + +// FIXME: compress, make a union if that will help +// insubmodel is only 1, flags is fewer than 32, spanstate could be a byte +typedef struct surf_s +{ + struct surf_s *next; // active surface stack in r_edge.c + struct surf_s *prev; // used in r_edge.c for active surf stack + struct espan_s *spans; // pointer to linked list of spans to draw + int key; // sorting key (BSP order) + int last_u; // set during tracing + int spanstate; // 0 = not in span + // 1 = in span + // -1 = in inverted span (end before + // start) + int flags; // currentface flags + msurface_t *msurf; + entity_t *entity; + float nearzi; // nearest 1/z on surface, for mipmapping + qboolean insubmodel; + float d_ziorigin, d_zistepu, d_zistepv; + + int pad[2]; // to 64 bytes +} surf_t; + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct edge_s +{ + fixed16_t u; + fixed16_t u_step; + struct edge_s *prev, *next; + unsigned short surfs[2]; + struct edge_s *nextremove; + float nearzi; + medge_t *owner; +} edge_t; + + +/* +==================================================== + +VARS + +==================================================== +*/ + +extern int d_spanpixcount; +extern int r_framecount; // sequence # of current frame since Quake + // started +extern float r_aliasuvscale; // scale-up factor for screen u and v + // on Alias vertices passed to driver +extern qboolean r_dowarp; + +extern affinetridesc_t r_affinetridesc; + +extern vec3_t r_pright, r_pup, r_ppn; + +void D_DrawSurfaces (void); +void R_DrawParticle( void ); +void D_ViewChanged (void); +void D_WarpScreen (void); +void R_PolysetUpdateTables (void); + +extern void *acolormap; // FIXME: should go away + +//=======================================================================// + +// callbacks to Quake + +extern drawsurf_t r_drawsurf; + +void R_DrawSurface (void); + +extern int c_surf; + +extern byte r_warpbuffer[WARP_WIDTH * WARP_HEIGHT]; + + + + +extern float scale_for_mip; + +extern qboolean d_roverwrapped; +extern surfcache_t *sc_rover; +extern surfcache_t *d_initial_rover; + +extern float d_sdivzstepu, d_tdivzstepu, d_zistepu; +extern float d_sdivzstepv, d_tdivzstepv, d_zistepv; +extern float d_sdivzorigin, d_tdivzorigin, d_ziorigin; + +extern fixed16_t sadjust, tadjust; +extern fixed16_t bbextents, bbextentt; + + +void D_DrawSpans16 (espan_t *pspans); +void D_DrawZSpans (espan_t *pspans); +void Turbulent8 (espan_t *pspan); +void NonTurbulent8 (espan_t *pspan); //PGM + +surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel); + +extern int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle; + +extern int d_pix_min, d_pix_max, d_pix_shift; + +extern pixel_t *d_viewbuffer; +extern short *d_pzbuffer; +extern unsigned int d_zrowbytes, d_zwidth; +extern short *zspantable[MAXHEIGHT]; +extern int d_scantable[MAXHEIGHT]; + +extern int d_minmip; +extern float d_scalemip[3]; + +//=================================================================== + +extern int cachewidth; +extern pixel_t *cacheblock; +extern int r_screenwidth; + +extern int r_drawnpolycount; + +extern int sintable[1280]; +extern int intsintable[1280]; +extern int blanktable[1280]; // PGM + +extern vec3_t vup, base_vup; +extern vec3_t vpn, base_vpn; +extern vec3_t vright, base_vright; + +extern surf_t *surfaces, *surface_p, *surf_max; + +// surfaces are generated in back to front order by the bsp, so if a surf +// pointer is greater than another one, it should be drawn in front +// surfaces[1] is the background, and is used as the active surface stack. +// surfaces[0] is a dummy, because index 0 is used to indicate no surface +// attached to an edge_t + +//=================================================================== + +extern vec3_t sxformaxis[4]; // s axis transformed into viewspace +extern vec3_t txformaxis[4]; // t axis transformed into viewspac + +extern float xcenter, ycenter; +extern float xscale, yscale; +extern float xscaleinv, yscaleinv; +extern float xscaleshrink, yscaleshrink; + +extern void TransformVector (vec3_t in, vec3_t out); +extern void SetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv, + fixed8_t endvertu, fixed8_t endvertv); + +extern int ubasestep, errorterm, erroradjustup, erroradjustdown; + +//=========================================================================== + +extern cvar_t *sw_aliasstats; +extern cvar_t *sw_clearcolor; +extern cvar_t *sw_drawflat; +extern cvar_t *sw_draworder; +extern cvar_t *sw_maxedges; +extern cvar_t *sw_maxsurfs; +extern cvar_t *sw_mipcap; +extern cvar_t *sw_mipscale; +extern cvar_t *sw_mode; +extern cvar_t *sw_reportsurfout; +extern cvar_t *sw_reportedgeout; +extern cvar_t *sw_stipplealpha; +extern cvar_t *sw_surfcacheoverride; +extern cvar_t *sw_waterwarp; + +extern cvar_t *r_fullbright; +extern cvar_t *r_lefthand; +extern cvar_t *r_drawentities; +extern cvar_t *r_drawworld; +extern cvar_t *r_dspeeds; +extern cvar_t *r_lerpmodels; + +extern cvar_t *r_speeds; + +extern cvar_t *r_lightlevel; //FIXME HACK + +extern cvar_t *vid_fullscreen; +extern cvar_t *vid_gamma; + + +extern clipplane_t view_clipplanes[4]; +extern int *pfrustum_indexes[4]; + + +//============================================================================= + +void R_RenderWorld (void); + +//============================================================================= + +extern mplane_t screenedge[4]; + +extern vec3_t r_origin; + +extern entity_t r_worldentity; +extern model_t *currentmodel; +extern entity_t *currententity; +extern vec3_t modelorg; +extern vec3_t r_entorigin; + +extern float verticalFieldOfView; +extern float xOrigin, yOrigin; + +extern int r_visframecount; + +extern msurface_t *r_alpha_surfaces; + +//============================================================================= + +void R_ClearPolyList (void); +void R_DrawPolyList (void); + +// +// current entity info +// +extern qboolean insubmodel; + +void R_DrawAlphaSurfaces( void ); + +void R_DrawSprite (void); +void R_DrawBeam( entity_t *e ); + +void R_RenderFace (msurface_t *fa, int clipflags); +void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf); +void R_TransformPlane (mplane_t *p, float *normal, float *dist); +void R_TransformFrustum (void); +void R_DrawSurfaceBlock16 (void); +void R_DrawSurfaceBlock8 (void); + +#if id386 + +void R_DrawSurfaceBlock8_mip0 (void); +void R_DrawSurfaceBlock8_mip1 (void); +void R_DrawSurfaceBlock8_mip2 (void); +void R_DrawSurfaceBlock8_mip3 (void); + +#endif + +void R_GenSkyTile (void *pdest); +void R_GenSkyTile16 (void *pdest); +void R_Surf8Patch (void); +void R_Surf16Patch (void); +void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode); +void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode); + +void R_AddPolygonEdges (emitpoint_t *pverts, int numverts, int miplevel); +surf_t *R_GetSurf (void); +void R_AliasDrawModel (void); +void R_BeginEdgeFrame (void); +void R_ScanEdges (void); +void D_DrawSurfaces (void); +void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist); +void R_StepActiveU (edge_t *pedge); +void R_RemoveEdges (edge_t *pedge); +void R_PushDlights (model_t *model); + +extern void R_Surf8Start (void); +extern void R_Surf8End (void); +extern void R_Surf16Start (void); +extern void R_Surf16End (void); +extern void R_EdgeCodeStart (void); +extern void R_EdgeCodeEnd (void); + +extern void R_RotateBmodel (void); + +extern int c_faceclip; +extern int r_polycount; +extern int r_wholepolycount; + +extern int ubasestep, errorterm, erroradjustup, erroradjustdown; + +extern fixed16_t sadjust, tadjust; +extern fixed16_t bbextents, bbextentt; + +extern mvertex_t *r_ptverts, *r_ptvertsmax; + +extern float entity_rotation[3][3]; + +extern int r_currentkey; +extern int r_currentbkey; + +void R_InitTurb (void); + +void R_DrawParticles (void); +void R_SurfacePatch (void); + +extern int r_amodels_drawn; +extern edge_t *auxedges; +extern int r_numallocatededges; +extern edge_t *r_edges, *edge_p, *edge_max; + +extern edge_t *newedges[MAXHEIGHT]; +extern edge_t *removeedges[MAXHEIGHT]; + +// FIXME: make stack vars when debugging done +extern edge_t edge_head; +extern edge_t edge_tail; +extern edge_t edge_aftertail; + +extern int r_aliasblendcolor; + +extern float aliasxscale, aliasyscale, aliasxcenter, aliasycenter; + +extern int r_outofsurfaces; +extern int r_outofedges; + +extern mvertex_t *r_pcurrentvertbase; +extern int r_maxvalidedgeoffset; + +typedef struct +{ + finalvert_t *a, *b, *c; +} aliastriangleparms_t; + +extern aliastriangleparms_t aliastriangleparms; + +void R_DrawTriangle( void ); +//void R_DrawTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2); +void R_AliasClipTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2); + + +extern float r_time1; +extern float da_time1, da_time2; +extern float dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2; +extern float se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2; +extern int r_frustum_indexes[4*6]; +extern int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs; +extern qboolean r_surfsonstack; + +extern mleaf_t *r_viewleaf; +extern int r_viewcluster, r_oldviewcluster; + +extern int r_clipflags; +extern int r_dlightframecount; +extern qboolean r_fov_greater_than_90; + +extern image_t *r_notexture_mip; +extern model_t *r_worldmodel; + +void R_PrintAliasStats (void); +void R_PrintTimes (void); +void R_PrintDSpeeds (void); +void R_AnimateLight (void); +void R_LightPoint (vec3_t p, vec3_t color); +void R_SetupFrame (void); +void R_cshift_f (void); +void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1); +void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip); +void R_SplitEntityOnNode2 (mnode_t *node); + +extern refdef_t r_newrefdef; + +extern surfcache_t *sc_rover, *sc_base; + +extern void *colormap; + +//==================================================================== + +float R_DLightPoint (vec3_t p); + +void R_NewMap (void); +void R_Register (void); +void R_UnRegister (void); +void Draw_InitLocal (void); +qboolean R_Init( void *hInstance, void *wndProc ); +void R_Shutdown (void); +void R_InitCaches (void); +void D_FlushCaches (void); + +void R_ScreenShot_f( void ); +void R_BeginRegistration (char *map); +struct model_s *R_RegisterModel (char *name); +void R_EndRegistration (void); + +void R_RenderFrame (refdef_t *fd); + +struct image_s *Draw_FindPic (char *name); + +void Draw_GetPicSize (int *w, int *h, char *name); +void Draw_Pic (int x, int y, char *name); +void Draw_StretchPic (int x, int y, int w, int h, char *name); +void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data); +void Draw_Char (int x, int y, int c); +void Draw_TileClear (int x, int y, int w, int h, char *name); +void Draw_Fill (int x, int y, int w, int h, int c); +void Draw_FadeScreen (void); + +void Draw_GetPalette (void); + +void R_BeginFrame( float camera_separation ); + +void R_CinematicSetPalette( const unsigned char *palette ); + +extern unsigned d_8to24table[256]; // base + +void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length); +void Sys_SetFPCW (void); + +void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height); + +void R_InitImages (void); +void R_ShutdownImages (void); +image_t *R_FindImage (char *name, imagetype_t type); +void R_FreeUnusedImages (void); + +void R_GammaCorrectAndSetPalette( const unsigned char *pal ); + +extern mtexinfo_t *sky_texinfo[6]; + +void R_InitSkyBox (void); + +typedef struct swstate_s +{ + qboolean fullscreen; + int prev_mode; // last valid SW mode + + byte gammatable[256]; + byte currentpalette[1024]; + +} swstate_t; + +void R_IMFlatShadedQuad( vec3_t a, vec3_t b, vec3_t c, vec3_t d, int color, float alpha ); + +extern swstate_t sw_state; + +/* +==================================================================== + +IMPORTED FUNCTIONS + +==================================================================== +*/ + +extern refimport_t ri; + +/* +==================================================================== + +IMPLEMENTATION FUNCTIONS + +==================================================================== +*/ + +void SWimp_BeginFrame( float camera_separation ); +void SWimp_EndFrame (void); +int SWimp_Init( void *hInstance, void *wndProc ); +void SWimp_SetPalette( const unsigned char *palette); +void SWimp_Shutdown( void ); +rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen ); +void SWimp_AppActivate( qboolean active ); + diff --git a/ref_soft/r_main.c b/ref_soft/r_main.c new file mode 100644 index 000000000..60232133e --- /dev/null +++ b/ref_soft/r_main.c @@ -0,0 +1,1422 @@ +/* +Copyright (C) 1997-2001 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_main.c + +#include "r_local.h" + +viddef_t vid; +refimport_t ri; + +unsigned d_8to24table[256]; + +entity_t r_worldentity; + +char skyname[MAX_QPATH]; +float skyrotate; +vec3_t skyaxis; +image_t *sky_images[6]; + +refdef_t r_newrefdef; +model_t *currentmodel; + +model_t *r_worldmodel; + +byte r_warpbuffer[WARP_WIDTH * WARP_HEIGHT]; + +swstate_t sw_state; + +void *colormap; +vec3_t viewlightvec; +alight_t r_viewlighting = {128, 192, viewlightvec}; +float r_time1; +int r_numallocatededges; +float r_aliasuvscale = 1.0; +int r_outofsurfaces; +int r_outofedges; + +qboolean r_dowarp; + +mvertex_t *r_pcurrentvertbase; + +int c_surf; +int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs; +qboolean r_surfsonstack; +int r_clipflags; + +// +// view origin +// +vec3_t vup, base_vup; +vec3_t vpn, base_vpn; +vec3_t vright, base_vright; +vec3_t r_origin; + +// +// screen size info +// +oldrefdef_t r_refdef; +float xcenter, ycenter; +float xscale, yscale; +float xscaleinv, yscaleinv; +float xscaleshrink, yscaleshrink; +float aliasxscale, aliasyscale, aliasxcenter, aliasycenter; + +int r_screenwidth; + +float verticalFieldOfView; +float xOrigin, yOrigin; + +mplane_t screenedge[4]; + +// +// refresh flags +// +int r_framecount = 1; // so frame counts initialized to 0 don't match +int r_visframecount; +int d_spanpixcount; +int r_polycount; +int r_drawnpolycount; +int r_wholepolycount; + +int *pfrustum_indexes[4]; +int r_frustum_indexes[4*6]; + +mleaf_t *r_viewleaf; +int r_viewcluster, r_oldviewcluster; + +image_t *r_notexture_mip; + +float da_time1, da_time2, dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2; +float se_time1, se_time2, de_time1, de_time2; + +void R_MarkLeaves (void); + +cvar_t *r_lefthand; +cvar_t *sw_aliasstats; +cvar_t *sw_allow_modex; +cvar_t *sw_clearcolor; +cvar_t *sw_drawflat; +cvar_t *sw_draworder; +cvar_t *sw_maxedges; +cvar_t *sw_maxsurfs; +cvar_t *sw_mode; +cvar_t *sw_reportedgeout; +cvar_t *sw_reportsurfout; +cvar_t *sw_stipplealpha; +cvar_t *sw_surfcacheoverride; +cvar_t *sw_waterwarp; + +cvar_t *r_drawworld; +cvar_t *r_drawentities; +cvar_t *r_dspeeds; +cvar_t *r_fullbright; +cvar_t *r_lerpmodels; +cvar_t *r_novis; + +cvar_t *r_speeds; +cvar_t *r_lightlevel; //FIXME HACK + +cvar_t *vid_fullscreen; +cvar_t *vid_gamma; + +//PGM +cvar_t *sw_lockpvs; +//PGM + +#define STRINGER(x) "x" + + +#if !id386 + +// r_vars.c + +// all global and static refresh variables are collected in a contiguous block +// to avoid cache conflicts. + +//------------------------------------------------------- +// global refresh variables +//------------------------------------------------------- + +// FIXME: make into one big structure, like cl or sv +// FIXME: do separately for refresh engine and driver + + +// d_vars.c + +// all global and static refresh variables are collected in a contiguous block +// to avoid cache conflicts. + +//------------------------------------------------------- +// global refresh variables +//------------------------------------------------------- + +// FIXME: make into one big structure, like cl or sv +// FIXME: do separately for refresh engine and driver + +float d_sdivzstepu, d_tdivzstepu, d_zistepu; +float d_sdivzstepv, d_tdivzstepv, d_zistepv; +float d_sdivzorigin, d_tdivzorigin, d_ziorigin; + +fixed16_t sadjust, tadjust, bbextents, bbextentt; + +pixel_t *cacheblock; +int cachewidth; +pixel_t *d_viewbuffer; +short *d_pzbuffer; +unsigned int d_zrowbytes; +unsigned int d_zwidth; + + +#endif // !id386 + +byte r_notexture_buffer[1024]; + +/* +================== +R_InitTextures +================== +*/ +void R_InitTextures (void) +{ + int x,y, m; + byte *dest; + +// create a simple checkerboard texture for the default + r_notexture_mip = (image_t *)&r_notexture_buffer; + + r_notexture_mip->width = r_notexture_mip->height = 16; + r_notexture_mip->pixels[0] = &r_notexture_buffer[sizeof(image_t)]; + r_notexture_mip->pixels[1] = r_notexture_mip->pixels[0] + 16*16; + r_notexture_mip->pixels[2] = r_notexture_mip->pixels[1] + 8*8; + r_notexture_mip->pixels[3] = r_notexture_mip->pixels[2] + 4*4; + + for (m=0 ; m<4 ; m++) + { + dest = r_notexture_mip->pixels[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; + } + } +} + + +/* +================ +R_InitTurb +================ +*/ +void R_InitTurb (void) +{ + int i; + + for (i=0 ; i<1280 ; i++) + { + sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP; + intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2; // AMP2, not 20 + blanktable[i] = 0; //PGM + } +} + +void R_ImageList_f( void ); + +void R_Register (void) +{ + sw_aliasstats = ri.Cvar_Get ("sw_polymodelstats", "0", 0); + sw_allow_modex = ri.Cvar_Get( "sw_allow_modex", "1", CVAR_ARCHIVE ); + sw_clearcolor = ri.Cvar_Get ("sw_clearcolor", "2", 0); + sw_drawflat = ri.Cvar_Get ("sw_drawflat", "0", 0); + sw_draworder = ri.Cvar_Get ("sw_draworder", "0", 0); + sw_maxedges = ri.Cvar_Get ("sw_maxedges", STRINGER(MAXSTACKSURFACES), 0); + sw_maxsurfs = ri.Cvar_Get ("sw_maxsurfs", "0", 0); + sw_mipcap = ri.Cvar_Get ("sw_mipcap", "0", 0); + sw_mipscale = ri.Cvar_Get ("sw_mipscale", "1", 0); + sw_reportedgeout = ri.Cvar_Get ("sw_reportedgeout", "0", 0); + sw_reportsurfout = ri.Cvar_Get ("sw_reportsurfout", "0", 0); + sw_stipplealpha = ri.Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE ); + sw_surfcacheoverride = ri.Cvar_Get ("sw_surfcacheoverride", "0", 0); + sw_waterwarp = ri.Cvar_Get ("sw_waterwarp", "1", 0); + sw_mode = ri.Cvar_Get( "sw_mode", "0", CVAR_ARCHIVE ); + + r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE ); + r_speeds = ri.Cvar_Get ("r_speeds", "0", 0); + r_fullbright = ri.Cvar_Get ("r_fullbright", "0", 0); + r_drawentities = ri.Cvar_Get ("r_drawentities", "1", 0); + r_drawworld = ri.Cvar_Get ("r_drawworld", "1", 0); + r_dspeeds = ri.Cvar_Get ("r_dspeeds", "0", 0); + r_lightlevel = ri.Cvar_Get ("r_lightlevel", "0", 0); + r_lerpmodels = ri.Cvar_Get( "r_lerpmodels", "1", 0 ); + r_novis = ri.Cvar_Get( "r_novis", "0", 0 ); + + vid_fullscreen = ri.Cvar_Get( "vid_fullscreen", "0", CVAR_ARCHIVE ); + vid_gamma = ri.Cvar_Get( "vid_gamma", "1.0", CVAR_ARCHIVE ); + + ri.Cmd_AddCommand ("modellist", Mod_Modellist_f); + ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f ); + ri.Cmd_AddCommand( "imagelist", R_ImageList_f ); + + sw_mode->modified = true; // force us to do mode specific stuff later + vid_gamma->modified = true; // force us to rebuild the gamma table later + +//PGM + sw_lockpvs = ri.Cvar_Get ("sw_lockpvs", "0", 0); +//PGM +} + +void R_UnRegister (void) +{ + ri.Cmd_RemoveCommand( "screenshot" ); + ri.Cmd_RemoveCommand ("modellist"); + ri.Cmd_RemoveCommand( "imagelist" ); +} + +/* +=============== +R_Init +=============== +*/ +qboolean R_Init( void *hInstance, void *wndProc ) +{ + R_InitImages (); + Mod_Init (); + Draw_InitLocal (); + R_InitTextures (); + + R_InitTurb (); + + view_clipplanes[0].leftedge = true; + view_clipplanes[1].rightedge = true; + view_clipplanes[1].leftedge = view_clipplanes[2].leftedge = + view_clipplanes[3].leftedge = false; + view_clipplanes[0].rightedge = view_clipplanes[2].rightedge = + view_clipplanes[3].rightedge = false; + + r_refdef.xOrigin = XCENTERING; + r_refdef.yOrigin = YCENTERING; + +// TODO: collect 386-specific code in one place +#if id386 + Sys_MakeCodeWriteable ((long)R_EdgeCodeStart, + (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart); + Sys_SetFPCW (); // get bit masks for FPCW (FIXME: is this id386?) +#endif // id386 + + r_aliasuvscale = 1.0; + + R_Register (); + Draw_GetPalette (); + SWimp_Init( hInstance, wndProc ); + + // create the window + R_BeginFrame( 0 ); + + ri.Con_Printf (PRINT_ALL, "ref_soft version: "REF_VERSION"\n"); + + return true; +} + +/* +=============== +R_Shutdown +=============== +*/ +void R_Shutdown (void) +{ + // free z buffer + if (d_pzbuffer) + { + free (d_pzbuffer); + d_pzbuffer = NULL; + } + // free surface cache + if (sc_base) + { + D_FlushCaches (); + free (sc_base); + sc_base = NULL; + } + + // free colormap + if (vid.colormap) + { + free (vid.colormap); + vid.colormap = NULL; + } + R_UnRegister (); + Mod_FreeAll (); + R_ShutdownImages (); + + SWimp_Shutdown(); +} + +/* +=============== +R_NewMap +=============== +*/ +void R_NewMap (void) +{ + r_viewcluster = -1; + + r_cnumsurfs = sw_maxsurfs->value; + + if (r_cnumsurfs <= MINSURFACES) + r_cnumsurfs = MINSURFACES; + + if (r_cnumsurfs > NUMSTACKSURFACES) + { + surfaces = malloc (r_cnumsurfs * sizeof(surf_t)); + surface_p = surfaces; + surf_max = &surfaces[r_cnumsurfs]; + r_surfsonstack = false; + // surface 0 doesn't really exist; it's just a dummy because index 0 + // is used to indicate no edge attached to surface + surfaces--; + R_SurfacePatch (); + } + else + { + r_surfsonstack = true; + } + + r_maxedgesseen = 0; + r_maxsurfsseen = 0; + + r_numallocatededges = sw_maxedges->value; + + if (r_numallocatededges < MINEDGES) + r_numallocatededges = MINEDGES; + + if (r_numallocatededges <= NUMSTACKEDGES) + { + auxedges = NULL; + } + else + { + auxedges = malloc (r_numallocatededges * sizeof(edge_t)); + } +} + + +/* +=============== +R_MarkLeaves + +Mark the leaves and nodes that are in the PVS for the current +cluster +=============== +*/ +void R_MarkLeaves (void) +{ + byte *vis; + mnode_t *node; + int i; + mleaf_t *leaf; + int cluster; + + if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1) + return; + + // development aid to let you run around and see exactly where + // the pvs ends + if (sw_lockpvs->value) + return; + + r_visframecount++; + r_oldviewcluster = r_viewcluster; + + if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis) + { + // mark everything + for (i=0 ; inumleafs ; i++) + r_worldmodel->leafs[i].visframe = r_visframecount; + for (i=0 ; inumnodes ; i++) + r_worldmodel->nodes[i].visframe = r_visframecount; + return; + } + + vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel); + + for (i=0,leaf=r_worldmodel->leafs ; inumleafs ; i++, leaf++) + { + cluster = leaf->cluster; + if (cluster == -1) + continue; + if (vis[cluster>>3] & (1<<(cluster&7))) + { + node = (mnode_t *)leaf; + do + { + if (node->visframe == r_visframecount) + break; + node->visframe = r_visframecount; + node = node->parent; + } while (node); + } + } + +#if 0 + for (i=0 ; ivis->numclusters ; i++) + { + if (vis[i>>3] & (1<<(i&7))) + { + node = (mnode_t *)&r_worldmodel->leafs[i]; // FIXME: cluster + do + { + if (node->visframe == r_visframecount) + break; + node->visframe = r_visframecount; + node = node->parent; + } while (node); + } + } +#endif +} + +/* +** R_DrawNullModel +** +** IMPLEMENT THIS! +*/ +void R_DrawNullModel( void ) +{ +} + +/* +============= +R_DrawEntitiesOnList +============= +*/ +void R_DrawEntitiesOnList (void) +{ + int i; + qboolean translucent_entities = false; + + if (!r_drawentities->value) + return; + + // all bmodels have already been drawn by the edge list + for (i=0 ; iflags & RF_TRANSLUCENT ) + { + translucent_entities = true; + continue; + } + + if ( currententity->flags & RF_BEAM ) + { + modelorg[0] = -r_origin[0]; + modelorg[1] = -r_origin[1]; + modelorg[2] = -r_origin[2]; + VectorCopy( vec3_origin, r_entorigin ); + R_DrawBeam( currententity ); + } + else + { + currentmodel = currententity->model; + if (!currentmodel) + { + R_DrawNullModel(); + continue; + } + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + + switch (currentmodel->type) + { + case mod_sprite: + R_DrawSprite (); + break; + + case mod_alias: + R_AliasDrawModel (); + break; + + default: + break; + } + } + } + + if ( !translucent_entities ) + return; + + for (i=0 ; iflags & RF_TRANSLUCENT ) ) + continue; + + if ( currententity->flags & RF_BEAM ) + { + modelorg[0] = -r_origin[0]; + modelorg[1] = -r_origin[1]; + modelorg[2] = -r_origin[2]; + VectorCopy( vec3_origin, r_entorigin ); + R_DrawBeam( currententity ); + } + else + { + currentmodel = currententity->model; + if (!currentmodel) + { + R_DrawNullModel(); + continue; + } + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + + switch (currentmodel->type) + { + case mod_sprite: + R_DrawSprite (); + break; + + case mod_alias: + R_AliasDrawModel (); + break; + + default: + break; + } + } + } +} + + +/* +============= +R_BmodelCheckBBox +============= +*/ +int R_BmodelCheckBBox (float *minmaxs) +{ + int i, *pindex, clipflags; + vec3_t acceptpt, rejectpt; + float d; + + clipflags = 0; + + for (i=0 ; i<4 ; i++) + { + // generate accept and reject points + // FIXME: do with fast look-ups or integer tests based on the sign bit + // of the floating point values + + pindex = pfrustum_indexes[i]; + + rejectpt[0] = minmaxs[pindex[0]]; + rejectpt[1] = minmaxs[pindex[1]]; + rejectpt[2] = minmaxs[pindex[2]]; + + d = DotProduct (rejectpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d <= 0) + return BMODEL_FULLY_CLIPPED; + + acceptpt[0] = minmaxs[pindex[3+0]]; + acceptpt[1] = minmaxs[pindex[3+1]]; + acceptpt[2] = minmaxs[pindex[3+2]]; + + d = DotProduct (acceptpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d <= 0) + clipflags |= (1<nodes; + + while (1) + { + if (node->visframe != r_visframecount) + return NULL; // not visible at all + + if (node->contents != CONTENTS_NODE) + { + if (node->contents != CONTENTS_SOLID) + return node; // we've reached a non-solid leaf, so it's + // visible and not BSP clipped + return NULL; // in solid, so not visible + } + + splitplane = node->plane; + sides = BOX_ON_PLANE_SIDE(mins, maxs, (cplane_t *)splitplane); + + if (sides == 3) + return node; // this is the splitter + + // not split yet; recurse down the contacted side + if (sides & 1) + node = node->children[0]; + else + node = node->children[1]; + } +} + + +/* +============= +RotatedBBox + +Returns an axially aligned box that contains the input box at the given rotation +============= +*/ +void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs) +{ + vec3_t tmp, v; + int i, j; + vec3_t forward, right, up; + + if (!angles[0] && !angles[1] && !angles[2]) + { + VectorCopy (mins, tmins); + VectorCopy (maxs, tmaxs); + return; + } + + for (i=0 ; i<3 ; i++) + { + tmins[i] = 99999; + tmaxs[i] = -99999; + } + + AngleVectors (angles, forward, right, up); + + for ( i = 0; i < 8; i++ ) + { + if ( i & 1 ) + tmp[0] = mins[0]; + else + tmp[0] = maxs[0]; + + if ( i & 2 ) + tmp[1] = mins[1]; + else + tmp[1] = maxs[1]; + + if ( i & 4 ) + tmp[2] = mins[2]; + else + tmp[2] = maxs[2]; + + + VectorScale (forward, tmp[0], v); + VectorMA (v, -tmp[1], right, v); + VectorMA (v, tmp[2], up, v); + + for (j=0 ; j<3 ; j++) + { + if (v[j] < tmins[j]) + tmins[j] = v[j]; + if (v[j] > tmaxs[j]) + tmaxs[j] = v[j]; + } + } +} + +/* +============= +R_DrawBEntitiesOnList +============= +*/ +void R_DrawBEntitiesOnList (void) +{ + int i, clipflags; + vec3_t oldorigin; + vec3_t mins, maxs; + float minmaxs[6]; + mnode_t *topnode; + + if (!r_drawentities->value) + return; + + VectorCopy (modelorg, oldorigin); + insubmodel = true; + r_dlightframecount = r_framecount; + + for (i=0 ; imodel; + if (!currentmodel) + continue; + if (currentmodel->nummodelsurfaces == 0) + continue; // clip brush only + if ( currententity->flags & RF_BEAM ) + continue; + if (currentmodel->type != mod_brush) + continue; + // see if the bounding box lets us trivially reject, also sets + // trivial accept status + RotatedBBox (currentmodel->mins, currentmodel->maxs, + currententity->angles, mins, maxs); + VectorAdd (mins, currententity->origin, minmaxs); + VectorAdd (maxs, currententity->origin, (minmaxs+3)); + + clipflags = R_BmodelCheckBBox (minmaxs); + if (clipflags == BMODEL_FULLY_CLIPPED) + continue; // off the edge of the screen + + topnode = R_FindTopnode (minmaxs, minmaxs+3); + if (!topnode) + continue; // no part in a visible leaf + + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + + r_pcurrentvertbase = currentmodel->vertexes; + + // FIXME: stop transforming twice + R_RotateBmodel (); + + // calculate dynamic lighting for bmodel + R_PushDlights (currentmodel); + + if (topnode->contents == CONTENTS_NODE) + { + // not a leaf; has to be clipped to the world BSP + r_clipflags = clipflags; + R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode); + } + else + { + // falls entirely in one leaf, so we just put all the + // edges in the edge list and let 1/z sorting handle + // drawing order + R_DrawSubmodelPolygons (currentmodel, clipflags, topnode); + } + + // put back world rotation and frustum clipping + // FIXME: R_RotateBmodel should just work off base_vxx + VectorCopy (base_vpn, vpn); + VectorCopy (base_vup, vup); + VectorCopy (base_vright, vright); + VectorCopy (oldorigin, modelorg); + R_TransformFrustum (); + } + + insubmodel = false; +} + + +/* +================ +R_EdgeDrawing +================ +*/ +void R_EdgeDrawing (void) +{ + edge_t ledges[NUMSTACKEDGES + + ((CACHE_SIZE - 1) / sizeof(edge_t)) + 1]; + surf_t lsurfs[NUMSTACKSURFACES + + ((CACHE_SIZE - 1) / sizeof(surf_t)) + 1]; + + if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) + return; + + if (auxedges) + { + r_edges = auxedges; + } + else + { + r_edges = (edge_t *) + (((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + } + + if (r_surfsonstack) + { + surfaces = (surf_t *) + (((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + surf_max = &surfaces[r_cnumsurfs]; + // surface 0 doesn't really exist; it's just a dummy because index 0 + // is used to indicate no edge attached to surface + surfaces--; + R_SurfacePatch (); + } + + R_BeginEdgeFrame (); + + if (r_dspeeds->value) + { + rw_time1 = Sys_Milliseconds (); + } + + R_RenderWorld (); + + if (r_dspeeds->value) + { + rw_time2 = Sys_Milliseconds (); + db_time1 = rw_time2; + } + + R_DrawBEntitiesOnList (); + + if (r_dspeeds->value) + { + db_time2 = Sys_Milliseconds (); + se_time1 = db_time2; + } + + R_ScanEdges (); +} + +//======================================================================= + + +/* +============= +R_CalcPalette + +============= +*/ +void R_CalcPalette (void) +{ + static qboolean modified; + byte palette[256][4], *in, *out; + int i, j; + float alpha, one_minus_alpha; + vec3_t premult; + int v; + + alpha = r_newrefdef.blend[3]; + if (alpha <= 0) + { + if (modified) + { // set back to default + modified = false; + R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table ); + return; + } + return; + } + + modified = true; + if (alpha > 1) + alpha = 1; + + premult[0] = r_newrefdef.blend[0]*alpha*255; + premult[1] = r_newrefdef.blend[1]*alpha*255; + premult[2] = r_newrefdef.blend[2]*alpha*255; + + one_minus_alpha = (1.0 - alpha); + + in = (byte *)d_8to24table; + out = palette[0]; + for (i=0 ; i<256 ; i++, in+=4, out+=4) + { + for (j=0 ; j<3 ; j++) + { + v = premult[j] + one_minus_alpha * in[j]; + if (v > 255) + v = 255; + out[j] = v; + } + out[3] = 255; + } + + R_GammaCorrectAndSetPalette( ( const unsigned char * ) palette[0] ); +// SWimp_SetPalette( palette[0] ); +} + +//======================================================================= + +void R_SetLightLevel (void) +{ + vec3_t light; + + if ((r_newrefdef.rdflags & RDF_NOWORLDMODEL) || (!r_drawentities->value) || (!currententity)) + { + r_lightlevel->value = 150.0; + return; + } + + // save off light value for server to look at (BIG HACK!) + R_LightPoint (r_newrefdef.vieworg, light); + r_lightlevel->value = 150.0 * light[0]; +} + + +/* +@@@@@@@@@@@@@@@@ +R_RenderFrame + +@@@@@@@@@@@@@@@@ +*/ +void R_RenderFrame (refdef_t *fd) +{ + r_newrefdef = *fd; + + if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) ) + ri.Sys_Error (ERR_FATAL,"R_RenderView: NULL worldmodel"); + + VectorCopy (fd->vieworg, r_refdef.vieworg); + VectorCopy (fd->viewangles, r_refdef.viewangles); + + if (r_speeds->value || r_dspeeds->value) + r_time1 = Sys_Milliseconds (); + + R_SetupFrame (); + + R_MarkLeaves (); // done here so we know if we're in water + + R_PushDlights (r_worldmodel); + + R_EdgeDrawing (); + + if (r_dspeeds->value) + { + se_time2 = Sys_Milliseconds (); + de_time1 = se_time2; + } + + R_DrawEntitiesOnList (); + + if (r_dspeeds->value) + { + de_time2 = Sys_Milliseconds (); + dp_time1 = Sys_Milliseconds (); + } + + R_DrawParticles (); + + if (r_dspeeds->value) + dp_time2 = Sys_Milliseconds (); + + R_DrawAlphaSurfaces(); + + R_SetLightLevel (); + + if (r_dowarp) + D_WarpScreen (); + + if (r_dspeeds->value) + da_time1 = Sys_Milliseconds (); + + if (r_dspeeds->value) + da_time2 = Sys_Milliseconds (); + + R_CalcPalette (); + + if (sw_aliasstats->value) + R_PrintAliasStats (); + + if (r_speeds->value) + R_PrintTimes (); + + if (r_dspeeds->value) + R_PrintDSpeeds (); + + if (sw_reportsurfout->value && r_outofsurfaces) + ri.Con_Printf (PRINT_ALL,"Short %d surfaces\n", r_outofsurfaces); + + if (sw_reportedgeout->value && r_outofedges) + ri.Con_Printf (PRINT_ALL,"Short roughly %d edges\n", r_outofedges * 2 / 3); +} + +/* +** R_InitGraphics +*/ +void R_InitGraphics( int width, int height ) +{ + vid.width = width; + vid.height = height; + + // free z buffer + if ( d_pzbuffer ) + { + free( d_pzbuffer ); + d_pzbuffer = NULL; + } + + // free surface cache + if ( sc_base ) + { + D_FlushCaches (); + free( sc_base ); + sc_base = NULL; + } + + d_pzbuffer = malloc(vid.width*vid.height*2); + + R_InitCaches (); + + R_GammaCorrectAndSetPalette( ( const unsigned char *) d_8to24table ); +} + +/* +** R_BeginFrame +*/ +void R_BeginFrame( float camera_separation ) +{ + extern void Draw_BuildGammaTable( void ); + + /* + ** rebuild the gamma correction palette if necessary + */ + if ( vid_gamma->modified ) + { + Draw_BuildGammaTable(); + R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table ); + + vid_gamma->modified = false; + } + + while ( sw_mode->modified || vid_fullscreen->modified ) + { + rserr_t err; + + /* + ** if this returns rserr_invalid_fullscreen then it set the mode but not as a + ** fullscreen mode, e.g. 320x200 on a system that doesn't support that res + */ + if ( ( err = SWimp_SetMode( &vid.width, &vid.height, sw_mode->value, vid_fullscreen->value ) ) == rserr_ok ) + { + R_InitGraphics( vid.width, vid.height ); + + sw_state.prev_mode = sw_mode->value; + vid_fullscreen->modified = false; + sw_mode->modified = false; + } + else + { + if ( err == rserr_invalid_mode ) + { + ri.Cvar_SetValue( "sw_mode", sw_state.prev_mode ); + ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - could not set mode\n" ); + } + else if ( err == rserr_invalid_fullscreen ) + { + R_InitGraphics( vid.width, vid.height ); + + ri.Cvar_SetValue( "vid_fullscreen", 0); + ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - fullscreen unavailable in this mode\n" ); + sw_state.prev_mode = sw_mode->value; +// vid_fullscreen->modified = false; +// sw_mode->modified = false; + } + else + { + ri.Sys_Error( ERR_FATAL, "ref_soft::R_BeginFrame() - catastrophic mode change failure\n" ); + } + } + } +} + +/* +** R_GammaCorrectAndSetPalette +*/ +void R_GammaCorrectAndSetPalette( const unsigned char *palette ) +{ + int i; + + for ( i = 0; i < 256; i++ ) + { + sw_state.currentpalette[i*4+0] = sw_state.gammatable[palette[i*4+0]]; + sw_state.currentpalette[i*4+1] = sw_state.gammatable[palette[i*4+1]]; + sw_state.currentpalette[i*4+2] = sw_state.gammatable[palette[i*4+2]]; + } + + SWimp_SetPalette( sw_state.currentpalette ); +} + +/* +** R_CinematicSetPalette +*/ +void R_CinematicSetPalette( const unsigned char *palette ) +{ + byte palette32[1024]; + int i, j, w; + int *d; + + // clear screen to black to avoid any palette flash + w = abs(vid.rowbytes)>>2; // stupid negative pitch win32 stuff... + for (i=0 ; ivalue; + + if (g == 1.0) + { + for (i=0 ; i<256 ; i++) + sw_state.gammatable[i] = i; + return; + } + + for (i=0 ; i<256 ; i++) + { + inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5; + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + sw_state.gammatable[i] = inf; + } +} + +/* +** R_DrawBeam +*/ +void R_DrawBeam( entity_t *e ) +{ +#define NUM_BEAM_SEGS 6 + + int i; + + vec3_t perpvec; + vec3_t direction, normalized_direction; + vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS]; + vec3_t oldorigin, origin; + + oldorigin[0] = e->oldorigin[0]; + oldorigin[1] = e->oldorigin[1]; + oldorigin[2] = e->oldorigin[2]; + + origin[0] = e->origin[0]; + origin[1] = e->origin[1]; + origin[2] = e->origin[2]; + + normalized_direction[0] = direction[0] = oldorigin[0] - origin[0]; + normalized_direction[1] = direction[1] = oldorigin[1] - origin[1]; + normalized_direction[2] = direction[2] = oldorigin[2] - origin[2]; + + if ( VectorNormalize( normalized_direction ) == 0 ) + return; + + PerpendicularVector( perpvec, normalized_direction ); + VectorScale( perpvec, e->frame / 2, perpvec ); + + for ( i = 0; i < NUM_BEAM_SEGS; i++ ) + { + RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i ); + VectorAdd( start_points[i], origin, start_points[i] ); + VectorAdd( start_points[i], direction, end_points[i] ); + } + + for ( i = 0; i < NUM_BEAM_SEGS; i++ ) + { + R_IMFlatShadedQuad( start_points[i], + end_points[i], + end_points[(i+1)%NUM_BEAM_SEGS], + start_points[(i+1)%NUM_BEAM_SEGS], + e->skinnum & 0xFF, + e->alpha ); + } +} + + +//=================================================================== + +/* +============ +R_SetSky +============ +*/ +// 3dstudio environment map names +char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; +int r_skysideimage[6] = {5, 2, 4, 1, 0, 3}; +extern mtexinfo_t r_skytexinfo[6]; +void R_SetSky (char *name, float rotate, vec3_t axis) +{ + int i; + char pathname[MAX_QPATH]; + + strncpy (skyname, name, sizeof(skyname)-1); + skyrotate = rotate; + VectorCopy (axis, skyaxis); + + for (i=0 ; i<6 ; i++) + { + Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]); + r_skytexinfo[i].image = R_FindImage (pathname, it_sky); + } +} + + +/* +=============== +Draw_GetPalette +=============== +*/ +void Draw_GetPalette (void) +{ + byte *pal, *out; + int i; + int r, g, b; + + // get the palette and colormap + LoadPCX ("pics/colormap.pcx", &vid.colormap, &pal, NULL, NULL); + if (!vid.colormap) + ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx"); + vid.alphamap = vid.colormap + 64*256; + + out = (byte *)d_8to24table; + for (i=0 ; i<256 ; i++, out+=4) + { + r = pal[i*3+0]; + g = pal[i*3+1]; + b = pal[i*3+2]; + + out[0] = r; + out[1] = g; + out[2] = b; + } + + free (pal); +} + +struct image_s *R_RegisterSkin (char *name); + +/* +@@@@@@@@@@@@@@@@@@@@@ +GetRefAPI + +@@@@@@@@@@@@@@@@@@@@@ +*/ +refexport_t GetRefAPI (refimport_t rimp) +{ + refexport_t re; + + ri = rimp; + + re.api_version = API_VERSION; + + re.BeginRegistration = R_BeginRegistration; + re.RegisterModel = R_RegisterModel; + re.RegisterSkin = R_RegisterSkin; + re.RegisterPic = Draw_FindPic; + re.SetSky = R_SetSky; + re.EndRegistration = R_EndRegistration; + + re.RenderFrame = R_RenderFrame; + + re.DrawGetPicSize = Draw_GetPicSize; + re.DrawPic = Draw_Pic; + re.DrawStretchPic = Draw_StretchPic; + re.DrawChar = Draw_Char; + re.DrawTileClear = Draw_TileClear; + re.DrawFill = Draw_Fill; + re.DrawFadeScreen= Draw_FadeScreen; + + re.DrawStretchRaw = Draw_StretchRaw; + + re.Init = R_Init; + re.Shutdown = R_Shutdown; + + re.CinematicSetPalette = R_CinematicSetPalette; + re.BeginFrame = R_BeginFrame; + re.EndFrame = SWimp_EndFrame; + + re.AppActivate = SWimp_AppActivate; + + Swap_Init (); + + return re; +} + +#ifndef REF_HARD_LINKED +// this is only here so the functions in q_shared.c and q_shwin.c can link +void Sys_Error (char *error, ...) +{ + va_list argptr; + char text[1024]; + + va_start (argptr, error); + vsprintf (text, error, argptr); + va_end (argptr); + + ri.Sys_Error (ERR_FATAL, "%s", text); +} + +void Com_Printf (char *fmt, ...) +{ + va_list argptr; + char text[1024]; + + va_start (argptr, fmt); + vsprintf (text, fmt, argptr); + va_end (argptr); + + ri.Con_Printf (PRINT_ALL, "%s", text); +} + +#endif diff --git a/ref_soft/r_misc.c b/ref_soft/r_misc.c new file mode 100644 index 000000000..ce6837ce9 --- /dev/null +++ b/ref_soft/r_misc.c @@ -0,0 +1,670 @@ +/* +Copyright (C) 1997-2001 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 "r_local.h" + +#define NUM_MIPS 4 + +cvar_t *sw_mipcap; +cvar_t *sw_mipscale; + +surfcache_t *d_initial_rover; +qboolean d_roverwrapped; +int d_minmip; +float d_scalemip[NUM_MIPS-1]; + +static float basemip[NUM_MIPS-1] = {1.0, 0.5*0.8, 0.25*0.8}; + +extern int d_aflatcolor; + +int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle; + +int d_pix_min, d_pix_max, d_pix_shift; + +int d_scantable[MAXHEIGHT]; +short *zspantable[MAXHEIGHT]; + +/* +================ +D_Patch +================ +*/ +void D_Patch (void) +{ +#if id386 + extern void D_Aff8Patch( void ); + static qboolean protectset8 = false; + extern void D_PolysetAff8Start( void ); + + if (!protectset8) + { + Sys_MakeCodeWriteable ((int)D_PolysetAff8Start, + (int)D_Aff8Patch - (int)D_PolysetAff8Start); + Sys_MakeCodeWriteable ((long)R_Surf8Start, + (long)R_Surf8End - (long)R_Surf8Start); + protectset8 = true; + } + colormap = vid.colormap; + + R_Surf8Patch (); + D_Aff8Patch(); +#endif +} +/* +================ +D_ViewChanged +================ +*/ +unsigned char *alias_colormap; + +void D_ViewChanged (void) +{ + int i; + + scale_for_mip = xscale; + if (yscale > xscale) + scale_for_mip = yscale; + + d_zrowbytes = vid.width * 2; + d_zwidth = vid.width; + + d_pix_min = r_refdef.vrect.width / 320; + if (d_pix_min < 1) + d_pix_min = 1; + + d_pix_max = (int)((float)r_refdef.vrect.width / (320.0 / 4.0) + 0.5); + d_pix_shift = 8 - (int)((float)r_refdef.vrect.width / 320.0 + 0.5); + if (d_pix_max < 1) + d_pix_max = 1; + + d_vrectx = r_refdef.vrect.x; + d_vrecty = r_refdef.vrect.y; + d_vrectright_particle = r_refdef.vrectright - d_pix_max; + d_vrectbottom_particle = + r_refdef.vrectbottom - d_pix_max; + + for (i=0 ; ivalue & 0xff ); + } + + alias_colormap = vid.colormap; + + D_Patch (); +} + + + +/* +============= +R_PrintTimes +============= +*/ +void R_PrintTimes (void) +{ + int r_time2; + int ms; + + r_time2 = Sys_Milliseconds (); + + ms = r_time2 - r_time1; + + ri.Con_Printf (PRINT_ALL,"%5i ms %3i/%3i/%3i poly %3i surf\n", + ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf); + c_surf = 0; +} + + +/* +============= +R_PrintDSpeeds +============= +*/ +void R_PrintDSpeeds (void) +{ + int ms, dp_time, r_time2, rw_time, db_time, se_time, de_time, da_time; + + r_time2 = Sys_Milliseconds (); + + da_time = (da_time2 - da_time1); + dp_time = (dp_time2 - dp_time1); + rw_time = (rw_time2 - rw_time1); + db_time = (db_time2 - db_time1); + se_time = (se_time2 - se_time1); + de_time = (de_time2 - de_time1); + ms = (r_time2 - r_time1); + + ri.Con_Printf (PRINT_ALL,"%3i %2ip %2iw %2ib %2is %2ie %2ia\n", + ms, dp_time, rw_time, db_time, se_time, de_time, da_time); +} + + +/* +============= +R_PrintAliasStats +============= +*/ +void R_PrintAliasStats (void) +{ + ri.Con_Printf (PRINT_ALL,"%3i polygon model drawn\n", r_amodels_drawn); +} + + + +/* +=================== +R_TransformFrustum +=================== +*/ +void R_TransformFrustum (void) +{ + int i; + vec3_t v, v2; + + for (i=0 ; i<4 ; i++) + { + v[0] = screenedge[i].normal[2]; + v[1] = -screenedge[i].normal[0]; + v[2] = screenedge[i].normal[1]; + + v2[0] = v[1]*vright[0] + v[2]*vup[0] + v[0]*vpn[0]; + v2[1] = v[1]*vright[1] + v[2]*vup[1] + v[0]*vpn[1]; + v2[2] = v[1]*vright[2] + v[2]*vup[2] + v[0]*vpn[2]; + + VectorCopy (v2, view_clipplanes[i].normal); + + view_clipplanes[i].dist = DotProduct (modelorg, v2); + } +} + + +#if !(defined __linux__ && defined __i386__) +#if !id386 + +/* +================ +TransformVector +================ +*/ +void TransformVector (vec3_t in, vec3_t out) +{ + out[0] = DotProduct(in,vright); + out[1] = DotProduct(in,vup); + out[2] = DotProduct(in,vpn); +} + +#else + +__declspec( naked ) void TransformVector( vec3_t vin, vec3_t vout ) +{ + __asm mov eax, dword ptr [esp+4] + __asm mov edx, dword ptr [esp+8] + + __asm fld dword ptr [eax+0] + __asm fmul dword ptr [vright+0] + __asm fld dword ptr [eax+0] + __asm fmul dword ptr [vup+0] + __asm fld dword ptr [eax+0] + __asm fmul dword ptr [vpn+0] + + __asm fld dword ptr [eax+4] + __asm fmul dword ptr [vright+4] + __asm fld dword ptr [eax+4] + __asm fmul dword ptr [vup+4] + __asm fld dword ptr [eax+4] + __asm fmul dword ptr [vpn+4] + + __asm fxch st(2) + + __asm faddp st(5), st(0) + __asm faddp st(3), st(0) + __asm faddp st(1), st(0) + + __asm fld dword ptr [eax+8] + __asm fmul dword ptr [vright+8] + __asm fld dword ptr [eax+8] + __asm fmul dword ptr [vup+8] + __asm fld dword ptr [eax+8] + __asm fmul dword ptr [vpn+8] + + __asm fxch st(2) + + __asm faddp st(5), st(0) + __asm faddp st(3), st(0) + __asm faddp st(1), st(0) + + __asm fstp dword ptr [edx+8] + __asm fstp dword ptr [edx+4] + __asm fstp dword ptr [edx+0] + + __asm ret +} + +#endif +#endif + + +/* +================ +R_TransformPlane +================ +*/ +void R_TransformPlane (mplane_t *p, float *normal, float *dist) +{ + float d; + + d = DotProduct (r_origin, p->normal); + *dist = p->dist - d; +// TODO: when we have rotating entities, this will need to use the view matrix + TransformVector (p->normal, normal); +} + + +/* +=============== +R_SetUpFrustumIndexes +=============== +*/ +void R_SetUpFrustumIndexes (void) +{ + int i, j, *pindex; + + pindex = r_frustum_indexes; + + for (i=0 ; i<4 ; i++) + { + for (j=0 ; j<3 ; j++) + { + if (view_clipplanes[i].normal[j] < 0) + { + pindex[j] = j; + pindex[j+3] = j+3; + } + else + { + pindex[j] = j+3; + pindex[j+3] = j; + } + } + + // FIXME: do just once at start + pfrustum_indexes[i] = pindex; + pindex += 6; + } +} + +/* +=============== +R_ViewChanged + +Called every time the vid structure or r_refdef changes. +Guaranteed to be called before the first refresh +=============== +*/ +void R_ViewChanged (vrect_t *vr) +{ + int i; + + r_refdef.vrect = *vr; + + r_refdef.horizontalFieldOfView = 2*tan((float)r_newrefdef.fov_x/360*M_PI);; + verticalFieldOfView = 2*tan((float)r_newrefdef.fov_y/360*M_PI); + + r_refdef.fvrectx = (float)r_refdef.vrect.x; + r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5; + r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1; + r_refdef.fvrecty = (float)r_refdef.vrect.y; + r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5; + r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width; + r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1; + r_refdef.fvrectright = (float)r_refdef.vrectright; + r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5; + r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99; + r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height; + r_refdef.fvrectbottom = (float)r_refdef.vrectbottom; + r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5; + + r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale); + r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale); + r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale); + r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale); + r_refdef.aliasvrectright = r_refdef.aliasvrect.x + + r_refdef.aliasvrect.width; + r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y + + r_refdef.aliasvrect.height; + + xOrigin = r_refdef.xOrigin; + yOrigin = r_refdef.yOrigin; + +// values for perspective projection +// if math were exact, the values would range from 0.5 to to range+0.5 +// hopefully they wll be in the 0.000001 to range+.999999 and truncate +// the polygon rasterization will never render in the first row or column +// but will definately render in the [range] row and column, so adjust the +// buffer origin to get an exact edge to edge fill + xcenter = ((float)r_refdef.vrect.width * XCENTERING) + + r_refdef.vrect.x - 0.5; + aliasxcenter = xcenter * r_aliasuvscale; + ycenter = ((float)r_refdef.vrect.height * YCENTERING) + + r_refdef.vrect.y - 0.5; + aliasycenter = ycenter * r_aliasuvscale; + + xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView; + aliasxscale = xscale * r_aliasuvscale; + xscaleinv = 1.0 / xscale; + + yscale = xscale; + aliasyscale = yscale * r_aliasuvscale; + yscaleinv = 1.0 / yscale; + xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView; + yscaleshrink = xscaleshrink; + +// left side clip + screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView); + screenedge[0].normal[1] = 0; + screenedge[0].normal[2] = 1; + screenedge[0].type = PLANE_ANYZ; + +// right side clip + screenedge[1].normal[0] = + 1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView); + screenedge[1].normal[1] = 0; + screenedge[1].normal[2] = 1; + screenedge[1].type = PLANE_ANYZ; + +// top side clip + screenedge[2].normal[0] = 0; + screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView); + screenedge[2].normal[2] = 1; + screenedge[2].type = PLANE_ANYZ; + +// bottom side clip + screenedge[3].normal[0] = 0; + screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView); + screenedge[3].normal[2] = 1; + screenedge[3].type = PLANE_ANYZ; + + for (i=0 ; i<4 ; i++) + VectorNormalize (screenedge[i].normal); + + D_ViewChanged (); +} + + +/* +=============== +R_SetupFrame +=============== +*/ +void R_SetupFrame (void) +{ + int i; + vrect_t vrect; + + if (r_fullbright->modified) + { + r_fullbright->modified = false; + D_FlushCaches (); // so all lighting changes + } + + r_framecount++; + + +// build the transformation matrix for the given view angles + VectorCopy (r_refdef.vieworg, modelorg); + VectorCopy (r_refdef.vieworg, r_origin); + + AngleVectors (r_refdef.viewangles, vpn, vright, vup); + +// current viewleaf + if ( !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) ) + { + r_viewleaf = Mod_PointInLeaf (r_origin, r_worldmodel); + r_viewcluster = r_viewleaf->cluster; + } + + if (sw_waterwarp->value && (r_newrefdef.rdflags & RDF_UNDERWATER) ) + r_dowarp = true; + else + r_dowarp = false; + + if (r_dowarp) + { // warp into off screen buffer + vrect.x = 0; + vrect.y = 0; + vrect.width = r_newrefdef.width < WARP_WIDTH ? r_newrefdef.width : WARP_WIDTH; + vrect.height = r_newrefdef.height < WARP_HEIGHT ? r_newrefdef.height : WARP_HEIGHT; + + d_viewbuffer = r_warpbuffer; + r_screenwidth = WARP_WIDTH; + } + else + { + vrect.x = r_newrefdef.x; + vrect.y = r_newrefdef.y; + vrect.width = r_newrefdef.width; + vrect.height = r_newrefdef.height; + + d_viewbuffer = (void *)vid.buffer; + r_screenwidth = vid.rowbytes; + } + + R_ViewChanged (&vrect); + +// start off with just the four screen edge clip planes + R_TransformFrustum (); + R_SetUpFrustumIndexes (); + +// save base values + VectorCopy (vpn, base_vpn); + VectorCopy (vright, base_vright); + VectorCopy (vup, base_vup); + +// clear frame counts + c_faceclip = 0; + d_spanpixcount = 0; + r_polycount = 0; + r_drawnpolycount = 0; + r_wholepolycount = 0; + r_amodels_drawn = 0; + r_outofsurfaces = 0; + r_outofedges = 0; + +// d_setup + d_roverwrapped = false; + d_initial_rover = sc_rover; + + d_minmip = sw_mipcap->value; + if (d_minmip > 3) + d_minmip = 3; + else if (d_minmip < 0) + d_minmip = 0; + + for (i=0 ; i<(NUM_MIPS-1) ; i++) + d_scalemip[i] = basemip[i] * sw_mipscale->value; + + d_aflatcolor = 0; +} + + +#if !id386 + +/* +================ +R_SurfacePatch +================ +*/ +void R_SurfacePatch (void) +{ + // we only patch code on Intel +} + +#endif // !id386 + + +/* +============================================================================== + + SCREEN SHOTS + +============================================================================== +*/ + + +/* +============== +WritePCXfile +============== +*/ +void WritePCXfile (char *filename, byte *data, int width, int height, + int rowbytes, byte *palette) +{ + int i, j, length; + pcx_t *pcx; + byte *pack; + FILE *f; + + pcx = (pcx_t *)malloc (width*height*2+1000); + if (!pcx) + return; + + pcx->manufacturer = 0x0a; // PCX id + pcx->version = 5; // 256 color + pcx->encoding = 1; // uncompressed + pcx->bits_per_pixel = 8; // 256 color + pcx->xmin = 0; + pcx->ymin = 0; + pcx->xmax = LittleShort((short)(width-1)); + pcx->ymax = LittleShort((short)(height-1)); + pcx->hres = LittleShort((short)width); + pcx->vres = LittleShort((short)height); + memset (pcx->palette,0,sizeof(pcx->palette)); + pcx->color_planes = 1; // chunky image + pcx->bytes_per_line = LittleShort((short)width); + pcx->palette_type = LittleShort(2); // not a grey scale + memset (pcx->filler,0,sizeof(pcx->filler)); + +// pack the image + pack = &pcx->data; + + for (i=0 ; iname[0]) + continue; + ri.Con_Printf (PRINT_ALL, "%8i : %s\n",mod->extradatasize, mod->name); + total += mod->extradatasize; + } + ri.Con_Printf (PRINT_ALL, "Total resident: %i\n", total); +} + +/* +=============== +Mod_Init +=============== +*/ +void Mod_Init (void) +{ + memset (mod_novis, 0xff, sizeof(mod_novis)); +} + +/* +================== +Mod_ForName + +Loads in a model for the given name +================== +*/ +model_t *Mod_ForName (char *name, qboolean crash) +{ + model_t *mod; + unsigned *buf; + int i; + + if (!name[0]) + ri.Sys_Error (ERR_DROP,"Mod_ForName: NULL name"); + + // + // inline models are grabbed only from worldmodel + // + if (name[0] == '*') + { + i = atoi(name+1); + if (i < 1 || !r_worldmodel || i >= r_worldmodel->numsubmodels) + ri.Sys_Error (ERR_DROP, "bad inline model number"); + return &mod_inline[i]; + } + + // + // search the currently loaded models + // + for (i=0 , mod=mod_known ; iname, name) ) + return mod; + + // + // find a free model slot spot + // + for (i=0 , mod=mod_known ; iname[0]) + break; // free spot + } + if (i == mod_numknown) + { + if (mod_numknown == MAX_MOD_KNOWN) + ri.Sys_Error (ERR_DROP, "mod_numknown == MAX_MOD_KNOWN"); + mod_numknown++; + } + strcpy (mod->name, name); + + // + // load the file + // + modfilelen = ri.FS_LoadFile (mod->name, (void **)&buf); + if (!buf) + { + if (crash) + ri.Sys_Error (ERR_DROP,"Mod_NumForName: %s not found", mod->name); + memset (mod->name, 0, sizeof(mod->name)); + return NULL; + } + + loadmodel = mod; + + // + // fill it in + // + + // call the apropriate loader + + switch (LittleLong(*(unsigned *)buf)) + { + case IDALIASHEADER: + loadmodel->extradata = Hunk_Begin (0x200000); + Mod_LoadAliasModel (mod, buf); + break; + + case IDSPRITEHEADER: + loadmodel->extradata = Hunk_Begin (0x10000); + Mod_LoadSpriteModel (mod, buf); + break; + + case IDBSPHEADER: + loadmodel->extradata = Hunk_Begin (0x1000000); + Mod_LoadBrushModel (mod, buf); + break; + + default: + ri.Sys_Error (ERR_DROP,"Mod_NumForName: unknown fileid for %s", mod->name); + break; + } + + loadmodel->extradatasize = Hunk_End (); + + ri.FS_FreeFile (buf); + + return mod; +} + + +/* +=============== +Mod_PointInLeaf +=============== +*/ +mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model) +{ + mnode_t *node; + float d; + mplane_t *plane; + + if (!model || !model->nodes) + ri.Sys_Error (ERR_DROP, "Mod_PointInLeaf: bad model"); + + node = model->nodes; + while (1) + { + if (node->contents != -1) + return (mleaf_t *)node; + plane = node->plane; + d = DotProduct (p,plane->normal) - plane->dist; + if (d > 0) + node = node->children[0]; + else + node = node->children[1]; + } + + return NULL; // never reached +} + + +/* +=================== +Mod_DecompressVis +=================== +*/ +byte *Mod_DecompressVis (byte *in, model_t *model) +{ + static byte decompressed[MAX_MAP_LEAFS/8]; + int c; + byte *out; + int row; + + row = (model->vis->numclusters+7)>>3; + out = decompressed; + +#if 0 + memcpy (out, in, row); +#else + if (!in) + { // no vis info, so make all visible + while (row) + { + *out++ = 0xff; + row--; + } + return decompressed; + } + + do + { + if (*in) + { + *out++ = *in++; + continue; + } + + c = in[1]; + in += 2; + while (c) + { + *out++ = 0; + c--; + } + } while (out - decompressed < row); +#endif + + return decompressed; +} + +/* +============== +Mod_ClusterPVS +============== +*/ +byte *Mod_ClusterPVS (int cluster, model_t *model) +{ + if (cluster == -1 || !model->vis) + return mod_novis; + return Mod_DecompressVis ( (byte *)model->vis + model->vis->bitofs[cluster][DVIS_PVS], + model); +} + +/* +=============================================================================== + + BRUSHMODEL LOADING + +=============================================================================== +*/ + +byte *mod_base; + + +/* +================= +Mod_LoadLighting + +Converts the 24 bit lighting down to 8 bit +by taking the brightest component +================= +*/ +void Mod_LoadLighting (lump_t *l) +{ + int i, size; + byte *in; + + if (!l->filelen) + { + loadmodel->lightdata = NULL; + return; + } + size = l->filelen/3; + loadmodel->lightdata = Hunk_Alloc (size); + in = (void *)(mod_base + l->fileofs); + for (i=0 ; i in[1] && in[0] > in[2]) + loadmodel->lightdata[i] = in[0]; + else if (in[1] > in[0] && in[1] > in[2]) + loadmodel->lightdata[i] = in[1]; + else + loadmodel->lightdata[i] = in[2]; + } +} + + +int r_leaftovis[MAX_MAP_LEAFS]; +int r_vistoleaf[MAX_MAP_LEAFS]; +int r_numvisleafs; + +void R_NumberLeafs (mnode_t *node) +{ + mleaf_t *leaf; + int leafnum; + + if (node->contents != -1) + { + leaf = (mleaf_t *)node; + leafnum = leaf - loadmodel->leafs; + if (leaf->contents & CONTENTS_SOLID) + return; + r_leaftovis[leafnum] = r_numvisleafs; + r_vistoleaf[r_numvisleafs] = leafnum; + r_numvisleafs++; + return; + } + + R_NumberLeafs (node->children[0]); + R_NumberLeafs (node->children[1]); +} + + +/* +================= +Mod_LoadVisibility +================= +*/ +void Mod_LoadVisibility (lump_t *l) +{ + int i; + + if (!l->filelen) + { + loadmodel->vis = NULL; + return; + } + loadmodel->vis = Hunk_Alloc ( l->filelen); + memcpy (loadmodel->vis, mod_base + l->fileofs, l->filelen); + + loadmodel->vis->numclusters = LittleLong (loadmodel->vis->numclusters); + for (i=0 ; ivis->numclusters ; i++) + { + loadmodel->vis->bitofs[i][0] = LittleLong (loadmodel->vis->bitofs[i][0]); + loadmodel->vis->bitofs[i][1] = LittleLong (loadmodel->vis->bitofs[i][1]); + } +} + + +/* +================= +Mod_LoadVertexes +================= +*/ +void Mod_LoadVertexes (lump_t *l) +{ + dvertex_t *in; + mvertex_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( (count+8)*sizeof(*out)); // extra for skybox + + loadmodel->vertexes = out; + loadmodel->numvertexes = count; + + for ( i=0 ; iposition[0] = LittleFloat (in->point[0]); + out->position[1] = LittleFloat (in->point[1]); + out->position[2] = LittleFloat (in->point[2]); + } +} + +/* +================= +Mod_LoadSubmodels +================= +*/ +void Mod_LoadSubmodels (lump_t *l) +{ + dmodel_t *in; + dmodel_t *out; + int i, j, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->submodels = out; + loadmodel->numsubmodels = count; + + for ( i=0 ; imins[j] = LittleFloat (in->mins[j]) - 1; + out->maxs[j] = LittleFloat (in->maxs[j]) + 1; + out->origin[j] = LittleFloat (in->origin[j]); + } + out->headnode = LittleLong (in->headnode); + out->firstface = LittleLong (in->firstface); + out->numfaces = LittleLong (in->numfaces); + } +} + +/* +================= +Mod_LoadEdges +================= +*/ +void Mod_LoadEdges (lump_t *l) +{ + dedge_t *in; + medge_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( (count + 13) * sizeof(*out)); // extra for skybox + + loadmodel->edges = out; + loadmodel->numedges = count; + + for ( i=0 ; iv[0] = (unsigned short)LittleShort(in->v[0]); + out->v[1] = (unsigned short)LittleShort(in->v[1]); + } +} + +/* +================= +Mod_LoadTexinfo +================= +*/ +void Mod_LoadTexinfo (lump_t *l) +{ + texinfo_t *in; + mtexinfo_t *out, *step; + int i, j, count; + float len1, len2; + char name[MAX_QPATH]; + int next; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( (count+6)*sizeof(*out)); // extra for skybox + + loadmodel->texinfo = out; + loadmodel->numtexinfo = count; + + for ( i=0 ; ivecs[0][j] = LittleFloat (in->vecs[0][j]); + len1 = VectorLength (out->vecs[0]); + len2 = VectorLength (out->vecs[1]); + len1 = (len1 + len2)/2; + if (len1 < 0.32) + out->mipadjust = 4; + else if (len1 < 0.49) + out->mipadjust = 3; + else if (len1 < 0.99) + out->mipadjust = 2; + else + out->mipadjust = 1; +#if 0 + if (len1 + len2 < 0.001) + out->mipadjust = 1; // don't crash + else + out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 ); +#endif + + out->flags = LittleLong (in->flags); + + next = LittleLong (in->nexttexinfo); + if (next > 0) + out->next = loadmodel->texinfo + next; + + Com_sprintf (name, sizeof(name), "textures/%s.wal", in->texture); + out->image = R_FindImage (name, it_wall); + if (!out->image) + { + out->image = r_notexture_mip; // texture not found + out->flags = 0; + } + } + + // count animation frames + for (i=0 ; itexinfo[i]; + out->numframes = 1; + for (step = out->next ; step && step != out ; step=step->next) + out->numframes++; + } +} + +/* +================ +CalcSurfaceExtents + +Fills in s->texturemins[] and s->extents[] +================ +*/ +void CalcSurfaceExtents (msurface_t *s) +{ + float mins[2], maxs[2], val; + int i,j, e; + mvertex_t *v; + mtexinfo_t *tex; + int bmins[2], bmaxs[2]; + + mins[0] = mins[1] = 999999; + maxs[0] = maxs[1] = -99999; + + tex = s->texinfo; + + for (i=0 ; inumedges ; i++) + { + e = loadmodel->surfedges[s->firstedge+i]; + if (e >= 0) + v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; + else + v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; + + for (j=0 ; j<2 ; j++) + { + val = v->position[0] * tex->vecs[j][0] + + v->position[1] * tex->vecs[j][1] + + v->position[2] * tex->vecs[j][2] + + tex->vecs[j][3]; + if (val < mins[j]) + mins[j] = val; + if (val > maxs[j]) + maxs[j] = val; + } + } + + for (i=0 ; i<2 ; i++) + { + bmins[i] = floor(mins[i]/16); + bmaxs[i] = ceil(maxs[i]/16); + + s->texturemins[i] = bmins[i] * 16; + s->extents[i] = (bmaxs[i] - bmins[i]) * 16; + if (s->extents[i] < 16) + s->extents[i] = 16; // take at least one cache block + if ( !(tex->flags & (SURF_WARP|SURF_SKY)) && s->extents[i] > 256) + ri.Sys_Error (ERR_DROP,"Bad surface extents"); + } +} + + +/* +================= +Mod_LoadFaces +================= +*/ +void Mod_LoadFaces (lump_t *l) +{ + dface_t *in; + msurface_t *out; + int i, count, surfnum; + int planenum, side; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( (count+6)*sizeof(*out)); // extra for skybox + + loadmodel->surfaces = out; + loadmodel->numsurfaces = count; + + for ( surfnum=0 ; surfnumfirstedge = LittleLong(in->firstedge); + out->numedges = LittleShort(in->numedges); + if (out->numedges < 3) + ri.Sys_Error (ERR_DROP,"Surface with %s edges", out->numedges); + out->flags = 0; + + planenum = LittleShort(in->planenum); + side = LittleShort(in->side); + if (side) + out->flags |= SURF_PLANEBACK; + + out->plane = loadmodel->planes + planenum; + + out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo); + + CalcSurfaceExtents (out); + + // lighting info is converted from 24 bit on disk to 8 bit + + for (i=0 ; istyles[i] = in->styles[i]; + i = LittleLong(in->lightofs); + if (i == -1) + out->samples = NULL; + else + out->samples = loadmodel->lightdata + i/3; + + // set the drawing flags flag + + if (!out->texinfo->image) + continue; + if (out->texinfo->flags & SURF_SKY) + { + out->flags |= SURF_DRAWSKY; + continue; + } + + if (out->texinfo->flags & SURF_WARP) + { + out->flags |= SURF_DRAWTURB; + for (i=0 ; i<2 ; i++) + { + out->extents[i] = 16384; + out->texturemins[i] = -8192; + } + continue; + } +//============== +//PGM + // this marks flowing surfaces as turbulent, but with the new + // SURF_FLOW flag. + if (out->texinfo->flags & SURF_FLOWING) + { + out->flags |= SURF_DRAWTURB | SURF_FLOW; + for (i=0 ; i<2 ; i++) + { + out->extents[i] = 16384; + out->texturemins[i] = -8192; + } + continue; + } +//PGM +//============== + } +} + + +/* +================= +Mod_SetParent +================= +*/ +void Mod_SetParent (mnode_t *node, mnode_t *parent) +{ + node->parent = parent; + if (node->contents != -1) + return; + Mod_SetParent (node->children[0], node); + Mod_SetParent (node->children[1], node); +} + +/* +================= +Mod_LoadNodes +================= +*/ +void Mod_LoadNodes (lump_t *l) +{ + int i, j, count, p; + dnode_t *in; + mnode_t *out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->nodes = out; + loadmodel->numnodes = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + p = LittleLong(in->planenum); + out->plane = loadmodel->planes + p; + + out->firstsurface = LittleShort (in->firstface); + out->numsurfaces = LittleShort (in->numfaces); + out->contents = CONTENTS_NODE; // differentiate from leafs + + for (j=0 ; j<2 ; j++) + { + p = LittleLong (in->children[j]); + if (p >= 0) + out->children[j] = loadmodel->nodes + p; + else + out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p)); + } + } + + Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs +} + +/* +================= +Mod_LoadLeafs +================= +*/ +void Mod_LoadLeafs (lump_t *l) +{ + dleaf_t *in; + mleaf_t *out; + int i, j, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->leafs = out; + loadmodel->numleafs = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + out->contents = LittleLong(in->contents); + out->cluster = LittleShort(in->cluster); + out->area = LittleShort(in->area); + + out->firstmarksurface = loadmodel->marksurfaces + + LittleShort(in->firstleafface); + out->nummarksurfaces = LittleShort(in->numleaffaces); + } +} + + +/* +================= +Mod_LoadMarksurfaces +================= +*/ +void Mod_LoadMarksurfaces (lump_t *l) +{ + int i, j, count; + short *in; + msurface_t **out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( count*sizeof(*out)); + + loadmodel->marksurfaces = out; + loadmodel->nummarksurfaces = count; + + for ( i=0 ; i= loadmodel->numsurfaces) + ri.Sys_Error (ERR_DROP,"Mod_ParseMarksurfaces: bad surface number"); + out[i] = loadmodel->surfaces + j; + } +} + +/* +================= +Mod_LoadSurfedges +================= +*/ +void Mod_LoadSurfedges (lump_t *l) +{ + int i, count; + int *in, *out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( (count+24)*sizeof(*out)); // extra for skybox + + loadmodel->surfedges = out; + loadmodel->numsurfedges = count; + + for ( i=0 ; ifileofs); + if (l->filelen % sizeof(*in)) + ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_Alloc ( (count+6)*sizeof(*out)); // extra for skybox + + loadmodel->planes = out; + loadmodel->numplanes = count; + + for ( i=0 ; inormal[j] = LittleFloat (in->normal[j]); + if (out->normal[j] < 0) + bits |= 1<dist = LittleFloat (in->dist); + out->type = LittleLong (in->type); + out->signbits = bits; + } +} + + +/* +================= +Mod_LoadBrushModel +================= +*/ +void Mod_LoadBrushModel (model_t *mod, void *buffer) +{ + int i; + dheader_t *header; + dmodel_t *bm; + + loadmodel->type = mod_brush; + if (loadmodel != mod_known) + ri.Sys_Error (ERR_DROP, "Loaded a brush model after the world"); + + header = (dheader_t *)buffer; + + i = LittleLong (header->version); + if (i != BSPVERSION) + ri.Sys_Error (ERR_DROP,"Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION); + +// swap all the lumps + mod_base = (byte *)header; + + for (i=0 ; ilumps[LUMP_VERTEXES]); + Mod_LoadEdges (&header->lumps[LUMP_EDGES]); + Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]); + Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]); + Mod_LoadPlanes (&header->lumps[LUMP_PLANES]); + Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]); + Mod_LoadFaces (&header->lumps[LUMP_FACES]); + Mod_LoadMarksurfaces (&header->lumps[LUMP_LEAFFACES]); + Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]); + Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]); + Mod_LoadNodes (&header->lumps[LUMP_NODES]); + Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]); + r_numvisleafs = 0; + R_NumberLeafs (loadmodel->nodes); + +// +// set up the submodels +// + for (i=0 ; inumsubmodels ; i++) + { + model_t *starmod; + + bm = &mod->submodels[i]; + starmod = &mod_inline[i]; + + *starmod = *loadmodel; + + starmod->firstmodelsurface = bm->firstface; + starmod->nummodelsurfaces = bm->numfaces; + starmod->firstnode = bm->headnode; + if (starmod->firstnode >= loadmodel->numnodes) + ri.Sys_Error (ERR_DROP, "Inline model %i has bad firstnode", i); + + VectorCopy (bm->maxs, starmod->maxs); + VectorCopy (bm->mins, starmod->mins); + + if (i == 0) + *loadmodel = *starmod; + } + + R_InitSkyBox (); +} + +/* +============================================================================== + +ALIAS MODELS + +============================================================================== +*/ + +/* +================= +Mod_LoadAliasModel +================= +*/ +void Mod_LoadAliasModel (model_t *mod, void *buffer) +{ + int i, j; + dmdl_t *pinmodel, *pheader; + dstvert_t *pinst, *poutst; + dtriangle_t *pintri, *pouttri; + daliasframe_t *pinframe, *poutframe; + int *pincmd, *poutcmd; + int version; + + pinmodel = (dmdl_t *)buffer; + + version = LittleLong (pinmodel->version); + if (version != ALIAS_VERSION) + ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)", + mod->name, version, ALIAS_VERSION); + + pheader = Hunk_Alloc (LittleLong(pinmodel->ofs_end)); + + // byte swap the header fields and sanity check + for (i=0 ; iskinheight > MAX_LBM_HEIGHT) + ri.Sys_Error (ERR_DROP, "model %s has a skin taller than %d", mod->name, + MAX_LBM_HEIGHT); + + if (pheader->num_xyz <= 0) + ri.Sys_Error (ERR_DROP, "model %s has no vertices", mod->name); + + if (pheader->num_xyz > MAX_VERTS) + ri.Sys_Error (ERR_DROP, "model %s has too many vertices", mod->name); + + if (pheader->num_st <= 0) + ri.Sys_Error (ERR_DROP, "model %s has no st vertices", mod->name); + + if (pheader->num_tris <= 0) + ri.Sys_Error (ERR_DROP, "model %s has no triangles", mod->name); + + if (pheader->num_frames <= 0) + ri.Sys_Error (ERR_DROP, "model %s has no frames", mod->name); + +// +// load base s and t vertices (not used in gl version) +// + pinst = (dstvert_t *) ((byte *)pinmodel + pheader->ofs_st); + poutst = (dstvert_t *) ((byte *)pheader + pheader->ofs_st); + + for (i=0 ; inum_st ; i++) + { + poutst[i].s = LittleShort (pinst[i].s); + poutst[i].t = LittleShort (pinst[i].t); + } + +// +// load triangle lists +// + pintri = (dtriangle_t *) ((byte *)pinmodel + pheader->ofs_tris); + pouttri = (dtriangle_t *) ((byte *)pheader + pheader->ofs_tris); + + for (i=0 ; inum_tris ; i++) + { + for (j=0 ; j<3 ; j++) + { + pouttri[i].index_xyz[j] = LittleShort (pintri[i].index_xyz[j]); + pouttri[i].index_st[j] = LittleShort (pintri[i].index_st[j]); + } + } + +// +// load the frames +// + for (i=0 ; inum_frames ; i++) + { + pinframe = (daliasframe_t *) ((byte *)pinmodel + + pheader->ofs_frames + i * pheader->framesize); + poutframe = (daliasframe_t *) ((byte *)pheader + + pheader->ofs_frames + i * pheader->framesize); + + memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name)); + for (j=0 ; j<3 ; j++) + { + poutframe->scale[j] = LittleFloat (pinframe->scale[j]); + poutframe->translate[j] = LittleFloat (pinframe->translate[j]); + } + // verts are all 8 bit, so no swapping needed + memcpy (poutframe->verts, pinframe->verts, + pheader->num_xyz*sizeof(dtrivertx_t)); + + } + + mod->type = mod_alias; + + // + // load the glcmds + // + pincmd = (int *) ((byte *)pinmodel + pheader->ofs_glcmds); + poutcmd = (int *) ((byte *)pheader + pheader->ofs_glcmds); + for (i=0 ; inum_glcmds ; i++) + poutcmd[i] = LittleLong (pincmd[i]); + + + // register all skins + memcpy ((char *)pheader + pheader->ofs_skins, (char *)pinmodel + pheader->ofs_skins, + pheader->num_skins*MAX_SKINNAME); + for (i=0 ; inum_skins ; i++) + { + mod->skins[i] = R_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin); + } +} + +/* +============================================================================== + +SPRITE MODELS + +============================================================================== +*/ + +/* +================= +Mod_LoadSpriteModel +================= +*/ +void Mod_LoadSpriteModel (model_t *mod, void *buffer) +{ + dsprite_t *sprin, *sprout; + int i; + + sprin = (dsprite_t *)buffer; + sprout = Hunk_Alloc (modfilelen); + + sprout->ident = LittleLong (sprin->ident); + sprout->version = LittleLong (sprin->version); + sprout->numframes = LittleLong (sprin->numframes); + + if (sprout->version != SPRITE_VERSION) + ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)", + mod->name, sprout->version, SPRITE_VERSION); + + if (sprout->numframes > MAX_MD2SKINS) + ri.Sys_Error (ERR_DROP, "%s has too many frames (%i > %i)", + mod->name, sprout->numframes, MAX_MD2SKINS); + + // byte swap everything + for (i=0 ; inumframes ; i++) + { + sprout->frames[i].width = LittleLong (sprin->frames[i].width); + sprout->frames[i].height = LittleLong (sprin->frames[i].height); + sprout->frames[i].origin_x = LittleLong (sprin->frames[i].origin_x); + sprout->frames[i].origin_y = LittleLong (sprin->frames[i].origin_y); + memcpy (sprout->frames[i].name, sprin->frames[i].name, MAX_SKINNAME); + mod->skins[i] = R_FindImage (sprout->frames[i].name, it_sprite); + } + + mod->type = mod_sprite; +} + +//============================================================================= + +/* +@@@@@@@@@@@@@@@@@@@@@ +R_BeginRegistration + +Specifies the model that will be used as the world +@@@@@@@@@@@@@@@@@@@@@ +*/ +void R_BeginRegistration (char *model) +{ + char fullname[MAX_QPATH]; + cvar_t *flushmap; + + registration_sequence++; + r_oldviewcluster = -1; // force markleafs + Com_sprintf (fullname, sizeof(fullname), "maps/%s.bsp", model); + + D_FlushCaches (); + // explicitly free the old map if different + // this guarantees that mod_known[0] is the world map + flushmap = ri.Cvar_Get ("flushmap", "0", 0); + if ( strcmp(mod_known[0].name, fullname) || flushmap->value) + Mod_Free (&mod_known[0]); + r_worldmodel = R_RegisterModel (fullname); + R_NewMap (); +} + + +/* +@@@@@@@@@@@@@@@@@@@@@ +R_RegisterModel + +@@@@@@@@@@@@@@@@@@@@@ +*/ +struct model_s *R_RegisterModel (char *name) +{ + model_t *mod; + int i; + dsprite_t *sprout; + dmdl_t *pheader; + + mod = Mod_ForName (name, false); + if (mod) + { + mod->registration_sequence = registration_sequence; + + // register any images used by the models + if (mod->type == mod_sprite) + { + sprout = (dsprite_t *)mod->extradata; + for (i=0 ; inumframes ; i++) + mod->skins[i] = R_FindImage (sprout->frames[i].name, it_sprite); + } + else if (mod->type == mod_alias) + { + pheader = (dmdl_t *)mod->extradata; + for (i=0 ; inum_skins ; i++) + mod->skins[i] = R_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin); +//PGM + mod->numframes = pheader->num_frames; +//PGM + } + else if (mod->type == mod_brush) + { + for (i=0 ; inumtexinfo ; i++) + mod->texinfo[i].image->registration_sequence = registration_sequence; + } + } + return mod; +} + +/* +@@@@@@@@@@@@@@@@@@@@@ +R_EndRegistration + +@@@@@@@@@@@@@@@@@@@@@ +*/ +void R_EndRegistration (void) +{ + int i; + model_t *mod; + + for (i=0, mod=mod_known ; iname[0]) + continue; + if (mod->registration_sequence != registration_sequence) + { // don't need this model + Hunk_Free (mod->extradata); + memset (mod, 0, sizeof(*mod)); + } + else + { // make sure it is paged in + Com_PageInMemory (mod->extradata, mod->extradatasize); + } + } + + R_FreeUnusedImages (); +} + + +//============================================================================= + +/* +================ +Mod_Free +================ +*/ +void Mod_Free (model_t *mod) +{ + Hunk_Free (mod->extradata); + memset (mod, 0, sizeof(*mod)); +} + +/* +================ +Mod_FreeAll +================ +*/ +void Mod_FreeAll (void) +{ + int i; + + for (i=0 ; isurfedges[], negative numbers + int numedges; // are backwards edges + +// surface generation data + struct surfcache_s *cachespots[MIPLEVELS]; + + short texturemins[2]; + short extents[2]; + + mtexinfo_t *texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; + byte *samples; // [numstyles*surfsize] + + struct msurface_s *nextalphasurface; +} msurface_t; + + +#define CONTENTS_NODE -1 +typedef struct mnode_s +{ +// common with leaf + int contents; // CONTENTS_NODE, to differentiate from leafs + int visframe; // node needs to be traversed if current + + short minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + +// node specific + mplane_t *plane; + struct mnode_s *children[2]; + + unsigned short firstsurface; + unsigned short numsurfaces; +} mnode_t; + + + +typedef struct mleaf_s +{ +// common with node + int contents; // wil be something other than CONTENTS_NODE + int visframe; // node needs to be traversed if current + + short minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + +// leaf specific + int cluster; + int area; + + msurface_t **firstmarksurface; + int nummarksurfaces; + int key; // BSP sequence number for leaf's contents +} mleaf_t; + + +//=================================================================== + +// +// Whole model +// + +typedef enum {mod_bad, mod_brush, mod_sprite, mod_alias } modtype_t; + +typedef struct model_s +{ + char name[MAX_QPATH]; + + int registration_sequence; + + modtype_t type; + int numframes; + + int flags; + +// +// volume occupied by the model graphics +// + vec3_t mins, maxs; + +// +// solid volume for clipping (sent from server) +// + qboolean clipbox; + vec3_t clipmins, clipmaxs; + +// +// brush model +// + int firstmodelsurface, nummodelsurfaces; + + int numsubmodels; + dmodel_t *submodels; + + int numplanes; + mplane_t *planes; + + int numleafs; // number of visible leafs, not counting 0 + mleaf_t *leafs; + + int numvertexes; + mvertex_t *vertexes; + + int numedges; + medge_t *edges; + + int numnodes; + int firstnode; + mnode_t *nodes; + + int numtexinfo; + mtexinfo_t *texinfo; + + int numsurfaces; + msurface_t *surfaces; + + int numsurfedges; + int *surfedges; + + int nummarksurfaces; + msurface_t **marksurfaces; + + dvis_t *vis; + + byte *lightdata; + + // for alias models and sprites + image_t *skins[MAX_MD2SKINS]; + void *extradata; + int extradatasize; +} model_t; + +//============================================================================ + +void Mod_Init (void); +void Mod_ClearAll (void); +model_t *Mod_ForName (char *name, qboolean crash); +void *Mod_Extradata (model_t *mod); // handles caching +void Mod_TouchModel (char *name); + +mleaf_t *Mod_PointInLeaf (float *p, model_t *model); +byte *Mod_ClusterPVS (int cluster, model_t *model); + +void Mod_Modellist_f (void); +void Mod_FreeAll (void); +void Mod_Free (model_t *mod); + +extern int registration_sequence; + +#endif // __MODEL__ diff --git a/ref_soft/r_part.c b/ref_soft/r_part.c new file mode 100644 index 000000000..cf732772d --- /dev/null +++ b/ref_soft/r_part.c @@ -0,0 +1,638 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +#include "r_local.h" + +vec3_t r_pright, r_pup, r_ppn; + +#define PARTICLE_33 0 +#define PARTICLE_66 1 +#define PARTICLE_OPAQUE 2 + +typedef struct +{ + particle_t *particle; + int level; + int color; +} partparms_t; + +static partparms_t partparms; + +#if id386 && !defined __linux__ + +static unsigned s_prefetch_address; + +/* +** BlendParticleXX +** +** Inputs: +** EAX = color +** EDI = pdest +** +** Scratch: +** EBX = scratch (dstcolor) +** EBP = scratch +** +** Outputs: +** none +*/ +__declspec(naked) void BlendParticle33( void ) +{ + // return vid.alphamap[color + dstcolor*256]; + __asm mov ebp, vid.alphamap + __asm xor ebx, ebx + + __asm mov bl, byte ptr [edi] + __asm shl ebx, 8 + + __asm add ebp, ebx + __asm add ebp, eax + + __asm mov al, byte ptr [ebp] + + __asm mov byte ptr [edi], al + + __asm ret +} + +__declspec(naked) void BlendParticle66( void ) +{ + // return vid.alphamap[pcolor*256 + dstcolor]; + __asm mov ebp, vid.alphamap + __asm xor ebx, ebx + + __asm shl eax, 8 + __asm mov bl, byte ptr [edi] + + __asm add ebp, ebx + __asm add ebp, eax + + __asm mov al, byte ptr [ebp] + + __asm mov byte ptr [edi], al + + __asm ret +} + +__declspec(naked) void BlendParticle100( void ) +{ + __asm mov byte ptr [edi], al + __asm ret +} + +/* +** R_DrawParticle (asm version) +** +** Since we use __declspec( naked ) we don't have a stack frame +** that we can use. Since I want to reserve EBP anyway, I tossed +** all the important variables into statics. This routine isn't +** meant to be re-entrant, so this shouldn't cause any problems +** other than a slightly higher global memory footprint. +** +*/ +__declspec(naked) void R_DrawParticle( void ) +{ + static vec3_t local, transformed; + static float zi; + static int u, v, tmp; + static short izi; + static int ebpsave; + + static byte (*blendfunc)(void); + + /* + ** must be memvars since x86 can't load constants + ** directly. I guess I could use fld1, but that + ** actually costs one more clock than fld [one]! + */ + static float particle_z_clip = PARTICLE_Z_CLIP; + static float one = 1.0F; + static float point_five = 0.5F; + static float eight_thousand_hex = 0x8000; + + /* + ** save trashed variables + */ + __asm mov ebpsave, ebp + __asm push esi + __asm push edi + + /* + ** transform the particle + */ + // VectorSubtract (pparticle->origin, r_origin, local); + __asm mov esi, partparms.particle + __asm fld dword ptr [esi+0] ; p_o.x + __asm fsub dword ptr [r_origin+0] ; p_o.x-r_o.x + __asm fld dword ptr [esi+4] ; p_o.y | p_o.x-r_o.x + __asm fsub dword ptr [r_origin+4] ; p_o.y-r_o.y | p_o.x-r_o.x + __asm fld dword ptr [esi+8] ; p_o.z | p_o.y-r_o.y | p_o.x-r_o.x + __asm fsub dword ptr [r_origin+8] ; p_o.z-r_o.z | p_o.y-r_o.y | p_o.x-r_o.x + __asm fxch st(2) ; p_o.x-r_o.x | p_o.y-r_o.y | p_o.z-r_o.z + __asm fstp dword ptr [local+0] ; p_o.y-r_o.y | p_o.z-r_o.z + __asm fstp dword ptr [local+4] ; p_o.z-r_o.z + __asm fstp dword ptr [local+8] ; (empty) + + // transformed[0] = DotProduct(local, r_pright); + // transformed[1] = DotProduct(local, r_pup); + // transformed[2] = DotProduct(local, r_ppn); + __asm fld dword ptr [local+0] ; l.x + __asm fmul dword ptr [r_pright+0] ; l.x*pr.x + __asm fld dword ptr [local+4] ; l.y | l.x*pr.x + __asm fmul dword ptr [r_pright+4] ; l.y*pr.y | l.x*pr.x + __asm fld dword ptr [local+8] ; l.z | l.y*pr.y | l.x*pr.x + __asm fmul dword ptr [r_pright+8] ; l.z*pr.z | l.y*pr.y | l.x*pr.x + __asm fxch st(2) ; l.x*pr.x | l.y*pr.y | l.z*pr.z + __asm faddp st(1), st ; l.x*pr.x + l.y*pr.y | l.z*pr.z + __asm faddp st(1), st ; l.x*pr.x + l.y*pr.y + l.z*pr.z + __asm fstp dword ptr [transformed+0] ; (empty) + + __asm fld dword ptr [local+0] ; l.x + __asm fmul dword ptr [r_pup+0] ; l.x*pr.x + __asm fld dword ptr [local+4] ; l.y | l.x*pr.x + __asm fmul dword ptr [r_pup+4] ; l.y*pr.y | l.x*pr.x + __asm fld dword ptr [local+8] ; l.z | l.y*pr.y | l.x*pr.x + __asm fmul dword ptr [r_pup+8] ; l.z*pr.z | l.y*pr.y | l.x*pr.x + __asm fxch st(2) ; l.x*pr.x | l.y*pr.y | l.z*pr.z + __asm faddp st(1), st ; l.x*pr.x + l.y*pr.y | l.z*pr.z + __asm faddp st(1), st ; l.x*pr.x + l.y*pr.y + l.z*pr.z + __asm fstp dword ptr [transformed+4] ; (empty) + + __asm fld dword ptr [local+0] ; l.x + __asm fmul dword ptr [r_ppn+0] ; l.x*pr.x + __asm fld dword ptr [local+4] ; l.y | l.x*pr.x + __asm fmul dword ptr [r_ppn+4] ; l.y*pr.y | l.x*pr.x + __asm fld dword ptr [local+8] ; l.z | l.y*pr.y | l.x*pr.x + __asm fmul dword ptr [r_ppn+8] ; l.z*pr.z | l.y*pr.y | l.x*pr.x + __asm fxch st(2) ; l.x*pr.x | l.y*pr.y | l.z*pr.z + __asm faddp st(1), st ; l.x*pr.x + l.y*pr.y | l.z*pr.z + __asm faddp st(1), st ; l.x*pr.x + l.y*pr.y + l.z*pr.z + __asm fstp dword ptr [transformed+8] ; (empty) + + /* + ** make sure that the transformed particle is not in front of + ** the particle Z clip plane. We can do the comparison in + ** integer space since we know the sign of one of the inputs + ** and can figure out the sign of the other easily enough. + */ + // if (transformed[2] < PARTICLE_Z_CLIP) + // return; + + __asm mov eax, dword ptr [transformed+8] + __asm and eax, eax + __asm js end + __asm cmp eax, particle_z_clip + __asm jl end + + /* + ** project the point by initiating the 1/z calc + */ + // zi = 1.0 / transformed[2]; + __asm fld one + __asm fdiv dword ptr [transformed+8] + + /* + ** bind the blend function pointer to the appropriate blender + ** while we're dividing + */ + //if ( level == PARTICLE_33 ) + // blendparticle = BlendParticle33; + //else if ( level == PARTICLE_66 ) + // blendparticle = BlendParticle66; + //else + // blendparticle = BlendParticle100; + + __asm cmp partparms.level, PARTICLE_66 + __asm je blendfunc_66 + __asm jl blendfunc_33 + __asm lea ebx, BlendParticle100 + __asm jmp done_selecting_blend_func +blendfunc_33: + __asm lea ebx, BlendParticle33 + __asm jmp done_selecting_blend_func +blendfunc_66: + __asm lea ebx, BlendParticle66 +done_selecting_blend_func: + __asm mov blendfunc, ebx + + // prefetch the next particle + __asm mov ebp, s_prefetch_address + __asm mov ebp, [ebp] + + // finish the above divide + __asm fstp zi + + // u = (int)(xcenter + zi * transformed[0] + 0.5); + // v = (int)(ycenter - zi * transformed[1] + 0.5); + __asm fld zi ; zi + __asm fmul dword ptr [transformed+0] ; zi * transformed[0] + __asm fld zi ; zi | zi * transformed[0] + __asm fmul dword ptr [transformed+4] ; zi * transformed[1] | zi * transformed[0] + __asm fxch st(1) ; zi * transformed[0] | zi * transformed[1] + __asm fadd xcenter ; xcenter + zi * transformed[0] | zi * transformed[1] + __asm fxch st(1) ; zi * transformed[1] | xcenter + zi * transformed[0] + __asm fld ycenter ; ycenter | zi * transformed[1] | xcenter + zi * transformed[0] + __asm fsubrp st(1), st(0) ; ycenter - zi * transformed[1] | xcenter + zi * transformed[0] + __asm fxch st(1) ; xcenter + zi * transformed[0] | ycenter + zi * transformed[1] + __asm fadd point_five ; xcenter + zi * transformed[0] + 0.5 | ycenter - zi * transformed[1] + __asm fxch st(1) ; ycenter - zi * transformed[1] | xcenter + zi * transformed[0] + 0.5 + __asm fadd point_five ; ycenter - zi * transformed[1] + 0.5 | xcenter + zi * transformed[0] + 0.5 + __asm fxch st(1) ; u | v + __asm fistp dword ptr [u] ; v + __asm fistp dword ptr [v] ; (empty) + + /* + ** clip out the particle + */ + + // if ((v > d_vrectbottom_particle) || + // (u > d_vrectright_particle) || + // (v < d_vrecty) || + // (u < d_vrectx)) + // { + // return; + // } + + __asm mov ebx, u + __asm mov ecx, v + __asm cmp ecx, d_vrectbottom_particle + __asm jg end + __asm cmp ecx, d_vrecty + __asm jl end + __asm cmp ebx, d_vrectright_particle + __asm jg end + __asm cmp ebx, d_vrectx + __asm jl end + + /* + ** compute addresses of zbuffer, framebuffer, and + ** compute the Z-buffer reference value. + ** + ** EBX = U + ** ECX = V + ** + ** Outputs: + ** ESI = Z-buffer address + ** EDI = framebuffer address + */ + // ESI = d_pzbuffer + (d_zwidth * v) + u; + __asm mov esi, d_pzbuffer ; esi = d_pzbuffer + __asm mov eax, d_zwidth ; eax = d_zwidth + __asm mul ecx ; eax = d_zwidth*v + __asm add eax, ebx ; eax = d_zwidth*v+u + __asm shl eax, 1 ; eax = 2*(d_zwidth*v+u) + __asm add esi, eax ; esi = ( short * ) ( d_pzbuffer + ( d_zwidth * v ) + u ) + + // initiate + // izi = (int)(zi * 0x8000); + __asm fld zi + __asm fmul eight_thousand_hex + + // EDI = pdest = d_viewbuffer + d_scantable[v] + u; + __asm lea edi, [d_scantable+ecx*4] + __asm mov edi, [edi] + __asm add edi, d_viewbuffer + __asm add edi, ebx + + // complete + // izi = (int)(zi * 0x8000); + __asm fistp tmp + __asm mov eax, tmp + __asm mov izi, ax + + /* + ** determine the screen area covered by the particle, + ** which also means clamping to a min and max + */ + // pix = izi >> d_pix_shift; + __asm xor edx, edx + __asm mov dx, izi + __asm mov ecx, d_pix_shift + __asm shr dx, cl + + // if (pix < d_pix_min) + // pix = d_pix_min; + __asm cmp edx, d_pix_min + __asm jge check_pix_max + __asm mov edx, d_pix_min + __asm jmp skip_pix_clamp + + // else if (pix > d_pix_max) + // pix = d_pix_max; +check_pix_max: + __asm cmp edx, d_pix_max + __asm jle skip_pix_clamp + __asm mov edx, d_pix_max + +skip_pix_clamp: + + /* + ** render the appropriate pixels + ** + ** ECX = count (used for inner loop) + ** EDX = count (used for outer loop) + ** ESI = zbuffer + ** EDI = framebuffer + */ + __asm mov ecx, edx + + __asm cmp ecx, 1 + __asm ja over + +over: + + /* + ** at this point: + ** + ** ECX = count + */ + __asm push ecx + __asm push edi + __asm push esi + +top_of_pix_vert_loop: + +top_of_pix_horiz_loop: + + // for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + // { + // for (i=0 ; icolor; + int i, izi, pix, count, u, v; + byte (*blendparticle)( int, int ); + + /* + ** transform the particle + */ + VectorSubtract (pparticle->origin, r_origin, local); + + transformed[0] = DotProduct(local, r_pright); + transformed[1] = DotProduct(local, r_pup); + transformed[2] = DotProduct(local, r_ppn); + + if (transformed[2] < PARTICLE_Z_CLIP) + return; + + /* + ** bind the blend function pointer to the appropriate blender + */ + if ( level == PARTICLE_33 ) + blendparticle = BlendParticle33; + else if ( level == PARTICLE_66 ) + blendparticle = BlendParticle66; + else + blendparticle = BlendParticle100; + + /* + ** project the point + */ + // FIXME: preadjust xcenter and ycenter + zi = 1.0 / transformed[2]; + u = (int)(xcenter + zi * transformed[0] + 0.5); + v = (int)(ycenter - zi * transformed[1] + 0.5); + + if ((v > d_vrectbottom_particle) || + (u > d_vrectright_particle) || + (v < d_vrecty) || + (u < d_vrectx)) + { + return; + } + + /* + ** compute addresses of zbuffer, framebuffer, and + ** compute the Z-buffer reference value. + */ + pz = d_pzbuffer + (d_zwidth * v) + u; + pdest = d_viewbuffer + d_scantable[v] + u; + izi = (int)(zi * 0x8000); + + /* + ** determine the screen area covered by the particle, + ** which also means clamping to a min and max + */ + pix = izi >> d_pix_shift; + if (pix < d_pix_min) + pix = d_pix_min; + else if (pix > d_pix_max) + pix = d_pix_max; + + /* + ** render the appropriate pixels + */ + count = pix; + + switch (level) { + case PARTICLE_33 : + for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth) + { +//FIXME--do it in blocks of 8? + for (i=0 ; ialpha > 0.66 ) + partparms.level = PARTICLE_OPAQUE; + else if ( p->alpha > 0.33 ) + partparms.level = PARTICLE_66; + else + partparms.level = PARTICLE_33; + + partparms.particle = p; + partparms.color = p->color; + +#if id386 && !defined __linux__ + if ( i < r_newrefdef.num_particles-1 ) + s_prefetch_address = ( unsigned int ) ( p + 1 ); + else + s_prefetch_address = ( unsigned int ) r_newrefdef.particles; +#endif + + R_DrawParticle(); + } + +#if id386 && !defined __linux__ + __asm fldcw word ptr [fpu_chop_cw] +#endif + +} + diff --git a/ref_soft/r_poly.c b/ref_soft/r_poly.c new file mode 100644 index 000000000..522f03cfd --- /dev/null +++ b/ref_soft/r_poly.c @@ -0,0 +1,1244 @@ +/* +Copyright (C) 1997-2001 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. + +*/ +#include +#include "r_local.h" + +#define AFFINE_SPANLET_SIZE 16 +#define AFFINE_SPANLET_SIZE_BITS 4 + +typedef struct +{ + byte *pbase, *pdest; + short *pz; + fixed16_t s, t; + fixed16_t sstep, tstep; + int izi, izistep, izistep_times_2; + int spancount; + unsigned u, v; +} spanletvars_t; + +spanletvars_t s_spanletvars; + +static int r_polyblendcolor; + +static espan_t *s_polygon_spans; + +polydesc_t r_polydesc; + +msurface_t *r_alpha_surfaces; + +extern int *r_turb_turb; + +static int clip_current; +vec5_t r_clip_verts[2][MAXWORKINGVERTS+2]; + +static int s_minindex, s_maxindex; + +static void R_DrawPoly( qboolean iswater ); + +/* +** R_DrawSpanletOpaque +*/ +void R_DrawSpanletOpaque( void ) +{ + unsigned btemp; + + do + { + unsigned ts, tt; + + ts = s_spanletvars.s >> 16; + tt = s_spanletvars.t >> 16; + + btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth); + if (btemp != 255) + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + *s_spanletvars.pz = s_spanletvars.izi >> 16; + *s_spanletvars.pdest = btemp; + } + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + } while (--s_spanletvars.spancount > 0); +} + +/* +** R_DrawSpanletTurbulentStipple33 +*/ +void R_DrawSpanletTurbulentStipple33( void ) +{ + unsigned btemp; + int sturb, tturb; + byte *pdest = s_spanletvars.pdest; + short *pz = s_spanletvars.pz; + int izi = s_spanletvars.izi; + + if ( s_spanletvars.v & 1 ) + { + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + if ( s_spanletvars.u & 1 ) + { + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + s_spanletvars.spancount--; + } + + s_spanletvars.sstep *= 2; + s_spanletvars.tstep *= 2; + + while ( s_spanletvars.spancount > 0 ) + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + + izi += s_spanletvars.izistep_times_2; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest += 2; + pz += 2; + + s_spanletvars.spancount -= 2; + } + } +} + +/* +** R_DrawSpanletTurbulentStipple66 +*/ +void R_DrawSpanletTurbulentStipple66( void ) +{ + unsigned btemp; + int sturb, tturb; + byte *pdest = s_spanletvars.pdest; + short *pz = s_spanletvars.pz; + int izi = s_spanletvars.izi; + + if ( !( s_spanletvars.v & 1 ) ) + { + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + if ( s_spanletvars.u & 1 ) + { + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + s_spanletvars.spancount--; + } + + s_spanletvars.sstep *= 2; + s_spanletvars.tstep *= 2; + + while ( s_spanletvars.spancount > 0 ) + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + + izi += s_spanletvars.izistep_times_2; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest += 2; + pz += 2; + + s_spanletvars.spancount -= 2; + } + } + else + { + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + while ( s_spanletvars.spancount > 0 ) + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + + s_spanletvars.spancount--; + } + } +} + +/* +** R_DrawSpanletTurbulentBlended +*/ +void R_DrawSpanletTurbulentBlended66( void ) +{ + unsigned btemp; + int sturb, tturb; + + do + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) ) + *s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest]; + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + } while ( --s_spanletvars.spancount > 0 ); +} + +void R_DrawSpanletTurbulentBlended33( void ) +{ + unsigned btemp; + int sturb, tturb; + + do + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) ) + *s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256]; + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + } while ( --s_spanletvars.spancount > 0 ); +} + +/* +** R_DrawSpanlet33 +*/ +void R_DrawSpanlet33( void ) +{ + unsigned btemp; + + do + { + unsigned ts, tt; + + ts = s_spanletvars.s >> 16; + tt = s_spanletvars.t >> 16; + + btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth); + + if ( btemp != 255 ) + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + *s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256]; + } + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + } while (--s_spanletvars.spancount > 0); +} + +void R_DrawSpanletConstant33( void ) +{ + do + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + *s_spanletvars.pdest = vid.alphamap[r_polyblendcolor+*s_spanletvars.pdest*256]; + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + } while (--s_spanletvars.spancount > 0); +} + +/* +** R_DrawSpanlet66 +*/ +void R_DrawSpanlet66( void ) +{ + unsigned btemp; + + do + { + unsigned ts, tt; + + ts = s_spanletvars.s >> 16; + tt = s_spanletvars.t >> 16; + + btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth); + + if ( btemp != 255 ) + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + *s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest]; + } + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + } while (--s_spanletvars.spancount > 0); +} + +/* +** R_DrawSpanlet33Stipple +*/ +void R_DrawSpanlet33Stipple( void ) +{ + unsigned btemp; + byte *pdest = s_spanletvars.pdest; + short *pz = s_spanletvars.pz; + int izi = s_spanletvars.izi; + + if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) ) + { + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) ) + { + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + s_spanletvars.spancount--; + } + + s_spanletvars.sstep *= 2; + s_spanletvars.tstep *= 2; + + while ( s_spanletvars.spancount > 0 ) + { + unsigned s = s_spanletvars.s >> 16; + unsigned t = s_spanletvars.t >> 16; + + btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) ); + + if ( btemp != 255 ) + { + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + } + + izi += s_spanletvars.izistep_times_2; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest += 2; + pz += 2; + + s_spanletvars.spancount -= 2; + } + } +} + +/* +** R_DrawSpanlet66Stipple +*/ +void R_DrawSpanlet66Stipple( void ) +{ + unsigned btemp; + byte *pdest = s_spanletvars.pdest; + short *pz = s_spanletvars.pz; + int izi = s_spanletvars.izi; + + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) ) + { + if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) ) + { + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + s_spanletvars.spancount--; + } + + s_spanletvars.sstep *= 2; + s_spanletvars.tstep *= 2; + + while ( s_spanletvars.spancount > 0 ) + { + unsigned s = s_spanletvars.s >> 16; + unsigned t = s_spanletvars.t >> 16; + + btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) ); + + if ( btemp != 255 ) + { + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + } + + izi += s_spanletvars.izistep_times_2; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest += 2; + pz += 2; + + s_spanletvars.spancount -= 2; + } + } + else + { + while ( s_spanletvars.spancount > 0 ) + { + unsigned s = s_spanletvars.s >> 16; + unsigned t = s_spanletvars.t >> 16; + + btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) ); + + if ( btemp != 255 ) + { + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + } + + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + + s_spanletvars.spancount--; + } + } +} + +/* +** R_ClipPolyFace +** +** Clips the winding at clip_verts[clip_current] and changes clip_current +** Throws out the back side +*/ +int R_ClipPolyFace (int nump, clipplane_t *pclipplane) +{ + int i, outcount; + float dists[MAXWORKINGVERTS+3]; + float frac, clipdist, *pclipnormal; + float *in, *instep, *outstep, *vert2; + + clipdist = pclipplane->dist; + pclipnormal = pclipplane->normal; + +// calc dists + if (clip_current) + { + in = r_clip_verts[1][0]; + outstep = r_clip_verts[0][0]; + clip_current = 0; + } + else + { + in = r_clip_verts[0][0]; + outstep = r_clip_verts[1][0]; + clip_current = 1; + } + + instep = in; + for (i=0 ; i= 0) + { + memcpy (outstep, instep, sizeof (vec5_t)); + outstep += sizeof (vec5_t) / sizeof (float); + outcount++; + } + + if (dists[i] == 0 || dists[i+1] == 0) + continue; + + if ( (dists[i] > 0) == (dists[i+1] > 0) ) + continue; + + // split it into a new vertex + frac = dists[i] / (dists[i] - dists[i+1]); + + vert2 = instep + sizeof (vec5_t) / sizeof (float); + + outstep[0] = instep[0] + frac*(vert2[0] - instep[0]); + outstep[1] = instep[1] + frac*(vert2[1] - instep[1]); + outstep[2] = instep[2] + frac*(vert2[2] - instep[2]); + outstep[3] = instep[3] + frac*(vert2[3] - instep[3]); + outstep[4] = instep[4] + frac*(vert2[4] - instep[4]); + + outstep += sizeof (vec5_t) / sizeof (float); + outcount++; + } + + return outcount; +} + +/* +** R_PolygonDrawSpans +*/ +void R_PolygonDrawSpans(espan_t *pspan, qboolean iswater ) +{ + int count; + fixed16_t snext, tnext; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivzspanletstepu, tdivzspanletstepu, zispanletstepu; + + s_spanletvars.pbase = cacheblock; + + if ( iswater ) + r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1)); + + sdivzspanletstepu = d_sdivzstepu * AFFINE_SPANLET_SIZE; + tdivzspanletstepu = d_tdivzstepu * AFFINE_SPANLET_SIZE; + zispanletstepu = d_zistepu * AFFINE_SPANLET_SIZE; + +// we count on FP exceptions being turned off to avoid range problems + s_spanletvars.izistep = (int)(d_zistepu * 0x8000 * 0x10000); + s_spanletvars.izistep_times_2 = s_spanletvars.izistep * 2; + + s_spanletvars.pz = 0; + + do + { + s_spanletvars.pdest = (byte *)d_viewbuffer + ( d_scantable[pspan->v] /*r_screenwidth * pspan->v*/) + pspan->u; + s_spanletvars.pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u; + s_spanletvars.u = pspan->u; + s_spanletvars.v = pspan->v; + + count = pspan->count; + + if (count <= 0) + goto NextSpan; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + // we count on FP exceptions being turned off to avoid range problems + s_spanletvars.izi = (int)(zi * 0x8000 * 0x10000); + + s_spanletvars.s = (int)(sdivz * z) + sadjust; + s_spanletvars.t = (int)(tdivz * z) + tadjust; + + if ( !iswater ) + { + if (s_spanletvars.s > bbextents) + s_spanletvars.s = bbextents; + else if (s_spanletvars.s < 0) + s_spanletvars.s = 0; + + if (s_spanletvars.t > bbextentt) + s_spanletvars.t = bbextentt; + else if (s_spanletvars.t < 0) + s_spanletvars.t = 0; + } + + do + { + // calculate s and t at the far end of the span + if (count >= AFFINE_SPANLET_SIZE ) + s_spanletvars.spancount = AFFINE_SPANLET_SIZE; + else + s_spanletvars.spancount = count; + + count -= s_spanletvars.spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivzspanletstepu; + tdivz += tdivzspanletstepu; + zi += zispanletstepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + tnext = (int)(tdivz * z) + tadjust; + + if ( !iswater ) + { + if (snext > bbextents) + snext = bbextents; + else if (snext < AFFINE_SPANLET_SIZE) + snext = AFFINE_SPANLET_SIZE; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < AFFINE_SPANLET_SIZE) + tnext = AFFINE_SPANLET_SIZE; // guard against round-off error on <0 steps + } + + s_spanletvars.sstep = (snext - s_spanletvars.s) >> AFFINE_SPANLET_SIZE_BITS; + s_spanletvars.tstep = (tnext - s_spanletvars.t) >> AFFINE_SPANLET_SIZE_BITS; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(s_spanletvars.spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + tnext = (int)(tdivz * z) + tadjust; + + if ( !iswater ) + { + if (snext > bbextents) + snext = bbextents; + else if (snext < AFFINE_SPANLET_SIZE) + snext = AFFINE_SPANLET_SIZE; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < AFFINE_SPANLET_SIZE) + tnext = AFFINE_SPANLET_SIZE; // guard against round-off error on <0 steps + } + + if (s_spanletvars.spancount > 1) + { + s_spanletvars.sstep = (snext - s_spanletvars.s) / (s_spanletvars.spancount - 1); + s_spanletvars.tstep = (tnext - s_spanletvars.t) / (s_spanletvars.spancount - 1); + } + } + + if ( iswater ) + { + s_spanletvars.s = s_spanletvars.s & ((CYCLE<<16)-1); + s_spanletvars.t = s_spanletvars.t & ((CYCLE<<16)-1); + } + + r_polydesc.drawspanlet(); + + s_spanletvars.s = snext; + s_spanletvars.t = tnext; + + } while (count > 0); + +NextSpan: + pspan++; + + } while (pspan->count != DS_SPAN_LIST_END); +} + +/* +** +** R_PolygonScanLeftEdge +** +** Goes through the polygon and scans the left edge, filling in +** screen coordinate data for the spans +*/ +void R_PolygonScanLeftEdge (void) +{ + int i, v, itop, ibottom, lmaxindex; + emitpoint_t *pvert, *pnext; + espan_t *pspan; + float du, dv, vtop, vbottom, slope; + fixed16_t u, u_step; + + pspan = s_polygon_spans; + i = s_minindex; + if (i == 0) + i = r_polydesc.nump; + + lmaxindex = s_maxindex; + if (lmaxindex == 0) + lmaxindex = r_polydesc.nump; + + vtop = ceil (r_polydesc.pverts[i].v); + + do + { + pvert = &r_polydesc.pverts[i]; + pnext = pvert - 1; + + vbottom = ceil (pnext->v); + + if (vtop < vbottom) + { + du = pnext->u - pvert->u; + dv = pnext->v - pvert->v; + + slope = du / dv; + u_step = (int)(slope * 0x10000); + // adjust u to ceil the integer portion + u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) + + (0x10000 - 1); + itop = (int)vtop; + ibottom = (int)vbottom; + + for (v=itop ; vu = u >> 16; + pspan->v = v; + u += u_step; + pspan++; + } + } + + vtop = vbottom; + + i--; + if (i == 0) + i = r_polydesc.nump; + + } while (i != lmaxindex); +} + +/* +** R_PolygonScanRightEdge +** +** Goes through the polygon and scans the right edge, filling in +** count values. +*/ +void R_PolygonScanRightEdge (void) +{ + int i, v, itop, ibottom; + emitpoint_t *pvert, *pnext; + espan_t *pspan; + float du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext; + fixed16_t u, u_step; + + pspan = s_polygon_spans; + i = s_minindex; + + vvert = r_polydesc.pverts[i].v; + if (vvert < r_refdef.fvrecty_adj) + vvert = r_refdef.fvrecty_adj; + if (vvert > r_refdef.fvrectbottom_adj) + vvert = r_refdef.fvrectbottom_adj; + + vtop = ceil (vvert); + + do + { + pvert = &r_polydesc.pverts[i]; + pnext = pvert + 1; + + vnext = pnext->v; + if (vnext < r_refdef.fvrecty_adj) + vnext = r_refdef.fvrecty_adj; + if (vnext > r_refdef.fvrectbottom_adj) + vnext = r_refdef.fvrectbottom_adj; + + vbottom = ceil (vnext); + + if (vtop < vbottom) + { + uvert = pvert->u; + if (uvert < r_refdef.fvrectx_adj) + uvert = r_refdef.fvrectx_adj; + if (uvert > r_refdef.fvrectright_adj) + uvert = r_refdef.fvrectright_adj; + + unext = pnext->u; + if (unext < r_refdef.fvrectx_adj) + unext = r_refdef.fvrectx_adj; + if (unext > r_refdef.fvrectright_adj) + unext = r_refdef.fvrectright_adj; + + du = unext - uvert; + dv = vnext - vvert; + slope = du / dv; + u_step = (int)(slope * 0x10000); + // adjust u to ceil the integer portion + u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) + + (0x10000 - 1); + itop = (int)vtop; + ibottom = (int)vbottom; + + for (v=itop ; vcount = (u >> 16) - pspan->u; + u += u_step; + pspan++; + } + } + + vtop = vbottom; + vvert = vnext; + + i++; + if (i == r_polydesc.nump) + i = 0; + + } while (i != s_maxindex); + + pspan->count = DS_SPAN_LIST_END; // mark the end of the span list +} + +/* +** R_ClipAndDrawPoly +*/ +void R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured ) +{ + emitpoint_t outverts[MAXWORKINGVERTS+3], *pout; + float *pv; + int i, nump; + float scale; + vec3_t transformed, local; + + if ( !textured ) + { + r_polydesc.drawspanlet = R_DrawSpanletConstant33; + } + else + { + + /* + ** choose the correct spanlet routine based on alpha + */ + if ( alpha == 1 ) + { + // isturbulent is ignored because we know that turbulent surfaces + // can't be opaque + r_polydesc.drawspanlet = R_DrawSpanletOpaque; + } + else + { + if ( sw_stipplealpha->value ) + { + if ( isturbulent ) + { + if ( alpha > 0.33 ) + r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple66; + else + r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple33; + } + else + { + if ( alpha > 0.33 ) + r_polydesc.drawspanlet = R_DrawSpanlet66Stipple; + else + r_polydesc.drawspanlet = R_DrawSpanlet33Stipple; + } + } + else + { + if ( isturbulent ) + { + if ( alpha > 0.33 ) + r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended66; + else + r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended33; + } + else + { + if ( alpha > 0.33 ) + r_polydesc.drawspanlet = R_DrawSpanlet66; + else + r_polydesc.drawspanlet = R_DrawSpanlet33; + } + } + } + } + + // clip to the frustum in worldspace + nump = r_polydesc.nump; + clip_current = 0; + + for (i=0 ; i<4 ; i++) + { + nump = R_ClipPolyFace (nump, &view_clipplanes[i]); + if (nump < 3) + return; + if (nump > MAXWORKINGVERTS) + ri.Sys_Error(ERR_DROP, "R_ClipAndDrawPoly: too many points: %d", nump ); + } + +// transform vertices into viewspace and project + pv = &r_clip_verts[clip_current][0][0]; + + for (i=0 ; izi = 1.0 / transformed[2]; + + pout->s = pv[3]; + pout->t = pv[4]; + + scale = xscale * pout->zi; + pout->u = (xcenter + scale * transformed[0]); + + scale = yscale * pout->zi; + pout->v = (ycenter - scale * transformed[1]); + + pv += sizeof (vec5_t) / sizeof (pv); + } + +// draw it + r_polydesc.nump = nump; + r_polydesc.pverts = outverts; + + R_DrawPoly( isturbulent ); +} + +/* +** R_BuildPolygonFromSurface +*/ +void R_BuildPolygonFromSurface(msurface_t *fa) +{ + int i, lindex, lnumverts; + medge_t *pedges, *r_pedge; + int vertpage; + float *vec; + vec5_t *pverts; + float tmins[2] = { 0, 0 }; + + r_polydesc.nump = 0; + + // reconstruct the polygon + pedges = currentmodel->edges; + lnumverts = fa->numedges; + vertpage = 0; + + pverts = r_clip_verts[0]; + + for (i=0 ; isurfedges[fa->firstedge + i]; + + if (lindex > 0) + { + r_pedge = &pedges[lindex]; + vec = currentmodel->vertexes[r_pedge->v[0]].position; + } + else + { + r_pedge = &pedges[-lindex]; + vec = currentmodel->vertexes[r_pedge->v[1]].position; + } + + VectorCopy (vec, pverts[i] ); + } + + VectorCopy( fa->texinfo->vecs[0], r_polydesc.vright ); + VectorCopy( fa->texinfo->vecs[1], r_polydesc.vup ); + VectorCopy( fa->plane->normal, r_polydesc.vpn ); + VectorCopy( r_origin, r_polydesc.viewer_position ); + + if ( fa->flags & SURF_PLANEBACK ) + { + VectorSubtract( vec3_origin, r_polydesc.vpn, r_polydesc.vpn ); + } + + if ( fa->texinfo->flags & SURF_WARP ) + { + r_polydesc.pixels = fa->texinfo->image->pixels[0]; + r_polydesc.pixel_width = fa->texinfo->image->width; + r_polydesc.pixel_height = fa->texinfo->image->height; + } + else + { + surfcache_t *scache; + + scache = D_CacheSurface( fa, 0 ); + + r_polydesc.pixels = scache->data; + r_polydesc.pixel_width = scache->width; + r_polydesc.pixel_height = scache->height; + + tmins[0] = fa->texturemins[0]; + tmins[1] = fa->texturemins[1]; + } + + r_polydesc.dist = DotProduct( r_polydesc.vpn, pverts[0] ); + + r_polydesc.s_offset = fa->texinfo->vecs[0][3] - tmins[0]; + r_polydesc.t_offset = fa->texinfo->vecs[1][3] - tmins[1]; + + // scrolling texture addition + if (fa->texinfo->flags & SURF_FLOWING) + { + r_polydesc.s_offset += -128 * ( (r_newrefdef.time*0.25) - (int)(r_newrefdef.time*0.25) ); + } + + r_polydesc.nump = lnumverts; +} + +/* +** R_PolygonCalculateGradients +*/ +void R_PolygonCalculateGradients (void) +{ + vec3_t p_normal, p_saxis, p_taxis; + float distinv; + + TransformVector (r_polydesc.vpn, p_normal); + TransformVector (r_polydesc.vright, p_saxis); + TransformVector (r_polydesc.vup, p_taxis); + + distinv = 1.0 / (-(DotProduct (r_polydesc.viewer_position, r_polydesc.vpn)) + r_polydesc.dist ); + + d_sdivzstepu = p_saxis[0] * xscaleinv; + d_sdivzstepv = -p_saxis[1] * yscaleinv; + d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu - ycenter * d_sdivzstepv; + + d_tdivzstepu = p_taxis[0] * xscaleinv; + d_tdivzstepv = -p_taxis[1] * yscaleinv; + d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu - ycenter * d_tdivzstepv; + + d_zistepu = p_normal[0] * xscaleinv * distinv; + d_zistepv = -p_normal[1] * yscaleinv * distinv; + d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu - ycenter * d_zistepv; + + sadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vright) + r_polydesc.s_offset ) * 0x10000 ); + tadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vup ) + r_polydesc.t_offset ) * 0x10000 ); + +// -1 (-epsilon) so we never wander off the edge of the texture + bbextents = (r_polydesc.pixel_width << 16) - 1; + bbextentt = (r_polydesc.pixel_height << 16) - 1; +} + +/* +** R_DrawPoly +** +** Polygon drawing function. Uses the polygon described in r_polydesc +** to calculate edges and gradients, then renders the resultant spans. +** +** This should NOT be called externally since it doesn't do clipping! +*/ +static void R_DrawPoly( qboolean iswater ) +{ + int i, nump; + float ymin, ymax; + emitpoint_t *pverts; + espan_t spans[MAXHEIGHT+1]; + + s_polygon_spans = spans; + +// find the top and bottom vertices, and make sure there's at least one scan to +// draw + ymin = 999999.9; + ymax = -999999.9; + pverts = r_polydesc.pverts; + + for (i=0 ; iv < ymin) + { + ymin = pverts->v; + s_minindex = i; + } + + if (pverts->v > ymax) + { + ymax = pverts->v; + s_maxindex = i; + } + + pverts++; + } + + ymin = ceil (ymin); + ymax = ceil (ymax); + + if (ymin >= ymax) + return; // doesn't cross any scans at all + + cachewidth = r_polydesc.pixel_width; + cacheblock = r_polydesc.pixels; + +// copy the first vertex to the last vertex, so we don't have to deal with +// wrapping + nump = r_polydesc.nump; + pverts = r_polydesc.pverts; + pverts[nump] = pverts[0]; + + R_PolygonCalculateGradients (); + R_PolygonScanLeftEdge (); + R_PolygonScanRightEdge (); + + R_PolygonDrawSpans( s_polygon_spans, iswater ); +} + +/* +** R_DrawAlphaSurfaces +*/ +void R_DrawAlphaSurfaces( void ) +{ + msurface_t *s = r_alpha_surfaces; + + currentmodel = r_worldmodel; + + modelorg[0] = -r_origin[0]; + modelorg[1] = -r_origin[1]; + modelorg[2] = -r_origin[2]; + + while ( s ) + { + R_BuildPolygonFromSurface( s ); + + if (s->texinfo->flags & SURF_TRANS66) + R_ClipAndDrawPoly( 0.60f, ( s->texinfo->flags & SURF_WARP) != 0, true ); + else + R_ClipAndDrawPoly( 0.30f, ( s->texinfo->flags & SURF_WARP) != 0, true ); + + s = s->nextalphasurface; + } + + r_alpha_surfaces = NULL; +} + +/* +** R_IMFlatShadedQuad +*/ +void R_IMFlatShadedQuad( vec3_t a, vec3_t b, vec3_t c, vec3_t d, int color, float alpha ) +{ + vec3_t s0, s1; + + r_polydesc.nump = 4; + VectorCopy( r_origin, r_polydesc.viewer_position ); + + VectorCopy( a, r_clip_verts[0][0] ); + VectorCopy( b, r_clip_verts[0][1] ); + VectorCopy( c, r_clip_verts[0][2] ); + VectorCopy( d, r_clip_verts[0][3] ); + + r_clip_verts[0][0][3] = 0; + r_clip_verts[0][1][3] = 0; + r_clip_verts[0][2][3] = 0; + r_clip_verts[0][3][3] = 0; + + r_clip_verts[0][0][4] = 0; + r_clip_verts[0][1][4] = 0; + r_clip_verts[0][2][4] = 0; + r_clip_verts[0][3][4] = 0; + + VectorSubtract( d, c, s0 ); + VectorSubtract( c, b, s1 ); + CrossProduct( s0, s1, r_polydesc.vpn ); + VectorNormalize( r_polydesc.vpn ); + + r_polydesc.dist = DotProduct( r_polydesc.vpn, r_clip_verts[0][0] ); + + r_polyblendcolor = color; + + R_ClipAndDrawPoly( alpha, false, false ); +} +